printf风格格式化字符串字符含义咨询(picoCTF格式字符串漏洞场景)
嘿,我来帮你把这个奇怪的语法拆明白!你在picoCTF格式字符串漏洞的脚本里看到的这种写法,其实是把Python自身的字符串格式化和漏洞利用的payload构造结合起来了,咱们一步步捋清楚:
首先先还原一个你大概率看到的典型代码片段(完全符合你描述的“多个%符号+%2493在外部”的特征):
from pwn import * target_addr = 0xdeadbeef # 要覆盖的目标内存地址 target_value = 2493 # 要写入的数值 # 第一种你困惑的写法 payload = p64(target_addr) # 先把目标地址放到payload开头 # 计算需要填充的长度:目标值减去地址的长度(8字节)再减去%hn部分的长度 padding = target_value - len(payload) - len("%10$hn") # 生成格式字符串部分:这里就是你说的多个%+外部%的写法 fmt_part = ("%%%dx%%10$hn" % padding) payload += fmt_part.encode()
1. 多个%符号的含义
这里的%%是Python字符串的转义写法——因为Python本身的%是格式化运算符,如果你想在字符串里输出一个真实的%字符,就必须写两个%来转义,避免被当成Python的格式化占位符。
拿"%%%dx%%10$hn"这个字符串来说:
- 前两个
%%→ 会被Python转换成一个单独的%字符 %d是Python的格式化占位符,用来填充后面的padding数值- 后面的
%%同样转义成一个%,然后跟着10$hn就是你已经熟悉的格式字符串漏洞写法:指定第10个参数的位置,用hn写入2字节的数值(也就是我们要的2493)
2. 外部的%和2493的作用
这里的%是Python的字符串格式化运算符,和漏洞里的格式符完全是两回事!它的作用是把右边的padding值(这个值是从2493计算而来的)填充到左边字符串的%d占位符里。
举个具体的计算例子:假设target_addr占8字节,"%10$hn"是5字节,那么padding = 2493 - 8 -5 = 2480。这时候("%%%dx%%10$hn" % 2480)就会生成字符串:"%2480x%10$hn"
这个字符串就是最终payload的一部分,它会让程序的printf类函数打印2480字节的十六进制填充内容,加上前面的8字节地址,总输出字节数刚好是2493,然后%10$hn就会把这个字节数写入到target_addr指向的内存里,完美实现用2493覆盖目标地址的目的。
为什么要这么写?
对比你熟悉的直接写死%2493x%10$hn的写法,这种动态生成的方式更灵活:如果payload前面的内容长度变化(比如目标地址是4字节而不是8字节),你不需要手动重新计算填充数值,Python会帮你自动算出正确的padding值,避免手动计算出错。
内容的提问来源于stack exchange,提问作者Zapho Oxx

