博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Jarvis Oj Pwn 学习笔记-fm
阅读量:5923 次
发布时间:2019-06-19

本文共 2161 字,大约阅读时间需要 7 分钟。

格式化串漏洞(32bit):

链接领走:

https://files.cnblogs.com/files/Magpie/fm.rar

nc pwn2.jarvisoj.com 9895

首先验身:

看到某种奇怪的鸟类不禁慌了一哈......

好,现在丢IDA:

先是看到了这样一个妩媚妖艳的东西...她被调用在main函数:

跟进去:

没看懂....(或许是我水平有限,以后有机会的话尽量填上这个坑)

回头看main函数:

一眼先关注到read,然而看了一下缓冲区长度,并没有溢出漏洞;

继续看,printf直接输出了用户可控的串,显然有格式化串漏洞可利用,往下看就知道基本就是改写x值控制判断执行流程了:

格式化串漏洞主要有两个利用:1.内存泄漏  2.篡改内存;显然此处是第二个利用,也就是对%n的利用:

首先介绍一哈原理:

一、当格式化串中出现%n时,会把%n之前已经打印出过的字符的个数,作为一个值写到对应的参数(一个可写的地址)上

比如:

   printf("2333%n",&a);

%n之前打印了2333,共四个字符,因此a就被赋值4,即执行完这条语句后,a==4;

因此利用这一点,可以构造携带%n的串篡改内存;

二、构造的关键:%n前输出正确个数的字符、计算%n对应地址指针在栈中的存储偏移->保证了将正确的值写入正确的内存地址

此处介绍一个格式化符的特殊用法:偏移量标志符$

先来分析一下本题main函数的传参方式(32bit):

从右往左压栈传参:

所以参数栈区的布局从低往高依次是格式化串指针、参数1、参数2、......、参数n

这是一块线性连续的栈区,在串中从前往后的各个格式化符在栈中依次对应了后面的各个参数

而$的用法是:例如%5$n,意味在拓展这个%n对应的内容时,参数偏移量为5,即从栈中的格式化串指针处,往高地址偏移5个参数,再做参数向串中的拓展。

注意:这里偏移量的单位是以参数为单位,而不是以内存地址为参数!

因此,我们在构造攻击性内存时,再保证之前正确的打印个数后,就需要在栈中精确计算格式化串指针目标改写地址指针在栈中的距离!

 原理大概就是这样子,请特别注意$符号表示的偏移是以参数个数为单位!

 现在我们回头看我们的程序:

===============汇编================

========x的内存地址========

 

确定目标:要把x改写成4

第一步:%n号之前打印正确的个数,应该打印4个

第二步:要写到的地方是0x804a02c处,我们需要找一个机会把这个地址值写到栈中,而唯一可供我们写数据的机会就是唯一的一个read函数

反应到地址值正好是四个字节,将它放在格式化串的%n之前,刚好满足了这两个步骤

第三步:计算$符号的offset

看伪代码和汇编或看IDA给的栈,易知,格式化串指针存在栈顶,

而0x804a02c这个地址值存在read输入的buffer的起始处,

而buffer的地址偏移是esp+2C,0x2c=44

因此为%44$n......??

问题就在这里,44是内存地址偏移,而单位应该是参数个数,一个参数对应了4byte所以正确的偏移应该是44 ÷ 4 = 11

给出exp:

1 from pwn import *2 context(arch='i386',os='Linux')3 r=remote('pwn2.jarvisoj.com',9895)4 payload=p32(0x804a02c)+'%11$n'5 r.send(payload)6 r.interactive()

分享一个教训....写exp别把send写成sent,上次手残写错了,咋找也找不到错误

#################################################################################

还没完!

上面只是一种做法,我们称之为“道系做法”:万物循宗,道从凿凿,精确计算offset,精准给出payload

其实还有另外一种“佛系做法”:夤夜樽饮复一樽,酒尽烛干自当眠,啥意思呢,直接上exp一看都明白了:

 

1 from pwn import * 2 context(arch = 'i386', os = 'linux') 3 for i in range(1,100): 4   r = remote('pwn2.jarvisoj.com', 9895) 5   payload=p32(0x0804a02c)+'%'+str(i)+"$n" 6   r.send(payload) 7   try: 8     if r.recv()[-3]=='.': 9       r.interactive()10       break11   except:12     print 'SEG_ERR'13   r.close()

 

管你偏移的多少,直接跑吧......反正跑出来就对了

不过...不建议用这种办法的,实在太蹩脚了,而且对于分析能力的提高并没有好处!

还是道家好一些。

 

转载于:https://www.cnblogs.com/Magpie/p/9168841.html

你可能感兴趣的文章
PHP-FPM 调优:为了高性能使用 pm static
查看>>
MongoDB数据库
查看>>
Spring-Mybatis运行机制概括
查看>>
记一次JavaScript API练习题
查看>>
Node.js中的事件循环(Event Loop),计时器(Timers)以及process.nextTick()
查看>>
nodejs配置微信小程序本地服务器(二):利用ws模块创建基于ssl证书的WebSocket服务器...
查看>>
创建git项目(vue),使用webstorm上传
查看>>
nginx的web-server的基本使用(二)
查看>>
基于Helm和Operator的K8S应用管理
查看>>
android精美时钟界面、游戏新闻客户端、美食APP、音乐助手等源码
查看>>
浅谈Vue模板的那些事儿
查看>>
[翻译] Async/Await 使你的代码更简洁
查看>>
NPM酷库:commander,命令行参数处理框架
查看>>
ES6时代,你真的会克隆对象吗?
查看>>
使用PHPExcel读写excel
查看>>
spring security系列二:过滤器机制
查看>>
Flask-restful 用法及自定义参数错误信息
查看>>
10个Python面试常问的问题
查看>>
AI重新定义Web安全
查看>>
C语言学习入门01
查看>>