Category Archives: Ramblings

Posts in this category are general ramblings which may or may not be about computer security.

Change the TPM Owner Password and BitLocker Recovery Key

I recently purchased a Microsoft Surface Pro 4 which came with Windows 10. BitLocker was enabled by default during setup, however the recovery key was automatically uploaded to my Microsoft account. While this is a really good feature and for the vast majority of users will not pose a problem, I have slightly different concerns than the average user… therefore I decided I did not want my recovery key to be entrusted to Microsoft.

The quickest and easiest option was to delete the recovery key from my Microsoft account, which can be done here. However although this would remove my ability to get my recovery key from my Microsoft account it gives me absolutely no guarantee that Microsoft actually deleted it in any kind of permanent way, and given that everyone¬†has a rigorous backup process (right? ūüėČ ), it is actually very likely that they actually still have my¬†recovery key.

To have slightly more confidence I decided to change both the TPM Owner Password and BitLocker Recovery Key on my machine and keep them in a safe place offline in case I ever needed them.

To change the TPM Owner Password, open tpm.msc, then select “Change Owner Password…” in the top right, I followed the prompts within the dialogue box to change the password and save the file to external media.

To change the BitLocker Recovery Key is slightly more involved and utilises  the BitLocker Device Encryption Configuration Tool:


Assuming C: is the BitLocker protected drive you want to change recovery password do the following within an elevated command prompt.

List the recovery passwords:

 manage-bde C: -protectors -get -type RecoveryPassword

Locate which protector you want to change, there is probably only one, and copy its ID field including the curly braces.

Delete this protector:

manage-bde C: -protectors -delete -id [ID you copied]

Create a new protector:

Type manage-bde C: -protectors -add -rp

Note you can specify a 48 digit password at the end of the previous command if you wish, however if one is not specified one is randomly generated for you  Рcomputers are much better at randomly generating passwords than you so probably best to let it do it.

Take heed of the output of the last command:


1. Save this numerical recovery password in a secure location away from your computer:


To prevent data loss, save this password immediately. This password helps ensure that you can unlock the encrypted volume.

As always, if you have any comments or suggestions please feel free to get in touch.


I recently had need to interpret bitfields with Python.
I’m quite happy with the 3¬†lines of code that I came up with so I thought I’d share them in case they are of use to anyone else.

Bitfields are basically a binary number where each bit is assigned a meaning which can either have a value of True ‘1’ or False ‘0’.
Usually they are interpreted using bit shifting and bitwise AND operations but this seemed to be quite involved to get the data into a usable form so I found another way.

Consider the pwdProperties attribute from Active Directory ( which contains several settings for the account as a bitfield which can be retrieved using an LDAP query.

Each of the bits of this attribute mean the following:

So if the pwdProperties attribute has a value of 17 in decimal, which equals 010001 in binary, the 1st and 5th bits (from the right) are set to 1 indicating that the domain requires complex passwords and stores passwords in cleartext.

Using python-ldap this attribute is returned in a dictionary as a decimal number represented as a string within a list, i.e.

attrs = {'pwdProperties': ['17']}

So the first step is to extract the string of the number and convert it to an integer:

pwd_properties = int(attrs['pwdProperties'][0])

Next the decimal number is converted to a string representation of the binary number with left 0 padding to the correct length:

pwd_properties = format(pwd_properties, "06b")

Then the binary number string is split into a list:

pwd_properties = list(pwd_properties)

For my purposes I needed the bitfields to be represented as a boolean. To do this a the string replace()¬†method is used to replace instances of ‘0’ with an empty string and then the bool() function is used to convert the result to either True or False while iterating over the list. (Note when dealing with strings an empty string is False and everything else is True).

bitfield_values = [bool(w.replace('0', '')) for w in pwd_properties]

Next a list containing the meaning of each bit is defined (make sure you have them in the correct order to match the bits) :

bitfield_keys = ['refuse_password_change', 'password_store_cleartext', 'lockout_admins', 'password_no_clear_change', 'password_no_anon_change', 'password_complex']

The two lists can then be formed into a list of tuples using zip() which is then used to create a dictionary using dict() :

pwd_properties = dict(zip(bitfield_keys, bitfield_values))

Finally this can all be condensed into :

bitfield_keys = ['refuse_password_change', 'password_store_cleartext', 'lockout_admins', 'password_no_clear_change', 'password_no_anon_change', 'password_complex']
bitfield_values = [bool(w.replace('0', '')) for w in list(format(int(attrs['pwdProperties'][0]), '06b'))]
pwd_properties = dict(zip(bitfield_keys, bitfield_values))

Resulting in a dictionary like this:

{'password_store_cleartext': True,
'password_no_anon_change': False,
'lockout_admins': False,
'refuse_password_change': False,
'password_no_clear_change': False,
'password_complex': True}

A limitation of this method is that it is not easy to go from the resulting dictionary back to the bitfield because a dictionary in Python is unordered. This can probably be overcome by using an ordered dictionary from the collections module. However for my current purpose there is no advantage to implementing this.

I have been mulling this over and come up with the following line to convert the dictionary back to a binary number :

int("{refuse_password_change}{password_store_cleartext}{lockout_admins}{password_no_clear_change}{password_no_anon_change}{password_complex}".format(**pwd_properties).replace('True', '1').replace('False', '0'), 2)

This is probably horribly inefficient due to the string replacement, but it works.
It takes advantage of unpacking and referencing keyword arguments to form a string with the values in the correct order, then replaces the strings ‘True’ and ‘False’ with ‘1’ and ‘0’ respectively before using the int() function to convert the string base 2 number (i.e. binary) to a decimal number.

It might be more efficient to avoid string replacement like this :

int("{refuse_password_change}{password_store_cleartext}{lockout_admins}{password_no_clear_change}{password_no_anon_change}{password_complex}".format(**dict(zip(pwd_properties.keys(), ['1' if pwd_properties[key] == True else '0' for key in pwd_properties.keys()]))), 2)

This recreates the dictionary with ‘1’ and ‘0’ by testing each key for True. Then takes advantage of unpacking and keyword arguments to get the bits in the correct order, before converting to a decimal number using int().

At some point I’ll time these two methods to find which is more efficient and update this post.

As always, if you have any comments or suggestions please feel free to get in touch.

Hello world!

This is my first blog post, following convention it is entitled “Hello world!”.

This blog will be very sporadic, I am by no means a literary genius and do not feel the need to post my thoughts and feelings to the Internet.

However this will be the means by which I document the tools and techniques that I use during my career as a Penetration Tester. Primarily for my own reference, but also in the hope that it is of some use to the wider community.

I will also be using this blog to share any tools and techniques that I develop to make my life easier or exploit vulnerabilities. I am not a software developer so the code is unlikely to be fantastic, but they will be tools that work (for the most part) and I hope are useful.