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,第八位就可以传入变量的地址了。
后续的内容需要花费一些时间,短时间内先放放,暂时放下不管,之后有时间再来补充。
相关文章:
pwn学习笔记(5)--格式化字符串漏洞(未完全完成)
pwn学习笔记(5)–格式化字符串漏洞 前言:由于条件有限,因此对于该漏洞的学习不算很多, 格式化字符串漏洞基础: 格式化字符串介绍: 格式化字符串函数可以接收可变数量的参数࿰…...

HTML标签之表单标签,web开发实例教程
标签语义化: 语义和默认样式的区别: 默认样式是浏览器设定的一些常用tag的表现形式;语义化的主要目的就是让大家直观的认识标签和属性的用途和作用; 标签语义化作用: 当只有HTML页面时,没有CSS…...
数据库-第四/五章 数据库安全性和完整性【期末复习|考研复习】
前言 总结整理不易,希望大家点赞收藏。 给大家整理了一下计数据库系统概论中的重点概念,以供大家期末复习和考研复习的时候使用。 参考资料是王珊老师和萨师煊老师的数据库系统概论(第五版)。 文章目录 前言4 第四章 数据库安全性4.1 数据库安全性定义4.…...

网站维护页面404源码
网站维护页面404源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面 下载地址 https://www.qqmu.com/2407.html...

CSS的文本样式属性值,web开发难点
什么是css块元素? 块级元素是独占一行显示的。它的兄弟元素必定不会与其在同一行中(除非脱离了文档流)。通俗点来说,就是块元素(block element)一般是其他元素的容器元素 戳这里领取完整开源项目:【一线大厂前端面试题…...

springboot+jsp汽车配件管理系统idea maven 项目lw
springbootweb汽车配件销售业绩管理系统服务于汽车配件公司业务,实现了客户管理,主要负责对客户相关数据的增删改查方面、渠道管理,主要对渠道信息也就是设备的供应商渠道信息进行管理、项目管理,主要是一些项目信息的记录与整理、销售数据管…...

计算机网络-网络安全(二)
1.应用层安全协议: S-HTTP或SHTTP(Sec HTTP),安全超文本传输协议,是HTTP扩展,使用TCP的80端口。HTTPS:HTTPSSL,使用TCP的443端口。和TLS(传输层安全标准)是双…...
Flutter App代码混淆
Flutter 应用混淆 Flutter 应用的混淆非常简单,只需要在构建 release 版应用时结合使用 --obfuscate 和 --split-debug-info 这两个参数即可。 flutter build apk –obfuscate --split-debug-info 命令需要指定输出调试文件的位置,该命令会生成一个符号映…...
pandas中apply函数的坑——错误信息Must provide ‘func‘ or tuples of ‘(column, aggfunc)的解决办法
近期需要获取某网站上的文章标题,并对文章来源以及不同来源的文章数量进行分析。已通过爬虫完成对文章标题、日期和文章链接的爬取,并存入pandas中的dataframe中,准备进行下一步的分析。 该网站一般情况下,文章标题前两个字是信息…...

《操作系统真相还原》读书笔记二:环境搭建 xshell连接virtualbox
修改 sshd_config 使用 vi /etc/ssh/sshd_config命令进入sshd服务配置,键盘输入i进行编辑,将监听端口、监听地址前的 # 号去除,开启允许远程登录,开启使用用户名密码来作为连接验证。修改完成,按一下Esc,输…...

CSS盒模型居中方法,大学生必备
96道前端面试题 下面给大家分享96道前端面试题 1,一些开放性题目 自我介绍:除了基本个人信息以外,面试官更想听的是你与众不同的地方和你的优势。项目介绍如何看待前端开发?平时是如何学习前端开发的?未来三到五年的…...
【Golang星辰图】构建健壮应用的秘籍:探索Go语言中最强大的测试工具库
精进单元测试:探秘Go语言中流行的测试框架和工具 前言 提高软件质量和稳定性是每个开发人员的目标之一。而单元测试是保证代码质量的重要手段之一,可以帮助我们检查代码是否按预期工作,并提早发现潜在的bug。Go语言提供了丰富的测试框架和工…...

刷题笔记day27-回溯算法3
39. 组合总和 var path []int var tmp []int var result [][]int// 还是需要去重复,题目中要求的是至少一个数字备选的数量不同。 // 所以需要剪枝操作,右边的要比左边的> func combinationSum(candidates []int, target int) [][]int {// 组合问题pa…...

【项目】Boost 搜索引擎
文章目录 1.背景2.宏观原理3.相关技术与开发环境4. 实现原理1.下载2.加载与解析文件2.1获取指定目录下的所有网页文件2.2. 获取网页文件中的关键信息2.3. 对读取文件进行保存 3.索引3.1正排与倒排3.2获取正排和倒排索引3.3建立索引3.3.1正排索引3.3.2倒排索引 4.搜索4.1 初始化…...
vue3 (六)自定义指令
1.定义自定义指令: app.directive(pos,{mounted(el,bunding){el.style[bunding.arg] bunding.value px;}, updated(el,bunding){el.style[bunding.arg] bunding.value px;} }) app.directive(指令名,{ mounted(el,bunding){}, updated(el,bunding){} }) 如果只…...
vite、mode如果为production打包后 .env.production 中 VITE_API_DOMAIN变量作为API地址吗
Vite 是一个现代化的前端构建工具,它使用 .env 文件来管理不同环境下的环境变量。通过为不同的环境(如开发环境、生产环境等)设置不同的 .env 文件,你可以控制这些环境中的变量,这些变量在构建时会被注入到项目中 当你…...

静态时序分析:SDC约束命令set_fasle_path详解
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 目录 指定建立/保持时间检查 指定上升/下降沿 指定时序路径起点 删除虚假路径 添加注释 简单使用 写在最后 在之前的文章中,我们讨论了如何使…...
浅谈马尔科夫链蒙特卡罗方法(MCMC)算法的理解
1.解决的问题 计算机怎么在任意给定的概率分布P上采样?首先可以想到把它拆成两步: (1)首先等概率的从采样区间里取一个待定样本x,并得到它的概率为p(x) (2)然后在均匀分布U[0,1]上取一个值&a…...
2403C++,C++20协程库
原文 基于C20协程的http库--cinatra cinatra是基于C20无栈协程实现的跨平台,仅头,高性能,易用的http/https库(http1.1),包括httpserver和httpclient,功能完备,不仅支持最普通的getpost等请求,还支持restfulapi,websocket,chunked,ranges,multipart,静态文件服务和反向代理等功…...
mybatis动态加载mapper.xml
mybatis动态加载mapper.xml mybatis动态加载mapper.xml、springboot mybatis动态加载mapper.xml 教程连接:https://blog.csdn.net/weixin_44480167/article/details/136356398...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...