CSAW CTF writeup — A Tour of x86
CSAW CTF writeup — A Tour of x86
The series of x86 assembly challenges in CSAW CTF are interesting, because it wraps with a very tiny i386 OS! How I miss the good old days of hand writing i386 boot assembly!
Part 1 is fairly elementary, I don’t want to waste a word on it. Part 2 is very easy too, the only thing I want to mention is that I used the following Qemu debugging trick to single step to where the OS stops and it clearly shows it pauses at the hlt instruction. You should know how to proceed to getting the flag!
hlt
qemu-system-x86_64 -serial stdio -d guest_errors -drive format=raw,file=tacOS.bin -s -S -d in_asm -singlestep
Now, let’s talk about part 3.
This part is slightly harder because it requires to write actual assembly code. Don’t worry, although it is embedded to the OS bootstrap code, you nearly don’t need to know anything about i386 interrupts or I/O ports. More importantly, at the time of the execution of our code, x86_64 is already properly setup, we can just write normal x86_64 assembly!
The only thing confusing is about the 0x1f character, it is a “protocol” for displaying characters via VGA, it means displaying a white-color character on a blue background. 0x00b8000 is the starting memory address of VGA video memory. All the rest are trivial, here is my NASM code:
bits 64
call get_ipget_ip: pop rsi
add rsi, 0x23 mov rdx, 0x00b8000
print_char_loop: cmp byte [rsi], 0 je done
mov byte bl, [rsi] mov byte [rdx], bl inc rdx inc rsi mov byte [rdx], 0x1f inc rdx jmp print_char_loop
done: hlt hlt
Compile it:
nasm -f bin -o printflag.bin printflag.asm
Translate it into hex:
xxd -p < printflag.bin | tr -d '\n'
Finally, feed them to the remote:
#!/usr/bin/env python
import subprocessfrom pwn import *
context.log_level = 'debug'
r = remote("rev.chal.csaw.io", 9004)r.recvline()r.sendline("e8000000005e4883c623ba00800b00803e0074128a1e881a48ffc248ffc6c6021f48ffc2ebe9f4f4")ret = r.recvline().rstrip('\n')port = ret.split(" ")[-1]subprocess.call(["vncviewer", "rev.chal.csaw.io:"+port])r.close()
In fact, I am sure we can put everything into a single pwntools Python script, I just didn’t want to spend much time on digging pwntools doc.