[Reverse] Midnightsun CTF 2019 - Hfs-mbr

Hfs-mbr 213

Description:
We made a military-grade secure OS for HFS members. Feel free to beta test it for us!
Service: stty -icanon -echo ; nc hfs-os-01.play.midnightsunctf.se 31337 ; stty sane
Download: hfs-os.tar.gz

First all I want to thank Midnightsun CTF organizers for such an amazing CTF even that I didn’t have much time to play it due to IRL responsibilities, the few challenges I solved, I learned a lot, it was worth the time invested unlike the time I invested on EncryptCTF where I learned nothing.

The most awesome of this is challenge is actually the organizers gave instructions on a README file on how to debug this kind of MBR challenges on ida I always debugged this using gdb which is alot harder to analyse and debug specially when both gef and pwndbg get bugged and stop working leaving you to work on vanilla gdb which is beyond crazy.

So after extracting we get a bunch of files:

1
2
$ ls
bin/ dos.img hfs-os.tar.gz notes.txt README run*

If we read the README we can get some instruction on how to debug on IDA

1
2
3
4
5
6
7
8
$ cat README
HFS-OS
./run debug (gdb stub) or ./run

How to debug with IDA
In IDA > Debugger > Attach > Remote debugger (host:1234) > (Debug options > Set specific options, UNCHECK 'software breakpoints at eip+1', CHECK 'use CS:IP in real mode') > OK
When attached, Debugger > Manual memory regions > Insert > CHECK 16bit segment > OK
In the IDA-View, press G, 0x7c00 is where the bootloader starts. Set a BP > F9

If we check up the contents of run file we can see if we add a debug parameter we can already setup qemu running on a gdb server at port 1234 (default port when not specifically set):

1
2
3
4
5
6
7
8
$ cat run 
#! /bin/bash

if [ "$1" = "debug" ] ; then
cd bin && ./qemu-system-i386 -s -S -m 16 -k en-us -rtc base=localtime -nographic -drive file=../dos.img -boot order=c
else
cd bin && ./qemu-system-i386 -m 16 -k en-us -rtc base=localtime -nographic -drive file=../dos.img -boot order=c
fi

Configuration IDA

You can skip this chapter if you already know about thsi and you just want to check on my solution to solve the challenge.

when opening dos.img change the loading offset to 0x7c00 so ida starts to convert the bytes into assembly form that point:

After clicking OK make sure you say no so IDA dissembles it in 16 bit mode:

Now we just need to follow the instructions on README file:

Select remote gdb debugger:

Go to debugger options:

Now into set specific options:

UNCHECK ‘software breakpoints at eip+1’, CHECK ‘use CS:IP in real mode’

Still on this window click on memory maps:

Right click and then insert:

Check 16-bit segment and then OK:

Go to process options:

Set up the hostname to your local ip from your linux machine and change to port to 1234

Solving the problem

First setup the debugging server but just running:

1
2
3
4
$ ./run debug
WARNING: Image format was not specified for '../dos.img' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.

Setup a breakpoint on 0x7c00 and start debugging:

We can ignore sub_7C0C since is just setting up into video mode if we look up into sub_7C15 (sometimes this bugs out and ida becomes messed up out of the sudden when this happens the only solution I found was to delete IDA database and redo the configuration steps don’t really know why this happens sometimes):

After sub7E21 you are going to jump into sub7E06:

From the picture above you can see before each call on sub_7E2B if you check on memory for this addresses you will see these are strings of the banner and the message to ask the password for the first part of the challenge:

By putting a breaking point on ret and running the binary until it reach you can see it printed the banner:

No we jump into loc_7E37:

The loose function 0x818a is the address of Wrong password string and sub_7E2B will print it so we want to avoid to jump here:

Now interpreting the rest of sub_7E2B

The result after jumping:

Now if you check the DEADCODE jump after pressing a you can see it after doing its thing it jumps into loc_7FD9:

Let’s see what happens if we press e:

If we check what happens if we jump to loc_7FCE:

Now just do this for every letter and you will end up with a list like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
a -> deadcode
b -> deadcode
c -> deadcode
d -> deadcode
e -> notdeadcode -> if byte_81BA == 7 then {byte_81BB++; byte_81BA++} else byte_81BA++
f -> deadcode
g -> deadcode
h -> deadcode
i -> deadcode
j -> notdeadcode -> if byte_81BA == 2 then {byte_81BB++; byte_81BA++} else byte_81BA++
k -> deadcode
l -> deadcode
m -> deadcode
n -> notdeadcode -> if byte_81BA == 6 then {byte_81BB++; byte_81BA++} else byte_81BA++
o -> notdeadcode -> if byte_81BA == 1 then {byte_81BB++; byte_81BA++} else byte_81BA++
p -> notdeadcode -> if byte_81BA == 4 then {byte_81BB++; byte_81BA++} else byte_81BA++
q -> deadcode
r -> notdeadcode -> if byte_81BA == 8 then {byte_81BB++; byte_81BA++} else byte_81BA++
s -> notdeadcode -> if byte_81BA == 0 then {byte_81BB++; byte_81BA++} else byte_81BA++
t -> deadcode
u -> notdeadcode -> if byte_81BA == 3 then {byte_81BB++; byte_81BA++} else byte_81BA++
v -> deadcode
w -> notdeadcode -> if byte_81BA == 5 then {byte_81BB++; byte_81BA++} else byte_81BA++
x -> deadcode
y -> deadcode
z -> deadcode

deadcode -> byte_81BA++

The calculations done to calculate the indexes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ python -c "print 0x73 ^ 0x73" # s
0
$ python -c "print (0x8e-(0x20))^0x6f" # o
1
$ python -c "print (0x38 + 0x30) ^ 0x6a" # j
2
$ python -c "print (0x88-(5*4))^0x70" # p
4
$ python -c "print (0x82 - 0x10)^0x77" # w
5
$ python -c "print 0x6e ^ 0x68" # n
6
$ python -c "print (0x2 + 0x60)^0x65" # e
7
$ python -c "print (0xac-(0x52-0x20))^0x72" # r
8

The password was sojupwner

Getting the flag:

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

[HFS SECURE BOOT] Loading ...
.-. .-.----.----. .-. .-.----..----.
| {_} | {_{ {__ | `.' | {} | {} }
| { } | | .-._} } | |\ /| | {} | .-. \
`-' `-`-' `----' `-' ` `-`----'`-' `-'
Enter the correct password to unlock the Operating System
[HFS_MBR]> sojupwner
....
[HFS SECURE SHELL] Here is your flag for HFS-MBR: midnight{w0ah_Sh!t_jU5t_g0t_RE
ALmode}
[HFS SECURE SHELL] loaded at 100f:0100 (0x101f0) and ready for some binary carna
ge!

The flag was HFS-MBR: midnight{w0ah_Sh!t_jU5t_g0t_REALmode}