def test_upx(): sample_path = 'tests/samples/upx' file_info = fileparser.FileParser(file_path=sample_path) module = __preprocessors__['UPX']['obj']() module.set_file(file_info) module.pre_process() assert file_info.malware_name != 'UPX'
def decode_sample(sample_path): file_info = fileparser.FileParser(file_path=sample_path) if file_info.malware_name in __decoders__: module = __decoders__[file_info.malware_name]['obj']() module.set_file(file_info) module.get_config() conf = module.config return conf
async def malconf(request): filepath=SAMPLEPATH + request.path_params['filename'] if path.exists(filepath): for package in DECODERS: if package == 'kevin': file_info=fileparser.FileParser(file_path=filepath) if file_info.malware_name in __decoders__: module = __decoders__[file_info.malware_name]['obj']() module.set_file(file_info) module.get_config() conf = module.config conf.update({'mal_family': file_info.malware_name}) return JSONResponse({'config': conf}) # else: # #raise if we couldn't find any config extractor # raise HTTPException(status_code=412) elif package == 'jurg': # move file to tmp if not os.path.exists(os.path.dirname('/tmp/'+request.path_params['filename'])): os.makedirs(os.path.dirname('/tmp/'+request.path_params['filename'])) shutil.copyfile(filepath,'/tmp/'+request.path_params['filename']) # execute qrypter check_call(['python3', DECODERSPATH+'java_malware_tools-master/unpackers/qrypter/current-qrypter.py', '/tmp/'+request.path_params['filename']], stdout=DEVNULL, stderr=DEVNULL) # check if we have the unpacked file if path.exists('/tmp/'+request.path_params['filename']+'.unpacked.jar'): conf=json.loads(check_output(['python3', DECODERSPATH+'java_malware_tools-master/config-extraction/qealler_config.py', '/tmp/'+request.path_params['filename']+'.unpacked.jar']).decode('utf-8')) conf.update({'mal_family': 'qealler'}) os.remove('/tmp/'+request.path_params['filename']) os.remove('/tmp/'+request.path_params['filename']+'.unpacked.jar') return JSONResponse({'config': conf}) else: #raise if we couldn't find the unpacked file raise HTTPException(status_code=412) elif package == 'revil': try: conf=json.loads(check_output(['python3', DECODERSPATH+'revil.py', filepath]).decode('utf-8')) conf.update({'mal_family': 'revil'}) return JSONResponse({'config': conf}) except: pass elif package == 'cs': try: conf=json.loads(check_output(['python3', DECODERSPATH+'CobaltStrikeBeacon.py','--json',filepath]).decode('utf-8')) conf.update({'mal_family': 'cobaltstrike'}) if conf['MaxGetSize'] == "Not Found" and conf['Spawnto_x86'] == "Not Found": raise HTTPException(status_code=412) else: return JSONResponse({'config': conf}) except: pass else: #raise if we couldn't find any config extractor raise HTTPException(status_code=412) else: #raise if we couldn't find the file in the OS raise HTTPException(status_code=404)
def preprocess(file_path): # Open and parse the file logger.info("[+] Loading File: {0}".format(file_path)) file_info = fileparser.FileParser(file_path=file_path) logger.info(" [-] Found: {0}".format(file_info.malware_name)) # First we preprocesss # Check for a packer we can unpack if file_info.malware_name in __preprocessors__: logger.info(" [+] Running PreProcessor {0}".format( file_info.malware_name)) module = __preprocessors__[file_info.malware_name]['obj']() module.set_file(file_info) module.pre_process() return file_info
def each(self, target): file_info = fileparser.FileParser(file_path=target) # Check for a valid decoder and then parse if file_info.malware_name in __decoders__: module = __decoders__[file_info.malware_name]["obj"]() module.set_file(file_info) module.get_config() self.add_probable_name(file_info.malware_name) self.add_extraction( "{} Configuration".format(file_info.malware_name), json.dumps(module.config, indent=2)) return True return False
def extract_from_droppper(self): file_info = self.file_info try: # Read Files encrypted_aes_key = file_info.file_from_zip('mega.download') rsa_serialized_key = file_info.file_from_zip('sky.drive') aes_encrypted_config = file_info.file_from_zip('drop.box') # Deserailize and retrieve the RSA Key rsa_key_string = self.extract_rsa_key(rsa_serialized_key) # Decrypt the AES Key using the RSA Key aes_key = crypto.decrypt_rsa(rsa_key_string, encrypted_aes_key) except: # Read in serialized RSA KeyRep file. aes_encrypted_config = file_info.file_from_zip('lp/sq/d.png') aes_key = 'lks03oeldkfirowl' # Use the AES Key to decrpyt the config aes_decrypted_xml = crypto.decrypt_aes(aes_key[-16:], aes_encrypted_config) parsed_xml = self.parse_xml(aes_decrypted_xml) # Extract the implant using the xml properties rsa_serialized_key_path = parsed_xml['PRIVATE_PASSWORD'].lstrip('/') aes_path = parsed_xml['PASSWORD_CRYPTED'].lstrip('/') implant_path = parsed_xml['SERVER_PATH'].lstrip('/') rsa_serialized_key = file_info.file_from_zip(rsa_serialized_key_path) encrypted_aes_key = file_info.file_from_zip(aes_path) aes_encrypted_jar = file_info.file_from_zip(implant_path) # Another round of extraction rsa_key_string = Jbifrost.extract_rsa_key(rsa_serialized_key) aes_key = crypto.decrypt_rsa(rsa_key_string, encrypted_aes_key) implant_jar = crypto.decrypt_aes(aes_key[-16:], aes_encrypted_jar) # Update for new file new_info = fileparser.FileParser(rawdata=implant_jar) self.file_info = new_info # Run config again self.get_config()
def static_config_parsers(yara_hit, file_data, cape_config): """Process CAPE Yara hits""" cape_name = yara_hit.replace('_', ' ') parser_loaded = False # Attempt to import a parser for the hit # DC3-MWCP if "cape_config" not in cape_config: cape_config.setdefault("cape_config", dict()) if cape_name and HAS_MWCP and cape_name in malware_parsers: try: reporter = mwcp.Reporter() reporter.run_parser(malware_parsers[cape_name], data=file_data) if not reporter.errors: log.info("CAPE: Imported DC3-MWCP parser %s", cape_name) parser_loaded = True try: tmp_dict = dict() if reporter.metadata.get("debug"): del reporter.metadata["debug"] if reporter.metadata.get("other"): for key, value in reporter.metadata["other"].items(): tmp_dict.setdefault(key, []) if value not in tmp_dict[key]: tmp_dict[key].append(value) del reporter.metadata["other"] tmp_dict.update(reporter.metadata) if "cape_config" not in cape_config: cape_config.setdefault("cape_config", dict()) #ToDo do we really need to convert it? cape_config["cape_config"] = convert(tmp_dict) else: cape_config["cape_config"].update(convert(tmp_dict)) except Exception as e: log.error( "CAPE: DC3-MWCP config parsing error with {}: {}". format(cape_name, e)) else: error_lines = reporter.errors[0].split("\n") for line in error_lines: if line.startswith('ImportError: '): log.info("CAPE: DC3-MWCP parser: %s", line.split(': ')[1]) reporter._Reporter__cleanup() del reporter except (ImportError, IndexError, TypeError) as e: log.error("MWCP Error: {}".format(e)) if not parser_loaded and cape_name in cape_malware_parsers: try: #changed from cape_config to cape_configraw because of avoiding overridden. duplicated value name. cape_configraw = cape_malware_parsers[cape_name].config(file_data) if isinstance(cape_configraw, list): for (key, value) in cape_configraw[0].items(): #python3 map object returns iterator by default, not list and not serializeable in JSON. if isinstance(value, map): value = list(value) cape_config["cape_config"].update({key: [value]}) elif isinstance(cape_configraw, dict): for (key, value) in cape_configraw.items(): #python3 map object returns iterator by default, not list and not serializeable in JSON. if isinstance(value, map): value = list(value) cape_config["cape_config"].update({key: [value]}) except Exception as e: log.error("CAPE: parsing error with {}: {}".format(cape_name, e)) elif not parser_loaded and cape_name in __decoders__: try: file_info = fileparser.FileParser(rawdata=file_data) module = __decoders__[file_info.malware_name]['obj']() module.set_file(file_info) module.get_config() malwareconfig_config = module.config #ToDo remove if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].items(): cape_config["cape_config"].update({key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.items(): cape_config["cape_config"].update({key: [value]}) except Exception as e: log.warning( "malwareconfig parsing error with %s: %s, you should submit issue/fix to https://github.com/kevthehermit/RATDecoders/", cape_name, e) if "cape_config" in cape_config: if cape_config["cape_config"] == {}: del cape_config["cape_config"] return cape_config
def static_config_parsers(yara_hit, file_data, cape_config): # Process CAPE Yara hits cape_name = yara_hit.replace('_', ' ') parser_loaded = False # Attempt to import a parser for the hit # DC3-MWCP if "cape_config" not in cape_config: cape_config.setdefault("cape_config", dict()) if cape_name and HAS_MWCP and cape_name in malware_parsers: try: reporter = mwcp.Reporter() reporter.run_parser(malware_parsers[cape_name], data=file_data) if reporter.errors == []: log.info("CAPE: Imported DC3-MWCP parser %s", cape_name) parser_loaded = True try: tmp_dict = dict() if reporter.metadata.get("debug"): del reporter.metadata["debug"] if reporter.metadata.get("other"): for key, value in reporter.metadata["other"].items(): tmp_dict.setdefault(key, []) if value not in tmp_dict[key]: tmp_dict[key].append(value) del reporter.metadata["other"] tmp_dict.update(reporter.metadata) if "cape_config" not in cape_config: cape_config.setdefault("cape_config", dict()) #ToDo do we really need to convert it? cape_config["cape_config"] = convert(tmp_dict) else: cape_config["cape_config"].update(convert(tmp_dict)) except Exception as e: log.error("CAPE: DC3-MWCP config parsing error with %s: %s", cape_name, e) else: error_lines = reporter.errors[0].split("\n") for line in error_lines: if line.startswith('ImportError: '): log.info("CAPE: DC3-MWCP parser: %s", line.split(': ')[1]) reporter._Reporter__cleanup() del reporter except (ImportError, IndexError) as e: log.error(e) if not parser_loaded and cape_name in malware_parsers: parser_loaded = True try: cape_config = malware_parsers[cape_name].config(file_data) if isinstance(cape_config, list): for (key, value) in cape_config[0].items(): cape_config["cape_config"].update({key: [value]}) elif isinstance(cape_config, dict): for (key, value) in cape_config.items(): cape_config["cape_config"].update({key: [value]}) except Exception as e: log.error("CAPE: parsing error with %s: %s", cape_name, e) if not parser_loaded and cape_name in __decoders__: try: file_info = fileparser.FileParser(rawdata=file_data) module = __decoders__[file_info.malware_name]['obj']() module.set_file(file_info) module.get_config() malwareconfig_config = module.config #ToDo remove if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].items(): cape_config["cape_config"].update({key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.items(): 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
def get_config(self): ''' This is the main entry :return: ''' file_info = self.file_info file_list = file_info.zip_namelist() internal_jar = None key_file = None config_data = None config_dict = {} for name in file_list: if name == 'key.dat': key_file = file_info.file_from_zip(name) if name == 'enc.dat': internal_jar = file_info.file_from_zip(name) if name == 'config.dat': config_data = file_info.file_from_zip(name) # If there is a wrapper around the jrat if internal_jar: drop_conf = key_file new_key = drop_conf[:16] drop_conf_fields = key_file[16:].split(b',') config_dict['dropper'] = [] for field in drop_conf_fields: try: decoded_field = b64decode(field).decode('utf-8') config_dict['dropper'].append(unhexlify(decoded_field)) except: pass new_jar_data = crypto.decrypt_aes(new_key, internal_jar) new_jar = fileparser.FileParser(rawdata=new_jar_data) # replace the keyfile and jar file with the new dropper for name in new_jar.zip_namelist(): if name == 'key.dat': key_file = new_jar.file_from_zip(name) if name == 'config.dat': config_data = new_jar.file_from_zip(name) # With the Key and Config Decrypt if len(key_file) == 16: # AES decrypted = crypto.decrypt_aes(key_file, config_data) if len(key_file) in [24, 32]: decrypted = crypto.decrypt_des3(key_file, config_data) # Process the decrypted Config decrypted = decrypted.decode('utf-8') # Clean it up a little for c in ['\x01', '\x03', '\x04', '\x06', '\x08']: decrypted = decrypted.replace(c, '') fields = decrypted.split('SPLIT') for field in fields: if '=' not in field: continue key, value = field.split('=') if key == 'ip': config_dict['Domain'] = value if key == 'addresses': dom_list = value.split(',') dom_count = 0 for dom in dom_list: if dom == '': continue config_dict['Domain {0}'.format(dom_count)] = value.split( ':')[0] config_dict['Port {0}'.format(dom_count)] = value.split( ':')[1] dom_count += 1 if key == 'port': config_dict['Port'] = value if key == 'os': config_dict['OS'] = value if key == 'mport': config_dict['MPort'] = value if key == 'perms': config_dict['Perms'] = value if key == 'error': config_dict['Error'] = value if key == 'reconsec': config_dict['RetryInterval'] = value if key == 'ti': config_dict['TI'] = value if key == 'pass': config_dict['Password'] = value if key == 'id': config_dict['CampaignID'] = value if key == 'mutex': config_dict['Mutex'] = value if key == 'toms': config_dict['TimeOut'] = value if key == 'per': config_dict['Persistance'] = value if key == 'name': config_dict['InstallName'] = value if key == 'tiemout': config_dict['TimeOutFlag'] = value if key == 'debugmsg': config_dict['DebugMsg'] = value config_dict["EncryptionKey"] = key_file # Set the config to the class for use self.config = config_dict
def static_config_parsers(yara_hit, file_data): """Process CAPE Yara hits""" cape_name = yara_hit.replace("_", " ") cape_config = dict() cape_config[cape_name] = dict() parser_loaded = False # Attempt to import a parser for the hit # DC3-MWCP if HAS_MWCP and cape_name and cape_name in malware_parsers: logging.debug("Running MWCP") try: reporter = mwcp.Reporter() reporter.run_parser(malware_parsers[cape_name], data=file_data) if not reporter.errors: parser_loaded = True tmp_dict = dict() if reporter.metadata.get("debug"): del reporter.metadata["debug"] if reporter.metadata.get("other"): for key, value in reporter.metadata["other"].items(): tmp_dict.setdefault(key, []) if value not in tmp_dict[key]: tmp_dict[key].append(value) del reporter.metadata["other"] tmp_dict.update(reporter.metadata) cape_config[cape_name] = convert(tmp_dict) logging.debug("CAPE: DC3-MWCP parser for %s completed", cape_name) else: error_lines = reporter.errors[0].split("\n") for line in error_lines: if line.startswith("ImportError: "): logging.debug("CAPE: DC3-MWCP parser: %s", line.split(": ")[1]) reporter._Reporter__cleanup() del reporter except pefile.PEFormatError: logging.error("pefile PEFormatError") except Exception as e: logging.error("CAPE: DC3-MWCP config parsing error with {}: {}".format(cape_name, e)) if HAVE_CAPE_EXTRACTORS and not parser_loaded and cape_name in cape_malware_parsers: logging.debug("Running CAPE") try: # changed from cape_config to cape_configraw because of avoiding overridden. duplicated value name. cape_configraw = cape_malware_parsers[cape_name].config(file_data) if isinstance(cape_configraw, list): for (key, value) in cape_configraw[0].items(): # python3 map object returns iterator by default, not list and not serializeable in JSON. if isinstance(value, map): value = list(value) cape_config[cape_name].update({key: [value]}) parser_loaded = True elif isinstance(cape_configraw, dict): for (key, value) in cape_configraw.items(): # python3 map object returns iterator by default, not list and not serializeable in JSON. if isinstance(value, map): value = list(value) cape_config[cape_name].update({key: [value]}) parser_loaded = True except Exception as e: logging.error("CAPE: parsing error with {}: {}".format(cape_name, e)) elif HAS_MALWARECONFIGS and not parser_loaded and cape_name in __decoders__: logging.debug("Running Malwareconfigs") try: module = False file_info = fileparser.FileParser(rawdata=file_data) # Detects name by embed yara if file_info.malware_name in __decoders__: module = __decoders__[file_info.malware_name]["obj"]() elif cape_name in __decoders__: module = __decoders__[cape_name]["obj"]() else: logging.warning(f"{cape_name}: wasn't matched by plugin's yara") if module: module.set_file(file_info) module.get_config() malwareconfig_config = module.config # ToDo remove if isinstance(malwareconfig_config, list): for (key, value) in malwareconfig_config[0].items(): cape_config[cape_name].update({key: [value]}) elif isinstance(malwareconfig_config, dict): for (key, value) in malwareconfig_config.items(): cape_config[cape_name].update({key: [value]}) except Exception as e: if "rules" in str(e): logging.warning("You probably need to compile yara-python with dotnet support") else: logging.error(e, exc_info=True) logging.warning( "malwareconfig parsing error with %s: %s, you should submit issue/fix to https://github.com/kevthehermit/RATDecoders/", cape_name, e, ) if cape_name in cape_config and cape_config[cape_name] == {}: return {} elif HAVE_MALDUCK and not parser_loaded and cape_name.lower() in malduck_modules_names: logging.debug("Running Malduck") if not File.yara_initialized: init_yara() # placing here due to not load yara in not related tools malduck_rules.rules = File.yara_rules["CAPE"] malduck_modules.rules = malduck_rules ext = ExtractManager.__new__(ExtractManager) ext.configs = {} ext.modules = malduck_modules tmp_file = tempfile.NamedTemporaryFile(delete=False) tmp_file.write(file_data) ext.push_file(tmp_file.name) tmp_file.close() tmp_config = ext.config del ext if tmp_config: for (key, value) in tmp_config[0].items(): cape_config[cape_name].update({key: [value]}) if not cape_config[cape_name]: return dict() return cape_config