Page cover

Pico CTF 2025

Hey, fellow hackers! 🏴‍☠️

I’m dropping a writeup for the Pico CTF 2025 challenges!️. I teamed up with my squad, P4rad0x. Let’s jump straight into the action! 💻🔥

Web

Challenge Description

A challenge named after everyone’s favorite blue, cookie-loving monster. The challenge name hints at cookies, implying that authentication or sensitive information might be stored within browser cookies.

Developer Tools

Upon visiting the website, I inspected the cookies using the browser's developer tools (Application > Cookies).

The cookie value was base64-encoded, which is a common method of simple obfuscation.

Decoding the base64 string revealed the flag.

CyberChef

picoCTF{c00k1e_m0nster_l0ves_c00kies_057BCB51}

Heap-Dump

Challenge Description

A web-based challenge involving an API where memory dumps might be accessible.

Website

Navigated through the web interface and identified api-docs revealing various API endpoints.

API endpoints

One particular endpoint, /heapdump, caught my attention as it could contain sensitive memory data. Using curl, I accessed the /heapdump and filtered through the output with grep to extract the flag.

picoCTF{Pat!3nt_15_Th3_K3y_388d10f7}

n0s4n1ty 1

Challenge Description

This challenge involved a file upload functionality that could be exploited for Remote Code Execution (RCE).

Website

The website allowed users to upload files without restriction. I attempted uploading a basic PHP command injection script to execute arbitrary commands.

After successfully uploading the file, I accessed it via the browser and executed system commands. Using cat flag, I retrieved the flag from the server.

Flag

picoCTF{wh47_c4n_u_d0_wPHP_a4ca6ea0}

SSTI1

Challenge Description

A web form suggested the possibility of Server-Side Template Injection (SSTI), a common vulnerability in improperly sanitized template engines.

Entered {{ 7*7 }} in the input field to confirm SSTI vulnerability. The output 49 verified that user input was being evaluated as code.

SSTI input
SSTI output

Once the vulnerability is confirmed, I can escalate it to execute system commands or read sensitive files. Extracted the flag using:

Flag

Reversing

Flag Hunters

Challenge Description

This challenge presented a Python script that dynamically sings a song, inserting the flag into the lyrics. The flag is stored in a file called flag.txt and is referenced within the script.

Understanding the code:

  • The script reads the flag from flag.txt and integrates it into the song lyrics.

  • It defines a song structure using labeled sections ([VERSE1], [REFRAIN], etc.).

  • The function reader(song, startLab``el) processes the song lyrics and follows control flow logic based on RETURN statements and user input.

  • The Crowd: prompt expects input, but simply providing RETURN 0;RETURN 0 skips unnecessary interaction and proceeds to reveal the flag.

  • The ';' is provided here because of for line in song_lines[lip].split(';'): splits the songs label with it and it will be converted into integer here elif re.match(r"RETURN [0-9]+", line): and it goes to the line "0" which is start of the program where it has the flag.

Connected to the remote instance via Netcat:

Observed the song lyrics being printed dynamically. Responded with RETURN 0;RETURN 0 when prompted, allowing the script to cycle through and eventually print the flag

picoCTF{70637h3r_f0r3v3r_a3d964ee}

Forensics

RED

Challenge Description

In this challenge, I was provided with a PNG file red.png and the word "RED" is all over the challenge.

The first step was to analyze the image using forensic tools. PNG files often hide information through steganography.

The zsteg tool, commonly used for extracting hidden messages from PNG images, was employed for analysis.

Running zsteg red.png revealed a Base64-encoded string. Decoding the Base64 string revealed the flag.

picoCTF{r3d_1s_th3_ult1m4t3_cur3_f0r_54dn355_}

Ph4nt0m 1ntrud3r

Challenge Description

The challenge provided a PCAP (Packet Capture) file myNetworkTraffic.pcap. Given the nature of network forensic challenges, I anticipated the flag might be hidden within packet data.

First, I opened the PCAP file using Wireshark. Observed a significant amount of TCP segment data, possibly encrypted or encoded.

Wireshark

Used tshark to extract TCP segment data. The data is indeed encoded using base64 and I decoded it.

There is so much unwanted data with frame length of "48" so i removed it and the remaining is the flag in wrong order.

