Reverse engineering a Gameboy ROM with radare2



A month ago in Barcelona I was attending to r2con for the first time. This is the official congress of the radare2 community where everyone can learn more about radare2 framework and dive deep into different aspects of reverse engineering, malware analysis, fuzzing, exploiting and more. It also the place where all of us, the contributors and developers of radare2, can meet, discuss and argue about every other line of code in the framework.

This was the second congress of radare2, after the success of the first congress in last year which was also a celebration for radare’s 10 years old birthday. This year the conference was bigger, fancier and probably organized much better. r2con was four days long, starting at September 6 and lasted until September 9. The first two days were dedicated to training and took place at Universitat de Barcelona. The other two days were talks days and took place at the MediaPro.

Crackmes Competition

During r2con this year there was a Crackmes competition where all the attendees were given with the same 5 challenges and had to publish a writeups to all the challenges they had solved. The scoring was based on the quality of the writeups along with the quantity of solved challenges.

I won the competition and got myself some cool swag!

  • Flag of radare2
  • POC | GTFO book
  • Orange PI with 3D printed case of r2con logo
  • Radare2 stickers
  • A beer 🍺

I thought of sharing some of my writeups with you, so you can taste a bit from what we had in the competition and so that others, coming from google, twitter and such, could learn how to use radare2 for solving different challenges. This article is aimed to those of you who are familiar with radare2. If you are not, I suggest you to start from part 1 of my series “A Journy Into Radare2”.

Getting radare2


Radare2’s development is pretty quick – the project evolves every day, therefore it’s recommended to use the current git version over the stable one. Sometimes the stable version is less stable than the current git version!

$ git clone
$ cd radare2
$ ./sys/

If you don’t want to install the git version or you want the binaries for another machine (Windows, OS X, iOS, etc) check out the download page at the radare2 website.


As I said before, it is highly recommended to always use the newest version of r2 from the git repository. All you need to do to update your r2 version from the git is to execute:

$ ./sys/

And you’ll have the latest version from git. I usually update my version of radare2 in the morning, while watching cat videos.

Playing with Gameboy ROM

This post will describe how I solved, a Gameboy ROM challenge written by @condret. It was actually my first time reversing a Gameboy ROM — and it was awesome!

First thing I did was to open the binary in radare2 and check for its architecture and format:

$ r2
— For a full list of commands see `strings /dev/urandom`
[0x00000100]> i~format
format   ningb
[0x00000100]> i~machine
machine  Gameboy

The i command gives us information about the binary. Check i? for more commands.

Tilde (~) is r2’s internal grep.

Surprise, surprise, it is a Gameboy ROM — dah. After reading a bit about its instruction set we should go to the mission. 

The obvious thing to do is open the ROM in an Gameboy emulator. I downloaded the good old emulator I used back in the days when I played Pokemon: VisualBoy Advance.

Let’s open the ROM in our emulator and see what we have:

Woops, wrong file. Bad habits… Let’s try again:

Cool! It’s a simple game where, by using the arrow keys, you increase/decrease 5 digits. We ‘simply’ need to find the correct password.

Continue reading


A journey into Radare 2 – Part 2: Exploitation



Welcome back to the second part of our journey into the guts of radare2! In this part we’ll cover more of the features of radare2, this time with the focus on binary exploitation.

A lot of you waited for the second part, so here it is! Hope to publish the next part faster, much faster. If you didn’t read the first part of the series I highly recommend you to do so. It describes the basics of radare2 and explains many of the commands that I’ll use here.

In this part of the series we’ll focus on exploiting a simple binary. radare2 has many features which will help us in exploitation, such as mitigation detection, ROP gadget searching, random patterns generation, register telescoping and more. You can find a Reference Sheet at the end of this post. Today I’ll show you some of these great features and together we’ll use radare2 to bypass nx protected binary on an ASLR enabled system. I assume that you are already familiar with the following prerequisites:

It’s really important to be familiar with these topics because I won’t get deep into them, or even won’t briefly explain some of them.

Updating radare2

First of all, let’s update radare2 to its newest git version:

$ git clone # clone radare2 if you didn't do it yet for some reason.
$ cd radare2
$ ./sys/

