-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Advisory: Kaspersky kl1.sys Kernel Stack Overflow Advisory ID: TKADV2008-004 Revision: 1.1 Release Date: 2008/06/06 Last Modified: 2008/06/12 Date Reported: 2008/02/25 Author: Tobias Klein (tk at trapkit.de) Affected Software: Kaspersky Anti-Virus 6.0 and 7.0 Kaspersky Internet Security 6.0 and 7.0 Kaspersky Anti-Virus 6.0 for Windows Workstations Remotely Exploitable: No Locally Exploitable: Yes Vendor URL: http://www.kaspersky.com/ Vendor Status: Vendor has released a fixed version CVE-ID: CVE-2008-1518 Patch development time: 78 days ====================== Vulnerability details: ====================== The kernel driver kl1.sys shipped with several Kaspersky products contains a vulnerability in the code that handles IOCTL requests. Exploitation of this vulnerability can result in: 1) local execution of arbitrary code at the kernel level (complete system compromise), or 2) local denial of service attacks (system crash due to a kernel panic) The issue can be triggered by sending a specially crafted IOCTL request. ====================== Technical description: ====================== The IOCTL call 0x800520e8 of the kl1.sys kernel driver accepts user supplied input that doesn't get validated enough. In consequence it is possible to pass user controlled data with an arbitrary length to a swprintf function. That leads to a kernel stack overflow. Disassembly of kl1.sys (version 6.1.26.0): [...] .text:000120D8 mov ebx, [edi+0Ch] <-- (1) .text:000120DB mov ebp, [esi+0Ch] <-- (2) .text:000120DE push edx .text:000120DF mov [esp+1Ch+var_8], 0 .text:000120E7 mov [esp+1Ch+Irp], eax .text:000120EB mov [esp+1Ch+Status], ecx .text:000120EF call sub_11BB0 .text:000120F4 test eax, eax .text:000120F6 jz short loc_12111 [...] .text:00012111 loc_12111: .text:00012111 cmp byte ptr [esi], 0Eh .text:00012114 jnz loc_121E8 .text:0001211A cmp ebp, 800520E8h <-- (3) .text:00012120 ja loc_121B3 [...] .text:00012197 loc_12197: .text:00012197 test ebx, ebx <-- (4) .text:00012199 jz short loc_121E0 .text:0001219B cmp [esp+18h+Irp], 21Ch <-- (5) .text:000121A3 jb short loc_121E0 .text:000121A5 push 0 .text:000121A7 lea edx, [ebx+14h] <-- (6) .text:000121AA push edx <-- (7) .text:000121AB push ebx <-- (8) .text:000121AC call sub_11DD0 <-- (9) [...] (1) A pointer to user supplied data gets copied into EBX (IOCTL input buffer) (2) Requested IOCTL control code gets copied into EBP (3) Vulnerable IOCTL control code (4) Check if IOCTL input buffer != 0 (5) Input buffer size must be >= 0x21c (6) The address of user supplied data + offset 0x14 gets copied into EDX (7) EDX (pointing to user supplied data) is used as a parameter for the sub_11DD0 function (8) EBX (also pointing to user supplied data) is used as a parameter for the sub_11DD0 function (9) The sub_11DD0 function gets called Disassembly of the sub_11DD0 function: [...] .text:00011DDC mov ecx, [esp+4+arg_8] .text:00011DE0 mov edx, [esp+4+arg_4] <-- (10) .text:00011DE4 push ecx .text:00011DE5 mov ecx, [esp+8+arg_0] <-- (11) .text:00011DE9 push edx <-- (12) .text:00011DEA push ecx <-- (13) .text:00011DEB mov ecx, eax .text:00011DED call sub_11790 <-- (14) [...] (10) A pointer to user supplied data gets copied into EDX (11) A pointer to user supplied data gets copied into ECX (12) + (13) EDX and ECX (both pointing to user supplied data) are used as parameters for the sub_11790 function (14) The sub_11790 function gets called Disassembly of the sub_11790 function: [...] .text:000117FE loc_117FE: .text:000117FE mov ebp, [esp+84Ch+a3] <-- (15) .text:00011805 mov eax, ebp <-- (16) .text:00011807 lea edx, [eax+2] .text:0001180A lea ebx, [ebx+0] [...] .text:00011810 loc_11810: .text:00011810 mov cx, [eax] <-- (17) .text:00011813 add eax, 2 .text:00011816 cmp cx, bx .text:00011819 jnz short loc_11810 [...] .text:0001181B sub eax, edx .text:0001181D sar eax, 1 .text:0001181F push '-NeG' ; Tag .text:00011824 lea eax, [eax+eax+2] .text:00011828 push eax ; NumberOfBytes .text:00011829 push ebx ; PoolType .text:0001182A call edi ; ExAllocatePoolWithTag <-- (18) .text:0001182C cmp eax, ebx .text:0001182E mov [esi+18h], eax <-- (19) .text:00011831 jz short loc_11848 [...] (15) A pointer to user supplied data gets copied into EBP (16) The value of EBP (see (15)) is copied into EAX (17) In this loop the length of the user supplied data is calculated (18) A kernel pool buffer gets allocated (NumberOfBytes = sizeof (user_data)) (19) A pointer to the kernel pool buffer (see (18)) gets stored at [esi+18h] [...] .text:00011833 mov ecx, ebp <-- (20) .text:00011835 mov edx, eax <-- (21) .text:00011837 .text:00011837 loc_11837: .text:00011837 movzx eax, word ptr [ecx] <-- (22) .text:0001183A mov [edx], ax .text:0001183D add ecx, 2 .text:00011840 add edx, 2 .text:00011843 cmp ax, bx .text:00011846 jnz short loc_11837 [...] .text:00011848 cmp [esp+84Ch+arg_8], bl .text:0001184F mov edx, [esi+18h] <-- (23) .text:00011852 jz short loc_11869 [...] .text:00011869 loc_11869: .text:00011869 push edx <-- (24) .text:0001186A push offset a??S ; "\\??\\%s" .text:0001186F lea eax, [esp+854h+SourceString] <-- (25) .text:00011876 push eax ; wchar_t * [...] .text:00011877 loc_11877: .text:00011877 call swprintf <-- (26) [...] (20) A pointer to user supplied data gets copied into ECX (21) A pointer to the kernel pool buffer (see (18)) gets copied into EDX (22) In this loop the user supplied data (pointed to by ECX) gets copied into the kernel pool buffer (pointed to by EDX) (23) A pointer to the kernel pool buffer (now filled with user data; see (22)) gets copied into EDX (24) The kernel pool buffer with user supplied data is used as a parameter for swprintf (25) The kernel stack buffer "SourceString" is used as destination buffer for swprintf (26) swprintf gets called and copies the user supplied data (pointed to by EDX) without any bounds checking into the kernel stack buffer "SourceString" (pointed to by EAX) Kernel stack buffer "SourceString": 000007D0 SourceString dw 1000 dup(?) This classical stack overflow can be exploited to control the kernel execution flow and to execute arbitrary code at the kernel level. ========= Solution: ========= A relevant patch is available to all users of vulnerable Kaspersky products via the built-in automatic updating module. ======== History: ======== 2008/02/25 - iDefense VCP notified 2008/03/19 - Initial vendor notification by iDefense 2008/03/20 - Initial vendor response to iDefense 2008/06/04 - Coordinated public disclosure by iDefense 2008/06/06 - Full technical description released ======== Credits: ======== Vulnerability found and advisory written by Tobias Klein. =========== References: =========== [1] http://labs.idefense.com/intelligence/vulnerabilities/ display.php?id=704 [2] http://www.kaspersky.com/technews?id=203038727 [3] http://www.trapkit.de/advisories/TKADV2008-004.txt ======== Changes: ======== Revision 0.1 - Initial draft release to the vendor Revision 1.0 - Public release Revision 1.1 - Advisory ID adjusted =========== Disclaimer: =========== The information within this advisory may change without notice. Use of this information constitutes acceptance for use in an AS IS condition. There are no warranties, implied or express, with regard to this information. In no event shall the author be liable for any direct or indirect damages whatsoever arising out of or in connection with the use or spread of this information. Any use of this information is at the user's own risk. ================== PGP Signature Key: ================== http://www.trapkit.de/advisories/tk-advisories-signature-key.asc Copyright 2008 Tobias Klein. All rights reserved. -----BEGIN PGP SIGNATURE----- wj8DBQFIUZaRkXxgcAIbhEERAs+EAKCiB1LFSgkIax3fQgv3+lA2AvVSQgCg/8Cy TZN9MmlFiMdjBuFsoBJqdTw= =+Lzo -----END PGP SIGNATURE-----