Friday, April 8, 2011

Bypassing XP Logon - without resetting any passwords (read Stealth)

The idea is to use kernel debugger in order to modify routine msv1_0!MsvpPasswordValidate in such a way it always returns TRUE, even for an incorrect password. I was impressed by the simplicity of the idea and decided to implement it using bootable CD instead of debugger. A great compilation of information on bootable CD is eEye's BootRoot [2]. Another inspirational material is [3].

Theory of operation:

Flow of execution
0. hic sum leones (DRAM initialization, POST, etc.) - see [4]
1. boot from CD:
        CD code hooks int 15h and copies itself to RAM
        CD code boots NTLDR from HDD
2. boot from HDD
        NTLDR is running
        NTLDR calls int 15h
        int 15h hooked handler patches NTDLR with 32 bit stager
        NTLDR is running
        32 bit stager is called
        32 bit stager calls payload
        payload hooks IoCreateDriver
        NTLDR is running
        IoCreateDriver is called, hook registers custom callback
            using PsSetLoadImageNotifyRoutine
        PspLoadImageNotifyRoutine notifies us about images being loaded
        if the image name is msv1_0.dll, hook (IAT style) RtlCompareMemory
3.  Windows logon dialog appears and arbitrary password is accepted
        for every account


  1.     int 15h is used instead of usual int 13h used in BootRoot and its clones
  2.     int 15h was found to be viable by using custom interrupt PCI-ROM based sniffer and leads to more compact code
  3.     msv1_0!MsvpPasswordValidate is not hooked, because it's not exported
  4.     password is validated also in ADVAPI32!SystemFunction031
  5.     both functions mentioned above call RtlCompareMemory, which is exported
  6.     RtlCompareMemory is modified in such a way it returns 0 (true) for all the blocks of length of password hash
  7.     it's dirty hack, it's not intended for production use :)

So, how does it work? When you enter password, Windows computes hash of the password and compares it with stored hash of the correct password. But the comparison routine was modified, so it returns true for any two hashes, i.e. for any password you enter.
Using the Code

This tool was designed for CD ISO and Windows XP x86. Feel free to try it with USB flash disk or modify it for new Windows.

    Burn the ISO on CD.
    Boot Windows XP machine from the CD.
    When logon dialog appears, enter required username (e.g. Administrator, SUPPORT_388945a0, etc.) and press enter.
    If everything worked out correctly, you're now logged in.

For building the project from source, you need FASM.exe and Microsoft CDIMAGE.exe.

fasm boot.asm bootkit.rom && cdimage -bbootkit.rom C:\bootkit\root\ C:\bootkit.iso

Assume that C:\bootkit\root is an arbitrary non-empty folder that will be the root of a newly created ISO image which will be written to C:\bootkit.iso.


code project site
Bootkit Source Code


