pwn学习笔记(5)--格式化字符串漏洞(未完全完成)

pwn学习笔记(5)–格式化字符串漏洞

前言:由于条件有限,因此对于该漏洞的学习不算很多,

格式化字符串漏洞基础:

格式化字符串介绍:

​ 格式化字符串函数可以接收可变数量的参数,并将第一个参数作为格式化字符串,根据其来解析之后的参数,格式化字符串的利用一般分为三个部分:

  • 格式化字符串函数
  • 格式化字符串
  • [后续参数]

格式化字符串函数:

​ 常见的格式化字符串有:

输入:

  • scanf()

输出:

函数基本介绍
printf输出到 stdout
fprintf输出到指定 FILE 流
vprintf根据参数列表格式化输出到 stdout
vfprintf根据参数列表格式化输出到指定 FILE 流
sprintf输出到字符串
snprintf输出指定字节数到字符串
vsprintf根据参数列表格式化输出到字符串
vsnprintf根据参数列表格式化输出指定字节到字符串
setproctitle设置 argv
syslog输出日志

格式化字符串的格式:

%[parameter][flags][field width][.precision][length]type

​ 其中,需要注意的有parameter参数,以及type参数:

parameter:

​ n$,获取格式化字符串中的指定参数

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。

​ 下面使用几个案例来说明下几个需要注意的参数:

parameter:

​ n$ 表示获取后面参数列表中的第几个参数。

​ 比如如下代码:

#include<stdio.h>
int main(){printf("%2$d\n",1,2,3);return 0;
}

​ 通过编译运行之后得到的值却是

root@g01den-virtual-machine:/home/g01den/Temp# ./a
2

​ 好了,我们稍微修改下刚刚的代码:

#include<stdio.h>
int main(){printf("%d%d%d\n",1,2,3);return 0;
}

​ 然后编译为32位之后,查看下汇编代码:

0000119d <main>:119d:       8d 4c 24 04             lea    0x4(%esp),%ecx11a1:       83 e4 f0                and    $0xfffffff0,%esp11a4:       ff 71 fc                push   -0x4(%ecx)11a7:       55                      push   %ebp11a8:       89 e5                   mov    %esp,%ebp11aa:       53                      push   %ebx11ab:       51                      push   %ecx11ac:       e8 2b 00 00 00          call   11dc <__x86.get_pc_thunk.ax>11b1:       05 27 2e 00 00          add    $0x2e27,%eax11b6:       6a 03                   push   $0x3      <-------------------------------11b8:       6a 02                   push   $0x2      <-------------------------------11ba:       6a 01                   push   $0x1      <-------------------------------11bc:       8d 90 30 e0 ff ff       lea    -0x1fd0(%eax),%edx11c2:       52                      push   %edx11c3:       89 c3                   mov    %eax,%ebx11c5:       e8 86 fe ff ff          call   1050 <printf@plt>11ca:       83 c4 10                add    $0x10,%esp11cd:       b8 00 00 00 00          mov    $0x0,%eax11d2:       8d 65 f8                lea    -0x8(%ebp),%esp11d5:       59                      pop    %ecx11d6:       5b                      pop    %ebx11d7:       5d                      pop    %ebp11d8:       8d 61 fc                lea    -0x4(%ecx),%esp11db:       c3                      ret

​ 能够发现在我指的那三行,在调用printf函数之前是先将参数从右向左压入栈中,之后通过读取栈的参数与格式化字符串一起打印出来。

格式化字符串漏洞:

​ 有了前面的那些储备知识,这个时候就可以来看看格式化字符串的漏洞了。

初探:

​ 首先,写一个程序,如下内容:

#include<stdio.h>
int main(){printf("%x  %x  %x  %x  \n",0x1);return 0;
}

​ 那么,直接进行动态调试,观看main的栈帧中相关的信息:

00:0000│ esp 0xffffd500 —▸ 0x56557008 ◂— '%x  %x  %x  %x  \n'
01:0004│-014 0xffffd504 ◂— 0x1                                            <--------------------
02:0008│-010 0xffffd508 —▸ 0xf7fbeb20 —▸ 0xf7c1acc6 ◂— 'GLIBC_PRIVATE'    <--------------------
03:000c│-00c 0xffffd50c —▸ 0x565561b1 (main+20) ◂— add eax, 0x2e27        <--------------------
04:0010│-008 0xffffd510 —▸ 0xffffd530 ◂— 0x1        					  <--------------------
05:0014│-004 0xffffd514 —▸ 0xf7e2a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
06:0018│ ebp 0xffffd518 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 —▸ 0x56555000 ◂— 0x464c457f

​ 然后,运行到printf函数之后,再看看输出的值是多少:

