COMMAND

    core

SYSTEMS AFFECTED

    Win NT 3.5, 3.51, and 4.0, Standard and Enterprise Editions

PROBLEM

    Following is  based on  L0pht Security  Advisory and  was found by
    dildog.  Microsoft Windows  NT 4.0 implements a  system-wide cache
    of file-mapping objects for the purpose of loading system  dynamic
    link  libraries  (DLLs)  as  quickly  as  possible.   These  cache
    objects, located  in the  system's internal  object namespace, are
    created with permissions such  that the 'Everyone' group  has full
    control over them.   Hence, it is  possible to delete  these cache
    objects and replace them with others that point to different DLLs.
    When  processes  are  created,  the  loader maps/loads the loading
    executable's imported DLLs into the process space.  If there is  a
    DLL cache object available, it  is simply mapped into the  process
    space,  rather  than  going  to  the  disk.   Hence,  there  is an
    exploitable condition, when a low-privilege user replaces a DLL in
    the cache with a trojan DLL, followed by a high-privelege  account
    launching a process.  The high priveleged process will map in  the
    trojan DLL and execute code  on behalf of the low  privelege user.
    This was tested on  Windows NT 4.0 Server  SP4 and Windows NT  4.0
    Workstation SP4.  Other service packs are likely to be vulnerable,
    but the exploit has not been  tested on them, neither has the  fix
    presented below.

    The Windows  NT object  namespace is  the place  where the  kernel
    keeps the names of  mutexes, semaphores, filemapping objects,  and
    other  kernel  objects.  It  is  organized  hierarchically, like a
    directory structure.  Amongst the directories are:

        \Device
        \BaseNamedObjects
        \Driver
        \KnownDlls
        ...

    The NT object  namespace is browsable  with a tool  called 'WinObj
    2.0' from System Internals (http://www.sysinternals.com).  You may
    wish  to  look  around  this  namespace  and  browse  the  default
    permissions of objects.  It is quiet entertaining, really.

    The  "\Knowndlls"  directory  contains  a  list  of  DLLs  in  the
    c:\winnt\system32 directory, like:

        \KnownDlls\COMCTL32.dll
        \KnownDlls\MPR.dll
        \KnownDlls\advapi32.dll
        \KnownDlls\kernel32.dll
        ...

    All of these objects are created at boot time, and are  'permanent
    shared objects'.  Normally, users can not create permanent  shared
    objects  (it's  an  advanced  user  right,  and it is normally not
    assigned  to  any  group,  even  Administrators).   But the system
    preloads this cache for you.  Permanent shared objects differ from
    regular shared objects only in the fact that they have a flag set,
    and an incremented reference count,  such that if you create  one,
    and then terminate  the creating process  or close all  handles to
    the  object,  it  does  not  disappear  from the object space.  To
    exploit the  poor permissions  on this  cache, one  first needs to
    delete  one  of  the  shared  objects  by  name, in order to later
    replace it.  So  we make a call  to the NTDLL.DLL native  function
    "OpenSection()", getting a handle to the object.  Then we call the
    NTOSKRNL.EXE  native   function  "ZwMakeTemporaryObject()"   which
    removes the 'permanent' flag and decrements the reference  counter
    from the  object.   Now we  just call  NTDLL.DLL:NtClose() on  the
    handle  and  it  is  destroyed.   To  create  a section, one calls
    NTDLL.DLL:CreateSection(), which is undocumented.  There are other
    calls one needs to make in order to set up the object and open the
    KnownDlls  directory,  but  they  are  trivial  and  will  not  be
    discussed here.  Feel free to browse the source code presented  at
    the  end  of  this  advisory  to  see  what you need to do though.
    Anyway, you create a section (aka file-mapping) object that points
    to a trojan DLL. A good candidate for DLL trojan is  KERNEL32.DLL,
    since it is loaded by pretty much every executable you're going to
    run.

    Note that any DLL  cache objects you create  as a user can  not be
    'permanent',  hence,  when  you  log  out, the cache object _will_
    disappear.  So how  can we get a  higher privelege process to  run
    while we're logged in?  There are  many ways.  We can wait for  an
    'At' job to go off, or we can  set up the DLL hack as an 'At'  job
    that goes off when someone else  is logged in.  But more  reliable
    is following.   When a  new Windows  NT subsystem  is started,  it
    creates  a  subsystem  process  to  handle various system details.
    Examples  of  these  processes  are  LSASS.EXE and PSXSS.EXE.  The
    PSXSS.EXE is the  POSIX subsystem.   But since no  one ever really
    uses the POSIX subsystem under NT.   So, chances are, it won't  be
    loaded into memory yet.  Once it is, though, it's loaded until the
    machine reboots.  If it  loaded, reboot the machine, and  it won't
    be.   So,  we  launch  our  DLL  cache  hack, and then run a POSIX
    subsystem command,  thus launching  PSXSS.EXE (which  runs as  'NT
    AUTHORITY\SYSTEM', the system account),  and running our DLL  with
    local administrator  privileges.   Incidentally, other  subsystems
    have the same effect, such  as the OS/2 subsystem (the  only other
    one that probably isn't started yet).

    Dildog wrote  up a  trojan to  test exploitability,  and it  was a
    simple  'forwarder'  DLL  that  had  the  same  exported  names as
    KERNEL32.DLL, but a different  'DllMain()' function, to be  called
    when the DLL is loaded.   The function calls in my trojan,  simply
    forward off to  the real KERNEL32.DLL  calls located in  a copy of
    the  kernel  that  you  make  in  'REALKERN.DLL'  in  the  c:\temp
    directory.  To try out this vulnerability, obtain an account as  a
    low-privilege  guest  user  (referred  to  as  'Dick')  and do the
    following:

        1. Log in as Dick at the console,
        2. Start up two "cmd.exe"  shells. Do the following in  one of
           them,
        3. Copy c:\winnt\system32\kernel32.dll to c:\temp\realkern.dll
           (The egg dll is hard coded to use the c:\temp directory  to
           find  this  file.   If  you  can't  put it in c:\temp, then
           modify  the  source  '.def'  file  to  point to a different
           location and recompile eggdll.dll),
        4. Copy the provided hackdll.exe and eggdll.dll to c:\temp,
        5. Ensure that there is no file named c:\lockout. If there is,
           delete it. The exploit uses this file as a lockfile,
        6. Delete the KERNEL32.DLL file-mapping object from the system
           cache:
                  c:\> cd\temp
                  c:\temp> hackdll -d kernel32.dll

        7. Insert the new file-mapping object with:
                  c:\temp> hackdll -a kernel32.dll c:\temp\eggdll.dll
           Don't hit a key in this window after hitting enter,
        8. Now move to the other cmd.exe window that you started,
        9. Run a POSIX subsystem command. A good way to start it is:
                  c:\temp> posix /c calc
           (if you have calculator installed. If not, pick some  other
           program)
       10. Now the EGGDLL.DLL will prompt you with a few message boxes:
           * Say no to the "User is DOMAIN\DICK, Spawn Shell?" box
           * Say no to the "User is \[garbage], Spawn Shell?" box
           * Say YES to the "User is NT AUTHORITY\SYSTEM, Spawn Shell?" box
           * Say YES to the "Winsta0" window station message box
           * Say YES to the "Desktop" window desktop message box
           You will now see a "System Console" command.com shell  open
           up (saying  yes to  the next  'winlogon' box  will give you
           something funny when you log out, btw).
       11. Now go back to your  first cmd.exe window and hit a  key to
           unpoison the DLL cache
       12. In the System Console window, run the User Manager program,
           and  modify  Dick's  account  (or  anyone  else's  for that
           matter) to your hearts content.
                  (NT Server) c:\winnt\system32> usrmgr
                  (NT Workstation) c:\winnt\system32> musrmgr

    Exploit  code   can  be   downloaded  from   L0pht's  website   at
    http://www.l0pht.com/advisories.html.  It is available in compiled
    form, and in pure  source form as two  zipfiles.  The L0pht  patch
    for  this  advisory  is  also  available  in  both source form and
    compiled form from the same URL.

SOLUTION

    Dildog developed a patch for this security problem in the form  of
    a Win32 Service program that can be installed by the Administrator
    of the  system. It  sets itself  to run  every time  the system is
    started,  and  before  the  user  has  the  opportunity to start a
    program,  it  adjusts  the  permissions   of  the  DLL  cache   to
    something much safer.   The source code  for this service  is also
    provided, along with  a compiled version.   Links to the  programs
    can be found at

        http://www.l0pht.com/advisories.html

    Microsoft come up with short term fix too.  Just set:

        HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\ProtectionMode=1

    and reboot.  Long term HF can be obtained depending on platform:

        ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40/hotfixes-postSP4/Smss-fix/Smssfixi.exe
        ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40TSE/hotfixes-postSP3/Smss-fix/Smssfixi.exe
        ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40/hotfixes-postSP4/Smss-fix/Smssfixa.exe
        ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40TSE/hotfixes-postSP3/Smss-fix/Smssfixa.exe