格式化字符串:告诉程序将数据以什么格式输出
printf("format", 输出表列)
format 结构:
%[标志][输出最小宽度][.精度][长度]类型
跟格式化字符串漏洞有关系的主要有以下几点
1、输出最小宽度:用十进制整数来表示输出的最少位数。若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0。
2、类型:
- d 表示输出十进制整数
- s 从内存中读取字符串
- x 输出十六进制数
# 特性一: printf()函数的参数个数不固定
只要我们能够控制format的,我们就可以一直读取内存数据。
例如:printf("%s %d %d %d %x\n",buf,a,b,c);
可以利用%x一直读取栈内的内存数据
可以用%s来获取指针指向的内存数据
# 特性二:利用%n格式符写入数据
%n是一个不经常用到的格式符,它的作用是把前面已经打印的长度写入某个内存地址
# 特性三:自定义打印字符串宽度
在格式符中间加上一个十进制整数来表示输出的最少位数,若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0
格式化字符串漏洞利用
%c:输出字符,配上%n可用于向指定地址写数据。
%d:输出十进制整数,配上%n可用于向指定地址写数据。
%x:输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要泄漏偏移i处8字节长的16进制数据,32bit和64bit环境下一样。
%p:输出16进制数据,与%x基本一样,只是附加了前缀0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32bit还是64bit。
%s:输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串,在32bit和64bit环境下一样,可用于读取GOT表等信息。
%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100x%10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。
%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据。
1、%x打印内存数据
例如: %5$x 打印偏移为5的数据
2、%p打印内存数据
%p的用法和%x的用法相同,不同的是%p会在打印的数据前面添加上0x(输出16进制数据)。
3、%s打印内存数据
%i&s是打印处偏移i处地址里面数据指向的内存地址的内容。 内存小端存储 ,打印的是转换为字符串之后的形式。
4、%n写入内存数据
%n和%s类似,会把%号之前的字符个数,写入第i处数据指向的地址空间
实验
对task进行分析
反汇编代码
在printf处设置断点,运行task
观察栈空间
确定输入内容:%a2000x%31$n