The coolest part of this blog post may be the CTF art! DEADFACE CTF was great, with many of the challenges being a mixture of things to do. The CTF had this phased thing going on, so challenges were gradually released in 5 phases. I wasn’t too fond of that, especially as a non-US player where our prime time often had no challenges left.
Here are some of the challenges I solved playing for Hack South, where we managed to get 11th place out of 1195 teams that scored.
solutions
The challenges weren’t available when I got to this writeup, so lot’s of detail on that front is missing.
starter
Flag: flag{themz_the_ru1es}
I noticed this flag before the CTF even started in this medium article. The flag was at the bottom.
programming
Flag: flag{0h-look-a-FlaG}
I forgot the name of this challenge, but it was the first programming one. We get some code:
#!/usr/bin/env python3
from binascii import unhexlify as u
def get_flag():
flag = '666c61677b30682d6c6f6f6b2d612d466c61477d'
return u(flag).decode('utf-8')
print(f'The flag is: ')
Solve by calling get_flag()
.
print(f'The flag is: ' + get_flag())
cereal killer
Flag: flag{c0unt-ch0cula-cereal-FTW}
We’re given Windows and Linux bins. Decompilation reveals a bunch of work that looks like a string getting XOR’d before asking the user for input.
Solve by breaking anywhere after that really and checking out stack contents. Either:
- break on
main
withb *main
r
disas main
b *0x0000555555555119
where0x0000555555555119
is the address tocall 0x555555555080 <puts@plt>
c
and read flag off stack
or
- break on the call to
puts
withb puts
r
- read flag off stack
poor megan
Flag: flag{Six-Parts-Honey-One-Part-Garlic}
I don’t really know how this works, but thanks to CyberChef’s “magic” module it somehow figured out the custom character set needed to base64 decode it.
Given the input j2rXjx9dkhW9eLKsnMR9cLDVjh/9dwz1QfGXm+b9=wKslL1Zpb45
, this recipe reveals the flag.
file 101
Flag: flag{Easy_Right}
You got a zip file to download that you had to crack the password for. Use zip2john
to get a hash, and then your favourite password cracker to finally reveal pumpkinpie
as the password (Reelix solved that part, thanks!).
Next, the image you get from the zipfile is corrupt. Use a hex editor to fix up the header (I used another valid PNG as reference) and open the file to reveal the flag.
the count
Flag: flag{d1c037808d23acd0dc0e3b897f344571ddce4b294e742b434888b3d9f69d9944}
This challenge was hosted. Connecting to the target gave you the instructions:
DEADFACE gatekeeper: Let us see how good your programming skills are.
If a = 0, b = 1, c = 2, etc.. Tell me what the sum of this word is:
You have 5 seconds to give me an answer.
Your word is: calendar
A alphabetic character position counter it is! One cool thing I learnt here is that I can call index()
on the character sets provided by string
to get the alphabetic position!
import string
from pwn import *
pos = lambda t : string.ascii_lowercase.index(t)
r = remote('code.deadface.io', 50000)
r.recvuntil('Your word is:')
w = r.recvline().strip().decode()
v = sum([pos(x) for x in w])
print(f'{w} = {v}')
r.send(f'{v}\n')
r.interactive()
r.close()
TheZeal0t’s Cryptoware IOC 1
Flag: flag{DEADFACE_LLABS_CRYPTOWARE/6.69}
Run the binary you get and view the network traffic in Wireshark to reveal the flag as the User-Agent header in an HTTP request.
Cereal Killer 3
Flag: flag{B00-B00-B00-Bury-IZ-DA-BOMB}
I remember laughing at this challenge. It was worth something like 500 points, and I think it was one I solved the fastest xD
Run the bin in gdb, then:
- break on
puts
withb puts
r
c
- read the flag as a string in
$ecx
. - lol
El Paso
Flag: flag{$877,401.00}
Some challenges built on top a “leaked” MySQL database that you had to run some queries on. The query to solve this challenge was:
select sum(loans.balance) from employees
right join loans on loans.employee_id = employees.employee_id
where employees.city = 'El Paso';
Trick or Treat
Flag: flag{CaNT_ch34t_d34th}
This challenge was built on PyGame, where you get the source code.
I originally solved it by commenting out the code that checked for collisions. Leaving that running, after a while the flag simply printed to the terminal. Later I realised, I could have just run a function called gs()
manually that would print the flag as well.
Syncopated Beat
Flag: flag{ELECTRIC-LIGHT-ORCHESTRA}
This was an audio steganography challenge. We’re given a video where the audio track sounds obviously weird at ~2 minutes in. I couldn’t make out what exactly it was, so I played around with it in Sonic Visualiser at first. That revealed nothing interesting.
Next, after extracting the audio from the video, opening the track in audacity reveals the section of interest pretty clearly.
I cut that section out and applied the “reverse” effect by browsing the menu system: “Effect -> Reverse”. Next, play the audio to hear the flag.
Decrypting Lytton Labs Cryptoware 2
Flag: flag{PEANUT-BUTTER-Crunch-Mixed-With-Cocoa-Puffs-Beats-All-Those-Cereals!}
More Golang malware (puke), but this one took me a while. We also got a decryptor this time. The code flow for the encryptor was not too different when compared to the first cryptoware challenge, which helped. The function to focus on was fetchKey
. As usual, a “key” was fetched remotely that could be revealed in Wireshark (or by blocking network access to the bin causing a panic that reveals the URL as well).
While normally I use (and really like) the Ghidra decompiler in cutter/r2, this time jsdec helped a lot in realising that once the key was fetched, an MD5 sum is calculated of the content. This was also visible in the disassembly, but I missed that initially
To decrypt the file, I ran ./zealotcrypt-02-decrypt.bin d8f5c876b36f019254a7307c1eb0fe09
.
The Victims of Lytton Labs
Flag: flag{D0nt-ME$$-with-The-ZEAL0t!!!}
(I didn’t solve this challenge myself completely, but it was interesting enough to writeup.)
We’re given a (fairly large) pcap to work with. There’s a lot going on, but after spending some time you’d see what looks like an FTP credential brute force that’s eventually successful. Then, some files are downloaded.
To extract the files from the pcap, just follow the TCP stream, view as Raw and hit “Save As”. This way you’d end up with a “secret” (encryption-password-cgeschicker.txt
), an encryptor (lytton-crypt.bin
) and some encrypted files (*.lcr
files). There was also what looked like a small reverse shell in a binary called secret_decoder.bin
.
Running the cryptor, we’d see a few flags could be passed:
$ ./lytton-crypt.bin
Usage is: ./lytton-crypt.bin -[orc][-sN] file1 file2..
-o Write output to standard out
-r Do NOT remove input files after processing
-c Do NOT compress files before encryption
-sN How many times to overwrite input files with random data
A lot of the cryptor logic was wrapped up in the main function, and depending on what files you passed it it, the cryptor figured out if it needed to encrypt or decrypt the input file.
As for the secret file you got, the value 75AC98147C07752767E09EF781CF998E401D19B01E30CBAA5109D6AD7EC9A174
from the encryption-password-cgeschicker.txt
was not a valid encryption key.
$ echo "75AC98147C07752767E09EF781CF998E401D19B01E30CBAA5109D6AD7EC9A174" | ./lytton-crypt.bin david-k.txt.lcr
Encryption key:
Invalid encryption key for file: david-k.txt.lcr
Stuck here for quite a while, @carlmonning realised the key value is actually a SHA256 hash, that when cracked is demagorgon
.
So, do decrypt the files and reveal the flag run:
echo "demagorgon" | ../lytton-crypt.bin *.lcr