pwndbg> n
1  f7fbeb20  565561b1  ffffd530

​ 发现输出的值和箭头指出来的值一样。因此,黑客则可以利用此漏洞配合**%n$d**来进行内存的读取了。

一次简单的漏洞的实例:

​ 实际上,格式化字符串的漏洞很多时候都是由于程序员们偷懒,才会导致一些漏洞的产生,比如下面的程序,如果写成这个样子:

#include<stdio.h>
int main(){char str[100];scanf("%s\n",str);printf("%s\n",str);return 0;
}

​ 如果是这样的话,程序运行就不会出现太大的问题,但是,当程序员偷懒,使用下面的写法,就会出现问题:

#include<stdio.h>
int main(){char str[100];scanf("%s",str);printf(str);return 0;
}

​ 运行的话就会出现如下的结果:

root@g01den-virtual-machine:/home/g01den/Temp# ./a
aaa.%x
aaa.fff53a28

​ 根据gdb调试,就会发现,它输出了比esp地址高4字节的那一地址的数据。

泄露内存:

​ 还是刚才那个程序,其实可以在这个时候多输入几个%x来进行父函数栈帧的esp高4字节的地址开始的多个字节的内存,或者通过n$来进行任意内存的读取:

aaa.fff53a28root@g01den-virtual-machine:/home/g01den/Temp# ./a
%x.%x.%x.%x.%x.%x.%x
ff8631d8.0.565a31d4.0.0.252e7825.78252e78root@g01den-virtual-machine:/home/g01den/Temp# ./a
%3$x
565cf1d4

泄露任意地址的内存:

​ 上一个方法只是泄露了栈上的数据,其实,格式化字符串可以对任意内存地址的数据进行泄露。、

​ 攻击者可以使用类似于"%s"的格式规范做到泄露栈中存放的值对应的地址的字符串的内容,这里引用下dalao的对于%s的讲解:

程序会将%s指向的地址作为一个ASCII字符串处理,直到遇到一个空字符。所以,如果攻击者能够操纵这个参数的值,那就可以泄露任意地址的内容。

或者说

%s 是把地址指向的内存内容给打印出来,可以把 函数的地址给打印出来。

​ 也就是说,想要做到任意地址的内存泄露,就需要想办法对栈上的某个地址的值进行修改为想要获得的那个字符串的地址。

覆盖栈内存:

​ %n不能够输出字符,但是,它能把已经成功输出的字符个数写入对应的整形指针参数所致的变量,只要变量对应的地址可写,就可以利用格式化字符串来改变其对应的值。

一般来说,这种方法利用的步骤为:

  • 确定覆盖地址
  • 确定相对位移
  • 进行覆盖

注:以下为我个人的见解,如有问题,请指正。

​ 首先,之前说过了%n这个格式化字符串的作用是啥:

%n,不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。

​ 之后,用一个程序作为示例:

#include <stdio.h>
int a = 123, b = 456;
int main() {int c = 789;char s[100];printf("%p\n", &c);scanf("%s", s);printf(s);if (c == 16) {puts("modified c.");} else if (a == 2) {puts("modified a for a small number.");} else if (b == 0x12345678) {puts("modified b for a big number!");}return 0;
}

​ 这个程序的格式化字符串漏洞的函数很容易就能找到,那就是printf(s),因此,假设对变量c进行修改,就需要用到%n对C进行修改,所以,格式如下:

c的地址+12个任意的字符+对应格式化字符串的参数的偏移

​ 好了,实际试试看吧:

AAAA,$p,$p,$p,$p,$p,$p,$p,$p,$proot@g01den-virtual-machine:/home/g01den/Temp# ./a
0xff8d3ad4
AAA,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p
AAA,0xff8d3ad8,(nil),0x565d51e4,(nil),0x315,0x2c414141,0x252c7025,0x70252c70,0x2c70252c,0x252c7025,0x70252c70

​ 由此可知,传入的格式化字符串AAA,所对应的参数是第六位,因此,对应格式化字符串对应的偏移为6,也就是说,值为%6$n,好的,之后就是c的地址,我在学到这里的时候出现了理解不能的问题,最后大致是整明白了,就是不知道对不对。

​ 对于C的地址,我认为是,正是因为构造的格式化字符串的前四个字节是c的地址,因此,%n这个格式化字符串在写的时候对应的就是第六个参数,而第六个参数的前四个字节就是c的地址,因此就成功修改了c这个变量的值;**那么问题就来了,为啥不能直接指定第五个参数进行修改呢?**我个人的理解是这样的:因为第五个参数存放的并不是c这个变量的地址,是789,因此,%n就试图把16写入789这个地址里去,但是,这个地址要么不存在,要么就是无法访问,则会出现segment fault,导致程序出现了错误。