We have a long journey ahead so while we’re waiting for the update to finish, let’s get some motivation boost — cute cats video!

Getting familiar with our binary

You can download the binary from here, and the source from here.
If you want to compile the source by yourself, use the following command:

$ gcc -m32  -fno-stack-protector megabeets_0x2.c -o megabeets_0x2

Our binary this time is quite similar to the one from the previous post with a few slight changes to the main() function:

  • Compiled without -z execstac to enable NX bit
  • Receives user input with scanf and not from program’s arguments
  • Uses mostly puts to print to screen
  • Little changes to the program’s output

This was the previous main():

int main(int argc, char *argv[])
    printf("\n  .:: Megabeets ::.\n");
    printf("Think you can make it?\n");
    if (argc >= 2 && beet(argv[1]))
        printf("Nop, Wrong argument.\n\n");

    return 0;

And now main looks like this:

int main(int argc, char *argv[])
    char *input; 
    puts("\n  .:: Megabeets ::.\n");
    puts("Show me what you got:");
    scanf("%ms", &input);
    if (beet(input))
        puts("Nop, Wrong argument.\n\n");

    return 0;

The functionality of the binary is pretty simple and we went through it in the previous post — It asks for user input, performs rot13 on the input and compares it with the result of rot13 on the string “Megabeets”. Id est, the input should be ‘Zrtnorrgf’.

$ ./megabeets_0x2 

  .:: Megabeets ::.

Show me what you got:
Nop, Wrong argument.

$ ./megabeets_0x2 

  .:: Megabeets ::.

Show me what you got:

It’s all well and good but today our post is not about cracking a simple Crackme but about exploiting it. Wooho! Let’s get to the work.

Understanding the vulnerability

As with every exploitation challenge, it is always a good habit to check the binary for implemented security protections. We can do it with rabin2 which I demonstrated in the last post or simply by executing i from inside radare’s shell. Because we haven’t opened the binary with radare yet, we’ll go for the rabin2 method:

$ rabin2 -I megabeets_0x2

arch     x86
binsz    6072
bintype  elf
bits     32
canary   false
class    ELF32
crypto   false
endian   little
havecode true
intrp    /lib/
lang     c
linenum  true
lsyms    true
machine  Intel 80386
maxopsz  16
minopsz  1
nx       true
os       linux
pcalign  0
pic      false
relocs   true
relro    partial
rpath    NONE
static   false
stripped false
subsys   linux
va       true

As you can see in the marked lines, the binary is NX protected which means that we won’t have an executable stack to rely on. Moreover, the file isn’t protected with canariespic  or relro.

Continue reading


A journey into Radare 2 – Part 1: Simple crackme


Update (2020): Since writing this article, it has become, in a way, the go-to tutorial for learning radare2. Your feedback was amazing and I am very happy for the opportunity to teach new people about radare2.

A lot has changed since I wrote this tutorial, both in radare2 and in me. I am now, for several years, a core member in the radare2 team and a maintainer of Cutter, a modern, GUI-based, reverse engineering framework that is powered by radare2.


I was playing a lot with radare2 in the past year, ever since I began participating in CTFs and got deeper into RE and exploitation challenges. I found radare2 very helpful with many CTFs tasks and my solutions had shortened significantly. It’s sometimes also my go-to tool for malware analysis tasks such as configuration retrievals. Sadly, I believe that only few people are familiar with radare2. It might be because they’re afraid to break out of their comfort zone (IDA Pro, OllyDBG, gdb) or they have simply not heard of it. Either way, I honestly believe that you must include radare2 in your toolbox.

Because I got really enthusiastic about the project and I want more and more researchers to be familiar with it, use it and hopefully contribute to the project, I decided to create a series of articles and use-cases of r2. Since these articles aim to teach you the basics of radare2, its features and capabilities, I’ll explain much more than you actually need to know in order to solve each task.

Welcome to IDA 10.0. (see radare2/doc/ for more fortunes)


radare2 is an open-source framework for reverse engineering and binary analysis which implements a rich command-line interface for disassembling, analyzing data, patching binaries, comparing data, searching, replacing, visualizing and more. It has great scripting capabilities, it runs on all major platforms (GNU/Linux, .Windows *BSD, iOS, OSX, Solaris…) and it supports tons of architectures and file formats. But maybe above all of its features stands the ideology – radare2 is absolutely libre.

