josh's posh #1 - parsing the useraccountcontrol property
This first one is the inspiration for the site. I've been a bit obsessed with bitwise anding and parsing flags stored as bits ever since BPF in SANS SEC503. I ran into a situation recently where I wanted to check whether a smartcard was required for an account, but I didn't have access to active directory users and computers (dsa). A quick google search told me that the value for “smartcard required” is 262144, which briefly confused me, since that same search also told me basically all those checkboxes on the account screen are governed by the useraccountcontrol
property. i found a table that made it much clearer: each flag is assigned a bit, with the highest one in the 27th bit, so really “smartcard required” is 000000001000000000000000000
.
Of course, it usually isn't just one check box; you might have an account that can't change their password and their password doesn't expire (000000000010000000001000000
), in which case the useraccountcontrol
property isn't 64,65536
, it gives you 65600
, which is less useful and requires math. Good thing computers are good at math.
There are 22 flags that can be set for the useraccountcontrol
property, which means, yes, not all bits correspond to a flag (and by extension not all values between 1 and 134217727 are possible). I built a handy little hashtable for “reference”:
$uacflags = @{1="script";2="accountdisable";8="homedir_required";16="lockout";32="passwd_notreqd";64="passwd_cant_change";128="encrypted_text_pwd_allowed";256="temp_duplicate_account";512="normal_account";2048="interdomain_trust_account";4096="workstation_trust_account";8192="server_trust_account";65536="dont_expire_password";131072="mns_logon_account";262144="smartcard_required";524288="trusted_for_delegation";1048576="not_delegated";2097152="use_des_key_only";4194304="dont_req_preauth";8388608="password_expired";16777216="trusted_to_auth_for_delegation";67108864="partial_secrets_account"}
As you can see, the third, eleventh, fifteenth, sixteenth, and twenty-sixth bits are unused. I don't know why, per se, but I'd guess it's for future use, especially since I'd bet that's a 32 bit value, which means bits 28-32 are unused as well.
So to make this useful to us, we can run that hashtable so that $uacflags
is available to reference, do a quick $user = get-aduser -filter * -properties name,useraccountcontrol | where-object {$_.name -like "masek*"}
to grab my user account, and then we can throw something like this at it:
$uacflags.Keys | where {$_ -band $user.useraccountcontrol} | foreach {$uacflags.Get_Item($_)}
Let's analyze. First, $uacflags.Keys
is just the numbers that we set equal to each flag. By piping it to the where
statement, we're getting the list of valid values that result from bitwise anding (-band
) that number against our useraccountcontrol
property. We then send those numbers to the foreach
statement, which just returns the values. In my case, $user.useraccountcontrol
was equal to 66048
. When I ran that line of code above, it returned:
normal_account
dont_expire_password
So, essentially, we have our list of valid flags and what they mean to humans (the hashtable), we then take each one and bitwise and it against the useraccountcontrol
property, and then we get the values that actually mean something to humans spat back. That alone is kinda useful for quick lookups, but the real value is getting a list of users (maybe everyone in your admin group) and using this to compare their useraccountcontrol
flags against the standard, and report on which users have misconfigured flags.