예제 #1
0
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'
예제 #2
0
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
예제 #3
0
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()
예제 #7
0
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
예제 #8
0
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
예제 #9
0
    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
예제 #10
0
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