This framework is composed of a set of utilities that can be used either together from r2 shell or independently – We’ll get familiar with tools such as rahash2, rabin2, ragg2. Together they create one of the most powerful tools in the field of static and dynamic analysis, hex editing and exploitation (I’ll dive deeper in the following articles).

It is important to note that r2’s learning curve is pretty steep – although r2 has an amazing GUI called Cutter, it is still young to compete with more mature RE applications such as IDA or Ghidra. The CLI, however, including its Visual Mode, is still the core of radare2 and where its power lays. Because of its complexity I’ll try to make things as clear and simple as I can.

This is more or less how r2 learning curve works.

This is more or less how r2 learning curve works.

Before we begin you can check out the “Unfair comparison between r2, and other RE platforms” to get an idea of what we’re dealing with.

Getting radare2


Radare2’s development is pretty quick – the project evolves every day, therefore it’s recommended to use the current git version over the stable one. Sometimes the stable version is less stable than the current git version!

git clone
cd radare2

If you don’t want to install the git version or you want the binaries for another machine (Windows, OS X, iOS, etc) check out the download page at the radare2 website.


As I said before, it is highly recommended to always use the newest version of r2 from the git repository. All you need to do to update your r2 version from the git is to execute:


And you’ll have the latest version from git. I usually update my version of radare2 in the morning, while watching cat videos.


I Can’t think of a reason for you to uninstall radare2 so early in the article but if you do want to, you can simply execute:

make uninstall
make purge

Getting Started

Download the first challenge from here.

Now that radare2 is installed on your system and you have downloaded the binary, we are ready to start exploring the basic usage of radare2. I’ll work on a Linux machine but most of the commands and explanations (if not all of them) would be the same for Windows machines and others.

Command Line Arguments

As most command-line utilities, the best approach to reveal the list of the possible arguments is to execute the program with the -h flag.

$ r2 -h

I won’t paste here the full output. Instead, I’ll point out those which I usually use in my daily work:

Usage: r2 [-ACdfLMnNqStuvwzX] [-P patch] [-p prj] [-a arch] [-b bits] [-i file]
          [-s addr] [-B baddr] [-m maddr] [-c cmd] [-e k=v] file|pid|-|--|=
 -            same as 'r2 malloc://512'
 -a [arch]    set asm.arch
 -A           run 'aaa' command to analyze all referenced code
 -b [bits]    set asm.bits
 -B [baddr]   set base address for PIE binaries
 -c 'cmd..'   execute radare command
 -d           debug the executable 'file' or running process 'pid'
 -i [file]    run script file
 -k [OS/kern] set asm.os (linux, macos, w32, netbsd, ...)
 -l [lib]     load plugin file
 -p [prj]     use project, list if no arg, load if no file
 -w           open file in write mode

Continue reading

[Pragyan CTF] Roller Coaster Ride



Bobby has been into Reverse Engineering and Binary Exploitation lately.
One day, he went to an amusement park in his city. It was very famouse for its Roller Coaster Rides.
But, Bobby, being 12 years old, was not allowed on those rides, as it was open for people who were 14 years or older.
This made Bobby very angry. On reaching home, he hacked into the servers of the amusement park, got hold of the validation software for the Roller Coaster rides, and modified it, so that nobody is allowed to have a ride on those Roller Coasters.



We are given with a file, lets run file command on it determine its type.

Megabeets$ file validation
validation.elf: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=f18f0acc149e2330b7549976f9e25c1b4e97e4f8, not stripped

Okay, it’s an ELF file. Lets execute it:

Megabeets$ ./validation

 Authenticate yourself

 Enter your name :- Megabeets

 Enter your age :- 74

 You are not old enough !!
 Go home Megabeets, and complete your homework ..

 This is not your cup of tea !!   -_-    -_-


Okay let’s disassemble the file and look at the functions call tree:

Oh, we have lot of functions. All of them looks something like this:

An hex value is moved to r9 (smetimes r8) and then xord with hex value that was moved to rax. I manually xord all the values by order of calls, turn the results to characters and end up with the flag:

>>> flag = chr(0x1a^0x68)+chr(0x85^181)+chr(0xfc^0xcd)+chr(0xa0^0xcc)+chr(0x2a^1)+chr(0xe2^0x96)+chr(0x4d^0x25)+chr(0x84^0xb7)+chr(0x0^0x6d)+chr(0xc2^0x9d)+chr(0xf1^0xc5)+chr(0x2^0x33)+chr(0xbc^0x8d)+chr(0x14^0x39)+chr(0xde^0xae)+chr(0xf2^0x87)+chr(0xde^0xae)+chr(0x68^0x47)+chr(0xb0^0xf0)+chr(0x82^0xec)+chr(0x3a^0x5e)+chr(0x96^0xe8)+chr(0x89^0xbd)+chr(0xee^0x99)+chr(0x56^0x16)+chr(0x5c^0x25)
>>> print flag

The flag was pragyanctf{r01l+th3m_411-up/@nd~4w@y}


Solving PwCTF Prequel



PwCTF is an on-site CTF event in Israel. It will take part on January 29-31 in Cybertech Tel-Aviv 2018. Honestly I’ve never heard of it before but I thought I’ll give it a try and ended up to be the first to finish the prequels. In the following writeup I’ll go step by step on how I solved each challenge. Here we go.


The first challenge

It was a morning time, I was eating my breakfast while reading messages on my security groups. One of the messages, by my friend Netanel Fisher, announced of the opening of CTF Prequalification Challenge. They said “challenge” and immediately caught my attention. I cannot say “no” to a challenge. So, I thought to myself that I’ll sign up and see what challenges are there. I clicked on the link to the CTF’s website and got into this lovely landing page:

It is clearly a login page, but since I didn’t have an account yet I (obviously) can’t log in. I searched for the register tab but couldn’t find it anywhere. There was only “Home” and “About” pages at the top navigation bar. I thought it might be a bug in the website so I changed the URL from /login.php to /register.php, ended up with “302 Not Found” and redirected back to the login page. There is where I started to think that the challenge is to register.

As every other initial web challenge, the first thing to do is to look at the source code. I pressed F12 on my browser and opened the source code. First thing to see is tons of comments, here are the most important of them:

Line 1 <!DOCTYPE html>
Line 2 <html lang="en">
Line 3 <head>
Line 12 
Line 13     <!-- Rotation -->
Line 61 <script type="application/javascript" id="hintScript" src="/js/hintjs.js"></script>
Line 62 </body>
Line 63 </html>
Line 64 <!-- Line: Base -->
Line 65 <!-- Line: 65 -->
Line 127 <!-- Line: 127 -->
Line 128 <!-- Comments Are Awesome! -->
Line 129 <!-- Line: 129 -->
Line 255 <!-- Line: 255 -->
Line 256 <!-- Scroll! -->
Line 257 <!-- Line: 257 -->
Line 511 <!-- Line: 511 -->
Line 512 <!-- Scroll More! -->
Line 513 <!-- Line: 513 -->
Line 1023 <!-- Line: 1023 -->
Line 1024 <!-- It's Not Enough! -->
Line 1025 <!-- Line: 1025 -->
Line 1336 <!-- Line: 1336 -->
Line 1337 <!-- So You Think You Got What It Takes To Own The CTF? 3062303031313131303130623030313131313031306230313030303130303062303131313030313130623031303131303030306230303131303030303062303130313030313130623031303130313130306230313131303130303062303131303030313030623031313130313030306230313031303131303062303131303030313030623031313030303130306230313031303030313062303130313031313030623031313031303030306230313131313030313062303130303130313030623031303031313030306230313130303030313062303130313030313130623031303130313030306230313031303131303062303031313030303030623031313131303031306230313031303130303062303130313031313030623031313031303031306230313030303130313062303130313031303030623031303130313130306230313130313030313062303130303031303130623031303130313031306230313031303131303062303131313130303030623031303031303031306230313030313031303062303130303131303130623031313031303030306230313030313131313062303130313030303030623031313031313131306230313130303131303062303131313130303130623030313130303130306230313131303030313062303131313031303030623031303031303030306230303131303031313062303131303131313130623031303031313031306230313030313131313062303130313030303030623031303131303031306230313131313030303062303130303130303130623030313130303130306230313030313130313062303131303130303030623031303130303131306230313031303130303062303131303131313030623031313130313131306230313030313131313062303130303031313030623031303031313031306230313130303031313062303131303031313130623030313130303130306230313130313131313062303131303130303130623031303030303031306230313031303031303062303130313031313030623031313031303030306230303131313030313062303130303130313030623031313031313130306230313130313130313062303130303030303130623031303031303131306230313030313130313062303130303031313130623031303031313131306230313131303131303062303131313030303030623030313130303031306230303131313030313062303130303130313030623031313130303130306230313131303130303062303130303031303030623031313131303130306230313130313131313062303131313031303130623031303031313131306230313030303131303062303130303131303130623031313031313030306230313030313030313062303130313031303030623031313031313130306230313131303130303062303130303031303030623030313130303131306230313130313131313062303131303030303130623031303031313131306230313030303131303062303131313030303130623031313031303031306230313131313030313062303130313031303130623031303130313130306230313131313031303062303131313130303130623031313131303030306230313031303131303062303131313031303030623031303031313130306230313031303030303062303130313031313030623031313130313030306230313130303031303062303130303131313030623031303131303031306230313131303131303062303031313031303030623031313130313130306230313130313131313062303131303130303130623031313131303031306230303131303031303062303131313030303030623031313031313031306230313030313030313062303031313030313030623031303031303030306230313131303130303062303130313031313030623031303031303131306230313131303030313062303131303130303130623031313131303031306230313031303130313062303130313031313030623031313031303031306230313030303130313062303130313031303130623031303130313130306230313131313030303062303130303130303130623031303130313030306230313131303030313062303131313031303130623031303130313131306230313030313031313062303130303131303130623031313031303030306230313030313030313062303031313030313030623031303031313031306230313131303130303062303131313130303030623031303130313031306230313130313131313062303131303031313130623030313131303031306230313031303130303062303130303131303130623031313031303030306230313031303031313062303131313130313030623031313130303030306230313131303130303062303130313130313030623031303031303131306230313130313131303062303131313031303030623030313130313030306230303131303031303062303131303131313130623031313030303131306230313030303130313062303130303130313130623031313130303031306230313130303131303062303031313130303130623030313130303130306230313131303030303062303131313031303030623031313131303030306230313130303030313062303131313030303030623031313131303031306230313030313130313062303130303130313130623031303030313031306230313131303131303062303130303131313030623031303130303030306230313031303131303062303131313031303030623031303031313130306230313131303131303062303130313030303030623031313031313131306230313030313131313062303131313031313030623031303030303130306230313131303131303062303130313130313030623031303031303131306230313030313130313062303031313030303030623030313131303031306230313131313031303062303131303131313130623031313130313130306230313030313131303062303130313030303030623031303130313130306230313031313030303062303131303130313030623031313130313130306230313031303131303062303031313130303030623031313131303030306230313030313030303062303130313031313130623031303030313030306230313131303030313062303031313030303130623031303031313031306230313131303131303062303131303130313030623031303031303031306230313130313131313062303031313031303030623031313031303130306230313031303130303062303131303131313130623031303131303031306230303131313030313062303131303131303130623031303031313031306230313030313131303062303130313031313130623031303130303030306230313031303131303062303031313031313030623031303130313130306230313031303030303062303130303131303130623031313031313030306230303131313030313062303031313030313030623031313130303031306230313130313130313062303130303030303130623031303031303131306230313030313130303062303131303130313030623031303130313131306230313031303030303062303130313031313030623031313130313030306230313130303031303062303130303131313030623031303131303031306230313131303131303062303130303131303030623031303130313030306230313131303030313062303130313030303130623031313130303031306230313031303031313062303130303130303030623031313130313130306230313030313131303062303131313031313030623031303030303130306230313131303131303062303130303130303030623031303031303130306230313130313131313062303131313031303130623030313130313031306230313131313031303062303131313030303030623031313131303031306230313030303030313062303130303130313130623031313130303031306230313131303131303062303130303131313030623031303130303030306230313031303131303062303130313130303030623031313031303130306230313131303131303062303130313031313030623031313031303130306230313031313031303062303131303131303130623031303031313030306230313130313130303062303130313130313030623031303130313030306230313030303030313062303131313130313030623031303130303131306230313031303030313062303130313130313030623031313031313030306230313030303130303062303130303031313130623031303030303130306230303131303031313062303130313031313030623031313131303130306230313030313130303062303131313130303130623031303030303031306230313131303131313062303130303131303130623031313131303130306230313031303131313062303131313130313030623031303131303130306230313131303130313062303130303131303130623031303130313030306230313030303030313062303131313130313030623031303030303031306230313030303131313062303130303131303030623031313131303130306230313131313030313062303131303131303130623031303030303031306230313131313030313062303130303031303130623031303031303130306230313031313031303062303131313031303130623031303130303131306230313131313031303062303130313031313030623031313130313030306230313130303031303062303131313031313130623031303130313130306230313130303130313062303031313031303130623031303031303130306230313131303030313062303131303031303030623031303130313131306230313031303030303062303130313031313030623031313130313030306230313130303031303062303131303130313030623031313130303130 -->
Line 1338 <!-- Line: 1338 -->
Line 2047 <!-- Line: 2047 -->
Line 2048 <!-- I Think You Missed It :S. Bip, Bip, Bip, Reversing To Line esaB... -->


