Poll
Is leak(test) protection important?
Articles
- Features of Modern Security Suites – Part 3
- Features of Modern Security Suites – Part 2
- Features of Modern Security Suites – Part 1
- KHOBE – 8.0 earthquake for Windows desktop security software
- Plague in (security) software drivers
- Introduction to Firewall Leak-testing
- Comparison of top five personal firewalls
- More about personal firewalls
- Design of ideal personal firewall
Plague in (security) software drivers
by Jakub Břečka & David Matoušek, members of www.matousec.com Research team,
special thanks to Ondřej Vlček of ALWIL Software for corrections
Published: 2007/09/18
Last update: 2008/04/14 - BSODhook version 2.0.0 released, the information about it moved to a separate web page
During our security analyses of personal firewalls and other security-related software that uses SSDT hooking, we found out that many vendors simply do not implement the hooks in a proper way. This allows local Denial of Service by unprivileged users or even privilege escalations exploits to be created. 100% of tested personal firewalls that implement SSDT hooks do or did suffer from this vulnerability! This article reviews the results of our testing and describes how a proper SSDT hook handler should be implemented. We also introduce BSODhook – a handy tool for every developer that deals with SSDT hooks and a possible cure for the plague in today's Windows drivers world.
Contents:
- Introduction
- The bug
- Structures with pointers
- Other issues and exploitability
- About BSODhook utility
- Research results
- Conclusion
Introduction
Hooking kernel functions by modifying the System Service Descriptor Table (SSDT) is a very popular method of implementation of additional security features and is used frequently by personal firewalls and other security and low-level software. Although undocumented and despised by Microsoft, this technique can be implemented in a correct and stable way. However, many software vendors do not follow the rules and recommendations for kernel-mode code writing and many drivers that implement SSDT hooking do not properly validate the parameters of the hooking functions.
Microsoft's Common Driver Reliability Issues document describes the correct parameter checking and contains many important notes to problems related to writing Windows drivers. Many vendors of today's software do not bother to read such documents and their implementations are thus vulnerable, and making the stable and trustworthy Windows kernel unreliable.
Parameters to SSDT function handlers are passed directly from user-mode and therefore must be checked before they are used. This article shows some incorrect implementations of SSDT hooking functions and describes how a proper validity check should be performed on various parameter types. To understand the following text, you will need some knowledge of Windows NT architecture. We do not cover a proper implementation of SSDT hooking techniques here. We focus on parameter validation problems. Some related and interesting information can be also found in Microsoft's Memory Management: What Every Driver Writer Needs to Know document.
The bug
For a demonstration of the bug, see the following code sample:
NTSTATUS HookNtOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{
if (ClientId->UniqueProcess==ProtectedProcess)
return STATUS_ACCESS_DENIED;
...
}
Example 1: No parameter validation at all.
This code shows a hook handler for a Windows Native API function NtOpenProcess and it implements a simple security check that will deny all requests to open a protected process with a specified process ID. For the purpose of this article, it is not important how such a hook is set, which is also a task that is pretty complicated if it is supposed to be performed correctly, or what is done after the security check, which is also non-trivial.
Unfortunately, the implementation in Example 1 is incorrect, because this hook handler function receives the parameters exactly as they were sent from user-mode, and it must therefore check all parameters' validity before using them. If a similar hook was implemented in user-mode (e.g. to intercept kernel32.OpenProcess or ntdll.NtOpenProcess calls), the need for a parameter validation would not be so necessary, because an invalid memory read or write in user-mode cannot corrupt the system's stability nor can it be exploited to escalate privileges. Such a lack of parameter checking will only corrupt or crash the application that invoked the invalid API call.
In the kernel however, the situation is different. All parameters coming from user-mode must be checked for validity before they are used. This is especially related to pointers to various structures. To access structure contents, the pointer must be dereferenced, which is a risky operation that can result in one of the following:
- A pointer to a valid memory is dereferenced – success.
- The pointer is invalid and points into user-mode memory – a page fault will occur and its handler will raise a SEH exception of ACCESS_VIOLATION, which, if not handled, will crash the system.
- The pointer is invalid and points into kernel-mode memory – this will not raise an exception, but instead a bugcheck (BSOD) will be invoked immediately.
SEH exceptions can be caught by enclosing the unsafe operations in try/except blocks. However, using try/except only is not enough, see the following code sample:
NTSTATUS HookNtOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{
HANDLE ProcessId;
try
{
ProcessId=ClientId->UniqueProcess;
} except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INVALID_PARAMETER;
}
if (ProcessId==ProtectedProcess)
return STATUS_ACCESS_DENIED;
...
}
Example 2: Invalid parameter validation, only user-mode pointers are validated properly.
In this function, the parameter ClientId is properly validated only for user-mode pointers. If ClientId points into an invalid kernel memory, the dereference will cause a BSOD to occur. A correct approach is to use the ProbeForRead function:
NTSTATUS HookNtOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{
HANDLE ProcessId;
if (ClientId!=NULL)
{
try
{
if (KeGetPreviousMode()!=KernelMode)
ProbeForRead(ClientId,sizeof(CLIENT_ID),1);
ProcessId=ClientId->UniqueProcess;
} except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INVALID_PARAMETER;
}
if (ProcessId==ProtectedProcess)
{
return STATUS_ACCESS_DENIED;
}
}
...
}
Example 3: Correct parameter validation for single-pointer structures like CLIENT_ID.
The call to ProbeForRead must be enclosed in the try/catch block as well as the access to the user supplied memory, because if the probing fails, an exception will be raised. You should also notice that ClientId is an OPTIONAL parameter. This means that it might not be present in a correct call. If it was NULL and we did not check this, the assignment to ProcessId would fail and we will return STATUS_INVALID_PARAMETER, which would disqualify some of correct NtOpenProcess calls.
See the following pseudo-code implementation of ProbeForRead:
VOID ProbeForRead(IN CONST VOID *Address,IN SIZE_T Length,IN ULONG Alignment)
{
// check for zero Length
if (Length==0)
return;
// check the alignment of Address
if (!CheckAlignment(Address,Alignment))
RaiseException(DATATYPE_MISALIGNMENT);
// check for an integer overflow
if (IsSumOverflow((ULONG)Address,Length))
RaiseException(ACCESS_VIOLATION);
// check if Address points into user-mode memory
if (((ULONG)Address+Length)>MmUserProbeAddress)
RaiseException(ACCESS_VIOLATION);
return;
}
Example 4: Internals of ProbeForRead in pseudo-code.
ProbeForRead checks whether the given pointer points into user-mode memory by comparing it to MmUserProbeAddress, which is the lowest invalid address for user-mode buffers. MmUserProbeAddress is typically set to 0x7FFF0000, or to 0xBFFF0000 on systems with 3GB user-space memory, activated by the /3GB switch in boot.ini.
It might seem odd, that the function does not perform any memory access to the desired memory area. But in fact, it is perfectly valid to access any user-mode memory, if the access is performed inside a try/except block. So, ProbeForRead only checks if the structure lies in the user-mode memory. This also means, that a function with a ProbeForRead call cannot be called from kernel-mode with a kernel memory pointer, because only user-mode addresses will pass the probe. This is why we use KeGetPreviousMode check, to allow kernel calls to pass without checking. You can find some information about it in Argument Validation in Windows NT part of Microsoft Windows NT: Design Goals article.
Note that you cannot use ProbeForRead or any similar function to perform a validity check on a kernel memory pointer. There is no easy mechanism that checks if an address in the kernel is valid or not. All kernel-mode pointers are trusted and there is no need to validate them – that is also the reason, why an invalid kernel memory access results in a BSOD and not a SEH exception. Simply, invalid kernel memory access is, unlike a user-mode memory access, a fatal error and should never occur in properly written drivers.
Structures with pointers
All we discussed so far were single-pointer structures. However, some Native API functions require complex structures with additional pointers in them as parameters. See the following example of a hook handler for NtQueryValueKey:
NTSTATUS HookNtQueryValueKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ValueName,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,OUT PVOID KeyValueInformation,
IN ULONG KeyValueInformationLength,OUT PULONG ResultLength)
{
if (_wcsicmp(ValueName->Buffer,L"ProtectedValue")==0)
return STATUS_ACCESS_DENIED;
...
}
Example 5: No validation for a PUNICODE_STRING parameter.
One of NtQueryValueKey function's parameters is a pointer to a UNICODE_STRING structure, which consist of three values: Length, MaximumLength and another pointer to an array of WCHARs. The code sample in Example 5 implements no parameter checking, so we know already that this is wrong.
If a function with a UNICODE_STRING is to be hooked properly, the hook handler must check the validity of the pointer to the Unicode string, before accessing the member values of this structure. Then the pointer to the array of wide characters must be validated. See the following example, which shows a correctly performed validity check:
NTSTATUS HookNtQueryValueKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ValueName,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,OUT PVOID KeyValueInformation,
IN ULONG KeyValueInformationLength,OUT PULONG ResultLength)
{
UNICODE_STRING name;
WCHAR *buffer=NULL;
try
{
if (KeGetPreviousMode()!=KernelMode)
ProbeForRead(ValueName,sizeof(UNICODE_STRING),1);
RtlCopyMemory(&name,ValueName,sizeof(name));
if (name.Length==wcslen(L"ProtectedValue")*sizeof(WCHAR))
{
if (KeGetPreviousMode()!=KernelMode)
{
ProbeForRead(name.Buffer,name.Length,1);
buffer=(WCHAR*)ExAllocatePoolWithTag(NonPagedPool,name.Length,TAG);
if (!buffer) return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(buffer,name.Buffer,name.Length);
} else buffer=name.Buffer;
if (_wcsnicmp(buffer,L"ProtectedValue",name.Length/sizeof(WCHAR))==0)
return STATUS_ACCESS_DENIED;
}
} except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INVALID_PARAMETER;
}
...
}
Example 6: Correct double-pointer structure (UNICODE_STRING) validation.
Note that we have to make a copy of ValueName before we can use its contents. If we did not make a copy and used its contents directly, another thread could change its contents after we checked its Length or after we probed its Buffer.
There are some other structures with additional pointers that appear as parameters in some Native API functions. All these pointers must be checked before they are dereferenced. See the following example, which checks the validity of a POBJECT_ATTRIBUTES parameter, which contains a pointer to a UNICODE_STRING structure. Therefore, a triple pointer check must be performed:
NTSTATUS HookNtCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,
IN ULONG CreateDisposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength)
{
UNICODE_STRING name;
WCHAR *buffer=NULL;
try
{
if (KeGetPreviousMode()!=KernelMode)
ProbeForRead(ObjectAttributes,sizeof(OBJECT_ATTRIBUTES),1);
PUNICODE_STRING ObjectName=ObjectAttributes->ObjectName;
if (KeGetPreviousMode()!=KernelMode)
ProbeForRead(ObjectName,sizeof(UNICODE_STRING),1);
RtlCopyMemory(&name,ObjectName,sizeof(name));
if (name.Length==wcslen(L"ProtectedValue")*sizeof(WCHAR))
{
if (KeGetPreviousMode()!=KernelMode)
{
ProbeForRead(name.Buffer,name.Length,1);
buffer=(WCHAR*)ExAllocatePoolWithTag(NonPagedPool,name.Length,TAG);
if (!buffer) return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(buffer,name.Buffer,name.Length);
} else buffer=name.Buffer;
if (_wcsnicmp(buffer,L"ProtectedValue",name.Length/sizeof(WCHAR))==0)
return STATUS_ACCESS_DENIED;
}
} except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INVALID_PARAMETER;
}
...
}
Example 7: Correct triple-pointer structure (OBJECT_ATTRIBUTES) validation.
Other issues and exploitability
Even more necessary is to perform validation checks on output parameters. If a hook handler writes to the memory through a user-mode supplied pointer (which again might be wrapped in a structure), it must check that the whole write memory area is valid for writing, for example using ProbeForWrite. It will similarly produce an exception, if some part of the memory is not writable.
Note that there also is a possibility of invalidating a memory during the processing of the hook handler. Therefore, even if a user-mode memory address is validated, a driver still cannot consider it safe to read/write. The memory can be invalidated at any time, so every consequent read or write attempt must be enclosed in a try/except block.
If a driver communicates with user-mode using Windows I/O or any other mechanism, all user-mode addresses must be validated in exactly the same way (ProbeForRead and/or ProbeForWrite) as stated before. If the application logic treats such address as a structure with additional pointers, all of these must be checked too. Especially, this validation must be performed on user buffers supplied through METHOD_NEITHER I/O.
Generally, there is no common pattern for exploiting these bugs. An invalid memory read will only produce a BSOD. However, some special cases of missing ProbeForWrite validation can certainly be exploited and may lead to a privilege escalation or even a local root exploit. For example, a missing parameter validation on an OUT PHANDLE argument may, in some cases, be exploited to bypass system's security checks or modify kernel objects. The outcoming value of a newly opened handle can be predicted and if we set this parameter to point somewhere in the kernel, for example inside the kernel structures or a carefully selected address inside kernel code, we can alter the code flow and bypass access checks.
Since Windows XP, a memory write protection is keeping any driver from altering the kernel code, which effectively blocks these kinds of exploits. However, we can still overwrite any part of the kernel stack or kernel objects (for example modify current EPROCESS structure to gain privileges). In general, in case of incorrect OUT parameter validation implementation, we may have arbitrary kernel mode write possibility, which is usually enough to take over the whole machine.
About BSODhook utility
We have developed a tool codenamed BSODhook that helps finding improper validation bugs in drivers that implement (not only) SSDT hooks. BSODhook (aka Kernel hooks probing tool) calls native functions with both valid and invalid parameters to produce a system crash (bugcheck). However, this tool comes with a kernel driver, which intercepts certain system functions to catch these bugchecks. Instead of crashing the system, an invalid memory access or other faulty behaviour that invoke the bugcheck will be caught, the calling thread will be terminated and the application will report that the tested API function is improperly validated. Moreover, BSODhook writes out the exact parameters of the function call that caused the crash. This allows vendors to find bugs in their drivers very quickly and efficiently.
In the second version, we have added support for SSDT GDI functions. We have also created a separate BSODhook web page and moved the information about this tool there.
You can download BSODhook right now and start probing. If you find some bugs in a software you use, which is not listed below, or if your Windows 2000 or XP kernel is not supported, please contact us. If your kernel is not supported, be sure to include a full information about your kernel version. If you are a vendor of a software that implements SSDT hooks and our tool helped you to improve it, we will be very glad if you tell us about it. Everyone is allowed to use BSODhook freely as is. There is no warranty or support for this product, but we will be glad to receive the feedback. There are also number of ways how to improve BSODhook itself, if you are an experienced Windows coder interested in doing so, feel free to contact us too.
Research results
Many personal firewalls use kernel-mode hooks to enforce their security measures. We began testing individual firewall distributions for these kind of vulnerabilities in spring 2006, when the first predecessor of BSODhook was implemented. During the first phase of testing, every single personal firewall that implemented SSDT hooks had at least one function vulnerable to the described bug of improper parameter validation. 100% of tested personal firewalls that implement SSDT hooks do or did suffer from this vulnerability!
After we released several advisories describing these vulnerabilities for 7 personal firewalls during 2006 and 2007, only Comodo and Sunbelt fixed their software products and remain not vulnerable to this bug. In some of tested software the problem has been fixed and reintroduced later again. We performed additional and updated testing of several types of software products that are using SSDT hooks for various reasons.
The following table shows individual vulnerable functions in the tested personal firewalls and similar software. Note that if BSODhook does not mark the function as vulnerable it does not mean it is implemented correctly.
| Product and version | Hooked SSDT functions, vulnerable functions are in red |
|---|---|
| BlackICE PC Protection 3.6.cqn see advisory published on September 01, 2006 |
NtCreateSection, NtOpenSection |
| Comodo Personal Firewall 2.4.18.184 old version was vulnerable, see advisory published on February 01, 2007 |
NtConnectPort, NtCreateFile, NtCreatePort, NtCreateSection, NtCreateThread, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtOpenProcess, NtOpenSection, NtOpenThread, NtSetInformationFile, NtSetValueKey, NtShutdownSystem, NtTerminateProcess, NtWriteFile, NtWriteFileGather |
| G DATA InternetSecurity 2007 | NtClose, NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtOpenKey, NtOpenProcess, NtSetValueKey |
| Ghost Security Suite beta 1.110 | NtCreateKey, NtCreateSymbolicLinkObject, NtCreateThread, NtDeleteKey, NtDeleteValueKey, NtDeviceIoControlFile, NtEnumerateKey, NtEnumerateValueKey, NtOpenSection, NtProtectVirtualMemory, NtQueryKey, NtQueryValueKey, NtSetContextThread, NtSetSystemInformation, NtSetValueKey, NtSuspendProcess, NtSuspendThread, NtTerminateProcess, NtTerminateThread, NtWriteVirtualMemory |
| Ghost Security Suite alpha 1.200 alpha version lent for testing after reporting vulnerabilities in version 1.110 |
NtCreateKey, NtCreateSymbolicLinkObject, NtCreateThread, NtDeleteKey, NtDeleteValueKey, NtOpenSection, NtProtectVirtualMemory, NtSetContextThread, NtSetSystemInformation, NtSetValueKey, NtSuspendProcess, NtSuspendThread, NtTerminateProcess, NtTerminateThread, NtWriteVirtualMemory |
| Kaspersky Internet Security 7.0.0.125 partially fixed, see advisory published on June 15, 2007, NtLoadDriver does not cause BSOD but it can be used to DoS KIS service avp.exe |
NtClose, NtCreateKey, NtCreateProcess, NtCreateProcessEx, NtCreateSection, NtCreateSymbolicLinkObject, NtCreateThread, NtDeleteKey, NtDeleteValueKey, NtDuplicateObject, NtEnumerateKey, NtEnumerateValueKey, NtFlushKey, NtInitializeRegistry, NtLoadDriver, NtLoadKey, NtLoadKey2, NtNotifyChangeKey, NtOpenFile, NtOpenKey, NtOpenProcess, NtOpenSection, NtQueryKey, NtQueryMultipleValueKey, NtQuerySystemInformation, NtQueryValueKey, NtReplaceKey, NtRestoreKey, NtResumeThread, NtSaveKey, NtSetContextThread, NtSetInformationFile, NtSetInformationKey, NtSetSecurityObject, NtSetValueKey, NtSuspendThread, NtSystemDebugControl, NtTerminateProcess, NtUnloadKey, NtWriteVirtualMemory |
| Norton Internet Security 2008 15.0.0.60 vulnerable since 2006, see advisory published on April 01, 2007 |
NtAlertResumeThread, NtAlertThread, NtAllocateVirtualMemory, NtConnectPort, NtCreateKey, NtCreateMutant, NtCreateThread, NtDebugActiveProcess, NtDeleteKey, NtDeleteValueKey, NtFreeVirtualMemory, NtImpersonateAnonymousToken, NtImpersonateThread, NtMapViewOfSection, NtOpenEvent, NtOpenProcessToken, NtOpenSection, NtOpenThreadToken, NtResumeThread, NtSetContextThread, NtSetInformationProcess, NtSetInformationThread, NtSetValueKey, NtSuspendProcess, NtSuspendThread, NtTerminateProcess, NtTerminateThread, NtUnmapViewOfSection, NtWriteVirtualMemory |
| Online Armor Personal Firewall 2.0.1.215 the vendor supposedly fixed the vulnerabilities immediately, the latest version is said to have these bugs fixed |
NtAllocateVirtualMemory, NtAssignProcessToJobObject, NtConnectPort, NtCreateFile, NtCreateKey, NtCreatePort, NtCreateProcess, NtCreateProcessEx, NtCreateSection, NtCreateThread, NtDebugActiveProcess, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtEnumerateKey, NtEnumerateValueKey, NtLoadKey, NtOpenFile, NtOpenKey, NtOpenProcess, NtOpenSection, NtOpenThread, NtProtectVirtualMemory, NtQueryKey, NtQueryValueKey, NtReadFile, NtReplaceKey, NtRequestWaitReplyPort, NtRestoreKey, NtResumeThread, NtSaveKey, NtSetContextThread, NtSetInformationFile, NtSetValueKey, NtSuspendProcess, NtSuspendThread, NtSystemDebugControl, NtTerminateProcess, NtTerminateThread, NtWriteFile, NtWriteVirtualMemory |
| Outpost Firewall Pro 4.0.1025.7828 old version was vulnerable, see advisory published on November 15, 2006, later version was fixed, but the bugs were reintroduced, the vendor declared version 5.x to be fixed |
NtAssignProcessToJobObject, NtClose, NtConnectPort, NtCreateFile, NtCreateKey, NtCreateProcess, NtCreateProcessEx, NtCreateSection, NtCreateSymbolicLinkObject, NtCreateThread, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtLoadDriver, NtMakeTemporaryObject, NtOpenFile, NtOpenKey, NtOpenProcess, NtOpenSection, NtOpenThread, NtProtectVirtualMemory, NtQueryDirectoryFile, NtQueryKey, NtQueryValueKey, NtReplaceKey, NtRestoreKey, NtSaveKey, NtSaveKeyEx, NtSecureConnectPort, NtSetContextThread, NtSetInformationFile, NtSetValueKey, NtTerminateProcess, NtTerminateThread, NtUnloadDriver, NtWriteVirtualMemory |
| Privatefirewall 5.0.14.2 the vendor expessed that the bugs will be fixed in upcoming version 6.x |
NtCreateFile, NtCreateKey, NtCreateThread, NtOpenFile, NtOpenKey, NtOpenProcess, NtOpenSection, NtOpenThread, NtSetValueKey, NtTerminateProcess |
| ProcessGuard 3.410 | NtCreateFile, NtCreateKey, NtCreateThread, NtDeleteKey, NtDeleteValueKey, NtFsControlFile, NtOpenFile, NtOpenKey, NtOpenSection, NtProtectVirtualMemory, NtReadVirtualMemory, NtRequestWaitReplyPort, NtSetContextThread, NtSetSystemInformation, NtSetValueKey, NtSuspendProcess, NtSuspendThread, NtTerminateProcess, NtTerminateThread, NtWriteVirtualMemory |
| ProSecurity 1.40 Beta 2 the vendor promised to fix the vulnerabilities as soon as possible |
NtClose, NtCreateFile, NtCreateKey, NtCreateSection, NtCreateThread, NtDebugActiveProcess, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtFsControlFile, NtLoadDriver, NtOpenFile, NtOpenSection, NtProtectVirtualMemory, NtQueueApcThread, NtReadFile, NtReadFileScatter, NtReadVirtualMemory, NtRequestWaitReplyPort, NtRestoreKey, NtResumeThread, NtSetContextThread, NtSetInformationFile, NtSetSecurityObject, NtSetSystemInformation, NtSetSystemPowerState, NtSetSystemTime, NtSetValueKey, NtShutdownSystem, NtSuspendProcess, NtSuspendThread, NtSystemDebugControl, NtTerminateJobObject, NtTerminateProcess, NtTerminateThread, NtWriteFile, NtWriteFileGather, NtWriteVirtualMemory |
| Sunbelt Personal Firewall 4.5.916.0 old version was vulnerable, see advisory published on October 01, 2006 |
NtClose, NtCreateFile, NtCreateKey, NtCreateProcess, NtCreateProcessEx, NtCreateThread, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtLoadDriver, NtMapViewOfSection, NtOpenFile, NtOpenKey, NtResumeThread, NtSetInformationFile, NtSetValueKey, NtWriteFile |
| ZoneAlarm Pro 7.0.362.000 old version was vulnerable, see advisory published on April 15, 2007, the vendor fixed the bugs, but later they were reintroduced |
NtConnectPort, NtCreateFile, NtCreateKey, NtCreatePort, NtCreateProcess, NtCreateProcessEx, NtCreateSection, NtCreateWaitablePort, NtDeleteFile, NtDeleteKey, NtDeleteValueKey, NtDuplicateObject, NtLoadDriver, NtLoadKey, NtMapViewOfSection, NtOpenFile, NtOpenProcess, NtOpenThread, NtRenameKey, NtReplaceKey, NtRequestWaitReplyPort, NtRestoreKey, NtSecureConnectPort, NtSetInformationFile, NtSetSystemInformation, NtSetValueKey, NtTerminateProcess, NtUnloadDriver |
The following table shows individual vulnerable functions for other tested (not personal firewall) software.
| Product and version | Hooked SSDT functions, vulnerable functions are in red |
|---|---|
| Daemon Tools Lite 4.10 X86 unofficial winner of our tests |
NtCreateKey, NtEnumerateKey, NtEnumerateValueKey, NtOpenKey, NtQueryKey, NtQueryValueKey, NtSetValueKey |
| Process Monitor 1.22 | NtClose, NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtEnumerateKey, NtEnumerateValueKey, NtFlushKey, NtLoadKey, NtOpenKey, NtQueryKey, NtQueryValueKey, NtSetValueKey, NtUnloadKey |
| RegMon 7.04 | NtClose, NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtEnumerateKey, NtEnumerateValueKey, NtFlushKey, NtLoadKey, NtOpenKey, NtQueryKey, NtQueryValueKey, NtSetValueKey, NtUnloadKey |
The following table is dedicated to vulnerabilities found by readers of this article using our BSODhook utility. We thank them for the reports and feedback we have received. The following results were not verified.
| Product and version | Hooked SSDT functions, vulnerable functions are in red |
|---|---|
| AntiHook 2.6 | NtCreateProcess, NtCreateSection, NtCreateThread, NtOpenThread, NtResumeThread, NtSetContextThread, NtSetValueKey, NtSuspendThread, NtTerminateProcess, NtWriteVirtualMemory |
| avast! Professional 4.7 the vendor noted that avast! hooks SSDT functions on Windows NT4 and 2000 only |
NtClose, NtCreateDirectoryObject, NtCreateFile, NtCreateProcess, NtCreateSection, NtOpenFile, NtSetInformationFile, NtWriteFile |
| Avira AntiVir Personal Edition (Premium) 7 | NtCreateThread, NtOpenProcess, NtOpenThread, NtTerminateProcess, NtWriteVirtualMemory |
| Core Force HIPS 0.95 | NtClose, NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtEnumerateKey, NtEnumerateValueKey, NtLoadKey, NtOpenKey, NtQueryKey, NtQueryValueKey, NtSetValueKey, NtUnloadKey |
| Dynamic Security Agent 1.0.8.8 | NtCreateFile, NtCreateKey, NtopenFile, NtOpenKey, NtOpenProcess, NtOpenSection, NtOpenThread, NtSetValueKey |
| Panda Internet Security 2008 | NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtEnumerateKey, NtEnumerateValueKey, NtQueryKey, NtQueryValueKey, NtSetValueKey, NtTerminateProcess, NtTerminateThread |
| PC Tools ThreatFire 3.0 | NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtOpenKey, NtSetValueKey, NtTerminateProcess |
| Sygate Personal Firewall Pro 5.6 build 2818 | NtAllocateVirtualMemory, NtCreateThread, NtMapViewOfSection, NtProtectVirtualMemory, NtShutdownSystem, NtTerminateProcess, NtWriteVirtualMemory |
| Symantec Client Firewall 8.7.4.97 | NtDeleteValueKey, NtSetValueKey |
| Trend Micro Internet Security 2007 | NtClose, NtConnectPort, NtCreateProcess, NtOpenProcess, NtRequestWaitReplyPort, NtWriteVirtualMemory |
| VirusBlokAda Vba32 3.12.2 | NtCreateThread, NtOpenProcess, NtOpenThread, NtTerminateProcess |
After seeing these results, one could say that having security software installed makes your machine unstable and more vulnerable than without it – sad, but at least a little bit true. You can see software products from Check Point, Kaspersky, Symantec, and even Sysinternals (or Microsoft if you consider that they acquired Sysinternals some time ago) are vulnerable! On the other side Daemon Tools shows us that it is possible to have SSDT hooks implemented without such basic mistakes.
Conclusion
Almost every software that implements SSDT hooks is vulnerable to the bug we introduce in this article. BlackICE PC Protection, G DATA InternetSecurity, Ghost Security Suite, Kaspersky Internet Security, Norton Internet Security, Online Armor Personal Firewall, Outpost Firewall Pro, Privatefirewall, ProcessGuard, ProSecurity, ZoneAlarm Pro, Process Monitor, RegMon are just a few examples of badly written, not properly tested, vulnerable software. There were only two personal firewalls that passed our argument validation testing successfully, Comodo Personal Firewall and Sunbelt Personal Firewall. Our tests revealed, that the current versions of these products are probably not vulnerable, but earlier versions of both these personal firewalls contained the bug and they were both fixed after our notifications to their vendors. So in fact, the only product that passed the tests was Daemon Tools.
We also found many articles, tutorials and papers that described either SSDT hooking or other driver code and contained improper parameter validation. Even more disturbing is that these bugs are present in professional software products and also in official Sysinternals (Microsoft) tools – Process Monitor and RegMon. Even Mark Russinovich and Bryce Cogswell, the authors of these tools and two of the most famous Windows kernel hackers, seem to have forgotten about validation in their tools. Process Monitor and RegMon have been vulnerable for ages.
We advise all vendors of affected products to download and use our tool and/or contact us
and order our software testing services.