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

格式化输出函数

可变参数:https://blog.csdn.net/smstong/article/details/50751121 (C语言可变参函数的实现)

首先我们了解格式化字符串漏洞前,需要对格式化输出的函数进行一个了解,在C中格式化输出函数一共有如下:

fprintf()  "按照格式字符串将输出写入流中。三个参数分别是流、格式字符串和变参列表。"
printf() "等同于fprintf(),但是它的输出流为stdout。"
sprintf() "等同于fprintf(),但是它的输出不是写入流而是写入数组。在写入的字符串末尾必须添加一个空字符。"
snprintf() "等同于sprintf(),但是它指定了可写入字符的最大值size。超过第size-1的部分会被舍弃,并且会在写入数组的字符串末尾添加一个空字符。"
dprintf() "等同于fprintf(),但是它的输出不是写入流而是一个文件描述符fd。" "分别与上面的函数对应,但是它们将变参列表换成了va_list类型的参数。"
vfprint()、vprintf()、vsprintf()、vsnprintf()、vdprintf()

格式化字符串漏洞

格式化字符串漏洞从2000年左右开始流行起来,几乎在各种软件中都能见到它的身影,随着技术的发展,软件安全性的提升,如今它在桌面端已经比较少见了,但在物联网设备 IoT上依然层出不穷。

#include <stdio.h>
void main()
{
printf("%s %d %s %x %x %x %3$s","Hello World!",233,"\n");
}

我们输入的参数只有三个,但是格式化字符串中还有3个%x和一个%3$s,其中3个%x由于没有参数他会泄漏出栈的地址

接下来继续来看一个例子,其中fgets来接受用户输入的字符串,但是如果是hack他就会输入控制字符串来泄漏出栈地址,这点感觉和Web中的xss有点像,程序员没有过滤敏感字符导致被攻击。由此可以总结出,格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配

#include <stdio.h>
void main()
{
char buf[50];
if(fgets(buf,sizeof buf,stdin) == NULL)
return;
printf(buf);
}

漏洞利用

对于格式化字符串漏洞的利用主要有:

  • 使程序崩溃
  • 栈数据泄露
  • 任意地址内存泄露
  • 栈数据覆盖
  • 任意地址内存覆盖

使程序崩溃

造成程序崩溃原因:printf需要在栈中取一个数字视为地址,然后打印出地址所指向的内存,知道出现空白字符;获取的某个数字可能并不是一个地址;获得的数组确实是一个地址,但改地址受保护。

在Linux中,存取无效的指针会使进程收到SIGSEGV信号。

printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")

栈数据泄露

#include <stdio.h>
void main()
{
char format[128];
int arg1 = 0x00123456,arg2 = 0x11111111,arg3 = 0x22222222;
char arg4[4] = "ABCD";
scanf("%s",format);
printf(format,arg1,arg2,arg3,arg4);
printf("\n");
}
输入 %p-%p-%p-%p-%p

可以根据泄漏出来的栈的数据,然后挨个的计算出参数的位置,因为栈中的数据一般都是挨着的,可以看到在0xffffd484的下个数据就是字符串ABCD字符串的地址。

现在我们已经知道了如何按顺序泄露栈数据,那么如果想直接泄露指定的某个数据,则可以使用与下面类似的格式字符串,这里的n表示位于格式字符串后的第n个数据%n$p

%<arg#>$<format>
%n$x 分别获取arg3、arg1、arg2、arg2、arg4 以及栈上经跟参数的两个值
"%3$x-%1$p-%2$p-%2$p-%4$p-%5$p-%6$p"

任意地址内存泄漏

攻击者使用类似%s的格式规范就可以泄露出参数(指针)所指向内存的数据,程序会将它作为一个ASCII字符串处理,直到遇到一个空字符。所以,如果攻击者能够操纵这个参数的值,那么就可以泄露任意地址的内容。

AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p
AAAA代表地址

栈数据覆盖

#include <stdio.h>
void main()
{
int i;
char str[] = "hello";
printf("%s %n\n",str,&i);
printf("%d\n",i);
}

这个例子i被赋值成了6,因为遇到转换指示符之前一共写入了6个字符("hello"加上一个空格)。在没有长度修饰符时,默认写入一个int类型的值。有关详细内容可以参考:https://blog.csdn.net/FollowGodSteps/article/details/74115138

以下例子参考文章:c语言中对字段宽度的理解?