From a quick glance, it is easy to spot some rows that seem like hints:

  • Line 13 says “<!– Rotation –>” ― Obviously ROT13 cipher
  • Line 64 says “Base” ― What else if not Base64
  • Line 1337 ― This leet line contains long string of numbers (HEX?) and a challenging sentence
  • Line 2048 is the last line and says “Reversing To Line esaB” ― The reversed “Base” seems like another hint

I started from the long sequence of numbers. To me it seemed like hexadecimal representation of something. The sequence only contains three numbers which repeat themselves in different order: 30, 31, and 62. I also noticed that 62 always comes after 30. Another things that immediately pops to mind is that 0x30 and 0x31 are the ASCII representation of “0” and “1” accordingly. 0x62 is the letter “b”. With that in mind, we should probably see this HEX string decoded into a binary string of zeroes and ones.

Let’s use python to decode the sequence and confirm whether my first impression was right:

# The HEX sequence was truncated for readability. The full line is in the source-code pasted above
>>> hx = "30623030313131313031306230303131313130313062303130303031303030623031313130303131"
>>> hx.decode('hex')

Just as we thought, it is a binary sequence where each byte is starting with “0b”, a binary literal prefix. Now we’ll try to decode the binary string. Again, I’ll use python for this:

# Where "hx" contains the full hexadecimal sequence
>>> hx_decoded = hx.decode('hex')

# Split the binary string to an array and omit the "0b"
>>> binary = hx_decoded[2:].split("0b")
>>> bin_decode = ""
>>> for b in binary:
...     bin_decode += chr(int(b,2))
>>> print bin_decode

Cool! We decoded the binary string and came out with a Base64 sequence. Fit exactly to the hint on line #64. But wait a second, if a Base64 sequence has “==” it should be at the end, not at the beginning. Remember the last hint? The one on line #2048: <!-- I Think You Missed It :S. Bip, Bip, Bip, Reversing To Line esaB... --> . The word “Base” is reversed here. We should reverse our output and then decode it:

>>> bin_decode[::-1].decode('base64')

We didn’t end up with an output that makes any sense. First I thought that it might be some type of file, but I checked the list of file signatures and nothing matched 0xae. Then I remembered another hint which we didn’t use, the one about ROT13. Let’s rotate the characters and make another try with the decoding:

