Пример #1
0
def heuristic_by_process_sids(memory_instance, pslist=None, workdir=None, dump_objects=False):
    """
    Dump suspicious processes, according to running user
    :param memory_instance: an instance of memory object
    :param pslist: list of processes obtained from get_new_pslist
    :param workdir: path to the workdir
    :param dump_objects: wether to dump suspicious results or not
    :return: dictionary of suspect code injection sections inside processes
    """

    process_whitelist = ['System', 'msiexec.exe', 'VMwareService.e', 'spoolsv.exe', 'svchost.exe', 'vmacthlp.exe',
                         'services.exe', 'winlogon.exe', 'csrss.exe', 'smss.exe', 'lsass.exe','vmtoolsd.exe']

    suspicious_processes = list()

    # Get process list
    if pslist is None:
        pslist = get_new_pslist(memory_instance)

    if workdir is None:
        workdir = create_workdir()

    # "columns": ["PID", "Process", "SID", "Name"]}
    output = execute_volatility_command(memory_instance, 'getsids')
    for priv in output:
        if priv['SID'] == 'S-1-5-18' and priv['Process'] not in process_whitelist:
            logging.info('Suspicious priv: {}'.format(priv))
            suspicious_processes.append(priv)
            if dump_objects:
                logging.info('Dumping {} due to suspicious SID'.format(priv['PID']))
                dump_process(memory_instance, priv['PID'], workdir,
                             process_name=priv['Process'],
                             memdump=True)
    return suspicious_processes
Пример #2
0
def heuristics_process_privileges(memory_instance, pslist=None, workdir=None, dump_objects=False):
    """
    Find suspicious processes according to process privileges
    :param memory_instance: memory instance object
    :param pslist: list of loaded processes created by get_new_pslist()
    :param workdir: path to working directory
    :param dump_objects: wether to dump suspicious object or not
    :return: dictionary of suspect processes
    """
    suspicious_privileges = ['SeDebugPrivilege', 'SeTcbPrivilege',
                             'SeTrustedCredManAccessPrivilege']

    privs_list = execute_volatility_command(memory_instance, 'privs')

    procs_with_suspicious_privs = list()
    dumped_process_list = list()
    for privilege in privs_list:
        if privilege['Privilege'] in suspicious_privileges:
            attributes_list = privilege['Attributes'].split(',')
            if 'Present' in attributes_list and 'Enabled' in attributes_list and 'Default' not in attributes_list:
                print(json.dumps(privilege))
                procs_with_suspicious_privs.append(privilege)

                if dump_objects and privilege['Pid'] not in dumped_process_list:
                    logging.info('Dumping {} due to suspicious privileges'.format(privilege['Pid']))
                    dump_process(memory_instance, privilege['Pid'], workdir, process_name=privilege['Process'])
                    dumped_process_list.append(privilege['Pid'])

    return procs_with_suspicious_privs
Пример #3
0
def heuristic_ssdt(memory_instance, pslist=None, workdir=None, dump_objects=False):
    ssdt = execute_volatility_command(memory_instance, 'ssdt')

    legitimate_owners = ['ntoskrnl.exe', 'win32k.sys']

    known_owners = list()
    for entry in ssdt:
        if entry['Owner'] not in legitimate_owners and entry['Owner'] not in known_owners:
            print('New ownwer: {}'.format(entry))
            known_owners.append(entry['Owner'])

    for driver_name in known_owners:
        # /usr/local/bin/vol.py --profile WinXPSP2x86 -f "/home/MemoryDumps/APT.img" moddump -r irykmmww.sys -D /tmp
        execute_volatility_command(memory_instance,'moddump',extra_flags='-r {} -D {}'.format(driver_name,workdir))

    return known_owners
Пример #4
0
def get_new_pslist(memory_instance):
    """
    Get output of Volatility pslist command
    :param object_instance: Reference to machine instance
    :return: list of currently running processes
    """
    return execute_volatility_command(memory_instance, 'pslist')
