Windows Phone 8 and greater allows the user to lock/unlock the phone by using a numeric PIN code: it's even possible to use a complex alphanumeric password. This post addresses how to obtain the simple numeric PIN code by cracking the authenticator kept in the SOFTWARE hive.
an useless quest?
Actually if you have a physical access to a Windows Phone you don't need the user pincode to examine the user data: with the proper hardware you can usually get a whole dump of the un-encrypted device memory. To my current knowledge the pincode is not used anywhere if not for device locking, so it's almost useless to know it. If the device is under a properly configured MDM, you could face a fully encrypted phone with TPM: in this case you'll have no chance to crack the pincode, even if more testing should be done.
This is exactly what I thought when my colleague Mattia Epifani tried to lure me with the Windows Phone PIN issue: he knows the curious monkey inside me... but I was a reluctant one. He then provided a couple of scenarios where knowing the pincode could be useful: in the end, I traded a couple of beers in return for the pincode cracker.
the starting lead and testbed
Mattia pointed out that the SOFTWARE hive registry key "\Microsoft\Comms\Security\DeviceLock\Object21" was related to the current pincode. This was the start of my travel. I had three physical dumps of three different Windows Phones: two with Windows 8.10 build 341 (label WPB_CXE_R1) and one with Windows 8.00 build 78 (label WP8_CXE_GDR2).
The next figure shows the Object21 registry key content coming from the 1st phone dump.
Indeed the pincode is composed by 5 numbers, but the most attractive value is for sure CredentialHash. In the next figure the bytes blob is reported.
Usually when I face an unknown blob of bytes I tried to figure out, with educated and cautious guesses, if there is a sort of schema: in other words if it represents a structured info. In this case it's quite easy to spot how that blob is organized. The first three DWORDs represent the length of the three following bytes array; the second one is the unicode string SHA256, and the last array has exactly the length of a SHA256 hash. Let me provide a better view of the data.
80 00 00 00 0E 00 00 00 20 00 00 00 87 A6 A5 93
5B 2D 8C 55 51 A1 20 07 50 3E A6 48 EB 63 5E CA
36 9B 4D 5C 65 50 0B 5C 1A 1B E9 34 7B 64 A3 CF
8B E2 A0 45 5E A0 C3 57 FD 3C 91 AE D8 9F 65 9C
CE 02 B1 9E 75 06 C7 50 D1 A7 93 ED 76 04 FA 2E
A4 0A 53 20 1B B1 FD 14 36 C2 2A A9 87 7B C9 BC
C6 7B 7E 34 A1 EB 2F 6B 33 3A 81 51 99 31 B5 3D
6F D2 1B 58 69 38 1F 45 5D E3 4B 51 18 36 27 2E
65 36 3F BB 5B 6A 72 FD F0 D3 38 B7 53 00 48 00
41 00 32 00 35 00 36 00 00 00 3C DA 9F 6D 42 E8
83 50 83 4B B2 5E 20 73 7A 4D 66 78 95 01 D0 5A
5D EA 20 BF 6B B5 53 F6 25 85
a bit of reversing
The question became "who is using that data and how?". Using the simplest approach aka old school effective string searching I got a couple of Windows DLL, SimplePinLap.dll and StrongPinLap.dll, whose names seem self-explanatory. I disclose that I'm really bad with ARM code reversing, but to be short, I spot some truly useful hints inside the SimplePinLap code, by looking for the usual BCryptHashData Win API function.
The 0x80 bytes array is a salt, pseudo-randomly generated. The 0x20 bytes array is the target hash, the one that must match if the inserted pincode is correct. I had some issues in understanding from the assembly how the inserted pin was used in the hashing process, but finally I got the following algorithm (easy, indeed).
HashAlgo(UTF-16-LE-NoTrailing0(pincode) + salt)
a bit of cracking
Finally the pincode seems not stored anywhere inside the system (not considering volatile artifacts): to get user's pincode you need to grab the SOFTWARE hive. If you own such file, you can use my cracking script winphonepincrk.py (link). Just provide it with the hive and all the magic will happen.
With this script I was able to crack the PIN codes coming out from the devices' dumps I have.
What abouf the StrongPinLap? A blind non-educated guess could state that the same algorithm is used, but the presence of a different library should suggest much more than that. I did not look the strong version: feel free to reach me with a message or a comment, in case you need extra info. Moreover I found some truly interesting stuffs that I will disclose in the next future, so stay tuned.
As I previously said, from my point of view getting the pincode it's an useless or unfeasible task: but I had some fun and I won a couple of beers. Mattia will offer a beer too to the first one who will crack the pincode stored in the blog post example, so hurry up (note: physical meeting needed)!
- Adrian Leong aka @Cheeky4n6Monkey correctly pointed out that the PIN hash data could reside in the Object31 key too. Moreover you could find the CredentialHash value in Object736, Object44... so, it's better to manually inspect all the keys in Microsoft\Comms\Security\DeviceLock. The reasons why the pin hashes can be saved around different keys are currently unknown, and, if you want to crack them, consider the fact that the CredentialActualLength value could be missing. In such cases you'll need to try different pin lengths before getting the result. Adrian provided a different script to crack the pin, which is more flexible but it requires (a bit) manually approach: you can find his script on https://github.com/cheeky4n6monkey. If you are interested in Windows Phone artifacts check Adrian awesome posts on his http://cheeky4n6monkey.blogspot.it/ blog.
- Someone asked me if this cracking could be seen as a security vulnerability. No, it's not. You have to physically own the device to grab, when possible, a physical dump or the required files. Different cases, aka device pwned, are out of scope here. In any case a different "vulnerability" must be exploited before pin cracking, which is a quite strong authenticator in this context.
- Finally if you want to explore Windows Phone from a DFIR point of view, Cindy Murphy, Mattia Epifani and me we'll be speaking on this topic at SANS DFIR Summit in Prague 2015.