Skip to content

Instantly share code, notes, and snippets.

@tyranid tyranid/wsh_experiment.ps1 Secret
Created Jan 2, 2020

Embed
What would you like to do?
# Script to run experiment on Windows Service Hardening.
# Needs to be run as SYSTEM with TCB privilege.
Import-Module NtObjectManager
function Get-ServiceToken {
Param(
[Parameter(Mandatory, Position = 0)]
[NtObjectManager.ServiceAccountType]$Account,
[Parameter(Mandatory, Position = 1)]
[string]$ServiceName,
[switch]$WriteRestricted
)
# Build additional group list.
$logon_sid = Get-NtSid -NewLogon
$groups = @($logon_sid)
if ($WriteRestricted) {
$groups += Get-NtSid -KnownSid WriteRestricted
}
$service_sid = Get-NtSid -ServiceName $ServiceName
$groups += $service_sid
# Create service token, duplicate to ensure it's impersonation.
$token = Get-NtToken -Service $Account `
-AdditionalGroups $groups -Duplicate
if ($null -eq $token) {
return
}
# Build default DACL.
$defdacl = New-NtSecurityDescriptor "D:(A;;GA;;;SY)(A;;RC;;;OW)(A;;GA;;;$service_sid)"
$token.DefaultDacl = $defdacl.Dacl
# Remove privileges.
Remove-NtTokenPrivilege -Token $token `
SeImpersonatePrivilege,SeAssignPrimaryTokenPrivilege
if (!$WriteRestricted) {
Write-Output $token
return
}
# Create write restricted token.
Use-NtObject($token) {
$rsids = @(Get-NtSid "WD") + $groups
Get-NtToken -Filtered -Token $token -Duplicate `
-RestrictedSids $rsids -Flags WriteRestricted | Write-Output
}
}
function Select-AccessCheckResult {
[CmdletBinding()]
Param(
[Parameter(Mandatory, Position = 0)]
[NtApiDotNet.NtToken]$Token,
[Parameter(Mandatory, Position = 1, ValueFromPipeline)]
[NtObjectManager.AccessCheckResult[]]$Result
)
BEGIN {
$owner = $Token.Owner
$tokenid = $Token.Id.ToInt64()
}
PROCESS {
$Result | ? {$_.TokenId -eq $tokenid -and $_.Owner -eq $owner} | Write-Output
}
}
function Select-ResultEntry {
[CmdletBinding()]
Param(
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[NtObjectManager.AccessCheckResult[]]$Result
)
PROCESS {
$Result | Select Name,Owner,TypeName,User,GrantedAccess,GrantedAccessString,`
IsRead,IsWrite,IsExecute,IsDirectory,SecurityDescriptor | Write-Output
}
}
function Get-CsvName {
Param(
[Parameter(Mandatory, Position = 0)]
[NtApiDotNet.NtToken]$Token
)
$wr = if ($Token.WriteRestricted) {
"WriteRestricted"
} else {
"Unrestricted"
}
$user = $Token.User.Sid.Name
if ($user.Contains("\")) {
$user = $user.Split("\")[1]
}
if ($user -eq "LOCAL SERVICE" -or $user -eq "NETWORK SERVICE") {
"{0}_{1}.csv" -f @($user,$wr)
} else {
"control.csv"
}
}
Set-NtTokenPrivilege SeTcbPrivilege,SeDebugPrivilege | Out-Null
# Build the 5 test tokens.
$tokens = @()
$tokens += Get-ServiceToken LocalService FakeService
$tokens += Get-ServiceToken LocalService FakeService -WriteRestricted
$tokens += Get-ServiceToken NetworkService FakeService
$tokens += Get-ServiceToken NetworkService FakeService -WriteRestricted
$tokens += Get-NtToken -Session -Duplicate
Write-Host "Gathering Process and Thread Access"
# Get accessible processes and threads.
$ps = Get-AccessibleProcess -Tokens $tokens `
-CheckMode ProcessAndThread -AllowEmptyAccess
Write-Host "Gathering Named Object Access"
# Get accessible named objects.
$os = Get-AccessibleObject \ -Recurse `
-Tokens $tokens -AllowEmptyAccess -WarningAction Ignore
Write-Host "Gathering File Access"
# Get accessible files on the system drive.
$fs = Get-AccessibleFile -Win32Path "$env:SystemDrive\" -FormatWin32Path `
-Recurse -Tokens $tokens -AllowEmptyAccess
Write-Host "Gathering Registry Key Access"
# Get accessible registry keys.
$ks = Get-AccessibleKey \Registry -FormatWin32Path -Recurse `
-Tokens $tokens -AllowEmptyAccess
function Output-Results {
Param(
[Parameter(Mandatory, Position = 0)]
[NtApiDotNet.NtToken]$Token,
[Parameter(Mandatory, Position = 1)]
[string]$Path
)
Write-Host "Writing results file '$Path'"
$ps | Select-AccessCheckResult $Token | Select-ResultEntry `
| Export-Csv -Path $Path -NoTypeInformation
$os | Select-AccessCheckResult $Token | Select-ResultEntry `
| Export-Csv -Path $Path -Append -NoTypeInformation
$fs | Select-AccessCheckResult $Token | Select-ResultEntry `
| Export-Csv -Path $Path -Append -NoTypeInformation
$ks | Select-AccessCheckResult $Token | Select-ResultEntry `
| Export-Csv -Path $Path -Append -NoTypeInformation
}
Use-NtObject($tokens) {
foreach($t in $tokens) {
$name = Get-CsvName $t
Output-Results $t $name
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.