Пример #5
0
def run_extractor(memory_instance, malware_sample, machine_instance=None):
    golden_image = pslist.load_golden_image(machine_instance)
    new_pslist = pslist.get_new_pslist(memory_instance)

    new_processes = []
    for proc in new_pslist:
        new_proc = True
        for proc_gi in golden_image:
            if proc['PID'] == proc_gi['PID']:
                new_proc = False
                break

            # TODO! Local patch!! Remove on production!!
            if proc['Name'] == 'wmiprvse.exe':
                new_proc = False
                break

        if new_proc:
            logging.info('Identified a new process: {} - {}'.format(proc['PID'], proc['Name']))
            new_processes.append(proc)

    workdir = os.path.dirname(os.path.realpath(malware_sample.file_path))
    db_connection = DataBaseConnection()

    for procdata in new_processes:
        output = execute_volatility_command(memory_instance, 'procdump',
                                            extra_flags='-p {} -D {}/'.format(procdata['PID'], workdir),
                                            has_json_output=False)

        # Rename the file, to contain process name
        src = workdir + "/executable." + str(procdata['PID']) + ".exe"
        if os.path.isfile(src):
            target_dump_path = workdir + "/" + procdata['Name'] + "." + str(procdata['PID']) + "._exe"
            os.rename(src, target_dump_path)

            current_dump = SampleDump(target_dump_path)
            current_dump.sha256 = calc_sha256(target_dump_path)
            current_dump.md5 = calc_md5(target_dump_path)
            current_dump.ephash = calc_ephash(target_dump_path)
            current_dump.imphash = calc_imphash(target_dump_path)
            current_dump.process_name = procdata['Name']
            current_dump.source = 'procdump'
            current_dump.parent_sample_id = malware_sample.id

            db_connection.add_dump(current_dump)

            # Load post processing modules here, if needed
            with open(target_dump_path + '.strings.json', 'w') as strings_output_file:
                strings_output_file.write(json.dumps(get_strings(current_dump), indent=4))

            with open(target_dump_path + '.static_analysis.json', 'w') as strings_output_file:
                strings_output_file.write(json.dumps(static_analysis(current_dump), indent=4))

            with open(target_dump_path + '.yara.json', 'w') as yara_output_file:
                yara_output_file.write(json.dumps(scan_with_yara(current_dump), indent=4))


        else:
            logging.info('Could not dump process {} (PID: {})'.format(procdata['Name'], str(procdata['PID'])))
Пример #6
0
def heuristic_libraries_by_path(memory_instance, pslist=None, workdir=None, dump_objects=False):
    """
    Heuristics by path, using statistics and dlllist
    :param memory_instance: memory instance object
    :param pslist: list of loaded processes created by get_new_pslist()
    :param workdir: path to working directory
    :param dump_objects: wether to dump suspicious object or not
    :return: dictionary of suspect processes
    """
    loaded_dlls = execute_volatility_command(memory_instance, 'dlllist')

    statistic_dict = dict()
    suspicious_dlls = list()

    max_files_threshold = 2
    statistic_anomalies_list = ['\\systemroot\\system32\\smss.exe', 'c:\\windows\\explorer.exe',
                                'c:\\program files\\internet explorer\\ieproxy.dll']

    for loaded_dll in loaded_dlls:
        # loaded_dll['Path'].lower()
        folder_path = '\\'.join(loaded_dll['Path'].lower().split('\\')[0:-1])
        try:
            statistic_dict[folder_path] += 1
        except KeyError:
            statistic_dict[folder_path] = 1

    suspect_path_list = list()
    sorted_dict = sorted(statistic_dict.items(), key=lambda x: x[1], reverse=True)
    for path in sorted_dict:
        if path[1] < max_files_threshold:
            print(path)
            suspect_path_list.append(path[0])

    for loaded_dll in loaded_dlls:
        for suspect_path in suspect_path_list:
            if '\\'.join(loaded_dll['Path'].lower().split('\\')[0:-1]) == suspect_path.lower():
                if loaded_dll['Path'].lower() not in statistic_anomalies_list:
                    suspicious_dlls.append(loaded_dll)
                    if dump_objects:
                        logging.info('Going to dump {} due to suspicious path'.format(loaded_dll))
                        dump_dll(memory_instance, loaded_dll['Pid'], loaded_dll['Base'], workdir)

    return suspicious_dlls
