[Reverse] InCTF 2018 - load3r



load3r
100

======= Difficulty level : Easy ========

A basic bootloader challenge. Note: The flag format is inctf{correct_input}

Note: The challenge must be run in qemu-system-i386 version 2.5.0

========== Authors : b3y0nd3r, r00tus3r ==========

They gave us a file named boot sector

1
2
$ file boot_try.bin 
boot_try.bin: DOS/MBR boot sector

So lets first run the binary on an emulator named qemu:

1
$ qemu-system-i386 -drive format=raw,file=boot_try.bin

We can see some strings like ENTER THE FLAG and the message NOOOO when we insert an incorrect flag, this strings can help us to localize certain parts of the code while reversing, so first thing I did was to look up for this strings in IDA and search on which zones they are referenced.

At first I was having some trouble with IDA because I was choosing the wrong architecture when opening the binary and IDA wasn’t able to disassemble the code, the only thing that was showing was the strings so make sure you say no to disassemble the binary in 16 bits instead of the 32 bits.

After pressing no, we can already see where is the location of the strings we saw when executing the binary…

So we can start taking some notes from where they start in the binary (note that since the boot sector hasn’t been loaded into memory by the bios, all the addresses are starting from 0 but when we start debugging it everything will start after 0x7c00):

1
2
3
4
5
0x7c16 ENTER THE FLAG\r\n -> calculated with 0x7c00 + 0x16
0x7c27 w2g1kS<c7me3keeuSMg1kSk%Se<=S3%/e/\r\n -> calculated with 0x7c00 + 0x27
0x7c4c Yeah, that is the flag\r\n -> calculated with 0x7c00 + 0x4c
0x7c65 8 7 NOOOO\r\n -> calculated with 0x7c00 + 0x65
0x7cc9 37 36 0100010011011101111111011010110101\r\n -> calculated with 0x7c00 + 0xc9

Now we have 2 subroutines to analyse, lets start by the smallest one:

IDA’s comments are very explanatory, this is a function that writes a character into the screen by performing an interruption, so we can just rename this function to print since will be easier to us to identify it when it is called again.

From the image above we can already assume that the flag must have 34 characters if we insert something that doesn’t have that size we go directly to printing the wrong flag message NOOO.

But if we instead give a 34 character string we go through the green flow

The image above is a loop, which iterates all the characters we inserted in the program, after doing the shifts we enter into the final character modification:

We need to reverse this encryption function by doing exactly the opposite:

Example

1
2
3
4
5
encryption function -> 
lr_string = '0'
flag_string = 'T'
for the first character (shift right because the 1st of lr_string is zero):
chr((ord('T') >> 1 ) ^ 5) = /

1
2
3
4
5
reverse function -> 
lr_string = '0'
encryption_string = '/'
for the first character (shift left because we are reversing it and before we shift righted):
chr((ord('/') ^ 5) << 1) = T

Of course it’s much easier to understand all this assembly while debugging and analysing the code… the way I did it was opening gdb and running this commands inside of it, after the commands bellow is just a matter of putting more breakpoints and reading registers etc etc:

1
2
3
target remote | qemu-system-i386 -S -gdb stdio -m 512 -hda boot_try.bin
set architecture i8086
b *0x7c00

We have now everything to recover the flag it’s trivial to write a python script that recovers the flag for us:

1
2
3
4
5
6
7
8
9
10
11
12
13
import string

left_or_right = '0100010011011101111111011010110101'
enc = "\x77\x32\x67\x31\x6B\x53\x3C\x63\x37\x6D\x65\x33\x6B\x65\x65\x75\x53\x4D\x67\x31\x6B\x53\x6B\x25\x53\x65\x3C\x3D\x53\x33\x25\x2F\x65\x2F"
flag = ""

for i, c in enumerate(enc[::-1]):
a = ord(c) ^ 5
if left_or_right[i] == '0':
flag += chr(a << 1)
else:
flag += chr(a >> 1)
print 'inctf{'+flag+'}'

Running it

1
2
$ python final.py
inctf{T0T@l+pr0+@7+7h1$+8007l04d3r+7h1n9}