5 minute read




For this challenge we were given an application and its source code (C program). Analysing the code I saw that it was vulnerable to format string since it was printing the user input directly when option 2 is selected


Another interesting thing is that if the variable set is equal to 4, and no valid option is selected, the app calls guess_me without generating a new fav_num (reusing the existing one)!

Launching the application and following the logic above to get me the flag.


So in order to exploit this vulnerability and get the flag, I had to use option 1 four times and then use option 2 once to exploit the format string vulnerability so I could get the fav_num in memory! Finally to get the flag I just needed to choose a random option (could not be neither 1 or 2… I choose 4 just because) so it would trigger a call to the gess_me function without generating a new number… Testing locally in GDB


The 7th value is the fav_num and what we want. Using that number and continuing I was successful (got an error with the cat command because I didn’t had the flag.txt file)


Good… now remotely


FLAG: SEE{4_f0r_4_f0rm4t5_0ebdc2b23c751d965866afe115f309ef}


Looking at the python code it, I saw that it was accepting an input for option 4 and opening a file (with cat command). The only check that was being made was to the filename, where it would verify if the user input contained any character from the string “FLAG”, failing if it did.


Since the filename was being used in an “eval” function, it was possible to just run code in it, so I encoded the string “FLAG” in hex and then wrote a python line to decode it again


running it against the server got me the flag


FLAG: SEE{wayyang_as_a_service_621331e420c46e29cfde50f66ad184cc}



I was given an application for this challenge, so using children to decompile it, I saw that the application was getting the flag from the user input, comparing each character to a character in an array after an XOR operation… if it failed it would print the index where it failed. Which makes it easy to brute force…


I wrote a simple python script to do this.

#!/usr/bin/env python
from pwn import *

context.log_level = 'error'
keep_going = True
current_error_index = 0
current_char = 33

while keep_going:
	p = process("./chall")
	p.recvuntil("Please enter the flag.")
	line = str(p.recvall(), "utf-8)")
	if "Flag check failed at index" in line:
		error_index = int(line[-2:])
		if current_error_index != error_index:

		current_error_index = error_index
		current_char = 33		
		print("Current flag is: %s" % flag)
				flag = flag[:error_index] + chr(current_char) + flag[error_index+1:]
			cursor_index += 1
			current_char += 1
		except Exception as e:
			print("error! %s" %e)
	elif "Success! Go get your points, champ." in line:
		keep_going = False

Running it and I got the flag.


FLAG: SEE{0n3_5m411_573p_81d215e8b81ae10f1c08168207fba396}


Close Enough

For this challenge I was given a cyphered text, a public key and python script that was used to encrypt the ciphered text.
Using RsaCtfTool.py I ran

RsaCtfTool.py --publickey key --private

This gave me the private key that was used.


Now with the private key I just parsed the cypher that was given in bytes (in the original code it was being parsed from bytes to long)

from Crypto.Util.number import long_to_bytes

cypher = 4881495507745813082308282986718149515999022572229780274224400469722585868147852608187509420010185039618775981404400401792885121498931245511345550975906095728230775307758109150488484338848321930294974674504775451613333664851564381516108124030753196722125755223318280818682830523620259537479611172718588812979116127220273108594966911232629219195957347063537672749158765130948724281974252007489981278474243333628204092770981850816536671234821284093955702677837464584916991535090769911997642606614464990834915992346639919961494157328623213393722370119570740146804362651976343633725091450303521253550650219753876236656017

cypher_bytes = long_to_bytes(cypher)


Finally using cyberchef


FLAG: SEE{i_love_really_secure_algorithms_b5c0b187fe309af0f4d35982fd961d7e}


Sniffed Traffic

For this challenge I was given a network capture file and I was told that someone downloaded a file and I would need to find the contents of that file. So filtering in wireshark for **http   http2   file** and I got a zip file


I saved that file and tried to unzip it but it was password protected so tried using strings and grep to see if it was shared in a message… and it was! I got the password 49949ec89a41ed9bdd18c4ce74f37ae4


Unzipping it got me a file called stuff, that was just seen as “data”. Using bin walk I found it was indeed a zip file again.


Trying to unzip it and I found that it was yet another password protected zip… tried different password until I decided to just brute force it… First, I ran zip2john to get a hash file that I could use in John.

zip2john -m stuff > stuff.hash

and then

john --wordlist=/opt/SecLists/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt  stuff.hash


password was “john”! Unzipping it and I got the flag.txt file!


FLAG: SEE{w1r35haRk_d0dod0_4c87be4cd5e37eb1e9a676e110fe59e3}



Removed all “SEE{“ and “} from the original file and using a regex to get the flag which had the correct format! I used the regex ^([A-Z]{5})([0-9]{5})([A-Z]{6})


Angry Zeyu2001

Downloading the challenge and unzipping it, got me 1219 jpg files. It was obvious from the names that it was width.height.jpg


So I wrote a small script to put it all together.

import sys
import os
from PIL import Image

arr = os.listdir("pieces/")
images = [Image.open("pieces/" + x) for x in arr]
total_width = 700
max_height = 250

new_im = Image.new('RGB', (total_width, max_height))

for im in images:
	sizes = im.filename.split("/")[-1].split(".")
	new_im.paste(im, (int(sizes[0]), int(sizes[1])))


The output of the script was a new JPG file with the flag


FLAG: SEE{boss_aint_too_happy_bout_me_9379c958d872435}



Followed the steps in the git page tutorial of this challenge, to setup the environment. Then I uploaded the contract from the challenge into remix IDE

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Bonjour {

  string public welcomeMessage;

  constructor() {
    welcomeMessage = "Bonjour";

  function setWelcomeMessage(string memory _welcomeMessage) public {
    welcomeMessage = _welcomeMessage;

  function isSolved() public view returns (bool) {
    return keccak256(abi.encodePacked("Welcome to SEETF")) == keccak256(abi.encodePacked(welcomeMessage));

After a bit of time playing with it, I connected Remix to my MetaMask wallet and pasted the contract address that I initiated in the challenge server in order to load it and interact with it.


The contract was simple enough to read, just had to set the message value to “Welcome to SEETF” and the isSolved() function would return true. In remixIDE i set the message and then in the challenge server I just got the flag.



Sourceless Guessy Web

This challenge was an obvious path traversal vulnerability… so after a few tries, i used page=../../../../etc/passwd and got the flag.