Its been over a year since I threw together the original Get-GPPPassword on a short flight and I was really having a hard time even looking at the code. In addition to a nagging bug, it needed to be rewritten and updated to include all the great recommendations from you guys. Its amazing how often I still see local passwords being enforced with Group Policy preferences. For some reason it actually feels like the problem is getting worse even with Microsoft's blatant warnings in Server 2012. The other issue that I have seen is that when administrators stop using preferences, the old XML file is not deleted. On more than one engagement I have found an old password which helped me guess the current one. We need to keep hammering at this poor practice.
Additionally, one of the things that jumped out at me while reworking this script is the simplicity of this task in PowerShell. Compared to accomplishing the same task in Ruby, PowerShell's XML parsing really gives it an edge. A lot of security professionals could benefit by spending a few days to learn it and Carlos Perez is teaching an awesome class at Derbycon!
Updates:
General flow, performance and bug fixes including better error handling and a fix for the problem with how the base64-encoded string was being padded.
Support for parsing not only groups.xml, but also scheduledtasks.xml, services.xml and datasources.xml. The original post that inspired me to write the function appears to be down, but there have been other posts that point out that passwords can be stored in other Group Policy preference files as well. I attempted to create each one of those XML files and created logic for the 4 that seem used.
Ryan Ries pointed out that the script could easily be pointed at the domain controller which removes the need for any parameters and makes the script easier to run:
I broke out the decryption function (Get-DecryptedCPassword) If you want to decrypt a password offline, you can use that.
As always, the most current version of the Get-GPPPassword is available from the PowerSploit Github page. Thanks for reading, keep the comments and recommendations coming and join Skip Duckwall and I at BlackHat where we will briefly discuss Group Policy preferences in relation to the Pass-the-Hash attack with practical mitigation techniques.
-Chris
Just found this and... well, we are setting local passwords across dozens of OUs. Obviously, we didn't know this was a security problem! It may be amazing to you that people are doing this, but what is the solution that gives centrally changeable (secure) passwords for local accounts?
ReplyDeleteIn addition to giving away your password, the other issue is that setting the same password on more than 1 box allows the Pass-the-Hash attack to be successful. I will try and get a post written up on how I recommend setting a unique password for every local account.
DeleteI don't what I am doing wrong, but not matter what policy I set the script comes out blank with no output whatsoever. No error message, nothing.
ReplyDeleteCan someone guide how to make it work?
Are you using the function from https://github.com/mattifestation/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1? If so, did you call the function? You can check out this demo I recorded for Blackhat: https://www.youtube.com/watch?v=S_H-BlGBzeg
Delete-Chris
Hello,
ReplyDeleteThe script is currently only working when there is only one password found of the group policy file. The reason is the parent node may contain multiple child nodes , and the current implementation assumes that only one instance of is returned. This would be a simple fix, but I just include my solution here if you need reference:
https://github.com/khai-tran/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1
Thanks.
Thanks I will take a look at that as soon as I get back from Derbycon!
DeleteThanks again. Took a look at your solution and it works with the XML parsing in PowerShell v3, but not 2. I think I solved the issue in the latest version though: https://github.com/mattifestation/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1
DeleteVery cool, thank you for updating it!
ReplyDeleteChris - I am loving your script software, but I am having an issue that I hope is user error. We have a larger set of local accounts that GPPs is definitely being used on. Your main output truncates the list of usernames and passwords though and I am trying to get a 1:1 match before I send this up our food chain.
ReplyDeleteI've tried running: Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq & Get-GPPPassword | ForEach-Object {$_.usernames} | Sort-Object -Uniq
with and without the Sort-Object, but the results don't seem to match up when I place them side by side with the accounts & passwords. Any ideas?
If you are sorting each each list separately than the list will not match. Also, there isn't a 1:1 relationship because of how GPP can be created setting multiple users. As long as the GPP isn't setting a new account name, you could do Get-GPPPassword | ForEach-Object {Return $_.usernames $_.passwords}
ReplyDelete