Top 16 Active Directory Vulnerabilities
Most organizations and business around the world today use Active Directory in their infrastructure as central management solution for managing their resources.
But as any other similar technology, Active Directory is very complex and securing it requires significant effort and years of experience.
- Introduction
- Top 16 Active Directory vulnerabilities
- 1. Users having rights to add computers to domain
- 2. AdminCount attribute set on common users
- 3. High number of users in privileged groups
- 4. Service accounts being members of Domain Admins
- 5. Excessive privileges allowing for shadow Domain Admins
- 6. Service accounts vulnerable to Kerberoasting
- 7. Users with non-expiring passwords
- 8. Users with password not required
- 9. Storing passwords using reversible encryption
- 10. Storing passwords using LM hashes
- 11. Service accounts vulnerable to AS-REP roasting
- 12. Weak domain password policy
- 13. Inactive domain accounts
- 14. Privileged users with password reset overdue
- 15. Users with a weak password
- 16. Credentials in SYSVOL and Group Policy Preferences (GPP)
- Conclusion
Introduction
The following information is meant to help penetration testers and auditors identify typical security related problems when it comes to administering Active Directory environments.
In contains steps on how to find each vulnerability practically from a perspective of a penetration tester, using standard offensive toolkit and readily available tools.
Top 16 Active Directory vulnerabilities
This list consist of 16 issues that are most commonly found during internal infrastructure penetration tests and vulnerability assessments. It’s nothing terribly sophisticated or new, simply a list of typical problems.
The list is organized in a random manner – it is therefore more like a checklist rather than an ordered ranking list.
Let’s get to it!
1. Users having rights to add computers to domain
In a default installation of Active Directory, any domain user can add workstations to the domain. This is defined by the ms-DS-MachineAccountQuota attribute which is by default set to 10.
This means that any low privileged domain user can join up to 10 computers to the domain. Ok, probably not great, but what’s the big deal?
The problem is that this settings allows any user to join their our own, unmanaged computer to access the corporate domain with the following advantages:
- No Antivirus or EDR solution will be pushed onto their machine
- No GPO settings or policies will be applied to their system
- Allows them having Administrative rights on their system
In corporate environments, users should never have local administrative privileges on their machines. This is one of the fundamental security controls which should be applied universally.
If users have administrative privileges on their machines, they can perform privileged operations on the network such as craft raw network packets, perform network scans, run exploits from their machine to attack other systems on the network and many other things.
Users should therefore be never allowed to join computers to the domain.
How to test
The easiest way to test this is it to have a Windows test machine (physical or a VM) connected to the target corporate network so that it can reach the domain controllers.
1) Run ‘sysdm.cpl’ to open ‘System Properties’ -> click ‘Change’ and provide the target domain name:
Click ‘OK’.
2) Now we will be prompted for credentials. Provide any low privileged domain user credentials.
If successful, we should see the “Welcome to the org.local domain!” message and our test machine should be added to the AD under the CN=Computers container.
Alternatively, we could also join our test machine to the AD using the following PowerShell command:
add-computer –domainname <FQDN-DOMAIN> -Credential <DOMAIN>\<USER> -restart –force
# Example
add-computer –domainname org.local -Credential ORG\john -restart –force
After restart of our test machine, the machine should be fully joined into the domain.
3) Now we should be able to verify that our computer was truly added to the domain by listing the domain computers.
Note that if we had access to domain controllers, here’s how we could list all computers that were added by non-admins:
Import-Module ActiveDirectory
Get-ADComputer -LDAPFilter "(ms-DS-CreatorSID=*)" -Properties ms-DS-CreatorSID
Go back to top.
2. AdminCount attribute set on common users
The AdminCount attribute in Active Directory is used to protect administrative users and members of privileged group such as:
- Domain Admins
- Enterprise Admins
- Schema Admins
- Backup Operators
- Server Operators
- Replicator
- etc.
The inner workings related to it is quite a complex topic involving AdminSDHolder object and SDProp process which periodically modifies such accounts. To make long story short, the AdminCount attribute should never be set on common users, because it can give them unnecessarily high privileges.
For instance, this can prevent users from having applied corporate Group Policies and ACL modifications, or on the other hand it can result in assigning them with high privileges (see persistence attack vector described here). In any case, this represents a risk of having “backdoor” users in the organization without knowing about it.
The problem is that the AdminCount attribute is set to 1 automatically when a user is assigned to any privileged group, but it is never automatically unset when the user is removed from these group(s).
This can result in having common low privileged users with AdminCount set to 1 without being members of any privileged group.
How to test
In order to find users with AdminCount attribute set to 1, we can use the LDAPDomainDump tool. This tool collects vital information about all users, group and computers in the domain. All we need is credentials of any low privileged domain user and the ability to reach LDAP port of any domain controller.
Here’s what to do..
1) First collect the information from the domain controller:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>
# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1
Note that instead of a password, we could also simply provide NTLM hash (pass-the-hash).
2) Once the dumping is done, we can get the list of users with AdminCount attribute set to 1 by parsing the ‘domain_users.json’ file:
jq -r '.[].attributes | select(.adminCount == [1]) | .sAMAccountName[]' domain_users.json
Alternatively, if we have access to domain controllers, we can get a list of these users like this:
Import-Module ActiveDirectory
Get-AdObject -ldapfilter "(admincount=1)" -properties admincount
Once we have the list of affected users, we should check whether they really belong to any privileged or administrative group.
Go back to top.
3. High number of users in privileged groups
This vulnerability is about having an excessive number of users in privileges groups such as:
- Domain Admins
- Schema Admins
- Enterprise Admins
Having a high number of users in privileged groups unnecessarily increases risk of domain compromise, because if some of those users gets compromised, it means total compromise of the domain.
It’s not only prudent, it is truly essential to follow principles of the least privilege and assign membership to these groups only when absolutely necessary, which is ideally never.
We have seen AD deployments with zero users in these groups and they worked just fine. It can be done.
How to test
In order to test for this, we only need low privileged domain account.
Here’s how to enumerate these groups from a domain joined Windows machine:
net group "Schema Admins" /domain
net group "Domain Admins" /domain
net group "Enterprise Admins" /domain
On a non-joined Windows machine, we would have to authenticate to the domain first:
runas /netonly /user:<DOMAIN>\<USER> cmd.exe
Here’s how we can test this from Linux (e.g. Kali Linux) using the ‘net’ command:
net rpc group members 'Schema Admins' -I <DC-IP> -U "<USER>"%"<PASS>"
net rpc group members 'Domain Admins' -I <DC-IP> -U "<USER>"%"<PASS>"
net rpc group members 'Enterprise Admins' -I <DC-IP> -U "<USER>"%"<PASS>"
# Example:
net rpc group members 'Domain Admins' -I 10.10.30.52 -U "john"%"pass123"
If there are too many users in any of the groups, something should be done about that.
Go back to top.
4. Service accounts being members of Domain Admins
The idea behind service account is to designate a specific user account with specific set of privileges to run a specific service (or an application), without requiring to provide it with full administrative privileges.
The problem is when these accounts get assigned exorbitant privileges and/or memberships, like being added to the “Domain Admins” group for example.
Such practice introduces a critical risk into the infrastructure, because service accounts typically have passwords set to never expire and so their passwords are rarely changed, if ever.
This means that if such vulnerable service account got compromised, it would allow the attacker to have full control over the AD domain. And for a long time probably.
How to test
Simply review all members belonging to the privileged groups:
net group "Schema Admins" /domain
net group "Domain Admins" /domain
net group "Enterprise Admins" /domain
On Linux we can use the ‘net’ command as shown in the previous vulnerability.
If there are any service accounts in any of these groups, we should flag it.
Go back to top.
5. Excessive privileges allowing for shadow Domain Admins
This vulnerability is more complex. It’s about misuse of Active Directory Rights and Extended Rights, a.k.a. Access Control Entries (ACEs).
The problem is when some of these rights are given to a low privileged user (or a group) to allow changing something important on a higher privileged user (or a group).
Some of the typically misused rights include:
- ForceChangePassword – Ability to reset password of another user
- GenericAll – Full control over an object (read/write)
- GenericWrite – Update of any attributes of an object
- WriteOwner – Assume ownership of an object
- WriteDacl – Modify the DACL of an object
- Self – Arbitrarily modify self
These things can have critical impact and often times lead to Domain Admin privileges. Users with such excessive privileges are thus called shadow Domain Admins (or Hidden Admins).
Here’s very good article describing this issue in more detail and with examples:
How to test
As mentioned above, this issue is more complex and requires a little bit of digging. All we need, however, is a low privileged domain user and the right tool.
One of the tools that greatly helps in this process is Bloodhound. Here’s its usage in a nutshell:
1) First we have use an “ingestor” to collect the data from the AD environment – e.g. SharpHound.
2) Then we upload the data into the Bloodhound front-end GUI where we can visualize relations between objects.
The Bloodhound query language then allows us find paths like in this example:
When we are looking for these rights and trust misconfigurations, we would typically start with the pre-built queries such as:
- “Find Top 10 Users with Most Local Admin Rights”
- “Find Shortest Paths to Domain Admins”
- “Map Domain Trusts”
- etc.
The idea is to find path to the “Domain Admins” group from our current position and level of privileges.
Here are some more queries that can help (link1, link2).
Go back to top.
6. Service accounts vulnerable to Kerberoasting
Kerberoasting is very popular attack vector aimed against service accounts in Active Directory.
The problem is when these service accounts have weak passwords and when there is weak Kerberos RC4 encryption used for encrypting their passwords.
Here’s the original paper (slides) from Tim Medin – the author of Kerberoasting:
How to test
This attack has been automated by multiple tools (e.g. Impacket or Rubeus) and all we need for testing is to have any low privileged domain user credentials.
Here’s an example using Impacket:
GetUserSPNs.py -request <DOMAIN>/<USER>:<PASS>
# Example:
GetUserSPNs.py -request example.com/john:pass123
Note that instead of a password, we could also use NTLM hash (pass-the-hash).
If we obtained any hashes, it means that there are service accounts vulnerable to Kerberoasting.
After we obtained the hashes, we can try to crack them in order to fully demonstrate the impact. Here’s an example of using Hashcat to perform a dictionary attack:
hashcat -m 13100 -a 0 hashes.txt wordlist.txt
# Faster with optimized kernels, but limited password length to 31 characters:
hashcat -m 13100 -a 0 -O --self-test-disable hashes.txt wordlist.txt
This is what we should be advising our clients when it comes to protecting service accounts against Kerberoasting:
- Use newer encryption algorithms such as AES128, AES256 or better
- Enforce usage of strong and complex passwords (ideally 25+ characters in length)
- Make sure their password periodically expire
- Keep their privileges as low as possible
Go back to top.
7. Users with non-expiring passwords
Mostly due to a convenience, some organizations have domain accounts configured with the DONT_EXPIRE_PASSWORD flag set.
This is typical configuration of service accounts, but also can be sometimes seen on more privileged domain accounts.
What this means is that their passwords will never expire. Although it is useful / convenient in some situations, it can also be quite damaging.
High privileged domain accounts with non-expiring passwords are ideal targets for privilege escalation attacks and are common “backdoor” users for maintaining access e.g. by APT groups.
How to test
In order to find users with non-expiring passwords, we can use again the LDAPDomainDump tool mentioned earlier. All we need is a low privileged domain user credentials and the ability to reach LDAP port of any domain controller.
Here are the steps:
1) First collect the information from the domain controller:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>
# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1
2) Once the dumping is done, we can get the list of users with non-expiring passwords using the following command:
grep DONT_EXPIRE_PASSWD domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $3}'
Alternatively, the following PowerShell command could be used on a domain controller to get the list of such users:
Import-Module ActiveDirectory
Get-ADUser -filter * -properties Name, PasswordNeverExpires | where { $_.passwordNeverExpires -eq "true" } | where {$_.enabled -eq "true" }
Go back to top.
8. Users with password not required
Another interesting flag in Active Directory is the PASSWD_NOTREQD flag. If a user account has this flag set, it means that the account doesn’t have to have a password.
This doesn’t mean that the user account doesn’t have a password, it simply means that it doesn’t have to have one. It means that any kind of password will be just fine – a short one, a non-compliant one (against domain password policy), or an empty one. Simply any.
This is of course a huge security risk and no user account ever should have this flag set.
How to test
Searching for users with PASSWD_NOTREQD flag set is very similar to searching for users with non-expiring passwords. We can again leverage the LDAPDomainDump tool.
All we need is a low privileged domain user credentials and the ability to reach LDAP port of any domain controller.
1) First collect the information from the domain controller:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>
# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1
2) Once the dumping is done, get the list of users with the PASSWD_NOTREQD flag using the following command:
grep PASSWD_NOTREQD domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $3}'
Alternatively, the following PowerShell command could be used on a domain controller to get the list of users with password not required:
Import-Module ActiveDirectory
Get-ADUser -Filter {UserAccountControl -band 0x0020}
Go back to top.
9. Storing passwords using reversible encryption
Some applications require user’s password in plain text in order to perform an authentication and this is why there is support for storing passwords using reversible encryption in Active Directory.
Storing passwords this way is essentially identical as storing them in plain text. It is a horrible idea, but it’s reality.
The only mitigating factor here is that an attacker would have to be able to pull password data from the domain controllers in order to read the password in plain text. This means to have either:
- Rights to perform DCSYNC operation (e.g. via Mimikatz)
- Access to the NTDS.DIT file on a domain controller
How to test
Both methods imply a full AD domain compromise already, so it’s not actually such a catastrophe.
Without that, there is no way to find which users have passwords stored using a reversible encryption. And even if we knew which ones, we wouldn’t be able to pull the passwords out, unless we have such a high privileges that we practically own the AD domain already.
So, in order to test for this vulnerability, we have to dump the NDTS.DIT file from the domain controller and extract the hashes from it. Only then we can see which users have passwords stored using reversible encryption – their passwords will be simply printed out in plain text.
Note that we could also get the plain text password using Mimikatz running in the context of a high privileged user (who is able to perform DCSYNC), but we would have to know the username of an affected user.
Here’s the Mimikatz command that would do it:
mimikatz # lsadump::dcsync /domain:<DOMAIN> /user:<AFFECTED-USER>
# Example:
mimikatz # lsadump::dcsync /domain:example.com /user:poorjohn
In any case, passwords should never be stored in a plain text. This vulnerability gives attackers who compromised the AD domain (e.g. APTs) and highly privileged insiders (e.g. domain administrators) instant access to plain text passwords of affected users.
Go back to top.
10. Storing passwords using LM hashes
Another vulnerability that typically surfaces after the Active Directory compromise is the storage of passwords as LM hash, instead of NTLM.
LM hash is an old deprecated method of storing passwords which has the following weaknesses:
- Password length is limited to 14 characters
- Passwords that are longer than 7 characters are split into two and each half is hashed separately
- All lower-case characters are converted to upper-case before hashing
Due to these weaknesses, LM hashes are extremely easy to crack. Anyone who has access to them, e.g. highly privileged insiders (domain administrators), can easily crack them and obtain plain text passwords.
How to test
As pointed out above, this issue is typically revealed after the AD is compromised and NTDS.DIT files are extracted.
Here’s a quick refresher to LM and NTLM hashes:
When the LM part is set to something other than ‘aad3b435b51404eeaad3b435b51404ee’ (empty string), it means that we are looking on an LM hash.
So, here’s how we can identify LM hashes:
grep -iv ':aad3b435b51404eeaad3b435b51404ee:' dumped_hashes.txt
Go back to top.
11. Service accounts vulnerable to AS-REP roasting
This vulnerability is very similar to Kerberoasting, but in this case the attack abuses user accounts that do not require Kerberos pre-authentication.
Simply speaking, it affects domain users with DONT_REQ_PREAUTH flag set.
Here’s a detailed article about AS-REP roasting:
How to test
Similarly to Kerberoasting, this attack has been automated by multiple tools (e.g. Impacket or Rubeus). But there are some subtle differences..
In order to test for AS-REP roasting, we don’t have to know any domain user credentials! The only thing we need to know is which users are affected.
If we don’t know any, well then we can try a wordlist with usernames like in this example with Impacket:
GetNPUsers.py <DOMAIN>/ -usersfile <USERLIST.TXT> -format [hashcat|john] -no-pass
# Example:
GetNPUsers.py example.com/ -usersfile userlist.txt -format hashcat -no-pass
On the other hand, if we are in possession of any low privileged domain user credentials, we can obtain the list of affected users right away, along with their Kerberos AS-REP hashes. Here’s how to do it:
GetNPUsers.py <DOMAIN>/<USER>:<PASS> -request -format [hashcat|john]
# Example:
GetNPUsers.py example.com/john:pass123 -request -format hashcat
If we get some hashes, we have a thing to report and we can try to crack them.
Here’s an example with Hashcat using a dictionary attack to crack the Kerberos AS-REP hashes:
hashcat -m 18200 -a 0 hashes.txt wordlist.txt
# Faster with optimized kernels, but limited password length to 31 characters:
hashcat -m 18200 -a 0 -O --self-test-disable hashes.txt wordlist.txt
Alternatively, the following PowerShell command could be used on a domain controller to get the list of users which do not require Kerberos pre-authentication:
Import-Module ActiveDirectory
Get-ADuser -filter * -properties DoesNotRequirePreAuth | where {$._DoesNotRequirePreAuth -eq "True" -and $_.Enabled -eq "True"} | select Name
Go back to top.
12. Weak domain password policy
Password policy is a topic that keeps evolving by time. There are many different views on it and opinions how an ideal password policy should look like.
Some organizations enforce long and complex passwords, changing them frequently. Some are more benevolent and some can even almost disregard enforcing strong password parameters altogether and just focus on strengthening their compensatory controls in their internal environments, holistically, so that an account compromise has only a very little impact.
Each approach certainly has its advantages and disadvantages, but as penetration testers we should stick to something prudent and generally accepted, even though the clients might ultimately make their own call.
For instance, the CIS Benchmark recommends the following Active Directory password policy:
- Minimum password length: 14
- Enforce Password History: 24
- Maximum password age: 60 or fewer days
- Minimum password age: 1 or more
- Password must meet complexity: Enabled
- Store passwords using reversible encryption: Disabled
- Account lockout threshold: Up to 10, but not 0
- Account lockout duration (minutes): 15 or more minutes
- Account lockout observation window (minutes): 30 minutes
How to test
In order to enumerate password policy, we don’t need any special privileges – any low privileged domain account can do this.
Here’s how we can display AD password policy from a domain joined Windows machine:
net accounts /domain
Here’s how we can display AD password policy from Linux (e.g. Kali Linux) using the ‘polenum’ command:
polenum --username <USER> --password <PASS> --domain <DC-IP>
# Example:
polenum --username john --password pass123 --domain 10.10.51.11
Alternatively, we could also use the ‘enum4linux’ utility:
enum4linux -P -u <USER> -p <PASS> -w <DOMAIN> <DC-IP>
# Example:
enum4linux -P -u john -p pass123 -w dom.local 172.21.1.60
Go back to top.
13. Inactive domain accounts
This vulnerability is about having active user accounts without being used for a long time, according to their ‘Last logon date’. These accounts are typically belonging to:
- Employees that left the company
- Temporary accounts
- Test accounts
Having unused domain accounts in the domain increases attack surface of the organization, because it provides opportunity to compromise these accounts, for example via login attacks.
There should be a mechanism (a policy) in place to disable or delete these accounts based on periodic checks, e.g. after 30 days of inactivity. Mileage can vary of course here.
How to test
In order to find inactive domain accounts, we can again leverage the LDAPDomainDump tool mentioned earlier.
All we need is a low privileged domain user credentials and the ability to reach LDAP port of any domain controller. Here’s what to do:
1) First collect the information from the domain controller:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>
# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1
2) Once the dumping is done, sort the users based on their last logon date using the following command:
sort -t ';' -k 8 domain_users.grep | grep -v ACCOUNT_DISABLED | awk -F ';' '{print $3, $8}'
If we see something like that (FYI it’s year 2020 at the time of writing this), we should inform the client.
Go back to top.
14. Privileged users with password reset overdue
This vulnerability is about having high privileged and administrative users configured with one password for a very long time, e.g. for half a year or more.
Why is this a problem?
Privileged accounts are likely targets for attackers (e.g. APTs) and if their passwords are not changed periodically, it gives the attackers sufficient time to successfully brute force their credentials.
As mentioned earlier, all privileged accounts and service accounts should have their passwords changed on regular basis.
How to test
How to exactly define a privileged user? One very good indicator is the AdminCount attribute that we already mentioned earlier. So, all we need to do is to get list of these users and look when was the last time of their password change.
Sounds a bit complicated, but with the LDAPDomainDump tool mentioned earlier, it’s a piece of cake. All we need is credentials of any low privileged domain user and the ability to reach LDAP port of any domain controller.
Here’s what to do..
1) First collect the information from the domain controller:
python ldapdomaindump.py -u <DOMAIN>\<USER> -p <PASS> -d <DELIMITER> <DC-IP>
# Example:
python ldapdomaindump.py -u example.com\john -p pass123 -d ';' 10.100.20.1
2) Once the dumping is done, get the list of users with AdminCount attribute set to 1 by parsing the ‘domain_users.json’ file:
jq -r '.[].attributes | select(.adminCount == [1]) | .sAMAccountName[]' domain_users.json > privileged_users.txt
3) Now iterate through the list of privileged users, display their last password reset date (pwdLastSet) and sort it:
while read user; do grep ";${user};" domain_users.grep; done < privileged_users.txt | \
grep -v ACCOUNT_DISABLED | sort -t ';' -k 10 | awk -F ';' '{print $3, $10}'
Seems like those 5 privileged users haven’t had a password change for a long time.
Go back to top.
15. Users with a weak password
Despite having strong corporate password policy and matured environment, there still can be domain accounts with weak passwords.
In fact, this is very common issue, especially in large Active Directory environments.
How to test
In order to test domain users for weak credentials, we have to have a list of users first. And in order to get the list, we have to have low privileged user access to the domain.
Here’s what we could do on a domain joined Windows machine:
1) First we need to get a list of users from the AD and for that we can use the following PowerShell combo:
$a = [adsisearcher]”(&(objectCategory=person)(objectClass=user))”
$a.PropertiesToLoad.add(“samaccountname”) | out-null
$a.PageSize = 1
$a.FindAll() | % { echo $_.properties.samaccountname } > users.txt
2) Now we could feed this list into any of the following tools to do the login attack:
- DomainPasswordSpray.ps1 PowerShell module
- Invoke-BruteForce.ps1 PowerShell module
- Metasploit smb_login scanner
- Nmap ldap-brute NSE script
- CrackMapExec tool
- Medusa tool
- Ncrack tool
- Hydra tool
Alternatively, we could also use our minimalistic AD login bruteforcer (github) if our hands are tied:
Import-Module ./adlogin.ps1
adlogin users.txt domain.com password123
Here’s how we could do the same thing on Linux (e.g. Kali Linux):
1) Get list of AD domain users using the ‘net’ command:
net rpc group members 'Domain Users' -I <DC-IP> -U "<USER>"%"<PASS>"
Example:
net rpc group members 'Domain Users' -I 192.168.10.50 -U "john"%"pass123" > users.txt
2) Now we could feed it into any aforementioned tools above, e.g. to Metasploit to do the login attack:
use auxiliary/scanner/smb/smb_login
set RHOSTS <DC-IP>
set SMBDomain <DOMAIN>
set SMBPass file:pwdlist.txt
set USER_FILE users.txt
set THREADS 5
run
WARNING: Before running any login attack, we should be always aware of the corporate password policy to prevent user lockouts.
Go back to top.
16. Credentials in SYSVOL and Group Policy Preferences (GPP)
This vulnerability is about storing credentials in SYSVOL network share folders, which are folders on domain controllers accessible and readable to all authenticated domain users.
SYSVOL folders are typically used to store corporate Group Policies, configuration files and other data that are pushed to the users upon logon and so on.
Storing credentials in SYSVOL folders is something that administrators sometimes do or chose to do at some point in time, in order to solve some configuration problem. For instance, starting an application on client machines upon logon which requires administrative privileges.
Needless to say, this is something that should never be done, because any domain user can access the SYSVOL shares and find the credentials.
Typical examples are:
- Group Policy Preferences (GPP) with cPassword attribute (MS14-025)
- Hard-coded credentials in various scripts and configuration files
How to test
In order to test for this, we need to be in possession of any low privileged domain user credentials.
Here’s what we could do from a domain joined Windows machine:
findstr /s /n /i /p password \\<DOMAIN>\sysvol\<DOMAIN>\*
# Example:
findstr /s /n /i /p password \\example.com\sysvol\example.com\*
This command will sift through all the files on the SYSVOL volume and look for the “password” pattern.
An equivalent command on Linux (e.g. Kali Linux) would be:
mount.cifs -o domain=<DOMAIN>,username=<USER>,password=<PASS> //<DC-IP>/SYSVOL /mnt
# Example:
mount.cifs -o domain=example.com,username=john,password="pass@123" //10.10.139.115/SYSVOL /mnt
# Search:
grep -ir 'password' /mnt
Chances are that we will find something interesting.
For instance, we could find a cPassword attribute in the GPP XML files, which we could instantly decrypt using the ‘gpp-decrypt’ utility:
Now we could try to use this password and authenticate with it to the Windows machines found on the network. Or we could try it elsewhere. Chances are that the password will be reused somewhere (see the top 10 vulnerabilities found during internal infrastructure penetration tests).
Go back to top.
Conclusion
Everyone who ever delved into the world of Active Directory will certainly agree with me when I say that securing Active Directory is no easy task. It takes tremendous level of expertise and years of experience to do it and to mitigate the risks that come with it.
But even then the job is not done. The job is actually never done, because there are always new requirements, new features, new discoveries and new vulnerabilities and so there is always room for improvement. But I’m sure this is no surprise for anyone in the infosec world..
I hope that this article provided at least some valuable information for penetration testers and auditors to help their customers securing their Active Directory environments.