So, a blog reader tracked me down on the interwebs in a panic. He had a forum question and one of my blog posts seemed to be headed in the general direction of his desired answer.
Instead of printing or saving the numeric BitLocker Recovery Key to a TXT file, the user wrote it down on a piece of paper.
Unfortunately, and as fate would have it, one of the number groups was mistakenly written only 5-digits long. When he later tried to unlock the USB drive that was secured with BitLocker, Windows popped up an error because the key was wrong.
He hoped there was some easy way to show the Recovery Key via PowerShell (which there is, but only if the drive was unlocked). And he couldn’t unlock the USB drive without the Recovery Key. It’s the classic ‘chicken or the egg’ scenario.
WHAT NEXT?
Since the drive was locked, PowerShell couldn’t display the BitLocker recovery key, and there were very few options left.
If you’re not super-familiar with BitLocker Recovery Keys, they follow this format:
- There are 8 groups of numbers
- Each group has exactly 6 digits (no more, no less)
- The digits can range from 0 through 9
- There are no letters
- There are no special characters
So, a fake BitLocker recovery key would be arranged like this:
111111-222222-333333-444444-555555-666666-777777-888888
8 groups x 6 digits each = 48 digits total (not including the dashes).
In the case of our person needing help, he was missing the 5th group of digits. So, if everything he knew of the key was changed into letters, we could present it like this:
“AAAAAA-BBBBBB-CCCCCC-DDDDDD-######-FFFFFF-GGGGGG-HHHHHH”
In other words, he was missing the “E’s” in the example above.
There are only 1 million combinations between 000000 – 999999
PowerShell would need to try and loop through each possible combination of ###### like this:
AAAAAA-BBBBBB-CCCCCC-DDDDDD-000000-FFFFFF-GGGGGG-HHHHHH
AAAAAA-BBBBBB-CCCCCC-DDDDDD-000001-FFFFFF-GGGGGG-HHHHHH
AAAAAA-BBBBBB-CCCCCC-DDDDDD-000002-FFFFFF-GGGGGG-HHHHHH
…all the way down to…
AAAAAA-BBBBBB-CCCCCC-DDDDDD-999997-FFFFFF-GGGGGG-HHHHHH
AAAAAA-BBBBBB-CCCCCC-DDDDDD-999998-FFFFFF-GGGGGG-HHHHHH
AAAAAA-BBBBBB-CCCCCC-DDDDDD-999999-FFFFFF-GGGGGG-HHHHHH
PROOF OF CONCEPT
First, we need the key groups with the missing digit(s). Below is a BitLocker Recovery Key broken into the 8 groups:
- 630564
- 061798
- 390588
- 707146
- – – missing / incomplete – –
- 631521
- 598389
- 222321
Yes, this is a real BitLocker Key. And, no, this isn’t the key from the user in question. It’s from a brand new USB flash drive that I just encrypted.
In plain English, we need PowerShell to take Groups 1-4, insert the dashes, insert 000001, append Groups 6-8 with the dashes, then try to unlock the drive.
If that key fails, do it again, but use 000002 in the middle (and so on, and so on) until the drive unlocks.
It was a bit frustrating to figure out the right syntax, but I was finally able to write a PowerShell script to plow through the possible combinations. The script now works as expected, effectively brute-forcing the drive unlock.
DISCLAIMER
- There is no crypto involved.
- This is exactly the same logic as opening a combination padlock
(you just try all combinations until it unlocks). - At a speed of 7 guesses per second, it takes about 40 hours to go through all 1,000,000 possible combinations of ######.
- The script could be modified to guess more of the Recovery Key, but each additional digit would increase the attack / break time by 10x:
- 7 digits would require 400 hours.
- 8 digits would require 4,000 hours.
- 12 digits (######-######) would take 40 million hours.
- 48 digits would be practically infinity.
- The practical benefit is if you’re missing 1-6 digits (and know where those digits go in the Recovery Key).
Note: Obviously, this is not meant to penetrate BitLocker. It’s just an edge-case tool where you know that one group of 6 numbers is missing or incomplete. If you’re ever in that situation yourself, Microsoft is certainly not going to help you.
LET’S RUN IT
Below is a screen shot of the PowerShell code (with line numbers).
Here is the script actively trying to find the correct fifth group of digits:
And here’s what it looks like after finishing successfully:
Yes, it really is that boring.
So I guess it’s time to give you the PowerShell code so you can test this IN YOUR OWN LAB ENVIRONMENT ONLY!
ACTUAL INSTRUCTIONS
- Open the PowerShell Integrated Scripting Environment (ISE)
(Right-click the PowerShell icon, click Run ISE as Administrator,
click Yes if prompted by User Account Control). - Copy everything in the box labeled “Actual PowerShell Code” below.
- Paste that text into Power Shell ISE window (the white window on top, not the blue window on the bottom)
- Replace "630564-061798-390588-707146-" on Line #7 with your first known groups of 6 digits. Make sure to include the dashes.
Note: If you’re missing the first group of 6 numbers (AAAAAA) change line #7 to
$FirstGroup = "" - Enter the remaining known groups of digits and dashes on Line #11.
Note: If you’re missing the last group of 6 numbers (HHHHHH) change line #7 to
$LastGroup = "" - Make sure your drive letter for the USB drive is correct on Line #29 & Line #48
- Hit F5 to run
- Sit back and watch it go. The script will stop when the drive is unlocked.
Note: If you want to stop the script prematurely you can hit Ctrl-C or the red Stop button in ISE.
ACTUAL POWERSHELL CODE
First – some caveats:
- This script is for BitLocker To Go (or hard drives that are connected to an already running operating system). If your C: drive is the one that is locked, take it out and slave it off of another functioning PC.
- You have to change the drive letter in the script to match your drive (see Step 6 above).
- And you have to know at least 42 of the 48 digits of the BitLocker Recovery Key.
Happy experimenting!
# The PowerShell Script tries to determine the recovery key by brute-forcing an unlock
# of a BitLockered drive. This script only works if you’re missing one of the 6-digit
# groups of numbers in the recovery key.# First group of Recovery Key characters, followed by a hyphen, in quotation marks
# Example: "630564-061798-390588-707146-"
$FirstGroup = "630564-061798-390588-707146-"# Last group of characters, preceded, in quotation marks
# Example: "-631521-598389-222321"
$LastGroup = "-631521-598389-222321"# Loop through the set of numbers
# Note: You can change the numbers from 1..100000 to a smaller range if you like
ForEach ($MiddleGroup in 0..999999)
{# Adds Leading Zeros
$Leading = $MiddleGroup.ToString("000000")# Concatenates the Recovery Key
$Key = "$FirstGroup$Leading$LastGroup"# Try to unlock the drive
.\manage-bde.exe -unlock F: -recoverypassword $Key >$null# Get the status of the drive
$Status = Get-BitlockerVolume -MountPoint "F:"
# Write the currently-guessed Recovery Key to Screen
Write-Host $Key# Check disk space of drive, if capacity equals "0" that means drive is still locked
# If capacity is not equal to "0", that means the drive is now unlocked
If ($Status.CapacityGB -ne "0") {Break}
}
# Output when successful
Write-Host
Write-Host
Write-Host "Drive successfully unlocked with the following Recovery Key:"
Write-Host
Write-Host " 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 " -BackgroundColor "Yellow" -ForegroundColor "Black"
Write-Host $Key -Back "Yellow" -Fore "Black"
Write-Host
Write-Host "(You should write this down immediately!)"
Write-Host
Get-BitLockerVolume -MountPoint "F:"
If you have questions, you can usually find me on Twitter: @timbarrett
Wow! very detailed and useful..
Hey Tim, thanks for this PS-script. One of my coworkers lost his BitLocker key and now we are trying to get it back somehow… Is it possible to expand your script so that it guesses all the 48 digits?
Bro, did you actually read the article? If you're cracking at 8 guesses per second and there are 10^48 possible combinations then how many years do you think it will take you to exhaust that whole keyspace? (round your answer to the nearest million please)
Daniel,
I was running into a similar issue and by doing all the digging so far, yes it can be done. Adding the 48 is not a problem. I have possibly come up with something myself. I will be honest, from what I've seen, it is seemingly impossible that it would be done in this lifetime.
If anyone else has any ideas I would like to hear them myself.
Alex
# The PowerShell Script tries to determine the recovery key by brute-forcing an unlock of a BitLockered drive.
#Like this 48 digits: 111111-222222-333333-444444-555555-666666-777777-888888
#Font: http://www.nogeekleftbehind.com/2018/01/19/mailba…
#How use: https://www.windowscentral.com/how-create-and-run…
#Loop through the set of numbers
ForEach ($Group1 in 0..999999)
{
# Adds Leading Zeros
$G1 = $Group1.ToString("000000")
ForEach ($Group2 in 0..999999)
{
# Adds Leading Zeros
$G2 = $Group2.ToString("000000")
ForEach ($Group3 in 0..999999)
{
# Adds Leading Zeros
$G3 = $Group3.ToString("000000")
ForEach ($Group4 in 0..999999)
{
# Adds Leading Zeros
$G4 = $Group4.ToString("000000")
ForEach ($Group5 in 0..999999)
{
# Adds Leading Zeros
$G5 = $Group5.ToString("000000")
ForEach ($Group6 in 0..999999)
{
# Adds Leading Zeros
$G6 = $Group6.ToString("000000")
ForEach ($Group7 in 0..999999)
{
# Adds Leading Zeros
$G7 = $Group7.ToString("000000")
ForEach ($Group8 in 0..999999)
{
# Adds Leading Zeros
$G8 = $Group8.ToString("000000")
# Concatenates the Recovery Key
$Key = "$G1$G2$G3$G4$G5$G6$G7$G8"
# Try to unlock the drive
.manage-bde.exe -unlock F: -recoverypassword $Key >$null
# Get the status of the drive
$Status = Get-BitlockerVolume -MountPoint "F:"
# Write the currently-guessed Recovery Key to Screen
Write-Host "$G1 | $G2 | $G3 | $G4 | $G5 | $G6 | $G7 | $G8"
# Check disk space of drive, if capacity equals "0" that means drive is still locked
# If capacity is not equal to "0", that means the drive is now unlocked
If ($Status.CapacityGB -ne "0") { Break }
}
}
}
}
}
}
}
}
#Output when successful
Write-Host
Write-Host
Write-Host "Drive successfully unlocked with the following Recovery Key:"
Write-Host
Write-Host " 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 " -BackgroundColor "Yellow" -ForegroundColor "Black"
Write-Host $Key -Back "Yellow" -Fore "Black"
Write-Host
Write-Host "(You should write this down immediately!)"
Write-Host
Get-BitLockerVolume -MountPoint "F:"
The format of the recovery key is described here: https://blogs.msdn.microsoft.com/si_team/2006/08/…
Each block must be divisible by 11, so you could increment the loop by a step of 11.
Each block is only 16 bits (max = 65535) multiplied by 11 (max = 720885 for each key block). The loop need only be run 65536 times for 1 block, not 1 million.