/*************************************************************************
> File Name: printf.c
> Author: Mr.Yang
> Purpose:演示printf的用法
> Created Time: 2017年05月21日 星期日 10时07分44秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h> int main(void)
{
float i = 10000.123; printf("%5f\n",i);
printf("%10f\n",i);
printf("%15f\n",i);
printf("%20f\n",i);
printf("%25f\n",i); return 0;
}

输出内容:

10000.123047
10000.123047
10000.123047
10000.123047
10000.123047

回到一开始的程序,我们尝试将arg2的值更改为任意值(例如0x00000020,十进制32),于是构造格式字符串\x28\xcd\xff\xff%08x%08x%012d%13$n,其中\x28\xcd\xff\xff是arg2的地址,占4字节,“%08x%08x”表示两个8字符宽的十六进制数,占16字节,“%012d”占12字节,三个部分加起来共占4+16+12=32字节,也就是把arg2赋值为0x00000020。格式字符串最后一部分“%13$n”是最重要的一部分,表示格式字符串的第13个参数,即写入0xffffcd28的地方(0xffffcd58),printf()通过该地址找到被覆盖数据。

对比printf()执行前后的栈,可以看到其首先解析“%13$n”,从0xffffcd58找到地址0xffffcd28,然后将其数据覆盖为“0x00000020”。

任意地址内存覆盖

也许已经有人发现了问题,使用上面的方法,值最小只能是4,因为光地址就占去了4个字节,那么怎样覆盖比4小的值呢?利用整数溢出是一个方法,但是在实践中这样做很难成功。再想一下,前面的输入中,地址都位于格式字符串之前,这样做真的有必要吗,能否将地址放在中间呢?我们来试一下,使用格式字符串“AA%15\(nA"+"\x38\xd5\xff\xff”,开头的“AA”占2个字节,即将地址赋值为2,中间“%15\)n”占5个字节(这里不是%13$n,因为地址被放在了后面),是第15个参数,后面跟上一个“A”占用1个字节。于是前半部分总共占用2+5+1=8个字节,刚好是两个参数的宽度,这里的8字节对齐十分重要。最后,输入我们要覆盖的地址“\x38\xd5\xff\xff”,如下所示。

PWN学习之格式化字符串漏洞的更多相关文章

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

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

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

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

  3. CTF必备技能丨Linux Pwn入门教程——格式化字符串漏洞

    Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...

  4. 格式化字符串漏洞 format string exploit(一)

    本文系原创,转载请说明出处 本文为基于CTF WIKI的PWN学习 0x00 格式化字符串原理 先附一张经典的图,如下 其栈上布局如下: some value 3.14 123456 addr of ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. jvm运行过程

    ------------恢复内容开始------------ 把文件编译成字节码文件的叫编译器的前端, 线程共享的方法去和堆,非线程共享的:java虚拟机栈,本地方法栈,还有程序计数器 都是每个线程独 ...

  2. Windows 10 64位操作系统 下安装、配置、启动、登录、连接测试oracle 11g

    一.下载oracle安装包 1:详细下载安装版本可见官网:https://www.oracle.com/technetwork/database/enterprise-edition/download ...

  3. git 操作 :从远程仓库gitLab上拉取指定分支到本地仓库;git如何利用分支进行多人开发 ;多人合作代码提交实践

    例如:将gitLab 上的dev分支拉取到本地 git checkout -b dev origin/dev 在本地创建分支dev并切换到该分支 git pull origin dev 就可以把git ...

  4. shell 一些常用命令

    一般自己虚拟机新安装的centos才需要此配置 setenforce 是Linux的selinux防火墙配置命令 执行setenforce 0 表示关闭selinux防火墙. getenforce 查 ...

  5. C++学习笔记:07 类的继承与派生

    课程<C++语言程序设计进阶>清华大学 郑莉老师) 基本概念 继承与派生的区别: 继承:保持已有类的特性而构造新类的过程称为继承. 派生:在已有类的基础上新增自己的特性(函数方法.数据成员 ...

  6. FastAPI(62)- FastAPI 部署在 Docker

    Docker 学习 https://www.cnblogs.com/poloyy/p/15257059.html 项目结构 . ├── app │   ├── __init__.py │ └── ma ...

  7. 现代 C++ 对多线程/并发的支持(上) -- 节选自 C++ 之父的 《A Tour of C++》

    本文翻译自 C++ 之父 Bjarne Stroustrup 的 C++ 之旅(A Tour of C++)一书的第 13 章 Concurrency.用短短数十页,带你一窥现代 C++ 对并发/多线 ...

  8. 安全通信协议SSH应用与分析

    一.实验简介: 本次实验属于安全协议应用与分析系列 二 实验环境: Windows server 2003 server windows xp 做client 三.实验目的 通过该实验了解SSH服务器 ...

  9. 微服务+异步工作流+ Serverless,Netflix 决定弃用稳定运行 7 年的旧平台

    作者 | Frank San Miguel 策划 | 田晓旭 2021 年,Netflix 会将大部分的工作负载从 Reloaded 转移到 Cosmos 平台.Cosmos 是一个计算平台,它将微服 ...

  10. js--typeof 和 instanceof 判断数据类型的区别及开发中的使用

    前言 日常的开发中,我们经常会遇到判断一个变量的数据类型或者该变量是否为空值的情况,你是如何去选择判断类型的操作符的?本文来总结记录一下我们开发人员必须掌握的关于 typeof 和 instanceo ...