格式化字符串漏洞 format string exploit(一)
本文系原创,转载请说明出处
本文为基于CTF WIKI的PWN学习
0x00 格式化字符串原理
先附一张经典的图,如下

其栈上布局如下:
| some value |
| 3.14 |
| 123456 |
| addr of "red" |
| addr of format string : " Color %s, Number %d, Float %4.2f" |
如果程序写成了:
printf("Color %s, Number %d, Float %4.2f");
分别将栈上的三个变量分别解析为:
- 解析其地址对应的字符串
- 解析其内容对应的整形值
- 解析其内容对应的浮点值
我们编写程序验证以下:
#include <stdio.h>
int main() { printf("Color %s, Number %d, Float %4.2f", “red”, , 3.14);
printf("Color %s, Number %d, Float %4.2f");
return ;
}
输入以下命令编译(记得安装libc6-dev-i386库):
gcc -m32 -fno-stack-protector -no-pie -o leakmemory 1.c
运行结果

gdb调试一下:
b printf后输入r运行

可以看到在第一个printf的运行中,stack的参数正如上文所说,先是格式化字符串,再是123456(的16进制),最后是3.14
继续调试至第二个printf(一直按n)

stack中我们发现,首先入栈的依旧是格式化字符串,但是上面三个参数不再是之前的那几个了。按照原理,第二次输出的应该是0xffffcfb4及之后的两个内存对应的内容。下面我们来细致讨论。
0x01 漏洞利用
利用格式化字符串漏洞,我们还可以获取我们所想要输出的内容。一般会有如下几种操作
- 泄露栈内存
- 获取某个变量的值 (%s)
- 获取某个变量对应地址的内存 (%p)
- 泄露任意地址内存
- 利用 GOT 表得到 libc 函数地址,进而获取 libc,进而获取其它 libc 函数地址 (addr%n$s)
- 盲打,dump 整个程序,获取有用信息。
一、泄露内存
(1)获取栈变量数值
这里使用ctf wiki上面的例子:
#include <stdio.h>
int main() {
char s[];
int a = , b = 0x22222222, c = -;
scanf("%s", s);
printf("%08x.%08x.%08x.%s\n", a, b, c, s);
printf(s);
return ;
}
编译运行调试

调试:
直接转载(copy)了:可以看出,此时此时已经进入了 printf 函数中,栈中第一个变量为返回地址,第二个变量为格式化字符串的地址,第三个变量为 a 的值,第四个变量为 b 的值,第五个变量为 c 的值,第六个变量为我们输入的格式化字符串对应的地址。继续运行程序,按c

将会把上图中0xffffcf44及其后面两个地址包含的内容输出输出:
并不是每次得到的结果都一样 ,栈上的数据会因为每次分配的内存页不同而有所不同,这是因为栈是不对内存页做初始化的。这可以从我上面的几个截图结果看出来。
(2)获取栈指定变量值
可以使用%n$x获得栈上第n+1个参数,格式化字符串是第一个参数,那么如果想获得printf的第n个参数,就需要加1.
如,我想获得第三个参数值f7e946bb,那么我就输入%3$x
(3)获取对应字符串:%s
(4)获取数据:%p
二、获取任意地址内存
上面的泄露并不强力,比赛中经常需要泄露某一个 libc 函数的 got 表内容,从而得到其地址,进而获取 libc 版本以及其他函数的地址,这时候,能够完全控制泄露某个指定地址的内存就显得很重要了。
这里我们再看一遍源程序代码:
#include <stdio.h>
int main() {
char s[];
int a = , b = 0x22222222, c = -;
scanf("%s", s);
printf("%08x.%08x.%08x.%s\n", a, b, c, s);
printf(s);
return ;
}
scanf接收入s的值,然后两个printf。这里我们输入%s,如下调试,打印出0xff007325, 就是%s对应的字符串值,所以,输出函数的栈分布,栈上的第一个参数就是格式化字符串的地址。

