def process_file(self, file_path, CAPE_output, append_file): """Process file. @return: file_info """ global cape_config cape_name = "" strings = [] buf = self.options.get("buffer", BUFSIZE) if file_path.endswith("_info.txt"): return texttypes = [ "ASCII", "Windows Registry text", "XML document text", "Unicode text", ] textchars = bytearray({7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7f}) is_binary_file = lambda bytes: bool(bytes.translate(None, textchars)) if os.path.exists(file_path + "_info.txt"): with open(file_path + "_info.txt", 'r') as f: metastring = f.readline() else: metastring = "" file_info = File(file_path, metastring).get_all() # Get the file data with open(file_info["path"], "r") as file_open: file_data = file_open.read(buf + 1) if is_binary_file(file_data[:8192]): file_info["data"] = None else: if len(file_data) > buf: file_info["data"] = convert_to_printable(file_data[:buf] + " <truncated>") else: file_info["data"] = convert_to_printable(file_data) metastrings = metastring.split(",") if len(metastrings) > 1: file_info["pid"] = metastrings[1] if len(metastrings) > 2: file_info["process_path"] = metastrings[2] file_info["process_name"] = metastrings[2].split("\\")[-1] if len(metastrings) > 3: file_info["module_path"] = metastrings[3] file_info["cape_type_code"] = 0 file_info["cape_type"] = "" if metastrings != "": try: file_info["cape_type_code"] = int(metastrings[0]) except Exception as e: pass if file_info["cape_type_code"] == COMPRESSION: file_info["cape_type"] = "Decompressed PE Image" if file_info["cape_type_code"] == INJECTION_PE: file_info["cape_type"] = "Injected PE Image" if len(metastrings) > 4: file_info["target_path"] = metastrings[4] file_info["target_process"] = metastrings[4].split( "\\")[-1] file_info["target_pid"] = metastrings[5] if file_info["cape_type_code"] == INJECTION_SHELLCODE: file_info["cape_type"] = "Injected Shellcode/Data" if len(metastrings) > 4: file_info["target_path"] = metastrings[4] file_info["target_process"] = metastrings[4].split( "\\")[-1] file_info["target_pid"] = metastrings[5] if file_info["cape_type_code"] == INJECTION_SECTION: file_info["cape_type"] = "Injected Section" if len(metastrings) > 4: file_info["section_handle"] = metastrings[4] if file_info["cape_type_code"] == EXTRACTION_PE: file_info["cape_type"] = "Extracted PE Image" if len(metastrings) > 4: file_info["virtual_address"] = metastrings[4] if file_info["cape_type_code"] == EXTRACTION_SHELLCODE: file_info["cape_type"] = "Extracted Shellcode" if len(metastrings) > 4: file_info["virtual_address"] = metastrings[4] type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" # PlugX if file_info["cape_type_code"] == PLUGX_CONFIG: file_info["cape_type"] = "PlugX Config" plugx_parser = plugx.PlugXConfig() plugx_config = plugx_parser.parse_config( file_data, len(file_data)) if not "cape_config" in cape_config and plugx_config: cape_config["cape_config"] = {} for key, value in plugx_config.items(): cape_config["cape_config"].update({key: [value]}) cape_name = "PlugX" else: log.error( "CAPE: PlugX config parsing failure - size many not be handled." ) append_file = False if file_info["cape_type_code"] == PLUGX_PAYLOAD: file_info["cape_type"] = "PlugX Payload" type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" # EvilGrab if file_info["cape_type_code"] == EVILGRAB_PAYLOAD: file_info["cape_type"] = "EvilGrab Payload" type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if file_info["cape_type_code"] == EVILGRAB_DATA: cape_name = "EvilGrab" file_info["cape_type"] = "EvilGrab Data" if not "cape_config" in cape_config: cape_config["cape_config"] = {} if file_info["size"] == 256 or file_info["size"] == 260: ConfigItem = "filepath" ConfigData = format(file_data) cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) if file_info["size"] > 0x1000: append_file = True else: append_file = False # Sedreco if file_info["cape_type_code"] == SEDRECO_DATA: cape_name = "Sedreco" cape_config["cape_type"] = "Sedreco Config" if not "cape_config" in cape_config: cape_config["cape_config"] = {} if len(metastrings) > 4: SedrecoConfigIndex = metastrings[4] if SedrecoConfigIndex == '0x0': ConfigItem = "Timer1" elif SedrecoConfigIndex == '0x1': ConfigItem = "Timer2" elif SedrecoConfigIndex == '0x2': ConfigItem = "Computer Name" elif SedrecoConfigIndex == '0x3': ConfigItem = "C&C1" elif SedrecoConfigIndex == '0x4': ConfigItem = "C&C2" elif SedrecoConfigIndex == '0x5': ConfigItem = "Operation Name" elif SedrecoConfigIndex == '0x6': ConfigItem = "Keylogger MaxBuffer" elif SedrecoConfigIndex == '0x7': ConfigItem = "Keylogger MaxTimeout" elif SedrecoConfigIndex == '0x8': ConfigItem = "Keylogger Flag" elif SedrecoConfigIndex == '0x9': ConfigItem = "C&C3" else: ConfigItem = "Unknown" ConfigData = format(file_data) if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) append_file = False # Cerber if file_info["cape_type_code"] == CERBER_CONFIG: file_info["cape_type"] = "Cerber Config" cape_config["cape_type"] = "Cerber Config" cape_name = "Cerber" if not "cape_config" in cape_config: cape_config["cape_config"] = {} ConfigItem = "JSON Data" parsed = json.loads(file_data.rstrip(b'\0')) ConfigData = json.dumps(parsed, indent=4, sort_keys=True) cape_config["cape_config"].update({ConfigItem: [ConfigData]}) append_file = True if file_info["cape_type_code"] == CERBER_PAYLOAD: file_info["cape_type"] = "Cerber Payload" cape_config["cape_type"] = "Cerber Payload" cape_name = "Cerber" type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" append_file = True # Ursnif if file_info["cape_type_code"] == URSNIF_CONFIG: file_info["cape_type"] = "Ursnif Config" cape_config["cape_type"] = "Ursnif Config" cape_name = "Ursnif" malwareconfig_loaded = False try: malwareconfig_parsers = os.path.join( CUCKOO_ROOT, "modules", "processing", "parsers", "malwareconfig") file, pathname, description = imp.find_module( cape_name, [malwareconfig_parsers]) module = imp.load_module(cape_name, file, pathname, description) malwareconfig_loaded = True log.info("CAPE: Imported malwareconfig.com parser %s", cape_name) except ImportError: log.info( "CAPE: malwareconfig.com parser: No module named %s", cape_name) if malwareconfig_loaded: try: if not "cape_config" in cape_config: cape_config["cape_config"] = {} malwareconfig_config = module.config(file_data) if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].iteritems(): cape_config["cape_config"].update( {key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.iteritems(): cape_config["cape_config"].update( {key: [value]}) except Exception as e: log.error( "CAPE: malwareconfig parsing error with %s: %s", cape_name, e) append_file = False # Hancitor if file_info["cape_type_code"] == HANCITOR_PAYLOAD: cape_name = "Hancitor" cape_config["cape_type"] = "Hancitor Payload" file_info["cape_type"] = "Hancitor Payload" if file_info["cape_type_code"] == HANCITOR_CONFIG: cape_name = "Hancitor" cape_config["cape_type"] = "Hancitor Config" file_info["cape_type"] = "Hancitor Config" if not "cape_config" in cape_config: cape_config["cape_config"] = {} ConfigStrings = file_data.split('\0') ConfigStrings = filter(None, ConfigStrings) ConfigItem = "Campaign Code" cape_config["cape_config"].update( {ConfigItem: [ConfigStrings[0]]}) GateURLs = ConfigStrings[1].split('|') for index, value in enumerate(GateURLs): ConfigItem = "Gate URL " + str(index + 1) cape_config["cape_config"].update({ConfigItem: [value]}) append_file = False # QakBot if file_info["cape_type_code"] == QAKBOT_CONFIG: file_info["cape_type"] = "QakBot Config" cape_config["cape_type"] = "QakBot Config" cape_name = "QakBot" if not "cape_config" in cape_config: cape_config["cape_config"] = {} for line in file_data.splitlines(): if '=' in line: index = line.split('=')[0] data = line.split('=')[1] if index == '10': ConfigItem = "Botnet name" ConfigData = data if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) if index == '11': ConfigItem = "Number of C2 servers" ConfigData = data if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) if index == '47': ConfigItem = "Bot ID" ConfigData = data if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) if index == '3': ConfigItem = "Config timestamp" ConfigData = datetime.datetime.fromtimestamp( int(data)).strftime('%H:%M:%S %d-%m-%Y') if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) if index == '22': values = data.split(':') ConfigItem = "Password #1" try: ConfigData = values[2] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "Username #1" try: ConfigData = values[1] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "C2 #1" try: ConfigData = values[0] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass if index == '23': values = data.split(':') ConfigItem = "Password #2" try: ConfigData = values[2] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "Username #2" try: ConfigData = values[1] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "C2 #2" try: ConfigData = values[0] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass if index == '24': values = data.split(':') ConfigItem = "Password #3" try: ConfigData = values[2] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "Username #3" try: ConfigData = values[1] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "C2 #3" try: ConfigData = values[0] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass if index == '25': values = data.split(':') ConfigItem = "Password #4" try: ConfigData = values[2] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "Username #4" try: ConfigData = values[1] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "C2 #4" try: ConfigData = values[0] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass if index == '26': values = data.split(':') ConfigItem = "Password #5" try: ConfigData = values[2] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "Username #5" try: ConfigData = values[1] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass ConfigItem = "C2 #5" try: ConfigData = values[0] if ConfigData: cape_config["cape_config"].update( {ConfigItem: [ConfigData]}) except: pass append_file = False if file_info["cape_type_code"] == QAKBOT_PAYLOAD: file_info["cape_type"] = "QakBot Payload" cape_config["cape_type"] = "QakBot Payload" cape_name = "QakBot" type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" append_file = True # UPX package output if file_info["cape_type_code"] == UPX: file_info["cape_type"] = "Unpacked PE Image" type_strings = file_info["type"].split() if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" # Attempt to decrypt script dump if file_info["cape_type_code"] == SCRIPT_DUMP: data = file_data.decode("utf-16").replace("\x00", "") file_info["data"] = data cape_name = "ScriptDump" malwareconfig_loaded = False try: malwareconfig_parsers = os.path.join( CUCKOO_ROOT, "modules", "processing", "parsers", "malwareconfig") file, pathname, description = imp.find_module( cape_name, [malwareconfig_parsers]) module = imp.load_module(cape_name, file, pathname, description) malwareconfig_loaded = True log.info("CAPE: Imported malwareconfig.com parser %s", cape_name) except ImportError: log.info( "CAPE: malwareconfig.com parser: No module named %s", cape_name) if malwareconfig_loaded: try: script_data = module.config(self, data) if script_data and "more_eggs" in script_data["type"]: bindata = script_data["data"] sha256 = hashlib.sha256(bindata).hexdigest() filepath = os.path.join(self.CAPE_path, sha256) tmpstr = file_info["pid"] tmpstr += "," + file_info["process_path"] tmpstr += "," + file_info["module_path"] if "text" in script_data["datatype"]: file_info["cape_type"] = "MoreEggsJS" outstr = str( MOREEGGSJS_PAYLOAD) + "," + tmpstr + "\n" with open(filepath + "_info.txt", "w") as infofd: infofd.write(outstr) with open(filepath, 'w') as cfile: cfile.write(bindata) elif "binary" in script_data["datatype"]: file_info["cape_type"] = "MoreEggsBin" outstr = str( MOREEGGSBIN_PAYLOAD) + "," + tmpstr + "\n" with open(filepath + "_info.txt", "w") as infofd: infofd.write(outstr) with open(filepath, 'wb') as cfile: cfile.write(bindata) if os.path.exists(filepath): self.script_dump_files.append(filepath) else: file_info["cape_type"] = "Script Dump" log.info( "CAPE: Script Dump does not contain known encrypted payload." ) except Exception as e: log.error( "CAPE: malwareconfig parsing error with %s: %s", cape_name, e) append_file = True # More_Eggs if file_info["cape_type_code"] == MOREEGGSJS_PAYLOAD: file_info["cape_type"] = "More Eggs JS Payload" cape_name = "MoreEggs" append_file = True if file_info["cape_type_code"] == MOREEGGSBIN_PAYLOAD: file_info["cape_type"] = "More_Eggs Binary Payload" cape_name = "MoreEggs" type_strings = file_info["type"].split() if type_strings[0] == "PE32+": file_info["cape_type"] += ": 64-bit " if type_strings[2] == "(DLL)": file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == "PE32": file_info["cape_type"] += ": 32-bit " if type_strings[2] == "(DLL)": file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" append_file = True # Process CAPE Yara hits for hit in file_info["cape_yara"]: # Check to see if file is packed with UPX if hit["name"] == "UPX": log.info( "CAPE: Found UPX Packed sample - attempting to unpack") self.upx_unpack(file_data, CAPE_output) # Check for a payload or config hit extraction_types = ["payload", "config", "loader"] try: for type in extraction_types: if type in hit["meta"]["cape_type"].lower(): file_info["cape_type"] = hit["meta"]["cape_type"] cape_name = hit["name"].replace('_', ' ') except: pass type_strings = file_info["type"].split() if "-bit" not in file_info["cape_type"]: if type_strings[0] == ("PE32+"): file_info["cape_type"] += ": 64-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" if type_strings[0] == ("PE32"): file_info["cape_type"] += ": 32-bit " if type_strings[2] == ("(DLL)"): file_info["cape_type"] += "DLL" else: file_info["cape_type"] += "executable" suppress_parsing_list = [ "Cerber", "Emotet_Payload", "Ursnif", "QakBot" ] if hit["name"] in suppress_parsing_list: continue # Attempt to import a parser for the hit # DC3-MWCP mwcp_loaded = False if cape_name: try: mwcp_parsers = os.path.join(CUCKOO_ROOT, "modules", "processing", "parsers", "mwcp", "parsers") mwcp = reporter.Reporter(parserdir=mwcp_parsers) kwargs = {} mwcp.run_parser(cape_name, data=file_data, **kwargs) if mwcp.errors == []: log.info("CAPE: Imported DC3-MWCP parser %s", cape_name) mwcp_loaded = True else: error_lines = mwcp.errors[0].split("\n") for line in error_lines: if line.startswith('ImportError: '): log.info("CAPE: DC3-MWCP parser: %s", line.split(': ')[1]) except ImportError: pass # malwareconfig malwareconfig_loaded = False if cape_name and mwcp_loaded == False: try: malwareconfig_parsers = os.path.join( CUCKOO_ROOT, "modules", "processing", "parsers", "malwareconfig") file, pathname, description = imp.find_module( cape_name, [malwareconfig_parsers]) module = imp.load_module(cape_name, file, pathname, description) malwareconfig_loaded = True log.info("CAPE: Imported malwareconfig.com parser %s", cape_name) except ImportError: log.info( "CAPE: malwareconfig.com parser: No module named %s", cape_name) # Get config data if mwcp_loaded: try: if not "cape_config" in cape_config: cape_config["cape_config"] = {} cape_config["cape_config"] = convert(mwcp.metadata) else: cape_config["cape_config"].update( convert(mwcp.metadata)) except Exception as e: log.error( "CAPE: DC3-MWCP config parsing error with %s: %s", cape_name, e) elif malwareconfig_loaded: try: if not "cape_config" in cape_config: cape_config["cape_config"] = {} malwareconfig_config = module.config(file_data) if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].iteritems(): cape_config["cape_config"].update({key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.iteritems(): cape_config["cape_config"].update({key: [value]}) except Exception as e: log.error("CAPE: malwareconfig parsing error with %s: %s", cape_name, e) if "cape_config" in cape_config: if cape_config["cape_config"] == {}: del cape_config["cape_config"] if cape_name: if "cape_config" in cape_config and "cape_name" not in cape_config: cape_config["cape_name"] = format(cape_name) if not "cape" in self.results: if cape_name != "UPX": self.results["cape"] = cape_name # Remove duplicate payloads from web ui for cape_file in CAPE_output: if file_info["size"] == cape_file["size"]: if HAVE_PYDEEP: ssdeep_grade = pydeep.compare(file_info["ssdeep"], cape_file["ssdeep"]) if ssdeep_grade >= ssdeep_threshold: append_file = False if file_info["entrypoint"] and file_info["entrypoint"] == cape_file["entrypoint"] \ and file_info["ep_bytes"] == cape_file["ep_bytes"]: append_file = False if append_file == True: CAPE_output.append(file_info) return file_info
def static_config_parsers(yara_hit, file_data, cape_config): # Process CAPE Yara hits cape_name = yara_hit.replace('_', ' ') # Attempt to import a parser for the hit # DC3-MWCP mwcp_loaded = False if cape_name: try: mwcp_parsers = os.path.join(CUCKOO_ROOT, "modules", "processing", "parsers", "mwcp", "parsers") mwcp = reporter.Reporter(parserdir=mwcp_parsers) kwargs = {} mwcp.run_parser(cape_name, data=file_data, **kwargs) if mwcp.errors == []: log.info("CAPE: Imported DC3-MWCP parser %s", cape_name) mwcp_loaded = True else: error_lines = mwcp.errors[0].split("\n") for line in error_lines: if line.startswith('ImportError: '): log.info("CAPE: DC3-MWCP parser: %s", line.split(': ')[1]) except ImportError as e: log.error(e) # malwareconfig malwareconfig_loaded = False if mwcp_loaded is False: try: malwareconfig_parsers = os.path.join(CUCKOO_ROOT, "modules", "processing", "parsers", "malwareconfig") file, pathname, description = imp.find_module( cape_name, [malwareconfig_parsers]) module = imp.load_module(cape_name, file, pathname, description) malwareconfig_loaded = True log.info("CAPE: Imported malwareconfig.com parser %s", cape_name) except ImportError: log.info("CAPE: malwareconfig.com parser: No module named %s", cape_name) # Get config data if mwcp_loaded: try: if not "cape_config" in cape_config: cape_config["cape_config"] = {} cape_config["cape_config"] = convert(mwcp.metadata) else: new = convert(mwcp.metadata) if new != cape_config["cape_config"]: for key in new.keys(): cape_config["cape_config"][key] = list( set(cape_config["cape_config"][key] + new[key])) except Exception as e: log.error("CAPE: DC3-MWCP config parsing error with %s: %s", cape_name, e) elif malwareconfig_loaded: try: if not "cape_config" in cape_config: cape_config["cape_config"] = {} malwareconfig_config = module.config(file_data) if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].iteritems(): cape_config["cape_config"].update({key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.iteritems(): cape_config["cape_config"].update({key: [value]}) except Exception as e: log.error("CAPE: malwareconfig parsing error with %s: %s", cape_name, e) if "cape_config" in cape_config: if cape_config["cape_config"] == {}: del cape_config["cape_config"] return cape_config