Bypassing ServerLock protection on Windows 2000

From: Jan Rutkowski (jkrutkowskiat_private)
Date: Thu Jul 17 2003 - 15:24:41 PDT

  • Next message: Cisco Systems Product Security Incident Response Team: "Cisco Security Advisory: Cisco IOS Interface Blocked by IPv4 Packet"

    		   Bypassing ServerLock protection on
    			     Windows 2000
    
    			   Jan K. Rutkowski
    		     <jkrutkowskiat_private>
    
    
    1. Background
    
    ServerLock for Windows 2000 is product of Watch Guard company. The
    purpose of this tool is to protect integrity of the operating system
    by ensuring that nobody can modify certain files (like DLLs or
    drivers), some registry keys and load unknown drivers.
    
    Watch Guard homepage: http://www.watchguard.com.
    
    There are two bugs in the recent version of Server Lock for Windows
    2000 which can be exploited to completely bypass its protection.
    
    2. Bug #1 - loading arbitrary modules (using Runtime Process Infection)
    
    2.1. Basics
    
    It is possible to circumvent ServerLock protection, so that attacker
    can load arbitrary module into kernel. Normally such action is
    restricted by ServerLock, because:
    
    a) it is not possible to create keys under
    HKLM\System\CurrentControlSet\Services, so official Windows 2000
    mechanism to load drivers cannot be used (SCM and ZwLoadDriver() which
    is used by SCM, require that each driver has a dedicated subkey under
    the 'services' key in the registry).
    
    b) it is not possible to replace a 'legal' driver (files form
    \Winnt\System32\drivers directory), because ServerLock protects these
    files from write access.
    
    c) there exists undocumented function: ZwSetSystemInformation(), which
    can be used to load driver, and this function doesn't require any keys
    in the registry. ServerLock protects these function, so that only
    'trusted' programs can use it.
    
    The method of attack, presented below, assumes ServerLock 2.0.1 for
    Windows 2000. Prior versions have not been tested, but it is likely
    that they are also vulnerable.
    
    2.2. DLL injection
    
    First of all, we should explain what 'trusted' program means. Every
    EXE file, which is guarded (i.e. modification is not allowed) by
    ServerLock is considered 'trusted'. The reason for this, is that
    attacker cannot change the trusted program's code.
    
    However this is not true, when we are considering running process.
    Attacker can open process object by means of OpenProcess() function,
    and then can use for example CreateRemoteThread() in order to inject
    DLL library of his choice into the target process address space. This
    is called 'DLL injection' and has been researched years ago, and can
    look like this (simplified):
    
    CreateRemoteThread (
    	hTargetProc,
    	...
    	addr_of_LoadLibrary,
    	addr_of_"bad.dll"_in_target_process,
    	...
    	);
    
    Of course before that, one must ensure that "bad.dll" string is
    present in the target process address space. This can be done by means
    of VirtualAllocEx() and WriteProcessMemory() functions.
    
    As we all know, just after DLL is loaded into the process memory,
    DLL's entry point, usually called DllMain, is executed.
    
    We see, that attacker, with proper privileges, can supply arbitrary
    instructions to 'trusted' process and these instructions will be
    executed. It should be noted that DLL injection is not the only
    technique to achieve this runtime process infection, but is the
    simplest one. Other techniques do not requires creation of additional
    file ("bad.dll") in the filesystem (which is not very stealthy).
    
    2.3. Calling ZwSetSystemInformation()
    
    Assuming that attacker's rootkit resides in file rootkit.sys, we can
    copy this file into \WINNT\system32\drivers\ directory as a
    rootkit.abc for example. ServerLock forbids creation only files with
    some known extensions like .sys, but for ZwSetSystemInformation()
    function extension doesn't matter.
    
    Using DLL injection technique (described above) we can force any
    'trusted' process to execute ZwSetSystemInformation()
    (SystemLoadAndCallImage class), thus allowing attacker to load his
    rootkit.abc module into kernel.
    
    2.4. Other usage of OpenProcess()
    
    Despite exploiting ZwSetSystemInfomration(), OpenProcess() function
    can be used to do API hooking in other processes. This future is used
    by some recently popular Windows usermode rootkis, like hxdef. It
    would be a good idea to restrict OpenProcess() then.
    
    3. Bug #2 - improper handling of symlinks to \Device\PhysicalMemory
    
    Server Lock is trying to restrict access to \Device\PhysicalMemory to
    disallow accessing kernel memory. However it is possible to create
    some symlinks to this object and then, open this device via symlink.
    
    The following output demonstrates just few possibilities:
    
    C:\>funWithLinks.exe
    creating link: \hak1 --> \Device
    creating link: \hak2 --> \Device\PhysicalMemory
    creating link: \hak3 --> \
    creating link: \hak4 -->  [failed]
    creating link: \Device\hak5 --> \Device
    creating link: \Device\hak6 --> \??\GLOBALROOT
    
    trying to open for READ|WRITE:
    opening \Device\PhysicalMemory ... [failed]
    opening \hak1\PhysicalMemory ... [it worked!]
    opening \hak2 ... [it worked!]
    opening \Device\hak5\PhysicalMemory ... [it worked!]
    opening \Device\hak5\hak5\PhysicalMemory ... [it worked!]
    opening \??\GLOBALROOT\Device\PhysicalMemory ... [it worked!]
    opening \Device\hak6\hak1\PhysicalMemory ... [it worked!]
    
    It should be obvious that having possibility to open
    \Device\PhysicalMemory for writing we can do whatever we want with the
    system, like loading some rootkits and backdoors. It means complete
    system compromise. Although this is not trivial, since we must
    translate linear addresses to physical, proof-of-concept codes can be
    found on the net.
    
    4. Vendor response
    
    17.02.2003:	bug 1 has been reported to Watch Guard
    10.03.2003:	bug 2 has been reported to Watch Guard
    28.03.2003:	SL 2.0.3 has been released which fixed bug #1
    02.07.2003:	SL 2.0.4 has been released which fixed bug #2
    
    SL 2.0.3 does not restrict OpenProcess(), but SL 2.0.4 does, which
    should stop Runtime Process Infection efforts.
    
    5. Epilog
    
    These bugs have been fixed and a patch made available to all current
    subscribers on vendor's LiveSecurity Web site at:
    https://www.watchguard.com/archive/softwarecenter.asp
    
    Watch Guard refused to provide details about how they fixed the bugs.
    



    This archive was generated by hypermail 2b30 : Thu Jul 17 2003 - 15:34:05 PDT