Пример #7
0
def heuristic_dest_port_anomallies(memory_instance, pslist=None, workdir=None, dump_objects=False):
    whitelisted_dest_ports = ['80', '443', '8443', '53', '3889']

    suspicious_processes = list()
    connections = execute_volatility_command(memory_instance, 'connections')
    for conn in connections:
        dst_ip, dst_port = conn['RemoteAddress'].split(':')
        if dst_port not in whitelisted_dest_ports:
            suspicious_processes.append(conn)
            if dump_objects:
                procname = 'unknown'
                for process in pslist:
                    if str(process['Offset(V)']) == str(conn['Offset(V)']):
                        logging.info("Found process name: {}".format(process['Name']))
                        procname = process['Name']
                        pid = str(process['PID'])
                        break
                dump_process(memory_instance, conn['PID'], workdir, process_name=procname)

    return suspicious_processes
Пример #8
0
def heuristic_dll_uncommon_on_machine(memory_instance, pslist=None, workdir=None, dump_objects=False):
    loaded_dlls = execute_volatility_command(memory_instance, 'dlllist')

    suspect_path_list = list()
    loaded_dlls_counter = dict()
    for loaded_dll in loaded_dlls:
        try:
            loaded_dlls_counter[loaded_dll['Path']]['counter'] += 1
        except KeyError:
            loaded_dlls_counter[loaded_dll['Path']] = {'counter': 0, 'first_seen': loaded_dll}

    for key in loaded_dlls_counter:
        if loaded_dlls_counter[key]['first_seen']['Path'] not in DLLS_IN_SYSDIR:
            if loaded_dlls_counter[key]['counter'] == 1 and loaded_dlls_counter[key]['first_seen']['LoadCount'] == 1:
                print('Going to dump: {}'.format(loaded_dlls_counter[key]['first_seen']))

                if dump_objects:
                    dump_dll(memory_instance, loaded_dlls_counter[key]['first_seen']['Pid'],
                             loaded_dlls_counter[key]['first_seen']['Base'], workdir)
                suspect_path_list.append(loaded_dlls_counter[key]['first_seen'])

    return suspect_path_list