覆盖小数字:

​ 那么,问题又出现了,因为如果让变量的地址作为开始的字符,就会导致%n写入的最小的值也是4,那么,如果要让某个变量被覆盖为2,又该怎么做呢?

注:以下对于内容的解释部分均为我自己的理解,如有错误,还请指正。

​ 照理来说,想要某个变量被覆盖为2的话,就需要诸如

aa%k$naa+地址

​ 这样的字符串,所以是为啥呢?

​ 这里借用julao们的说法是

aa%k n x x ,如果用这样的方式,前面 a a nxx,如果用这样的方式,前面 aa%k 是第六个参数, nxx,如果用这样的方式,前面aanxx 是第七个参数,后面在跟一个 我们想要修改的地址,那么这个地址就是第八个参数,只需要把 k 改成 8 就可以把这第八个参数改成 2,aa%8$nxx

​ 我个人的理解为,在栈中,每个字符的长度为1字节,另外,对于格式化字符串的参数传递而言,每个参数都占用了四个字节(32位),所以,这里需要前和中都构成四个字节的字符串,因此,第六位的字符串就是aa%k,第七位就是$naa,第八位就可以传入变量的地址了。

后续的内容需要花费一些时间,短时间内先放放,暂时放下不管,之后有时间再来补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/722279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

清除注册表的U盘(USB盘)使用记录,或者电脑的U盘记录

清除注册表的U盘(USB盘)使用记录&#xff0c;或者电脑的U盘记录 1、可以考虑使用psexec.exe&#xff0c;在Windows图标按右键选择Windows PowerShell(管理员)(A)&#xff0c;然后输入PsExec.exe -i -d -s regedit.exe就可以删除(如果打开注册表&#xff0c;删除id需要右键修改…

鸿蒙学习-数据持久化

应用数据持久化概述 应用数据持久化&#xff0c;是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象&#xff0c;存储介质上的数据形态可能是文本、数据库、二进制文件等。 HarmonyOS标准系统支持典型的存储数据形态…

win11下安装mysql

一、下载MySQL 官方下载传送门 我安装的版本是5.7.83 二、安装MySQL 1.双击安装包 2.选择Custom(自定义安装)&#xff0c;然后Next> 3.根据你的系统做选择&#xff0c;我的是64位&#xff0c;所选MySQL Servers 5.7.38 -x64&#xff0c;然后按箭头将选中的版本移到右边…

qt学习:QPaintEvent绘图事件+QPainter画家

目录 QPaintEvent绘图事件 常见事件 QPainter 初始化 QPainter 设置画笔和画刷 绘制图形 结束绘制 画线 画矩形 画圆形 画弧线 画扇形 指定画笔大小 QPen 抗锯齿 无边框 画指针 多边形 渐变色 QLinearGradient 使用步骤 示例一 线性渐变 示例二 径向渐…

Java基于springboot的社区团购系统设计论文

摘 要 本课题是根据用户的需要以及网络的优势建立的一个社区团购系统&#xff0c;来满足用户团购的需求。 本社区团购系统应用Java技术&#xff0c;MYSQL数据库存储数据&#xff0c;基于Spring Boot框架开发。在网站的整个开发过程中&#xff0c;首先对系统进行了需求分析&…

小迪安全32WEB 攻防-通用漏洞文件上传二次渲染.htaccess变异免杀

#知识点&#xff1a; 1、文件上传-二次渲染 2、文件上传-简单免杀变异 3、文件上传-.htaccess 妙用 4、文件上传-PHP 语言特性 #详细点&#xff1a; 1、检测层面&#xff1a;前端&#xff0c;后端等 2、检测内容&#xff1a;文件头&#xff0c;完整性&#xff0c…

青蛙过河。

&#xff01;&#xff01;&#xff01;思路和代码源自蓝桥云课大佬题解 问题描述 小青蛙住在一条河边&#xff0c;它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。 河里的石头排成了一条直线小青蛙每次跳跃必须落在一块石头或者岸上。 不过,每块石头有一个高度,…

【数据结构】拆分详解 - 排序

文章目录 前言一、排序的概念及其运用  1.1 排序的概念  1.2 排序的运用  1.3 常见的排序算法  1.4 排序算法性能测试对比函数 二、常见排序算法的实现  2.1 插入排序   2.1.1  基本思想   2.1.2  直接插入排序   2.1.3  希尔排序     1. 预排序&am…

特殊设计模式

