def find_scouts(self): """ Find all 'Scout' level implants using their distinctive watermarks - these index the configuration files, allowing us to obtain AES key information """ scouts = [] # Dynamically generate Yara rules from watermark if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") rules = self.gen_yara_rules() for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): hitdata = scanner.address_space.zread(address, 8) # Second hit from Yara rule is the 'FIRST_WI' string that we use to differentiate from Elite implants # This is a wide string, so the second character is a '\x00' - the first hit is on the watermark that we want to use. if hitdata[1] != "\x00": scouts.append({ "watermark": hitdata, "confidence": 4, "pid": str(task.UniqueProcessId), "task": task, "process_name": str(task.ImageFileName), "address_space": scanner.address_space, "address": address, "implant_type": "Scout", "threat_actor": hit.rule.split('__')[2] }) return scouts
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") if not has_crypto: debug.error("pycrypto must be installed for this plugin") if not has_pbkdf2: debug.error("pbkdf2 must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=quasar_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] offset = 0 for pattern in CONFIG_PATTERNS: mc = re.search(pattern, data) if mc: offset = mc.end() configs = [] if offset > 0: while 1: strings = [] string_len = ord(data[offset]) if ord(data[offset]) == 0x80 or ord( data[offset]) == 0x81: string_len = ord(data[offset + 1]) + ( (ord(data[offset]) - 0x80) * 256) offset += 1 offset += 1 for i in range(string_len): if data[offset + i] != "\x00": strings.append(data[offset + i]) configs.append("".join(strings)) offset = offset + string_len if len(configs) > 10: break config_data.append(self.parse_config(configs)) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): addr_space = utils.load_as(self._config) if not has_yara: debug.error("You must install yara to use this plugin") if not self._config.DUMP_DIR: debug.error("You must supply a --dump-dir parameter") if self._config.PHYSICAL: # Find the FileAddressSpace while addr_space.__class__.__name__ != "FileAddressSpace": addr_space = addr_space.base scanner = malfind.DiscontigYaraScanner(address_space=addr_space, rules=DumpCerts.rules) for hit, address in scanner.scan(): cert = obj.Object( DumpCerts.type_map.get(hit.rule), vm=scanner.address_space, offset=address, ) if cert.is_valid(): yield None, cert else: for process in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=process, rules=DumpCerts.rules) for hit, address in scanner.scan(): cert = obj.Object( DumpCerts.type_map.get(hit.rule), vm=scanner.address_space, offset=address, ) if cert.is_valid(): yield process, cert
def calculate(self): if not has_yara: debug.error('Yara must be installed for this plugin.') addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error('This command does not support the selected profile.') rules = yara.compile(sources=xxmm_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() memdata = proc_addr_space.get_available_addresses() config_data = [] for m in memdata: if 0x2000 < m[1]: continue p_data = {} data = proc_addr_space.zread(m[0], m[1]) offset = 0 p_data['param'] = [] while (True): param = {} l, param['id'], param['data'] = self.extract_param( data, offset) if l == None: if len( p_data['param'] ) == 1 and p_data['param'][0]['type'] == 'Unknown': offset = 0 break for c in data[offset:]: if ord(c) != 0x00: offset = 0 break break offset += l if param['id'] in DATA_TYPE.keys(): param['type'] = DATA_TYPE[param['id']] else: param['type'] = 'Unknown' p_data['param'].append(param) if offset == 0: continue p_data['offset'] = m[0] p_data['length'] = offset config_data.append(p_data) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=emotet_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] p_data = OrderedDict() for pattern in CONFIG_PATTERNS: mc = re.search(pattern, data) if mc: try: d = 4 i = 0 while 1: ip = data[mc.start() + d + 3] + data[mc.start() + d + 2] + data[ mc.start() + d + 1] + data[mc.start() + d] port = unpack( "=H", data[mc.start() + d + 4:mc.start() + d + 6])[0] d += 8 if ip == "\x00\x00\x00\x00" and port == 0: break else: p_data["IP " + str(i)] = str( inet_ntoa(ip)) + ":" + str(port) i += 1 except: outfd.write("[!] Not found config data.\n") config_data.append( {"RSA Public Key": self.extract_rsakey(data)}) config_data.append(p_data) yield task, vad_base_addr, end, hit, memory_model, config_data break
def get_ghost_process(self, magic, mal_process, add_space): rule = "rule Gh0strat_process {strings: $any_variant = " + '"' + magic + '"' + " condition: $any_variant}" ghost_proc_sig = {'ghostrat_process': rule} rules = yara.compile(sources=ghost_proc_sig) for task in self.filter_tasks(tasks.pslist(add_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): if task.obj_name == "_EPROCESS": process = str(task.ImageFileName) pid = task.UniqueProcessId mal_process[process] = pid
def calculate(self): ### Not used here but kept if needed for improvements """ Required: Runs YARA search to find hits """ if not HAS_YARA: debug.error('Yara must be installed for this plugin') addr_space = utils.load_as(self._config) rules = yara.compile(sources=YARA_SIGS) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr = self.get_vad_base(task, address) yield task, address
def calculate(self): if not has_yara: debug.error('Yara must be installed for this plugin.') addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error('This command does not support the selected profile.') rules = yara.compile(sources=azorult_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() memdata = proc_addr_space.get_available_addresses() config_data = [] for m in memdata: if m[1] < 0x100000: continue p_data = {} data = proc_addr_space.zread(m[0], m[1]) for pattern in CONFIG_PATTERNS: m = re.search(pattern, data) if m: offset = m.start() - 0x1c else: continue i = 0 while (True): _, _, param_len = unpack_from("<III", data, offset) if param_len > 0x100: break offset = offset + 0xc param_data = data[offset:offset + param_len] p_data[i] = param_data rest_len = 4 - (param_len % 4) offset += param_len + rest_len i += 1 config_data.append(p_data) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): addr_space = utils.load_as(self._config) if not is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") rules = yara.compile(sources=SIGNATURES) for task in tasks.pslist(addr_space): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(maxlen=MAX_SCAN_SIZE): vad_base_addr = get_vad_base(task, address) yield task, vad_base_addr break
def calculate(self): if not has_yara: debug.error('Yara must be installed for this plugin.') addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error('This command does not support the selected profile.') rules = yara.compile(sources=trickbot_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() memdata = proc_addr_space.get_available_addresses() config_data = [] for m in memdata: if m[1] <= 0x1000: continue data = proc_addr_space.zread(m[0], m[1]) for pattern in CONFIG_PATTERNS: m = re.search(pattern, data) if m: offset = m.start() else: continue p_data = OrderedDict() xml_data = data[offset:m.end()] root = ET.fromstring(xml_data) i = 0 for e in root.getiterator(): if e.text is None: if len(e.attrib) != 0: p_data[i] = e.tag + ": " + str(e.attrib) else: p_data[i] = e.tag + ": " + str(e.text) i += 1 config_data.append(p_data) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): """ Required: Runs YARA search to find hits """ if not has_yara: debug.error('Yara must be installed for this plugin') addr_space = utils.load_as(self._config) rules = yara.compile(sources = signatures) for task in self.filter_tasks(tasks.pslist(addr_space)): if not task.ImageFileName.lower() in ['chrome.exe', 'firefox.exe', 'iexplore.exe']: continue scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): yield task, address
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) tasks = win32.tasks.pslist(addr_space) for proc in tasks: if str(proc.ImageFileName) == "explorer.exe": rules = yara.compile(sources = { 'n':'rule toast {strings: $a=/<toast.*\/toast>/ condition: $a}' }) scanner = malfind.VadYaraScanner(task=proc, rules=rules) for hit,address in scanner.scan(maxlen=0x40000000): yield (proc, address, hit, scanner.address_space.zread(address, 0x4000))
def calculate(self): if not can_run: debug.error( "Yara, Capstone and PyCrypto must be installed for this plugin" ) addr_space = utils.load_as(self._config) rules = yara.compile(sources=signatures) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, addr in scanner.scan(): yield task, addr
def calculate(self): addr_space = utils.load_as(self._config) if not has_yara: debug.error("You must install yara to use this plugin") if not self._config.DUMP_DIR: debug.error("You must supply a --dump-dir parameter") # Wildcard signatures to scan for rules = yara.compile( sources={ 'x509': 'rule x509 {strings: $a = {30 82 ?? ?? 30 82 ?? ??} condition: $a}', 'pkcs': 'rule pkcs {strings: $a = {30 82 ?? ?? 02 01 00} condition: $a}', }) # These signature names map to these data structures type_map = { 'x509': '_X509_PUBLIC_CERT', 'pkcs': '_PKCS_PRIVATE_CERT', } if self._config.PHYSICAL: # Find the FileAddressSpace while addr_space.__class__.__name__ != "FileAddressSpace": addr_space = addr_space.base scanner = malfind.DiscontigYaraScanner(address_space=addr_space, rules=rules) for hit, address in scanner.scan(): cert = obj.Object( type_map.get(hit.rule), vm=scanner.address_space, offset=address, ) if cert.is_valid(): yield None, cert else: for process in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=process, rules=rules) for hit, address in scanner.scan(): cert = obj.Object( type_map.get(hit.rule), vm=scanner.address_space, offset=address, ) if cert.is_valid(): yield process, cert
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) osversion, memory_model = self.is_valid_profile(addr_space.profile) base = os.path.dirname(os.path.abspath(__file__)) rules = yara.compile(base + "/yara/rule.yara") if osversion == "windows": for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) malname = str(hit).lower() if str(hit) in [ "Himawari", "Lavender", "Armadill", "zark20rk" ]: malname = "redleaves" if str(hit) in "TSC_Loader": malname = "tscookie" if "Agenttesla" in str(hit): malname = "agenttesla" try: module = import_module( "volatility.plugins.malware.utils.{name}scan". format(name=malname)) module_cls = getattr(module, malname + "Config") instance = module_cls(self._config) except: debug.error( "Can't loading module volatility.plugins.malware.utils.{name}scan" .format(name=malname)) for task, vad_base_addr, end, hit, memory_model, config_data in instance.calculate( ): yield task, vad_base_addr, end, hit, memory_model, config_data break elif osversion == "linux": debug.error("Please use linux_malconfscan.") else: debug.error("This command does not support the selected profile.")
def calculate(self): """ Required: Runs YARA search to find hits """ if not has_yara: debug.error('Yara must be installed for this plugin') addr_space = utils.load_as(self._config) rules = yara.compile(sources = signatures) for task in self.filter_tasks(tasks.pslist(addr_space)): if 'vmwareuser.exe' == task.ImageFileName.lower(): continue if not 'java' in task.ImageFileName.lower(): continue scanner = malfind.VadYaraScanner(task = task, rules = rules) for hit, address in scanner.scan(): vad_base_addr = self.get_vad_base(task, address) yield task, address
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") rules = yara.compile(sources=signatures) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): if self.get_vad_perms(task, address) == 6: # RWX vad vad_base_addr = self.get_vad_base(task, address) yield task, vad_base_addr
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") if not has_crypto: debug.error("pycrypto must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=agenttesla_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] dlist = {} for word in self.strings(data): try: dec = self.stringdecrypt(word) dec = re.sub( "([\x00,\x01,\x02,\x03,\x04,\x05,\x06,\x07,\x08,\x09,\x0a,\x0b,\x0c,\x0d,\x0e,\x0f,\x10]{1})", "\x00", dec) dlist[word.strip().replace('\0', '')] = dec.strip().replace( "\n", "").replace("\r", "") except: pass config_data.append(dlist) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=signatures) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] if len(data) < 0x10000 or len(data) > 0x200000: continue for nw in NETWIRE_INFO: m = re.search(nw["pattern"], data) if m: offset = m.start() break else: continue cfg_addr = unpack("=I", data[offset + nw["cfg_offset"]:offset + nw["cfg_offset"] + 4])[0] if cfg_addr < vad_base_addr: continue cfg_addr -= vad_base_addr cfg_blob = data[cfg_addr:cfg_addr + nw["cfg_size"]] config_data.append(self.parse_config(cfg_blob, nw)) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error('Yara must be installed for this plugin.') addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error('This command does not support the selected profile.') rules = yara.compile(sources=noderat_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() memdata = proc_addr_space.get_available_addresses() config_data = [] for m in memdata: if m[1] < 0x100000: continue p_data = {} data = proc_addr_space.zread(m[0], m[1]) for pattern in CONFIG_PATTERNS: m = re.search(pattern, data) if m: offset = m.start() else: continue json_data = data[offset:m.end()] d = json.loads(json_data) config_data.append(d) break yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") if not has_crypto: debug.error("pycrypto must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=agenttesla_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] dlist = OrderedDict() if "type1" in str(hit): for word in self.base64strings(data): try: dec = self.stringdecrypt_type1(word) dec = self.remove_unascii(dec).rstrip() dlist[word.strip().replace('\0', '')] = dec except: pass if "type2" in str(hit): dlist = self.stringdecrypt_type2(data) config_data.append(dlist) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=bebloh_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] rsa_key_index = data.find(RSA_HEADER) rsa_key = data[rsa_key_index:rsa_key_index + 0x94] dga_key = self.crc32(rsa_key, 0xCA0B56EE) for pattern in CONFIG_PATTERNS: offset = re.search(pattern, data).start() while not (data[offset] == "\xBA" or data[offset] == "\xB8"): offset += 1 (config_addr, ) = unpack("=I", data[offset + 1:offset + 5]) config_addr -= vad_base_addr config_data.append( self.parse_config(data, config_addr, rsa_key, dga_key)) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") if not has_crypto: debug.error("pycrypto must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=asyncrat_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] dlist = OrderedDict() for pattern in CONFIG_PATTERNS: m = data.find(pattern) if m > 0: unicode_strings = self.storage_stream_us_parser( data[m + 3:]) dlist = self.parse_config(unicode_strings) break else: debug.info( "Asyncrat configuration signature not found.") config_data.append(dlist) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=ramnit_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] # resource PE search dll_index = data.rfind(MZ_HEADER) dll_data = data[dll_index:] try: pe = pefile.PE(data=dll_data) except: outfd.write("[!] Can't mapped PE.\n") continue for section in pe.sections: if ".data" in section.Name: data_address = section.PointerToRawData config_data.append(self.parse_config(pe, dll_data, data_address)) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=poisonivy_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] for pattern in CONFIG_PATTERNS: mc = re.search(pattern, data) if mc: offset = mc.start() while data[offset] != "\xC3": offset -= 1 while data[offset:offset + 2] != "\x00\x00": (idx, size) = unpack_from("<HH", data, offset + 1) if size > 0: enc = data[offset + 5:offset + 5 + size] config_data.append(self.parse_config(idx, enc)) offset = offset + size + 4 yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) rules = yara.compile(sources=sigs) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) config = False start_add = False stop_add = False for hit, address in scanner.scan(): if str(hit) == 'darkcomet_config': config = hit start_add = address stop_add = address + 0x190 if config and start_add and stop_add: yield task, config, start_add, stop_add else: pass
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=cobaltstrike_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] for nw in CONF_PATTERNS: cfg_addr = data.find(nw['pattern']) if cfg_addr != -1: break else: continue cfg_blob = data[cfg_addr:cfg_addr + nw['cfg_size']] config_data.append( self.parse_config(self.decode_config(cfg_blob), nw)) yield task, vad_base_addr, end, hit, memory_model, config_data break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") addr_space = utils.load_as(self._config) if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") # For each process in the list for task in self.filter_tasks(tasks.pslist(addr_space)): # print task.ImageFileName for vad, address_space in task.get_vads( vad_filter=task._injection_filter): # Injected code detected if there's values returned rules = yara.compile(sources=signatures) scanner = malfind.VadYaraScanner(task=task, rules=rules) # print 'before' for hit, address in scanner.scan(): vad_base_addr = self.get_vad_base(task, address) # Get a chuck of memory of size 2048 next to where the string was detected content = address_space.zread(address, 2048) yield task, address, vad_base_addr, content break
def calculate(self): if not has_yara: debug.error("Yara must be installed for this plugin") if not has_yara: debug.error("Aplib must be installed for this plugin") addr_space = utils.load_as(self._config) os, memory_model = self.is_valid_profile(addr_space.profile) if not os: debug.error("This command does not support the selected profile.") rules = yara.compile(sources=ursnif_sig) for task in self.filter_tasks(tasks.pslist(addr_space)): scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): vad_base_addr, end = self.get_vad_base(task, address) proc_addr_space = task.get_process_address_space() data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr) config_data = [] # Parse standard Ursnif config_data = self.parse_joinned_data(data) # Parse static configuration type Ursnif if not config_data: p_data = OrderedDict() data = self.pe_magic_check(data) try: pe = pefile.PE(data=data) except: continue imagebase = pe.NT_HEADERS.OPTIONAL_HEADER.ImageBase for pattern in CONFIG_PATTERNS: m = re.search(pattern, data) if m: if pe.FILE_HEADER.Machine in ( pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']): c2_num = unpack("b", data[m.start(7) + 19])[0] else: c2_num = unpack("b", data[m.start(6)])[0] if c2_num >= 16: c2_num = 1 for i in range(c2_num): if pe.FILE_HEADER.Machine in ( pefile.MACHINE_TYPE[ 'IMAGE_FILE_MACHINE_IA64'], pefile.MACHINE_TYPE[ 'IMAGE_FILE_MACHINE_AMD64']): c2_addr = m.start(4) + unpack( "=I", data[m.start(3):m.start(3) + 4])[0] c2_table_offset = unpack( "=Q", data[c2_addr + (8 * i):c2_addr + 8 + (8 * i)])[0] - imagebase else: c2_addr = unpack( "=I", data[m.start(4):m.start(4) + 4])[0] - imagebase c2_table_offset = unpack( "=I", data[c2_addr + (4 * i):c2_addr + 4 + (4 * i)])[0] - imagebase try: c2 = self.decode_data( data, pe, c2_table_offset) except: c2 = "Decode fail" p_data["Server " + str(i)] = c2 if pe.FILE_HEADER.Machine in ( pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']): serpent_key_offset = m.start(8) + unpack( "=I", data[m.start(7):m.start(7) + 4])[0] else: serpent_key_offset = unpack( "=I", data[m.start(8):m.start(8) + 4])[0] - imagebase try: serpent_key = self.decode_data( data, pe, serpent_key_offset) except: serpent_key = "Decode fail" p_data["Serpent key"] = serpent_key for pattern in RSA_PATTERNS: m = re.search(pattern, data) if m: if pe.FILE_HEADER.Machine in ( pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile. MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']): rsa_key_offset = m.start(2) + unpack( "=I", data[m.start(1):m.start(1) + 4])[0] rsa_key = data[rsa_key_offset + 4:rsa_key_offset + 0x44] rsa_mod = data[rsa_key_offset + 0x44:rsa_key_offset + 0x84] else: rsa_key_offset = unpack( "=I", data[m.start(1):m.start(1) + 4])[0] - imagebase rsa_key = data[rsa_key_offset:rsa_key_offset + 0x40] mod_offset = unpack( "=I", data[m.start(4):m.start(4) + 4])[0] - imagebase rsa_mod = data[mod_offset:mod_offset + 0x40] p_data["RSA key"] = rsa_key.encode("hex") p_data["RSA modulus"] = rsa_mod.encode("hex") config_data.append(p_data) yield task, vad_base_addr, end, hit, memory_model, config_data break
def extract_elite_config(self, pid_list): configurations = {} target_pids = [ t["pid"] for t in pid_list if t["implant_type"] != "Scout" ] addr_space = utils.load_as(self._config) # Check all the things that could be wrong... if not has_yara: debug.error("Yara must be installed for this plugin") if not self.is_valid_profile(addr_space.profile): debug.error("This command does not support the selected profile.") if self._config.DUMP_DIR == None: debug.error("Please specify a dump directory (--dump-dir)") if not os.path.isdir(self._config.DUMP_DIR): debug.error(self._config.DUMP_DIR + " is not a directory") sources = { 'namespace1': 'rule HT_ELITE {strings: $a = {22 53 59 4e 43 22} condition: $a}' } # Search for "SYNC" rules = yara.compile(sources=sources) tasklist = [ t for t in tasks.pslist(addr_space) if str(t.UniqueProcessId) in target_pids ] # Only target Elite implants we've discovered - saves work and false positives for task in tasklist: scanner = malfind.VadYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): hitdata = scanner.address_space.zread(address - 768, 1024) # Now go backwards until we get to a binary character (i.e. the start of the ascii configuration file) binary_found = False start = address character = scanner.address_space.zread(start, 1) while character in string.printable: start = start - 1 character = scanner.address_space.zread(start, 1) start = start + 1 # Avoids \x00 at beginning # Search forwards until we find the end of the ascii configuration file end = address character = scanner.address_space.zread(end, 1) while character in string.printable: end = end + 1 character = scanner.address_space.zread(end, 1) config_file = scanner.address_space.zread(start, end - start) # Now try to parse the config file data = config_file try: config = json.loads(data) except: # Our config isn't entirely intact - try to repair - this is not exact # Count quotes quotes = [i for i in data if i == "\""] if len(quotes) % 2 != 0: data = "\"" + data # Count Braces right_braces = [i for i in data if i == "}"] left_braces = [i for i in data if i == "{"] if left_braces < right_braces: data = "{" + data elif left_braces > right_braces: data = data + "}" # Now try to decode again try: config = json.loads(data) dump_file = "configuration_elite_" + str( task.UniqueProcessId) + "_" + hex(start) + ".json" config_file = json.dumps(config, indent=4) config_json = True except: dump_file = "configuration_elite_" + str( task.UniqueProcessId) + "_" + hex(start) + ".text" config_json = False # Write config file out to directory with open(os.path.join(self._config.DUMP_DIR, dump_file), 'w') as f: f.write(config_file) pid_dict = [ i for i in pid_list if i["pid"] == str(task.UniqueProcessId) ][0] index = pid_list.index(pid_dict) pid_list[index]["config_file"] = os.path.join( self._config.DUMP_DIR, dump_file) if config_json: # Try to parse the json to extract the C2 server try: for action in config["actions"]: if action["desc"] == "SYNC": pid_list[index]["c2_server"] = action[ "subactions"][0]["host"] except: pid_list[index]["c2_server"] = None else: pid_list[index]["c2_server"] = None # Now for the other pids that don't have a configuration file: for pid in pid_list: if "config_file" not in pid.keys(): pid["config_file"] = None pid["c2_server"] = None return pid_list