这就意味着格式化字符串内容可控,同时,还需要注意的是,第一个参数虽然放置的是格式化字符串的地址,但是,输出函数并没有在这里开始调用,你也可以从上图中看到,在0xffffcf50处,又有一个%s,这里才是调用格式化字符串的时候,输出格式化字符串表达的内容时刻。这就意味着,因为格式化字符串我们可以自己控制,那么,如果我格式化字符串里面包含了%s,它会输出%s对应地址(0xff007325)所包含的内容,如果包含scanf@got, 它会输出scanf@got对应地址包含的内容,也就是scanf的真实地址。
总结:1、格式化字符串可以按照自己的意愿输入。2、格式化字符串的地址为栈上的第一个参数,顺序之后的某个位置会调用这个格式化字符串,以格式化字符串的内容输出内容。
所以,我们只要知道,调用这个格式化字符串的位置就可以了。
根据CTF WIKI上的说明方案,我们可以使用下面的字符来确定格式化字符串在哪调用:
[tag]%p%p%p%p%p%p...
如果输出栈的内容与我们前面的 tag 重复了,那么我们就可以有很大把握说明该地址就是格式化字符串的地址,之所以说是有很大把握,这是因为不排除栈上有一些临时变量也是该数值(0x41414141)。如:

AAAA 0XFFD2RC30 0XC2 0XF7E596BB 0X41414141 0X702570250
我们调试看一下:
我输入的是AAAA加上8个%p

你会看到,AAAA后面依次输出8个内容,
第一个输出AAAA,这本来就是字符,作为一个标志显示出来罢了。然后往后,%p开始作用,依次是0xffffcfa0(可以看到格式化字符串为第一个参数,%p从格式字符串下一个开始),0xc2, 0xf7e946bb这些都是跟着格式化字符串后面的参数,之后,便打印出来0xffffcfa0地址对应的内容,即字符串。也就是说,其相对printf函数,为第5个参数(第五行),但是相对格式化字符串(第一行),是第四个参数。那么既然是第四个参数,我们使用%4$s看看测试一下。
然后你会发现core dump:

为啥?调试。