▶实现一个类&#xff0c;不能被拷贝 ▶实现一个类&#xff0c;只能在堆上创建 ❗实现一个类&#xff0c;只能创建在栈上 ❗设计一个不能继承的类 ❗单例模式——一个类只能生成一个对象   ❔饿汉模式——在每次程序启动都会自动生成一个对象   ❓懒汉模式——在第一次需要…

学编程怎么样才能更快入手,编程怎么简单易学

学编程怎么样才能更快入手&#xff0c;编程怎么简单易学 一、前言 对于初学编程建议先从简单入手&#xff0c;然后再学习其他复杂的编程语言。 今天给大家分享的中文编程开发语言工具 进度条构件的用法。 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 …

JAVA集合4-HashMap

介绍 HashMap 它实现了 Map 接口&#xff0c;提供了键值对的存储和检索功能。HashMap 的底层数据结构是基于哈希表实现的,JDK7 是数组链表&#xff0c;JDK8 是数组链表红黑 树。其中有两个重要的参数&#xff1a; 容量负载因子 容量的默认大小是 16&#xff0c;负载因子是 0…

代码随想录算法训练营第四十六天| 139.单词拆分、卡码网第56题

代码随想录算法训练营第四十六天| 139.单词拆分、卡码网第56题 139.单词拆分卡码网第56题 139.单词拆分 题目链接 文章讲解 class Solution { public:bool wordBreak(string s, vector<string>& wordDict) {int bagSize s.size(), n wordDict.size();vector<boo…

数字化转型导师坚鹏:成为数字化转型顾问 引领数字化美好未来

成为数字化转型顾问 引领数字化美好未来 ——数字化人才与企业的共赢之路 数字经济新时代&#xff0c;中国企业向数字化转型要效益&#xff1b; 转型顾问创未来&#xff0c;职场精英借数字化转型成良师。 我们中国政府特别重视数字经济发展及数字化人才培养。早在2020年8月2…

idea内置的database和chat2DB如何?

捉妖啦 最近由于某些众所周知的因素&#xff0c;要求卸载navicat,所以寻找替代品是当下任务。如果知识MySQL数据库的话&#xff0c;那替代品可太多了&#xff0c;由于使用的是MongoDB&#xff0c;所以至今没有找到一个称手的工具。 需要一款像Navicat一样&#xff0c;可以直…

什么样的跨网数据交换产品 能实现数据摆渡和数据同步?

首先&#xff0c;为什么会产生跨网数据摆渡的需求和场景呢&#xff1f;那是因为做了网络隔离&#xff0c;企业进行网络隔离的原因主要包括以下几点&#xff1a; 1、提高安全性&#xff1a;网络隔离是防止未授权访问和网络攻击的有效手段。通过将网络划分为多个独立的子网&…

L2785(Java). 将字符串中的元音字母排序

题目 1.如何以char类型便利字符串 2.自定义优先队列解决 class Solution {public String sortVowels(String s) {Map<Character,Integer> m new HashMap<>();m.put(a,1);m.put(e,1);m.put(i,1);m.put(o,1);m.put(u,1);m.put(A,1);m.put(E,1);m.put(I,1);m.put(O,…

[AIGC] 深入理解Flink中的窗口、水位线和定时器

Apache Flink是一种流处理和批处理的混合引擎&#xff0c;它提供了一套丰富的APIs&#xff0c;以满足不同的数据处理需求。在本文中&#xff0c;我们主要讨论Flink中的三个核心机制&#xff1a;窗口&#xff08;Windows&#xff09;、水位线&#xff08;Watermarks&#xff09;…

wait() 、notify()、notifyAll() 的详细用法

文章目录 &#x1f490;wait() 讲解&#x1f490;notify() 讲解&#x1f490;notifyAll()&#x1f4a1;wait() 和 sleep() 的区别 首先&#xff0c;我们知道&#xff0c;线程的执行顺序是随机的(操作系统随机调度的&#xff0c;抢占式执行)&#xff0c;但是有时候&#xff0c;我…

C语言内存池实现-对齐、重用、双向链表管理

概述 在项目上&#xff0c;经常遇到芯片内存不够导致编码困扰问题&#xff0c;在此写个笔录&#xff0c;方便后续查阅。 此示例&#xff0c;考虑了一些额外的功能和边界条件&#xff0c;例如内存分配的对齐、内存池的重用等。这个示例使用了双向链表来管理内存块。 源码如下&a…

【MySQL】视图、索引

目录 视图视图的用途优点视图的缺点创建视图查看视图修改视图删除视图注意事项 索引索引的原理索引的数据结构二分查找法Hash结构Hash冲突&#xff01;&#xff01;&#xff01; B树二叉查找树 存在问题改造二叉树——B树降低树的高度 B树特点案例继续优化的方向 改造B树——B树…