nt_th4t } e1ff063 _34sy_t {1t_w4s picoCTF bh_4r_2

I assembled it as flag.

picoCTF{1t_w4snt_th4t_34sy_tbh_4r_2e1ff063}

Bitlocker-1

Challenge Description

The challenge provided a Windows BitLocker-encrypted image file (MBR Boot Sector File) bitlocker.dd. The goal was to unlock and extract the flag.

First step for Identifying the file type I used the file command to confirm that the provided .dd file was an MBR boot sector with BitLocker encryption.

Secondly for the extracting password hashes I used bitlocker2john to extract BitLocker password hashes from the image file.

For cracking the hash, I used hashcat , which is a popular tool to for cracking hashes. It successfully cracked the hash and retrieved the password -> jacqueline

hashcat

After that, I created a mount point and used dislocker tool to unlock BitLocker.

Then I mounted the decrypted BitLocker volume and accessed the file system to read the flag.txt file.

picoCTF{us3_b3tt3r_p4ssw0rd5_pl5!_3242adb1}

Cryptography

HashCrack

Challenge Description

In this challenge, I had to connect to a remote server using netcat. Upon connection, the server presented a series of hashed passwords that I needed to crack in order to progress. The hashes were of different types, including MD5, SHA-1, and SHA-256.

Upon connecting to the server:

I received the following prompts:

  1. MD5 Hash

  • Hash: 482c811da5d5b4bc6d497ffa98491e38

  • Cracked password: password123

  • Response: "Correct! You've cracked the MD5 hash with no secret found!"

  1. SHA-1 Hash

  • Hash: b7a875fc1ea228b9061041b7cec4bd3c52ab3ce3

  • Cracked password: letmein

  • Response: "Correct! You've cracked the SHA-1 hash with no secret found!"

  1. SHA-256 Hash

  • Hash: 916e8c4f79b25028c9e467f1eb8eee6d6bbdff965f9928310ad30a8d88697745

  • Cracked password: qwerty098

  • Response: "Correct! You've cracked the SHA-256 hash with a secret found."

The final response revealed the flag:

picoCTF{UseStr0nG_h@shEs_&PaSswDs!_29028be8}

Even RSA Can Be Broken???

Challenge Description

In this challenge, I was given an RSA encryption script encrypt.py and had to decrypt an encrypted flag. The server provided the RSA parameters: N (modulus), e (public exponent), and the ciphertext.

Upon connecting to the server:

Understanding the Encryption Code

The encryption process in encrypt.py follows the standard RSA encryption technique:

So, i used an online tool dcode.fr which has RSA decryption function.

dcode.fr

The decrypted message revealed the flag. picoCTF{tw0_1$_pr!m33991588e}

Binary Exploitation

PIE TIME

Challenge Description

In this challenge, I was provided with a remote connection to a binary running on a server:

Additionally, we receive two downloadable files:

Analyzing the Source Code

The provided vuln.c code snippet is as follows:

Understanding the code:

  • The program prints the address of the main() function.

  • It prompts the user for an address to jump to.

  • It then treats the given input as a function pointer and executes it.

  • If an incorrect address is given, a segfault handler prevents crashes.

  • The win() function, which prints the flag, is not explicitly called anywhere in the program.

The goal? Find and provide the correct address for win() so the program jumps to it!

Bypassing Position-Independent Executable (PIE)

Since PIE is enabled, the memory addresses change on each execution. However, the offset between functions remains the same. To determine this offset, we analyze the binary using Radare2:

Observations:

  • The offset between win() and main() is 150 bytes.

  • When we connect to the remote server, it prints the dynamically assigned main() address.

Thus, we can calculate win() address:

win_address = main_address - 150

Connecting to the challenge server:

picoCTF{b4s1c_p051t10n_1nd3p3nd3nc3_3d38fb4b}

General Skills

Rust Fixme 1

Challenge Description

This is a challenges which presents a piece of Rust code with several syntax and logical errors. The goal is to identify and fix these issues to successfully decrypt an encrypted message.

Given Rust code with errors:

Fixed Rust code:

Key Fixes and Explanation:

  1. Fixed missing semicolon (;) → Rust requires semicolons to terminate statements.

  2. Replaced ret; with return; → Rust does not have a ret keyword.

  3. Corrected println! syntax → Used {} instead of :? for formatted output.

  4. Passed encrypted_buffer as a reference → Ensures proper memory handling.

picoCTF{4r3_y0u_4_ru$t4c30n_n0w?}

Rust Fixme 2

Challenge Description

In this it requires modifying a function so that it correctly updates a mutable string passed as an argument.

Given Rust code with errors:

Fixed Rust code:

Key Fixes and Explanation:

  1. Used &mut String → Allows modification of borrowed_string inside the function.

  2. Declared party_foul as mutablelet mut party_foul = String::from("...").

  3. Passed party_foul as &mut → Enables mutation within decrypt() .

picoCTF{4r3_y0u_h4v1n5_fun_y31?}

Rust Fixme 3

Challenge Description

This challenge focuses on eliminating unnecessary unsafe operations and ensuring safe memory handling in Rust.

Given Rust code with errors:

Fixed Rust code:

Key Fixes and Explanation:

  1. Removed unnecessary raw pointer operations → Rust is memory-safe by default; avoid unsafe unless absolutely needed.

  2. Used a simple reference (&decrypted_buffer) instead of unsafe slices.

  3. Preserved Rust’s memory safety principles → The corrected code works efficiently without unsafe blocks.

picoCTF{n0w_y0uv3_f1x3d_1h3m_411}


Last updated