In the first part of @ZephrFish's Paving the way to DA series, he demonstrates an attack targeting an older vulnerability in Windows domains affecting Group Policy Preferences. As he discusses, this issue only affects Server 2008 R2 or earlier, since Microsoft rolled out a patch in 2014. We can't, therefore, target the Server 2016 instance in our lab and we'll need to spin up a new server.
There are a few ways we could approach this but I'm going to create an isolated domain for this scenario because, frankly, managing Windows Server 2k8 from Ansible is a bit of a ballache and it was hard enough getting it working in its own domain. Additionally, we're going to have to do some fakery because, as of yet, I have been unable to find a way to programmatically interact with the necessary Group Policy Preference. Not to worry though, the scenario will behave familiarly enough to a real world environment to be useful practice.
Provisioning the lab
Firstly, we have to provision our Windows 2k8R2 server. As per usual, lets get the playbook out and have a look at what we've got.
There is a lot going on here. If you've been following along the past few posts, it will look vaguely familiar but you will likely note the increase in use of raw shell commands. This is primarily because the Ansible modules rely on newer PowerShell modules and updated functionality of modern Windows server versions. I've endeavoured to make these as idempotent and error-resistant as possible but I make no guarantees - you may need to tweak this but give me a shout and we can solve it together.
Once executed, the playbook will put the server in much the same state as we have our 2016 server. However, before we can use the playbook, we need to spin up the virtual machine. Let's look at our Vagrantfile.
Once again, we're relying on the hard work of Jordan Borean. This is my Hyper-V version but I've run up a quick Virtualbox version too.
Important: When you first run this Vagrantfile, it is likely going to run into an error - the Windows 2008 Server may not be licensed. The solution is quick and easy. Connect to the VM via the GUI and when the dialog loads, choose the Ask me later option. After this, you can run
vagrant up --provision and the provisioning will proceed as normal. I will try to solve this over the next few days and get rid of this friction - for the time being, sorry, but this is the best option.
I've also provisioned a Windows 10 workstation specifically for this scenario but this is not explicitly necessary. You can repurpose the existing Windows 10 host. Either way, you'll want to target it with a playbook similar to this. The only modification I've made is to target the
gpp.hacklab.local domain defined in the earlier playbook. You will need to swap out the comments on line 19 and 20.
Once you have provisioned the server and either spun up a new workstation or redirected the other, we can create our SYSVOL/GPP scenario from @ZephrFish's post.
Creating the attack scenario
This was an enormous pain in the arse. Newer versions of PowerShell and associated modules introduced the ability to target more of the Group Policy Management (GPM) options. Namely, Get-GPRegistryValue and Set-GPPrefRegistryValue, which I expected to allow me to access the necessary entries to simulate the weakness detailed in Zephr's blog. Nope. That was foolish of me to assume they did what they were supposed to do. The only way to create a Group Policy Preference (GPP) defining a built-in Administrator password, as far as I have been able to divine, is through the GPM GUI. This, as you would expect, does not go very well with the idea of automating the lab.
However! Since we know how this weakness occurs, we can manually simulate the conditions in a way that lets us practice the attack in a realistic manner. When the GPP is created, it writes a directory to SYSVOL which contains all the components needed for us to perform the actual attack. So if we produce it using the GUI and then create a copy of the directory and contents, we can, in a sense, replay it by pushing the copy to the correct location. This is not ideal because it is not how most systems administrators would handle such administration (although, it is not entirely farfetched that some might do it this way). So, lets take a look at what we're going to push into SYSVOL. You do not need to repeat the following steps yourself because I'm going to provide the zipped GPO for you. However, if you want to produce your own, here's how.
In the subdirectory path
Machine\Preferences\Groups, we find
Here we can now see the
cpassword field where the eNcRyPtEd password resides. The next step is to stick this whole directory tree in a zip archive so we can pull it to our host system and use it to inject the policy later. First though, let's quickly follow one step of Zephr's guide to make sure the policy is targetable.
That's a bingo. We can see the path to the
Groups.xml that the script is pulling the
cpassword value out of and very kindly decrypting for us too! Now then, let's delete the policy via the GUI and then use Ansible to push the zipped policy right back into SYSVOL. Deleting the GPO is as easy as right-clicking on it from the GUI and its associated subdirectory will then dissapear from the
Injecting the vulnerable GPO
The first step in Ansible is to copy the GPO archive on to the server and then we can simply unzip the archive. Thankfully, this is a really simple operation.
As I said above, I've pulled the GPO from my server and zipped it up for you to use if you'd like to save time. If you want to use mine, you can download it here:
Once you've downloaded it or created your own, you can stick it in the directory with your Ansible playbook and Vagrantfile. The snippet above, if added to your playbook or run separately (you'll need to add a hosts and tasks declaration), will push the archive onto the target and then unpack the archive into the correct subdirectory of the SYSVOL share.
And if we jump back on to our workstation and run
Get-GPPPassword again, we can once again collect the decrypted
That was a lot of work to pull a password out of a file, right? However, we now have a viable Server 2008 (R2) lab. We could explore some legacy attack paths and techniques. I can say confidently that I still encounter 2008 servers in the wild - hell, 2003 still hasn't fully died a death yet - so there's a lot of value to be found in learning how to break legacy environments. Stay tuned for some ways to spice up your 2k8 lab and also for some collaborative posts with as yet undisclosed parties.
Troubleshooting and errata
This one was complicated and took a lot of duct tape and chewing gum so I expect this may throw up some teething issues for anyone following it. Please reach out if you run into problems of any kind so I can help you iron them out and also improve this guide. As always, you can get at me on Twitter 0x616e6874.
Masthead image credit: Gael Varoquaux, Ski touring: up to the mountains