2024 HuntressCTF - System Code
2024-10-08

Summary
Author: Truman Kain
Follow the white rabbit.
NOTE: Bruteforce is permitted for this challenge instance if you feel it is necessary.
Steps
When starting this challenge we are presented with a red or blue pill. The blue pill to redirect to a matrix screen with a text box. If you input the incorrect value, you’ll receive this error: “Incorrect. You will receive the flag with the correct input.”.
At the bottom of the website is a credit link that will take you to the matrix repo. After several hours or not making any progress, I worked with ChatGPT to come up with a script to download the files from the repo and then perform a HTTP request to the same file on the challenge server and look for differences.
import os
import subprocess
import requests
from filecmp import cmp
RED_BOLD = "\033[1;31m"
RESET = "\033[0m"
# Step 1: Clone the repo if it hasn't been cloned yet
repo_url = "https://github.com/Rezmason/matrix"
repo_dir = "matrix_repo"
if not os.path.isdir(repo_dir):
subprocess.run(["git", "clone", repo_url, repo_dir])
# Step 2: Define the base URL for the CTF server
ctf_base_url = "http://challenge.ctf.games:31711/"
# Step 3: Function to download a file from the CTF server
def download_ctf_file(ctf_url, ctf_file_path):
response = requests.get(ctf_url)
if response.status_code == 200:
with open(ctf_file_path, "wb") as f:
f.write(response.content)
return True
else:
print(f"Failed to download {ctf_url}")
return False
# Step 4: Walk through the repository files and compare each one
for root, dirs, files in os.walk(repo_dir):
for file in files:
# Construct the relative file path in the repo
repo_file_path = os.path.join(root, file)
relative_path = os.path.relpath(repo_file_path, repo_dir)
# Construct the URL for the corresponding file on the CTF server
ctf_url = ctf_base_url + relative_path
ctf_file_path = "ctf_" + file
# Download the file from the CTF server
if download_ctf_file(ctf_url, ctf_file_path):
# Compare the repo file with the CTF filei
if cmp(repo_file_path, ctf_file_path, shallow=False):
print(f"{relative_path}: Files are identical.")
else:
print(f"{RED_BOLD}{relative_path}: Files are different.{RESET}")
# Remove the downloaded CTF file after comparison
os.remove(ctf_file_path)
else:
print(f"{relative_path}: File not found on CTF server.")
The script will enumerate through the various files and you’ll see if found that config.js
was different.
After comparing the config.js file, I found backupGlyphsTwr: ["a", "b", "c", "d", "e", "f"], // The characters to fallback to if glyphs fail to load
.
I spent time with BurpSuite to make sure the various .png files failed to load, but this never actually rendered a flag or helped make progress. Eventually, I had ChatGPT create every permutation of a+b+c+d+e+f
which resulted in a 720 line file. I passed this to BurpSuite and used intruder to test each iteration, which turned out to be the flag.
GET /enter=bfdaec HTTP/1.1
Host: challenge.ctf.games:31711
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: */*
Referer: http://challenge.ctf.games:31711//
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Flag: flag{dc9edf4624504202eec5d3fab10bbccd}