In the last Microsoft Security Bulletins (August 2010), Microsoft is patching several kernel level bugs MoonSols reported including, two CVEs in MS10-048 and several defense-in-depth changes for the win32k.sys kernel module and one CVE in MS10-058 for the Windows TCP/IP kernel module.
* Matthieu Suiche of MoonSols (http://moonsols.com/) for reporting the Win32k Pool Overflow Vulnerability (CVE-2010-1895)
* Matthieu Suiche of MoonSols (http://moonsols.com/) for reporting the Win32k User Input Validation Vulnerability (CVE-2010-1896)
* Matthieu Suiche of MoonSols (http://moonsols.com/) for working with us on the defense-in-depth changes addressed in MS10-048 described by SRD Team here
* Matthieu Suiche of MoonSols for reporting the Integer Overflow in Windows Networking Vulnerability (CVE-2010-1893)
I am only going to describe the tcpip.sys (CVE-2010-1893 vulnerability because it had been introduced into Windows 7/Windows 2008 R2 by removing safe-int functions at the beginning of IppSortDestinationAddresses() before calling the pool allocation function.
IppSortDestinationAddresses() is reachable locally from user-land by calling WSAIoctl and using the SIO_ADDRESS_LIST_SORT IOCTL. The buffer passed to SIO_ADDRESS_LIST_SORT is a SOCKET_ADDRESS_LIST structure. Each SOCKET_ADDRESS in the list must be in SOCKADDR_IN6 format.
At the beginning of IppSortDestinationAddresses(), we have the following pseudo-code :
DestinationAddresses = ExAllocatePoolWithTag(NumberOfDestinationAddresses * sizeof(SOCKADDR_IN6));
// sizeof(SOCKADDR_IN6) = 0x1C
NtStatus = IppFlattenAddressList(SocketAddressList, DestinationAddresses);
if (!NT_SUCCESS(NtStatus)) ExFreePoolWithTag(DestinationAddresses);
This issue could have been avoided if developpers would have use safe-int functions such as RtlULongMult() like in the following part of code :
NtStatus = RtlUlongMult(NumberOfDestinationAddresses, sizeof(SOCKADDR_IN6), &BufferSize);
if (!NT_SUCCESS(NtStatus))
{
//
// INT OVERFLOW !
//
return NtStatus;
}
DestinationAddresses = ExAllocatePoolWithTag(BufferSize);
//
// ...
//
Please note that int safe functions also exist in user-land (UlongAdd, etc..) You can found the full list on the Microsoft MSDN Website.
The integer overflow is caused in IppSortDestinationAddresses() function and the kernel-land pool overflow in IppFlattenAddressList() function. The following code is a pseudo-code and contains only the most important part of the function.
NTSTATUS
IppFlattenAddressList(IN PSOCKET_ADDRESS_LIST SocketAddressList,
OUT PSOCKADDR_IN6 FlattenAddressList)
{
PSOCKADDR_IN6 Address;
// [...]
for (Index = 0; Index < SocketAddressList->iAddressCount; Index += 1) {
if (SocketAddressList->Address[Index].iSockaddrLength != sizeof(SOCKADDR_IN6)) return STATUS_INVALID_PARAMETER;
Address = SocketAddressList->Address[Index].lpSockaddr;
// Of course, there is a ProbeForRead + __try if the function is called from Userland
FlattenAddressList[Index] = *Address; // <--- Pool Overflow is occuring here.
//
// The following part is important if you want to proceed to the overflow.
//
if (FlattenAddressList[Index].sin6_family != AF_INET6) return STATUS_INVALID_PARAMETER;
}
// [...]
}
Because SocketAddressList->iAddressCount will have a too high value, the loop will continue to copy data into the kernel pool until the sin6_family will be different from AF_INET6 or until iSockaddrLength would be different from sizeof(SOCKADDR_IN6);
In both case, the IppFlattenAddressList() function will return STATUS_INVALID_PARAMETER which will force the caller to release the kernel pool.
sin6_family which is the first field of SOCKADDR_IN6 structure, would be read as PreviousSize field from POOL_HEADER structure during the unlinking which might make the exploitation harder for the attacker in addition to the safe kernel pool unlinking mechanism added in Windows 7.
Structures of Windows 7 x86 POOL_HEADER and Windows 7 x64 POOL_HEADER can be found on MoonSols Developer Network.
The following bug check resumes what have been said above :
BAD_POOL_HEADER (19)
The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arguments:
Arg1: 00000020, a pool block header size is corrupt.
Arg2: 85fcf1d8, The pool entry we were looking for within the page.
Arg3: 85fcf218, The next pool entry.
Arg4: 08080003, (reserved)
...
kd> dt nt!_POOL_HEADER 85fcf1d8
+0x000 PreviousSize : 0y000000011 (0x3)
+0x000 PoolIndex : 0y0000000 (0)
+0x002 BlockSize : 0y000001000 (0x8)
+0x002 PoolType : 0y0000100 (0x4)
+0x000 Ulong1 : 0x8080003
+0x004 PoolTag : 0x73617049
+0x004 AllocatorBackTraceIndex : 0x7049
+0x006 PoolTagHash : 0x7361
kd> dt nt!_POOL_HEADER 85fcf218
+0x000 PreviousSize : 0y000010111 (0x17)
+0x000 PoolIndex : 0y0000000 (0)
+0x002 BlockSize : 0y101000001 (0x141)
+0x002 PoolType : 0y0100000 (0x20)
+0x000 Ulong1 : 0x41410017
+0x004 PoolTag : 0x41414141
+0x004 AllocatorBackTraceIndex : 0x4141
+0x006 PoolTagHash : 0x4141
kd> db 85fcf218
85fcf218 17 00 41 41 41 41 41 41-41 41 41 41 41 41 41 41 ..AAAAAAAAAAAAAA
85fcf228 41 41 41 41 41 41 41 41-41 41 41 41 01 00 00 00 AAAAAAAAAAAA....
85fcf238 00 00 00 00 0c 00 08 00-40 5c 74 82 00 00 00 00 ........@\t.....
85fcf248 01 00 04 00 00 00 00 00-50 f2 fc 85 50 f2 fc 85 ........P...P...
85fcf258 08 00 5c 00 49 6f 20 20-d8 6c 74 82 d8 6c 74 82 ..\.Io .lt..lt.
85fcf268 e0 0a e5 84 55 72 62 54-28 bd e5 84 38 f4 02 86 ....UrbT(...8...
85fcf278 00 00 00 00 94 f1 ed 85-04 63 b2 85 01 00 00 00 .........c......
85fcf288 06 00 08 08 45 76 65 ee-b8 3d 0f 86 40 00 00 00 ....Eve..=..@..
To avoid common mistakes in kernel development, I suggest you to read Avoiding driver security pitfalls (Matt Miller, Microsoft) - Or contact
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
to review your code ;-)
-- Matthieu