Metastealer
DGAs and obfuscation as malware goes meta
Overview
This is a stealer that has been in operation since atleast May 2022. Recent versions have added a DGA!
References
- MetaStealer: String Decryption and DGA overview
- Metastealer – filling the Racoon void
- IOCs from Unit42
Sample
-
6cf8bfba1b221effcb1eccec0c91fb0906d0b8996932167f654680cb3ac53aac
UnpacMe
Analysis
This sample has many strings related to the build process that have not been stripped. We can use these for our yara rule.
"powershell -inputformat none -outputformat none -NonInteractive -Command Add-MpPreference -ExclusionExtension \"exe\"",
C:\Workspace\Projects\rat\client\stealer\third_party
C:\Workspace\Projects\rat\client\stealer\out\build\x86-Releaseird_party\cryptopp\_deps\cryptopp\rijndael_simd.cpp
stealertest.dll
IBrowserBase@stealer
ChromeBrowser@stealer
EdgeBrowser@stealer
FirefoxBrowser@stealer
This sample looks similar maybe an earlier version
5e5cc4f42c7d5481db280b28d1227568c17ed8cc4208970b7a963a4f30c7cc83
C:\3001_1\notbotnet\client\stealer\out\third_party\cryptopp
C:\3001_1\notbotnet\client\stealer\third_party
stealertest.dll
Yara Rule
rule metastealer_dga {
strings:
$libs = "rat\\client\\stealer" ascii wide
$rtti_1 = "IBrowserBase@stealer"
$rtti_2 = "ChromeBrowser@stealer"
$rtti_3 = "EdgeBrowser@stealer"
$rtti_4 = "FirefoxBrowser@stealer"
$name = "stealertest.dll"
condition:
$name or
all of ($rtti_*) or
$libs
}
String Decryption
This is a modified version of Jason Reeves' script from his blog
'''
rule meta_s
{
meta:
author = "sysopfb"
strings:
$snippet1 = {66 0? ef}
$snippet2 = {c5 ?? ef}
condition:
($snippet1 or $snippet2)
}
'''
import re
file_data = open('/tmp/metastealer.bin', 'rb').read()
offsets = []
string_egg = rb'\x66[\x00-\x0f]\xef'
for m in re.finditer(string_egg, file_data, re.DOTALL):
offsets.append(m.start())
ret = []
out = None
length_off = False
prev_offset = 0
for offset in offsets:
test = file_data[prev_offset:offset]
vals = re.findall(b'''\xc7\x85..\xff\xff....''',test)
if vals != []:
if len(vals) > 8:
temp = vals[-8:]
else:
temp = vals
try:
xdata = temp[0][-4:]
xdata += temp[1][-4:]
xdata += temp[2][-4:]
xdata += temp[3][-4:]
xkey = temp[4][-4:]
xkey += temp[5][-4:]
xkey += temp[6][-4:]
xkey += temp[7][-4:]
xdata = bytearray(xdata)
xkey = bytearray(xkey)
for i in range(len(xdata)):
xdata[i] ^= xkey[i]
tmp_str = b''.join(xdata.split(b'\x00'))
if tmp_str.isascii():
print(tmp_str)
except:
pass
prev_offset = offset
import re
import struct
seed_egg = rb'\x68\xEF\x06\x00\x00.{6,16}\x68(..\x00\x00)'
for m in re.finditer(seed_egg, file_data, re.DOTALL):
tmp_seed = struct.unpack('<I', m.group(1))[0]
print(hex(tmp_seed))