Пример #9
0
def run_extractor(memory_instance, malware_sample,machine_instance=None):
    pslist_new_data = pslist.get_new_pslist(memory_instance)

    target_dump_dir = os.path.join(get_workdir_path(malware_sample), 'injected')
    os.mkdir(target_dump_dir)

    output = execute_volatility_command(memory_instance, 'malfind', extra_flags='-D {}/'.format(target_dump_dir),
                                        has_json_output=False)
    db_connection = DataBaseConnection()

    # Find malfind injections that are binaries, and rename them
    for single_dump in os.scandir(target_dump_dir):
        splitted_line = re.split('\.', single_dump.path.rstrip('\n'))
        logging.info('offset: {}, Imagebase: {}'.format(splitted_line[1], splitted_line[2]))
        offset = splitted_line[1]
        imagebase = splitted_line[2]

        # Verify if it is PE or not
        try:
            pe = pefile.PE(single_dump.path)
            isPE = True
        except PEFormatError:
            isPE = False

        if isPE:
            db_connection.add_tag("Injects_Code", malware_sample)
            logging.info('[*] Processing {}'.format(single_dump.path))
            logging.info('offset: %s, Imagebase: %s'.format(offset, imagebase))
            logging.info('Altering image base: {} => {}'.format(pe.OPTIONAL_HEADER.ImageBase, imagebase))

            fixed_pe = fix_pe_from_memory(pe, imagebase=imagebase)

            # Get original process name
            process_name = "unknown"

            for proc_gi in pslist_new_data:
                if str(hex(proc_gi['Offset(V)'])) == offset:
                    logging.info("Found process name: {}".format(proc_gi['Name']))
                    process_name = proc_gi['Name']
                    pid = str(proc_gi['PID'])
                    break

            outputpath = os.path.join(target_dump_dir, process_name + '.' + offset + '.' + imagebase + '.fixed_bin')
            fixed_pe.write(filename=outputpath)
            pe.close()

            if process_name != 'unknown':
                # Generate impscan IDC
                output = execute_volatility_command(memory_instance, 'impscan',
                                                    extra_flags='-b {} -p {} --output=idc'.format(imagebase, pid),
                                                    has_json_output=False)

                # Write IDC data to file
                with open(outputpath + '.idc', 'w') as idc:
                    idc.write('#include <idc.idc>\n')
                    idc.write('static main(void) {{\n')
                    idc.write(output)
                    idc.write('Exit(0);}}')

                current_dump = SampleDump(outputpath)
                current_dump.parent_sample_id = malware_sample.id
                current_dump.sha256 = calc_sha256(outputpath)
                current_dump.md5 = calc_md5(outputpath)
                current_dump.process_name = process_name
                current_dump.source = 'injected_code'

                # Calc imphash, or make the parameter = fail
                current_dump.ephash = calc_ephash(outputpath)

                # Calc EPhash, or make the parameter = fail
                current_dump.imphash = calc_imphash(outputpath)

                db_connection.add_dump(current_dump)

                # Load post processing modules here, if needed
                with open(outputpath + '.strings.json', 'w') as strings_output_file:
                    strings_output_file.write(json.dumps(get_strings(current_dump, imagebase=imagebase), indent=4))

                with open(outputpath + '.static_analysis.json', 'w') as static_analysis_output_file:
                    static_analysis_output_file.write(json.dumps(static_analysis(current_dump), indent=4))

                with open(outputpath + '.yara.json', 'w') as yara_output_file:
                    yara_output_file.write(json.dumps(scan_with_yara(current_dump), indent=4))

                with open(outputpath + '.ysa.json', 'w') as yara_semantic_output_file:
                    yara_semantic_output_file.write(json.dumps(semantically_analyze(current_dump), indent=4))
