One particularly annoying occurance that’s happened to me on a couple of occasions is losing the password to a long-forgotten test VM that I need to thaw for some reason or another, months from the last time I used it. (If you follow good password practices and use differing passwords for accounts, you might find yourself in this position.)
Normally, you’re kind of sunk if you’re in this position, which is the whole idea – no administrator password is no administrative access to the box, right?
The officially supported solution in this case, assuming you don’t have a password reset disk (does anyone actually use those?) is to reformat. Oh, what fun that is, especially if you just need to grab something off of a test system and be done with it in a few minutes.
Well, with physical access (or the equivalent if the box is a VM), you can do a bit better with the kernel debugger. It’s a bit embarassing having to “hack” (and I use that term very loosely) into your own VM because you don’t remember which throwaway password you used 6 months ago, but it beats waiting around for a reformat (and in the case of a throwaway test VM, it’s probably not worth the effort anyway compared to cloning a new one, unless there was something important on the drive).
(Note that as far as security models go, I don’t really think that this is a whole lot of a security risk. After all, to use the kernel debugger, you need physical access to the system, and if you have that much, you could always just use a boot CD, swap out hard drives, or a thousand other different things. This is just more convenient if you’ve got a serial cable and a second box with a serial port, say a laptop, and you just want to reset the password for an account on an existing install.)
This is, however, perhaps an instructive reminder in how much access the kernel debugger gives you over a system – namely, the ability to do whatever you want, like bypass password authentication.
The basic idea behind this trick is to use the debugger to disable the password cheeck used at interactive logon inside LSA.
The first step is to locate the LSA process. The typical way to do this is to use the !process 0 0 command and look for a process name of LSASS.exe. The next step requires that we know the EPROCESS value for LSA, hence the enumeration. For instance:
kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS fffffa80006540d0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00124000 ObjectTable: fffff88000000080 HandleCount: 545. Image: System [...] PROCESS fffffa8001a893a0 SessionId: 0 Cid: 025c Peb: 7fffffda000 ParentCid: 01ec DirBase: 0cf3e000 ObjectTable: fffff88001b99d90 HandleCount: 822. Image: lsass.exe
Now that we’ve got the LSASS EPROCESS value, the next step is to switch to it as the active process. This is necessary as we’re going to need to set a conditional breakpoint in the context of LSA’s address space. For this task, we’ll use the .process /p /r eprocess-pointer command, which changes the debugger’s process context and reloads user mode symbols.
kd> .process /p /r fffffa8001a893a0 Implicit process is now fffffa80`01a893a0 .cache forcedecodeuser done Loading User Symbols .....
Next, we set up a breakpoint on a particular internal LSA function that is used to determine whether a given password is accepted for a local account logon. The breakpoint changes the function to always return TRUE, such that all local account logons will succeed if they get to the point of a password check. After that, execution is resumed.
kd> ba e1 msv1_0!MsvpPasswordValidate "g @$ra ; r @al = 1 ; g" kd> g
We can dissect this breakpoint to understand better just what it is doing:
- Set a break on execute hardware breakpoint on msv1_0!MsvpPasswordValidate. Why did I use a hardware breakpoint? Well, they’re generally more reliable when doing user mode breakpoints from the kernel debugger, especially if what you’re setting a breakpoint on might be paged out. (Normal breakpoints require overwriting an instruction with an “int 3”, whereas a hardware breakpoint simply programs an address into the processor such that it’ll trap if that address is accessed for read/write/execute, depending on the breakpoint type.)
- The breakpoint has a condition (or command) attached to it. Specifically, this command runs the target until it returns from the current function (“g @$ra” continues the target until the return address is hit. @$ra is a special platform-independent psueod-register that refers to the return address of the ccurrent function.) Once the function has returned, the al register is set to 1 and execution is resumed. This function returns a BOOLEAN value (in other words an 8-bit value), which is stored in al (the low 8 bits of the eax or rax register, depending on whether you’re on x86 or x64). IA64 targets don’t store return values in this fashion and so the breakpoint is x86/x64-specific.
Now, log on to the console. Make sure to use a local account and not a domain account, so the authentication is processed by the Msv1_0 package. Also, non-console logons might not run through the Msv1_0 package, and may not be affected. (For example, Network Level Authentication (NLA) for RDP in Vista/Srv08 doesn’t seem to use Msv1_0, even for local accounts. The console will still allow you to log in, however.)
From there, you can simply reset the password for your account via the Computer Management console. Be warned that this will wipe out EFS keys and the like, however. To restore password checking to normal, either reboot the box without the kernel debugger, or use the bc* command to disable the breakpoint you set.
(For the record, I can’t really take credit for coming up with this trick, but it’s certainly one I’ve found handy in a number of scenarios.)
Now, one thing that you might take away from this article, from a security standpoint, is that it is important to provide physical security for critical computers. To be honest, if someone really wants to access a box they have physical access to, this is probably not even the easist way; it would be simplere to just pop in a bootable CD or floppy and load a different operating system. As a result, as previously mentioned, I wouldn’t exactly consider this a security hole as it already requires you to have physical access in order to be effective. It is, however, a handy way to reset passwords for your own computers or VMs in a pinch if you happen to know a little bit about the debugger. Conversely, it’s not really a supported “solution” (more of a giant hack at best), so use it with care (and don’t expect PSS to bail you out if you break something by poking around in the kernel debugger). It may break without warning on future OS versions (and there are many cases that won’t be caught by this trick, such as domain accounts that use the Kerberos provider to process authentication).
Update: I forgot to mention the very important fact that you can turn on the kernel debugger from the “F8” boot menu when booting the system, even if you don’t have kernel debugging enabled in the boot configuration or boot.ini. This will enable kernel debugging on the highest numbered COM port, at 19200bps. (On Windows Vista, this also seems capable of auto-selecting 1394 if your machine had a 1394 port, if memory serves. I don’t know offhand whether that translates to downlevel platforms, though.)