def check_core_alteration(self, core_url: str) -> List[Alteration]: self.get_archive_name() alterations = [] temp_directory = uCMS.TempDir.create() LOGGER.print_cms("info", "[+] Checking core alteration", "", 0) try: response = requests.get(core_url) response.raise_for_status() if response.status_code == 200: zip_file = zipfile.ZipFile(io.BytesIO(response.content), "r") zip_file.extractall(temp_directory) zip_file.close() except requests.exceptions.HTTPError as e: LOGGER.print_cms( "alert", "[-] Unable to find the original archive. Search manually !", "", 0 ) self.core.alterations = alterations LOGGER.debug(str(e)) return self.core.alterations clean_core_path = os.path.join(temp_directory, Path(self.get_archive_name())) dcmp = dircmp(clean_core_path, self.dir_path, self.core.ignored_files) uCMS.diff_files(dcmp, alterations, self.dir_path) # type: ignore # ignore for "dcmp" variable self.core.alterations = alterations if alterations is not None: msg = "[+] For further analysis, archive downloaded here : " + clean_core_path LOGGER.print_cms("info", msg, "", 0) return self.core.alterations
def addon_analysis(self, addon_type: str) -> List[Addon]: temp_directory = uCMS.TempDir.create() addons = [] addons_path = "" LOGGER.print_cms( "info", "#######################################################" + "\n\t\t" + addon_type + " analysis" + "\n#######################################################", "", 0, ) # Get the list of addon to work with if addon_type == "plugins": addons_path = self.plugins_dir elif addon_type == "themes": addons_path = self.themes_dir addons_name = uCMS.fetch_addons( os.path.join(self.dir_path, addons_path), "standard") for addon_name in addons_name: addon = Addon() addon.type = addon_type addon.name = addon_name addon.filename = addon_name + self.addon_extension LOGGER.print_cms("info", "[+] " + addon_name, "", 0) addon_path = os.path.join(self.dir_path, addons_path, addon_name) try: # Get addon version self.get_addon_version(addon, addon_path, self.regex_version_addon, '"') # Check addon last version self.get_addon_last_version(addon) # Check if there are known CVE self.check_vulns_addon(addon) # Check if the addon have been altered self.check_addon_alteration(addon, addon_path, temp_directory) addons.append(addon) except Exception as e: LOGGER.debug(str(e)) addons.append(addon) pass if addon_type == "plugins": self.plugins = addons elif addon_type == "themes": self.themes = addons return addons
def check_addon_alteration(self, addon: Addon, addon_path: str, temp_directory: str) -> str: addon_url = self.get_addon_url(addon) LOGGER.print_cms("default", f"To download the addon: {addon_url}", "", 1) altered = "" try: response = requests.get(addon_url) response.raise_for_status() if response.status_code == 200: zip_file = zipfile.ZipFile(io.BytesIO(response.content), "r") zip_file.extractall(temp_directory) zip_file.close() project_dir_hash = dirhash(addon_path, "sha1") ref_dir = os.path.join(temp_directory, addon.name) ref_dir_hash = dirhash(ref_dir, "sha1") if project_dir_hash == ref_dir_hash: altered = "NO" LOGGER.print_cms("good", f"Different from sources : {altered}", "", 1) else: altered = "YES" LOGGER.print_cms("alert", f"Different from sources : {altered}", "", 1) dcmp = dircmp(addon_path, ref_dir, self.ignored_files_addon) uCMS.diff_files(dcmp, addon.alterations, addon_path) addon.altered = altered if addon.alterations is not None: LOGGER.print_cms( "info", f"[+] For further analysis, archive downloaded here : {ref_dir}", "", 1, ) except requests.exceptions.HTTPError as e: addon.notes = "The download link is not standard. Search manually !" LOGGER.print_cms("alert", addon.notes, "", 1) LOGGER.debug(str(e)) return addon.notes return altered
def detect_core_major_version(self) -> str: version_major = "" dpl_file_paths = { "8": "core/lib/Drupal.php", "7": "includes/bootstrap.inc" } for dpl_version, dpl_file_path in dpl_file_paths.items(): if os.path.isfile(os.path.join(self.dir_path, dpl_file_path)): version_major = dpl_version LOGGER.debug(version_major) return version_major
def get_core_last_version(self) -> str: """ Fetch information on last release """ url_release = self.get_url_release() try: response = requests.get(url_release) response.raise_for_status() if response.status_code == 200: self.last_version = self.extract_core_last_version(response) except requests.exceptions.HTTPError as e: LOGGER.print_cms("alert", "[-] Unable to retrieve last version. Search manually !", "", 1) LOGGER.debug(str(e)) pass return self.last_version
def get_core_version(self) -> str: suspects = [] try: with open( os.path.join(self.dir_path, self.core_suspect_file_path)) as version_file: for line in version_file: version_core_match = self.regex_version_core.search(line) if version_core_match: suspects.append(version_core_match.group(1).strip()) break except FileNotFoundError as e: LOGGER.debug(str(e)) pass suspects_length = len(suspects) if suspects_length == 0: LOGGER.print_cms("alert", "[-] Version not found. Search manually !", "", 0) return "" elif suspects_length == 1: LOGGER.print_cms("info", "[+] Version used : " + suspects[0], "", 0) self.core.version = suspects[0] self.core.version_major = suspects[0].split(".")[0] return suspects[0] else: for suspect in suspects: LOGGER.print_cms( "alert", "[-] Multiple versions found." + suspect + " You " "should probably check by yourself manually.", "", 0, ) return ""