Пример #10
0
def heuristic_suspicious_handles(memory_instance, pslist=None, workdir=None, dump_objects=False):
    """
    Heuristics by suspicious handles
    :param memory_instance: memory instance object
    :param pslist: list of loaded processes created by get_new_pslist()
    :param workdir: path to working directory
    :param dump_objects: wether to dump suspicious object or not
    :return: dictionary of suspect processes
    """
    handles_list = execute_volatility_command(memory_instance, 'handles', extra_flags='-s')
    supported_handles = ['Key', 'File', 'Mutant', 'Thread']

    # Initiate a dict with scoring per PID...
    process_scoring = dict()
    for process in pslist:
        process_scoring[process['PID']] = {'Name': process['Name'], 'PID': process['PID'], 'PPID': process['PPID'],
                                           'susp_keys': 0,
                                           'susp_files': 0,
                                           'susp_mutex': 0,
                                           'susp_thread_handles': 0,
                                           'Key': list(), 'File': list(), 'Mutant': list(),
                                           'Thread': list()}

    # for each process, add its handles to his dict
    for handle in handles_list:
        if handle['Type'] in supported_handles:
            try:
                process_scoring[handle['Pid']][handle['Type']].append(handle)
            except KeyError:
                logging.info('PID does not exists ({})'.format(handle['Pid']))

    # Get a dictionary of running processes by name, for easier iteration (from pslist)
    running_processes = dict()
    for running_process in pslist:
        running_processes[str(running_process['PID'])] = running_process['Name']

    # Anomaly detection phase:

    # Find processes with handles to threads in other processes...
    for process_pid in process_scoring:
        for thread_handle in process_scoring[process_pid]['Thread']:
            # Get pid from regex:
            m = re.search(r'^TID (\d{2,4})\sPID\s(\d{2,4})$', thread_handle['Details'])
            if m:
                tid = m.group(1)
                pid = m.group(2)
                if pid != str(process_pid) and pid != str(process_scoring[process_pid]['PPID']) and \
                                process_scoring[process_pid]['Name'] != 'csrss.exe':

                    try:
                        if process_scoring[process_pid]['Name'] == 'services.exe' and running_processes[
                            pid] == 'lsass.exe':
                            continue
                        if process_scoring[process_pid]['Name'] == 'lsass.exe' and running_processes[
                            pid] == 'svchost.exe':
                            continue

                        logging.info(
                            'This process has an handle to a thread in another process: {}-{} ---> {} ({})'.format(
                                process_scoring[process_pid]['Name'], process_pid, thread_handle['Details'],
                                running_processes[pid]))
                    except KeyError:
                        logging.info('This process has an handle to a thread in another process: {}-{} ---> {}'.format(
                            process_scoring[process_pid]['Name'], process_pid, thread_handle['Details']))

                    process_scoring[process_pid]['susp_thread_handles'] += 1

    # Mutants (i.e statistically outstanding mutants)
    # TODO: import fuzzywuzzy, from fuzzywuzzy import fuzz, fuzz.ratio(a,b)

    # Files (i.e executables/DLLs from unusual paths)

    # Keys (i.e persistency keys...)

    # Create a final list of processes with more suspicious handles than the treshold:
    threshold = 0
    suspect_processes = list()
    for process_pid in process_scoring:
        if (process_scoring[process_pid]['susp_keys'] + process_scoring[process_pid]['susp_files'] +
                process_scoring[process_pid]['susp_mutex'] + process_scoring[process_pid][
            'susp_thread_handles']) > threshold:
            suspect_processes.append({'pid': process_pid, 'name': process_scoring[process_pid]['Name'],
                                      'susp_keys': process_scoring[process_pid]['susp_keys'],
                                      'susp_files': process_scoring[process_pid]['susp_files'],
                                      'susp_mutex': process_scoring[process_pid]['susp_mutex'],
                                      'susp_thread_handles': process_scoring[process_pid]['susp_thread_handles']})

    return suspect_processes
Пример #11
0
def heuristic_injected_code(memory_instance, pslist=None, workdir=None, dump_objects=False, delete_non_pe=False):
    """
    Dump injected code
    :param memory_instance: an instance of memory object
    :param pslist: list of processes obtained from get_new_pslist
    :param workdir: path to the workdir
    :param dump_objects: wether to dump suspicious results or not
    :param delete_non_pe: delete non PE files or not, they could be shellcode injections
    :return: dictionary of suspect code injection sections inside processes
    """
    # Get process list
    if pslist is None:
        pslist = get_new_pslist(memory_instance)

    if workdir is None:
        workdir = create_workdir()

    injected_dumps_list = list()
    if dump_objects:
        logging.info('Going to dump injected processes to {}'.format(workdir))
        output = execute_volatility_command(memory_instance, 'malfind', extra_flags='-D {}/'.format(workdir),
                                            has_json_output=False)

        # Find malfind injections that are binaries, and rename them
        for single_dump in os.scandir(workdir):
            splitted_line = single_dump.path.strip().split('.')
            if len(splitted_line) == 4:
                offset = splitted_line[1]
                imagebase = splitted_line[2]
                try:
                    pe = pefile.PE(single_dump.path)

                    fixed_pe = fix_pe_from_memory(pe, imagebase=imagebase)
                    # Get original process name
                    procname = "unknown"

                    for process in pslist:
                        if str(process['Offset(V)']) == str(int(offset, 16)):
                            logging.info("Found process name: {}".format(process['Name']))
                            procname = process['Name']
                            pid = str(process['PID'])
                            break

                    outputpath = os.path.join(workdir, procname + '.' + offset + '.' + imagebase + '.fixed_bin')
                    logging.info('Dumping fixed PE to {}'.format(outputpath))
                    fixed_pe.write(filename=outputpath)
                    pe.close()

                    if procname != 'unknown':
                        injected_dumps_list.append({'path': outputpath, 'process_name': procname, 'pid': pid})
                    else:
                        injected_dumps_list.append(outputpath)

                    current_dump = SampleDump(outputpath)
                    with open(outputpath + '.strings.json', 'w') as strings_output_file:
                        strings_output_file.write(json.dumps(get_strings(current_dump), indent=4))

                    with open(outputpath + '.static_analysis.json', 'w') as strings_output_file:
                        strings_output_file.write(json.dumps(static_analysis(current_dump), indent=4))

                except PEFormatError:
                    logging.info('Corrupted, or not PE file...')
                    if delete_non_pe:
                        os.remove(single_dump)
                    pass

        result = {'PE_dump_list': injected_dumps_list}
    else:
        logging.info('Not output workdir defined, not going to dump injected processes.')
        output = execute_volatility_command(memory_instance, 'malfind')
        result = {'malfind_output': output}

    return result