>>> import codecs
>>> print codecs.encode(bin_decode[::-1], "rot13").decode('base64')
  "junk": "aa1de79fa3f4fa2bff3ebb794201f4c2c30",
  "username": "PWCtf",
  "password": "@g?Kll8m\"gWP%I<",
  "notes": [
    "Every solution is randomly generated to your Session.",
    "If you got here and your Session Cookie changed, You will need to do it again :("

HOORAY! We solved it and got the credentials. Now we can log into the website.

The final code

Here’s the final script to solve the first challenge. It receives a hexadecimal sequence and prints the answer:

import codecs

# Where "hx" contains the full hexadecimal sequence
def decodeComment(hx) :
	hx_decoded = hx.decode('hex')
        # Split the binary string to an array and omit the "0b"
	binary = hx_decoded.split("0b")
	bin_decode = ""
	for b in binary:
		bin_decode += chr(int(b,2))
	print codecs.encode(bin_decode, "rot-13")[::-1].decode('base64')

The second challenge

After using these credentials to login, we are facing this screen:

It’s a simple README screen with a description. Two of the words in the description are bolded and combined into “SOURCE CONTROL“. There’s also a button, let’s click on it.

This is the source of a file, a popular file that can be found in source-control repositories. This hint, along with the previous one, can tell us about the possible existent of a Source Control on this server. The most popular of them is Git. First thing I tried is to change “” to “”, “flag.txt” et cetera,  but all I got was 404 messages. Next thing I wanted to try is if indeed the server contains a Git repository. So I tried to access .git and got a 302 error code.

Seems like I am on the right direction. Let’s see if we can access the HEAD file.

What is a HEAD file?
The HEAD file is a symbolic reference to the branch you’re currently on. By symbolic reference, we mean that unlike a normal reference, it doesn’t generally contain a SHA-1 value but rather a pointer to another reference.

We successfully accessed HEAD and that means that the repository is downloadable. We can manually clone the repository file by file using wget but there’s better approach ― using GitDumper by internetwache. This is my favorite tool to dump Git repositories.

beet:/ctfs/pwctf/pre/chal2$ ./ dumped_pwctf
# GitDumper is part of
# Developed and maintained by @gehaxelt from @internetwache
# Use at your own risk. Usage might be illegal in certain circumstances.
# Only for educational purposes!

[*] Destination folder does not exist
[+] Creating dumped_pwctf/.git/
[+] Downloaded: HEAD

It should take a few minutes and at the end we’ll have a folder with the repository contained. Let’s cd to it and execute git status:

git status
Displays paths that have differences between the index file and the current HEAD commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by Git.

$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    interesting.txt

no changes added to commit (use "git add" and/or "git commit -a")

It shows us that there are two files that were deleted from the repository. “interesting.txt” will probably contains the answer. Let’s find which commits changed the file:

git log
Shows the commit logs.

 git log -- interesting.txt
commit e24a3a95d60b16038abb3a99b79629bda984b1b0
Author: Ubuntu <>
Date:   Sun Jan 14 13:11:46 2018 +0000

    Commit 128

commit d72763151f4f2aa317cfa0aebfd55954821d940f
Author: Ubuntu <>
Date:   Sun Jan 14 13:11:46 2018 +0000

    Commit 127

commit 25ed69be46b3fdf0a46dca227dcbe793e808b1be
Author: Ubuntu <>
Date:   Sun Jan 14 13:11:46 2018 +0000

    Commit 126

commit 58836bee9eb9fbd617dc721309eb9bfa7f7d1130
Author: Ubuntu <>
Date:   Sun Jan 14 13:11:46 2018 +0000

    Commit 125


We received a huge output, the file must have been changed in each of these commits to confuse us. We can write a quick bash one-liner to reveal all the versions of this file:

$ git rev-list --all --objects -- interesting.txt  | cut -d ' ' -f1 | while read h; do (git cat-file -p $h:interesting.txt >> output.txt); done 2>/dev/null

$ cat output.txt
Not Mississippilessly? 128 Mississippi127 Mississippi126 Mississippi125 Mississippi124 Mississippi123 Mississippi122 Mississippi121 Mississippi120 Mississippi119 Mississippi118  ... <TRUNACTED> ... Mississippi8 Mississippi7 Mississippi6 Mississippi5 Mississippi4 Mississippi3 Mississippi2 Mississippi1 Mississippib

Et voilà! We got a link to the registration form and successfully finished the prequels 🙂



The prequels to the PwCTF wasn’t highly technical, it didn’t involve hardcore reverse engineering, exploitation and similar, but there’s no doubt that it was challenging. Netanel which is responsible of creating this event and Tomer who helped writing the CTF’s challenges, are both invested time end efforts to make it as great as it was. Thank you guys, I really enjoyed solving it.