首先,%4$s对应的存放地址为0xffffcfa0, 我们查看内存发现存着的是0x73243425, 再看看0x73243425放着什么,啥都没有,那肯定崩溃。
我们输入%4$s是0x73243425, 我们输入%5$s是0x732434525,................
那就是说,我们确定了参数为第几个后,在tag处输入想要获得的内容的地址,那么,输出的将是输入的地址对应的内容。
然后使用CTF wiki上payload改改就可以实现获取scanf的地址:
from pwn import *
sh = process('./leakmemory')
leakmemory = ELF('./leakmemory')
__isoc99_scanf_got = leakmemory.got['__isoc99_scanf'] #获取got地址
print hex(__isoc99_scanf_got)
payload = p32(__isoc99_scanf_got) + '%4$s' #想要输出的地址加上确定好的参数位置
print payload
sh.sendline(payload)
sh.recvuntil('%4$s\n')
print hex(u32(sh.recv()[4:8])) # 去掉 __isoc99_scanf@got的地址
sh.interactive()
格式化字符串漏洞 format string exploit(一)的更多相关文章
- [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇
目录 [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇 格式化输出函数 printf函数族功能介绍 printf参数 type(类型) flags(标志) number(宽度) precisi ...
- 格式化字符串漏洞利用实战之 njctf-decoder
前言 格式化字符串漏洞也是一种比较常见的漏洞利用技术.ctf 中也经常出现. 本文以 njctf 线下赛的一道题为例进行实战. 题目链接:https://gitee.com/hac425/blog_d ...
- Linux下的格式化字符串漏洞利用姿势
linux最早的漏洞防护机制nx-stack刚刚出现后就有人想出了突破方法.那就是只有栈是不可执行,而除了栈以外的其他地方还是可以执行的,只要把返回地址执行别的地方就可以. 一.格式化字符串漏洞 格式 ...
- PWN学习之格式化字符串漏洞
目录 PWN学习之格式化字符串漏洞 格式化输出函数 格式化字符串漏洞 漏洞利用 使程序崩溃 栈数据泄露 任意地址内存泄漏 栈数据覆盖 任意地址内存覆盖 PWN学习之格式化字符串漏洞 格式化输出函数 可 ...
- Linux pwn入门教程(6)——格式化字符串漏洞
作者:Tangerine@SAINTSEC 0x00 printf函数中的漏洞 printf函数族是一个在C编程中比较常用的函数族.通常来说,我们会使用printf([格式化字符串],参数)的形式来进 ...
- Linux pwn入门教程——格式化字符串漏洞
本文作者:Tangerine@SAINTSEC 原文来自:https://bbs.ichunqiu.com/thread-42943-1-1.html 0×00 printf函数中的漏洞printf函 ...
- 格式化字符串漏洞利用实战之 0ctf-easyprintf
前言 这是 0ctf 的一道比较简单的格式化串的题目. 正文 逻辑非常简单 do_read 可以打印内存地址的数据,可用来 泄露 got. leave 格式化字符串漏洞. printf(s) 直接调用 ...
- 通过格式化字符串漏洞绕过canary
1.1 canary内存保护机制 1.1.1 canary工作原理 canary保护机制类似于/GS保护机制,是Linux下gcc编译器的安全保护机制之一,在栈中的结构如下图所示: 在函数 ...
- [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】
YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出[高危] 问题描述: YS VTM模块开放对外监听端口(8554和8664),此次使用sulley fuzzing框架对监听在8664端口 ...
随机推荐
- 达梦"记录超长"警告
出现"记录超长"背景介绍: 导入数据库时,出现数据库记录超长警告,导致数据无法正常导入! 1.重新建库,把页大小改大 这种方式是在建立数据库实例的时候进行的 修改[页大小] 2.把 ...
- 20191010-9 alpha week 1/2 Scrum立会报告+燃尽图 07
此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/8752 一.小组情况 队名:扛把子 组长:迟俊文 组员:宋晓丽 梁梦瑶 韩昊 ...
- 🔥《手把手教你》系列练习篇之1-python+ selenium自动化测试(详细教程)
1.简介 相信各位小伙伴或者同学们通过前面已经介绍了的Python+Selenium基础篇,通过前面几篇文章的介绍和练习,Selenium+Python的webUI自动化测试算是 一只脚已经迈入这个门 ...
- 关于JDK源码:我想聊聊如何更高效地阅读
简介 大家好,我是彤哥,今天我想和大家再聊聊JDK源码的几个问题: 为什么要看JDK源码 JDK源码的阅读顺序 JDK源码的阅读方法 为什么要看JDK源码 一,JDK源码是其它所有源码的基础,看懂了J ...
- 使用Xdroid进行端口映射,出现adb server version (36) doesn't match this client (39); killing...的解决方案
第一反应就是adb冲突了,因为Xdroid这个产品看起来就不像是给开发人员用的模拟器,因为不能选择各种版本进行适配,所以肯定自带了一个adb. whereis命令发现果然有两个adb,一个直接是安装在 ...
- 【集训Day2】字符串
字符串(string) [问题描述] 给一个字符串T,问在字符串T 中可以包含最多多少个不重叠的字符串S. 字符串中的每个字符为小写或者大写字母. [输入格式] 第一行输入一个字符串S. 第二行输入一 ...
- Matlab生成Word--xdd
摘自<MATLAB统计分析与应用:40个案例分析>(谢中华老师著)P452页function CreatWord %利用Matlab生成word filespec_user = [pwd ...
- linux bash shell编程之参数变量和流程控制。
参数变量:用来向脚本中传递参数 我们在执行脚本的时候可以在其后面加入一些参数,通常来说这些参数与脚本中变量为对应关系. start.sh argu1 argu2 引用方式: $1,,2,……${10} ...
- linux磁盘分区三步走
为了便于理解硬盘的物理结构 ,可将硬盘看作一个圆,它是坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等.每个盘有两面,都可记录信息.要了解硬盘的物理结构,需要弄懂磁道.扇区.柱面.簇等几 ...
- Service Mesh 是新瓶装旧酒吗?
点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 李云(花名: ...