Пример #12
0
def run_extractor(memory_instance, malware_sample,machine_instance=None):
    if machine_instance is None:
        return None

    # Whitelist of modules by name, not optimal at all...
    mod_white_list = ['TDTCP.SYS', 'RDPWD.SYS', 'kmixer.sys', 'Bthidbus.sys', 'rdpdr.sys', 'tdtcp.sys', 'tssecsrv.sys']

    # Get golden image data:
    with open(os.path.join(VOLATILITYBOT_HOME, 'GoldenImage', machine_instance.machine_name,
                           'modscan.json')) as data_file:
        modscan_golden_image = json.load(data_file)

    modscan_run = execute_volatility_command(memory_instance, 'modscan')

    db_connection = DataBaseConnection()

    new_modules = []
    for mod in modscan_run:
        new_mod = True
        for mod_gi in modscan_golden_image:
            if mod['File'] == mod_gi['File']:
                if mod['Size'] == mod_gi['Size']:
                    new_mod = False

        for wl_mod in mod_white_list:
            # print '[DEBUG] modscan %s : %s' % (mod['filename'],wl_mod)
            if (mod['Name'] == wl_mod):
                new_mod = False

        if new_mod:
            logging.info('Identified a new module: {} - {}'.format(mod['File'], mod['Size']))
            new_modules.append(mod)

            output = execute_volatility_command(memory_instance, 'moddump',
                                                extra_flags='-b {} -D {}/'.format(mod['Base'],
                                                                                  get_workdir_path(malware_sample)),
                                                has_json_output=False)

            base = mod['Base']
            src = os.path.join(get_workdir_path(malware_sample), "driver." + base[2:] + ".sys")
            dest = os.path.join(get_workdir_path(malware_sample), mod['Name'] + '.' + base[2:] + '.sys')

            try:
                os.rename(src, dest)
            except Exception as e:
                logging.error('Could not rename driver, leaving it as it is... ({})'.format(e) )
                dest = src

            current_dump = SampleDump(dest)
            current_dump.parent_sample_id = malware_sample.id
            current_dump.sha256 = calc_sha256(dest)
            current_dump.md5 = calc_md5(dest)
            current_dump.process_name = mod['Name']
            current_dump.source = 'KMD'

            current_dump.ephash = calc_ephash(dest)
            current_dump.imphash = calc_imphash(dest)

            db_connection.add_dump(current_dump)

            with open(dest + '.strings.json', 'w') as strings_output_file:
                strings_output_file.write(json.dumps(get_strings(current_dump), indent=4))

            with open(dest + '.yara.json', 'w') as yara_output_file:
                yara_output_file.write(json.dumps(scan_with_yara(current_dump), indent=4))
Пример #13
0
def create_golden_image(memory_instance):
    return execute_volatility_command(memory_instance, 'modscan')