CSAW 2018 A tour of x86 pt 2
Now for this challenge, we have to compile and run a binary (which we will need nasm and qemu installed to do):
$ sudo apt-get install nasm qemu qemu-system-i386
You can compile it like this:
$ ls
Makefile stage-1.asm stage-2.bin
$ make
nasm -Wall -D NUM_SECTORS=8 -f bin -o stage-1.bin stage-1.asm
stage-1.asm:240: warning: uninitialized space declared in .text section: zeroing
dd bs=512 if=stage-1.bin of=tacOS.bin
1+0 records in
1+0 records out
512 bytes copied, 0.000172661 s, 3.0 MB/s
dd bs=512 seek=1 if=stage-2.bin of=tacOS.bin
0+1 records in
0+1 records out
470 bytes copied, 8.6686e-05 s, 5.4 MB/s
You can run the binary like this (or you can just look in the Makefile and see the qemu command to run it):
$ make run
Binary is 4 KB long
qemu-system-x86_64 -serial stdio -d guest_errors -drive format=raw,file=tacOS.bin
When we run it, we see a screen that comes up and prints some text. It doesn't look like anything important yet. So we take a quick look again through stage-1.asm
and we see this on line 224
load_second_stage:
; this bit calls another interrupt that uses a file-descriptor-like thing, a daps, to find a load a file from disk.
; load the rest of the bootloader
mov si, daps ; disk packet address
mov ah, 0x42 ; al unused
mov dl, 0x80 ; what to copy
int 0x13 ; do it (the interrupt takes care of the file loading)
This coupled with the fact that we are on stage 2, we can reasonably assume that the code in stage-2.bin
is being ran. Let's take a quick look at the stage-2.bin
in Ghidra. When we do this, we will need to specify the x86
processor (also I analyzed it for the default
variant). After that I disassembled the binary data starting at 0x0
(you can do this either by right clicking, then Disassemble):
//
// ram
// fileOffset=0, length=470
// ram: 00000000-000001d5
//
assume DF = 0x0 (Default)
00000000 f4 HLT
00000001 e4 92 IN AL,0x92
00000003 0c 02 OR AL,0x2
00000005 e6 92 OUT 0x92,AL
00000007 31 c0 XOR EAX,EAX
00000009 8e d0 MOV SS,AX
0000000b bc 01 60 MOV ESP,0xd88e6001
8e d8
00000010 8e c0 MOV ES,AX
00000012 8e e0 MOV FS,AX
00000014 8e e8 MOV GS,AX
00000016 fc CLD
00000017 66 bf 00 00 MOV DI,0x0
0000001b 00 00 ADD byte ptr [EAX],AL
0000001d eb 07 JMP LAB_00000026
0000001f 90 NOP
We see that there is a hlt
instruction on the first line. This would stop the rest of the code in here from running. We can simply patch a NOP instruction (the code for it is 0x90
), which has code execution continues with the next instruction. You can do this with any hex editor, or Ghidra. I just used Ghidra. Right click on the instruction, then click on Patch Instruction, then just type in NOP
. After that, just delete tacOS.bin
and recompile it, then run the new binary.
When we run it again, we can see that after it gets past the point where it stopped before we patched it, there is a blue screen that pops up with the flag flag{0ne_sm411_JMP_for_x86_on3_m4ss1ve_1eap_4_Y0U}
(patched version is found in solved
directory). Also as a side note, when you run the patched version in Ubuntu 19.04 it appears to crash. Running it in something like Ubuntu 16.04 seems to work just fine. Just like that, we solved the challenge!