To test the bootkit, you can setup XP in VMWare to boot from C:\bootkit.iso
(don't forget to change boot device in VMWare BIOS to CD). If you want
to see what's going on during the logon process, you can attach windbg.

  1. Grab your free copy of Debugging Tools for Windows from Microsoft and install it.
  2. Edit VMWare machine settings: Add Serial port, 'Output to named
    pipe', 'This end is the server.', 'The other end is application', finish
    and check 'Yield CPU on poll'.
  3. Start XP in VMWare and edit boot.ini using msconfig (add option /DEBUG with COM1 and fastest baudrate). Turn off XP.
  4. Start XP again and run windbg using a shortcut like this one:

    "C:\Program Files\Debugging Tools for Windows 
    (x86)\windbg.exe" -y srv*c:\windows\symbols* -b -k com:pipe,

    If you're successful, you'll see:

    Microsoft (R) Windows Debugger Version 6.9.0003.113 X86
    Copyright (c) Microsoft Corporation. All rights reserved.

    Opened \\.\pipe\com_1
    Waiting to reconnect...
    Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
    Kernel Debugger connection established. (Initial Breakpoint requested)
    Symbol search path is: srv*c:\windows\symbols*;SRV**
    Executable search path is:
    Windows XP Kernel Version 2600 UP Free x86 compatible
    Built by: 2600.xpsp_sp2_rtm.040803-2158
    Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055ab20
    System Uptime: not available
    Break instruction exception - code 80000003 (first chance)
    * *
    * You are seeing this message because you pressed either *
    * CTRL+C (if you run kd.exe) or, *
    * CTRL+BREAK (if you run WinDBG), *
    * on your debugger machine's keyboard. *
    * *
    * *
    * If you did not intend to break into the debugger, press the "g" key, then *
    * press the "Enter" key now. This message might immediately reappear. If it *
    * does, press "g" and "Enter" again. *
    * *
    804e3b25 cc int 3

  5. Now windbg is attached to windows. Let's see hooked function IoCreateDriver:

    kd> u IoCreateDriver
    805d60e3 b8c3f00980 <span class="code-keyword">mov</span> eax,8009F0C3h <- address of payload.asm/_stager
    805d60e8 ffd0 <span class="code-keyword">call</span> <span class="code-keyword">eax</span> <- <span class="code-keyword">call</span> _stager
    kd> uf 8009F0C3h <- _stager
    8009f0c3 802c2407 <span class="code-keyword">sub</span> <span class="code-keyword">byte</span> <span class="code-keyword">ptr</span> [esp],7
    8009f0c7 <span class="code-digit">60</span> pushad
    8009f0c8 66bb53a3 <span class="code-keyword">mov</span> bx,0A353h
    8009f0cc e80b010000 <span class="code-keyword">call</span> 8009f1dc
    8009f0d1 68ecf00980 <span class="code-keyword">push</span> 8009F0ECh <- address of payload.asm/
    8009f0d6 ffd0 <span class="code-keyword">call</span> <span class="code-keyword">eax</span>
    cleanup hook

    8009F0ECh <- PspLoadImageNotifyRoutine
    - checks if the loaded module is msv1_0.dll
    - if yes, hooks IAT RtlCompareMemory

  6. Module 'msv1_0.dll' is now patched. Enter 'g' and wait till logon screen appears. Then break in (Ctrl+Break).

    kd> !process 0 0 winlogon.exe
    PROCESS 819aaa88 SessionId: 0 Cid: 0274 Peb: 7ffd8000 ParentCid: 01f0
    DirBase: 0a5b2000 ObjectTable: e13d6110 HandleCount: 398.
    Image: winlogon.exe
    kd> .process /p /r 819aaa88
    Implicit process is now 819aaa88
    .cache forcedecodeuser done
    Loading User Symbols

    kd> uf msv1_0!MsvpPasswordValidate <- we want this function to return always TRUE
    77c69927 ?? ???
    ^ Memory access error in
    'u msv1_0!MsvpPasswordValidate l3'
    kd> .pagein msv1_0!MsvpPasswordValidate
    You need to continue execution (press 'g' <enter>) for the pagein to be brought in.
    When the debugger breaks in again, the page will be present.

    kd> g
    Break instruction exception - code 80000003 (first chance)
    804e3b25 cc int 3

    kd> dd msv1_0!_imp__RtlCompareMemory l1 <- this is IAT entry for RtlCompareMemory
    77c610cc 77c60fe5 <- and this is address of our
    new RtlCompareMemory: RtlCompareMemoryPatch

    kd> u 77c60fe5 <- payload.asm/RtlCompareMemoryPatch
    - if size of chunks to compare is 10h (hash size), then return 0 (=TRUE)
    - else call original RtlCompareMemory
    - it's a nasty hack, use different method in production use :)

  7. Now press you can put breakpoint using 'bp msv1_0!MsvpPasswordValidate' (to remove it, type 'bc*') and step through the login process using commands 't' or 'p'. For help, type command '.help command_name'.