Reverse engineering a Gameboy ROM with radare2

Standard

 Prologue

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

Installation

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 https://github.com/radare/radare2.git
$ cd radare2
$ ./sys/install.sh

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.

Updating

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/install.sh

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 simple.gb, 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 simple.gb
— 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

[Pragyan CTF] Roller Coaster Ride

Standard

Description:

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.

validation

 

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
r01l+th3m_411-pup/@nd~4w@y

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

[Pragyan CTF] The Karaboudjan

Standard

Description

The Karaboudjan | Forensics 150 pts

Captain Haddock is on one of his ship sailing journeys when he gets stranded off the coast of North Korea. He finds shelter off a used nuke and decides to use the seashells to engrave a message on a piece of paper. Decrypt the message and save Captain Haddock.

->-.>-.—.–>-.>.>+.–>–..++++.


.+++.


.->-.->-.++++++++++.+>+++.++.-[->+++<]>+.+++++.++++++++++..++++[->+++<]>.–.->–.>.

clue.zip

 

This was funny challenge, I struggled with that Brainfuck but all it was is just brainfuck. Nothing more, we don’t need it to solve the challenge. Sorry guys.

I downloaded the zip file which was encrypted, I then cracked it using “fcrakzip” and dictionary attack. And found that the password is “dissect“. Inside the zip was a pcap file with one packet:

 

That’s it, we got the flag 🙂

The flag was pragyanctf{5n00p_d099}

[Pragyan CTF] New Avenger

Standard

Description:

New Avenger | Stego 300 pts
The Avengers are scouting for a new member. They have travelled all around the world, looking for suitable candidates for the new position.
Finally, they have found the perfect candidate. But, they are in a bad situation. They do not know who the guy is behind the mask.
Can you help the Avengers to uncover the identity of the person behind the mask ?
Those of you who read my blog frequently are already know how much I’m into superheroes. Give me a challenge with superheroes and you bought me. Although I’m more DC guy, this challenge was with the Marvels and still it was awesome! We’re given with a gif file. I ran `binwalk` on it to find whether it contains another files within.
Megabeets$ binwalk avengers.gif

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
0               0x0             GIF image data, version 8"9a", 500 x 272
885278          0xD821E         Zip archive data, at least v2.0 to extract, compressed size: 13422, uncompressed size: 13780, name: "1_image.jpg"
898769          0xDB6D1         Zip archive data, at least v1.0 to extract, compressed size: 1796904, uncompressed size: 1796904, name: "image_2.zip"

Yep, the gif file contains two more files within, lets unzip the image:

Megabeets$ unzip ./avengers.gif
Archive:  avengers.gif
warning [avengers.gif]:  885278 extra bytes at beginning or within zipfile
  (attempting to process anyway)
  inflating: 1_image.jpg
 extracting: image_2.zip

Nice! We now have two more files: image_2.zip and 1_image.jpg. Now lets try to unzip image_2.zip.

Megabeets$ unzip ./image_2.zip
Archive:  image_2.zip
[image_2.zip] 2_image.jpg password:

Oh-no, it requires a password. Lets have a look at 1_image.jpg.
Haha, funny image. Now I want to have a deeper look at this picture, I opened it in hex editor and found the password:

So the password is “sgtgFhswhfrighaulmvCavmpsb”, lets unzip the file:

Megabeets$ unzip ./image_2.zip
Archive:  image_2.zip
[image_2.zip] 2_image.jpg password: <em>sgtgFhswhfrighaulmvCavmpsb</em>
  inflating: 2_image.jpg
 extracting: image_3.zip

Again?! We got 2 more files, and the password to the new zip was at the end of the new image, and the new zip contained another zip and an image. Well, I see where it going to, so I opened python and automate the process:

from zipfile import ZipFile
import string

# list storing the passwords, it might help 
passwords =[]
i = 1

while True:
    # read the last line of the file
    f = reversed(open("%s_image.jpg"%i).readlines())
    passw = f.next()
    try:
        # extract the password from the last line, if failed - it's the last zip.
        passw = passw[passw.index(':- ')+3:passw.index(' \n')]
    except:
        break
    # extract the zip file using the password
    with ZipFile('image_%s.zip'%(i+1)) as zf:
        zf.extractall(pwd=passw)
    i+=1    # add the password to the list of passwords
    passwords.append(passw)

Ta-dah! We extracted all the zip files and gםt 16 images and 15 passwords. This was the last image:

lol.

So now we have 15 passwords, each contains 26 characters:

sgtgFhswhfrighaulmvCavmpsb
lppujmioEaynaqrctesAnztgib
lrphntGpzjhkswskepnilrwwjm
hmohAmgcomgpjjhLnqpkepuazi
qjqxzuSkiyjzazwwsqchiqvgoQ
ujinpqyghiulozjnyprZpnswnp
tsquviQwxtgpgarlxelvakaOpo
jljykvfZSycpvscqvzjwelKhok
cqjausmhroogiuabcbpRmsyzpo
qakrlxrGswfovmxhxpjzfyfrie
jyxbLszctbveelbgxtilzfbQng
heojthirkakqvvmxjgAWzuekcp
nkpbhyUmiabnymvzmcppejiisy
mIsmsmsmxpfvkolTbnkafkgvgx
tsYinxviqeykguqznjscomgqbh

The password looks like garbage, it’s not Base64 or some known encoding. The first thing to pop up is the capital letter inside each password. Every password contains one or two capital letters. I know that the English alphabet contains 26 letters, so maybe I can map the location of each capital to the matching letter in the alphabet. i.e, if ‘F’ is in passw[4] i’ll take alphabet[4] which is ‘e’ and so on. I added this code to my script:

locations = []
for p in passwords:
    for c in range(26):
        if p[c] in string.uppercase:
            locations.append(c)

map_result = ''
for l in locations:
    map_result += string.lowercase[l]

print "Result: ", map_result
#Result:  etitgepgztgxhiwthexstgbpc

I ran the script and got meaningless string: “etitgepgztgxhiwthexstgbpc”. Damn! I was so sure that the mapping is the solution, how can’t it be?! All the facts point towards mapping the alphabet. I decided not to give up and ran Caesar Cipher on the string:

YAY! I was so happy to find Spidey is the new Avenger!

Here’s the full script:

The flag was: pragyanctf{peterparkeristhespiderman}

[Pragyan CTF] The Vault

Standard

Description:

[!@# a-z $%^ A-Z &* 0-9] [1,3]
All we got is a file and regular expression.
Lets run file command on the file to determine its type:
$ file ./file.kdb
file: Keepass password database 1.x KDB, 3 groups, 4 entries, 50000 key transformation rounds

The file is KDB file which is Keepass password database. Keepass is a famous opensource password manager.

I tried open it using KeePassX for windows, but we need a password to open the database. The password probably should match the regex, so I generated a dictionary with all the possible passwords (more then 300,000 words).

import string
import itertools

# strings match the regex
chars = string.lowercase + string.uppercase + string.digits + '!@#$%^&*'
f = open('dict.txt','a')

all_permutations = list(itertools.permutations(chars,1))+ list(itertools.permutations(chars,2))+ list(itertools.permutations(chars,3))

for p in all_permutations:
    f.write(''.join(p)+'\n')

 

And I the ran John the Ripper to crack the password and went to eat lunch.

$ keepass2john file.kdb > kp
$ john  --wordlist=dict.txt -format:keepass kp
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64 OpenSSL])
Press 'q' or Ctrl-C to abort, almost any other key for status
k18              (file.kdb)

When I came back I saw that John found the password, now lets open the file:

 

The flag was pragyanctf{closed_no_more}