├── PshSummit2017-AshleyMcGlone.pptx ├── 7_Reset.ps1 ├── LICENSE ├── 2_Functions.ps1 ├── 5_OtherCases.ps1 ├── 1_BasicDemo.ps1 ├── 4_InstallSoftware.ps1 ├── 3_CrossDomain.ps1 ├── 6_Invoke-DoubleHop.ps1 ├── readme.md ├── RBKCD.md └── RBKCD.psm1 /PshSummit2017-AshleyMcGlone.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoateePFE/PshSummit2017/HEAD/PshSummit2017-AshleyMcGlone.pptx -------------------------------------------------------------------------------- /7_Reset.ps1: -------------------------------------------------------------------------------- 1 | # All computers with RB KCD configured 2 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Properties PrincipalsAllowedToDelegateToAccount -Server dc1.alpineskihouse.com | Format-List Name,PrincipalsAllowedToDelegateToAccount 3 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Properties PrincipalsAllowedToDelegateToAccount -Server dc.proseware.com | Format-List Name,PrincipalsAllowedToDelegateToAccount 4 | 5 | # Clear all computers with this configured 6 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Server dc1.alpineskihouse.com | % {Set-ADComputer -Identity $_ -PrincipalsAllowedToDelegateToAccount $null -Server dc1.alpineskihouse.com -Credential $DomainCCred} 7 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Server dc.proseware.com | % {Set-ADComputer -Identity $_ -PrincipalsAllowedToDelegateToAccount $null -Server dc.proseware.com -Credential $DomainBCred} 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ashley McGlone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /2_Functions.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | Import-Module C:\PshSummit\RBKCD.psm1 28 | Get-Command -Module RBKCD 29 | 30 | break 31 | 32 | Get-Help Enable-RBKCD -ShowWindow 33 | Get-Command Enable-RBKCD -Syntax 34 | 35 | # Get creds for both domains 36 | $DomainBCred = (Get-Credential proseware\administrator) 37 | $DomainCCred = (Get-Credential alpineskihouse\administrator) 38 | 39 | 40 | # Enable RB KCD 41 | $p = @{ 42 | ServerB = 'sb.proseware.com' 43 | ServerC = 'sc.proseware.com' 44 | Credential = $DomainBCred 45 | Verbose = $true 46 | } 47 | Enable-RBKCD @p 48 | 49 | Get-RBKCD -ServerC sc.proseware.com -DomainCCred $DomainBCred 50 | 51 | Invoke-Command -ComputerName sb -ScriptBlock { 52 | dir \\sc\C$ 53 | } 54 | 55 | Disable-RBKCD -ServerC sc.proseware.com -DomainCCred $DomainBCred 56 | 57 | # Try again to see failure without RB KCD 58 | -------------------------------------------------------------------------------- /5_OtherCases.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | break 28 | 29 | <# 30 | CASE: 31 | Workstation -> JumpServer -> Domain Controller 32 | #> 33 | 34 | $p = @{ 35 | ServerB = 'sb.proseware.com' 36 | ServerC = 'dc.proseware.com' 37 | Credential = $DomainBCred 38 | Verbose = $true 39 | } 40 | Enable-RBKCD @p 41 | 42 | Get-RBKCD -ServerC dc.proseware.com -DomainCCred $DomainBCred 43 | 44 | Enter-PSSession -ComputerName sb 45 | cd \ 46 | Get-Process lsass -ComputerName dc 47 | Get-EventLog -LogName System -Newest 1 -ComputerName dc 48 | #This line takes a while. 49 | #Get-Service -Name bits -ComputerName dc 50 | Get-DnsServer -ComputerName dc 51 | (Get-DnsServer -ComputerName dc).ServerSetting 52 | Add-DnsServerResourceRecordA -Name foo -IPv4Address 172.168.1.12 -ZoneName proseware.com -ComputerName dc -PassThru 53 | Remove-DnsServerResourceRecord -RRType A -Name foo -ZoneName proseware.com -ComputerName dc -PassThru -Force 54 | Exit-PSSession 55 | 56 | # Now demonstrate without RB KCD 57 | Disable-RBKCD -ServerC dc.proseware.com -DomainCCred $DomainBCred 58 | -------------------------------------------------------------------------------- /1_BasicDemo.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | break 28 | 29 | # proseware.com domain 30 | # servers: dc, sa, sb, sc 31 | 32 | $B = Get-ADComputer -Identity sb 33 | $C = Get-ADComputer -Identity sc 34 | 35 | # Test before the delegation 36 | $cred = Get-Credential proseware\administrator 37 | # Note that SMB firewall rule is enabled to allow SMB on server SC 38 | Invoke-Command -ComputerName $B.Name -Credential $cred -ScriptBlock { 39 | dir \\$($Using:C.Name)\C$ 40 | } 41 | 42 | # Allow ServerB to delegate to ServerC 43 | Set-ADComputer -Identity $C -PrincipalsAllowedToDelegateToAccount $B 44 | $void = Invoke-Command -ComputerName $B.Name -ScriptBlock { 45 | klist purge -li 0x3e7 46 | } 47 | 48 | # View the computer account attribute 49 | $ServerC = Get-ADComputer -Identity $C -Properties PrincipalsAllowedToDelegateToAccount,'msDS-AllowedToActOnBehalfOfOtherIdentity' 50 | $ServerC.PrincipalsAllowedToDelegateToAccount 51 | $ServerC.'msDS-AllowedToActOnBehalfOfOtherIdentity' 52 | $ServerC.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access 53 | 54 | # Test again with success now 55 | 56 | # Remove delegation 57 | Set-ADComputer -Identity $C -PrincipalsAllowedToDelegateToAccount $null 58 | 59 | # Test again with failure after removal 60 | -------------------------------------------------------------------------------- /4_InstallSoftware.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | break 28 | 29 | <# 30 | CASE: Install software on remote machines 31 | while pulling source from third server, 32 | in this case also in a different domain 33 | 34 | / ServerB \ 35 | ServerA -> ServerB -> ServerC 36 | \ ServerB / 37 | 38 | Invoke-Command 39 | Copy from ServerC 40 | Install software 41 | #> 42 | 43 | # Multiple ServerB 44 | # Enable RB KCD 45 | $p = @{ 46 | ServerB = 'sb.proseware.com','sc.proseware.com' 47 | ServerC = 'ms1.alpineskihouse.com' 48 | DomainBCred = $DomainBCred 49 | DomainCCred = $DomainCCred 50 | Verbose = $true 51 | } 52 | Enable-RBKCD @p 53 | 54 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 55 | 56 | # Try to install software on these three computers. 57 | # Pull source from "ServerC" in other domain. 58 | # Only SB and SC have been delegated. 59 | $Computers = 'sa','sb','sc' 60 | 61 | Invoke-Command -ComputerName $Computers -ScriptBlock { 62 | 63 | $ErrorActionPreference = 'Stop' 64 | Try { 65 | md C:\temp\ -ErrorAction SilentlyContinue | Out-Null 66 | 67 | # Must use SMB file copy. WinRM file copy not supported with RB KCD. 68 | # This line fails without RB KCD. 69 | Copy-Item -Path \\ms1.alpineskihouse.com\Source\LogParser.msi ` 70 | -Destination c:\temp\LogParser.msi -Force 71 | 72 | # Change /i to /x to uninstall 73 | $proc = Invoke-WMIMethod Win32_Process -name Create ` 74 | -ArgumentList 'msiexec /i "c:\temp\LogParser.msi" /qn /norestart' 75 | do {$a = Get-Process -Id $proc.processid -ErrorAction SilentlyContinue} 76 | While ($a -ne $null) 77 | 78 | "Software installed on $(hostname)" 79 | } 80 | Catch { 81 | "Error installing software on $(hostname)" 82 | } 83 | } 84 | 85 | 86 | # Validate install 87 | Invoke-Command -ComputerName $Computers -ScriptBlock { 88 | #dir c:\temp\ 89 | #Get-CimInstance -Query 'SELECT * FROM Win32_Product WHERE Name LIKE "%parser%"' 90 | #Get-Package 91 | "$(hostname) $(Test-Path 'C:\Program Files (x86)\Log Parser 2.2\LogParser.exe')" 92 | } 93 | 94 | 95 | 96 | # Turn off delegation 97 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 98 | 99 | Disable-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 100 | 101 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 102 | -------------------------------------------------------------------------------- /3_CrossDomain.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | break 28 | 29 | # Now go across domains 30 | 31 | # Direct success 32 | dir \\ms1.alpineskihouse.com\Source 33 | 34 | # Second hop failure 35 | Invoke-Command -ComputerName sb -ScriptBlock { 36 | dir \\ms1.alpineskihouse.com\Source 37 | } 38 | 39 | # Enable RB KCD 40 | $p = @{ 41 | ServerB = 'sb.proseware.com' 42 | ServerC = 'ms1.alpineskihouse.com' 43 | DomainBCred = $DomainBCred 44 | DomainCCred = $DomainCCred 45 | Verbose = $true 46 | } 47 | Enable-RBKCD @p 48 | 49 | # Validate 50 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 51 | 52 | 53 | # Second hop test 54 | # Success with RB KCD 55 | Invoke-Command -ComputerName sb -ScriptBlock { 56 | dir \\ms1.alpineskihouse.com\Source 57 | } 58 | # Failure without RB KCD (different ServerB for comparison) 59 | Invoke-Command -ComputerName sc -ScriptBlock { 60 | dir \\ms1.alpineskihouse.com\Source 61 | } 62 | 63 | 64 | # Multiple ServerB 65 | # Enable RB KCD 66 | $p = @{ 67 | ServerB = 'sa.proseware.com','sb.proseware.com','sc.proseware.com' 68 | ServerC = 'ms1.alpineskihouse.com' 69 | DomainBCred = $DomainBCred 70 | DomainCCred = $DomainCCred 71 | Verbose = $true 72 | } 73 | Enable-RBKCD @p 74 | 75 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 76 | 77 | 78 | # Second hop test 79 | Invoke-Command -ComputerName sa -ScriptBlock { 80 | dir \\ms1.alpineskihouse.com\Source 81 | } 82 | 83 | Invoke-Command -ComputerName sb -ScriptBlock { 84 | dir \\ms1.alpineskihouse.com\Source 85 | } 86 | 87 | Invoke-Command -ComputerName sc -ScriptBlock { 88 | dir \\ms1.alpineskihouse.com\Source 89 | } 90 | 91 | 92 | # Turn it off and try again 93 | Disable-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 94 | 95 | 96 | 97 | 98 | # Multiple ServerB & ServerC 99 | $p = @{ 100 | ServerB = 'sa.proseware.com','sb.proseware.com','sc.proseware.com' 101 | ServerC = 'ms1.alpineskihouse.com','dc1.alpineskihouse.com' 102 | DomainBCred = $DomainBCred 103 | DomainCCred = $DomainCCred 104 | Verbose = $true 105 | } 106 | Enable-RBKCD @p 107 | 108 | # Validate 109 | # cross-domain returns the SID 110 | Get-RBKCD -ServerC ms1.alpineskihouse.com -DomainCCred $DomainCCred 111 | Get-RBKCD -ServerC dc1.alpineskihouse.com -DomainCCred $DomainCCred 112 | 113 | Invoke-Command -ComputerName sa,sb,sc -ScriptBlock { 114 | dir \\ms1.alpineskihouse.com\source\*.msi -File 115 | } 116 | 117 | Invoke-Command -ComputerName sa,sb,sc -ScriptBlock { 118 | dir \\dc1.alpineskihouse.com\sysvol 119 | } 120 | 121 | 122 | 123 | # All computers with RB KCD configured 124 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Properties PrincipalsAllowedToDelegateToAccount -Server dc1.alpineskihouse.com | Format-List Name,PrincipalsAllowedToDelegateToAccount 125 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Properties PrincipalsAllowedToDelegateToAccount -Server dc.proseware.com | Format-List Name,PrincipalsAllowedToDelegateToAccount 126 | 127 | # Clear all computers with this configured 128 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Server dc1.alpineskihouse.com | % {Set-ADComputer -Identity $_ -PrincipalsAllowedToDelegateToAccount $null -Server dc1.alpineskihouse.com -Credential $DomainCCred} 129 | Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' -Server dc.proseware.com | % {Set-ADComputer -Identity $_ -PrincipalsAllowedToDelegateToAccount $null -Server dc.proseware.com -Credential $DomainBCred} 130 | -------------------------------------------------------------------------------- /6_Invoke-DoubleHop.ps1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | break 28 | 29 | # Avoid WinRM limitations of RB KCD by passing creds with $Using to the second hop 30 | 31 | $ServerB = 'sb' 32 | $ServerC = 'sc' 33 | 34 | $Cred = (Get-Credential proseware\administrator) 35 | 36 | # Works without RB KCD, passing creds again with $using: 37 | # NOTE: PSComputerName returns ServerB, not ServerC! 38 | Invoke-Command -ComputerName $ServerB -Credential $Cred -ScriptBlock { 39 | 40 | Invoke-Command -ComputerName $using:ServerC -Credential $using:Cred -ScriptBlock {"Invoked on ServerC: $(hostname)"} 41 | 42 | $cim = New-CimSession -ComputerName $using:ServerC -Credential $using:Cred 43 | Get-CimInstance -ClassName win32_computersystem -CimSession $cim 44 | Get-ScheduledTask -CimSession $cim | Select-Object -First 1 45 | Get-NetAdapter -CimSession $cim | Select-Object -First 1 46 | Remove-CimSession $cim 47 | 48 | } 49 | 50 | 51 | # Works across domains 52 | 53 | $ServerB = 'sb.proseware.com' 54 | $ServerC = 'ms1.alpineskihouse.com' 55 | 56 | $DomainBCred = (Get-Credential proseware\administrator) 57 | $DomainCCred = (Get-Credential alpineskihouse\administrator) 58 | 59 | # Works without RB KCD, passing creds again with $using: 60 | # NOTE: PSComputerName returns ServerB, not ServerC! 61 | Invoke-Command -ComputerName $ServerB -Credential $DomainBCred -ScriptBlock { 62 | 63 | Invoke-Command -ComputerName $using:ServerC -Credential $using:DomainCCred -ScriptBlock {"Invoked on ServerC: $(hostname)"} 64 | 65 | $cim = New-CimSession -ComputerName $using:ServerC -Credential $using:DomainCCred 66 | Get-CimInstance -ClassName win32_computersystem -CimSession $cim 67 | Get-ScheduledTask -CimSession $cim | Select-Object -First 1 68 | Get-NetAdapter -CimSession $cim | Select-Object -First 1 69 | Remove-CimSession $cim 70 | 71 | } 72 | 73 | 74 | 75 | # Helper function INVOKE-DOUBLEHOP 76 | Import-Module C:\PshSummit\RBKCD.psm1 77 | Get-Command -Module RBKCD 78 | 79 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 80 | dir \\dc\c$ 81 | } 82 | 83 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 84 | $PSSenderInfo 85 | $PSSenderInfo.UserInfo.Identity 86 | $PSSenderInfo.UserInfo.WindowsIdentity 87 | } 88 | 89 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 90 | hostname 91 | $env:COMPUTERNAME 92 | Get-WmiObject Win32_ComputerSystem 93 | Get-CimInstance Win32_ComputerSystem 94 | } 95 | 96 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 97 | Unlock-ADAccount -Identity alice -Verbose 98 | } 99 | 100 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 101 | Get-WinEvent -LogName Microsoft-Windows-WinRM/Operational -MaxEvents 5 102 | } 103 | 104 | 105 | # Now cross-domain 106 | 107 | $p = @{ 108 | ServerB = 'sb' 109 | ServerC = 'dc1.alpineskihouse.com' 110 | DomainBCred = $DomainBCred 111 | DomainCCred = $DomainCCred 112 | } 113 | 114 | Invoke-DoubleHop @p -Scriptblock { 115 | dir C:\ 116 | } 117 | 118 | Invoke-DoubleHop @p -Scriptblock { 119 | $env:COMPUTERNAME 120 | $PSSenderInfo 121 | } 122 | 123 | Invoke-DoubleHop @p -Scriptblock { 124 | hostname 125 | $env:COMPUTERNAME 126 | Get-WmiObject Win32_ComputerSystem 127 | Get-CimInstance Win32_ComputerSystem 128 | } 129 | 130 | Invoke-DoubleHop @p -Scriptblock { 131 | Unlock-ADAccount -Identity alice -Verbose 132 | } 133 | 134 | 135 | # Now criss-cross-domain 136 | # proseware -> alpineskihouse -> proseware 137 | 138 | $p = @{ 139 | ServerB = 'ms1.alpineskihouse.com' 140 | ServerC = 'sb.proseware.com' 141 | DomainBCred = $DomainCCred 142 | DomainCCred = $DomainBCred 143 | } 144 | 145 | Invoke-DoubleHop @p -Scriptblock { 146 | dir \\sb\C$ 147 | } 148 | 149 | Invoke-DoubleHop @p -Scriptblock { 150 | $env:COMPUTERNAME 151 | $PSSenderInfo 152 | $PSSenderInfo.UserInfo.Identity 153 | $PSSenderInfo.UserInfo.WindowsIdentity 154 | } 155 | 156 | Invoke-DoubleHop @p -Scriptblock { 157 | hostname 158 | $env:COMPUTERNAME 159 | Get-WmiObject Win32_ComputerSystem 160 | Get-CimInstance Win32_ComputerSystem 161 | } 162 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## PowerShell Remoting and Kerberos Double Hop: Old Problem - New Secure Solution 2 | 3 | ## PowerShell and DevOps Global Summit 2017 4 | 5 | This week I enjoyed presenting at the annual PowerShell Summit. 6 | If you have not attended, I highly encourage it. 7 | You will get to meet PowerShell team members from Microsoft, MVPs, and the people you follow on Twitter! 8 | Follow [@PshSummit](https://twitter.com/PSHSummit) on Twitter to get the alerts for registration. 9 | I even work for Microsoft, and I learn a ton every year from the amazing sessions. 10 | It is also great connecting with everyone in the PowerShell community. 11 | 12 | ## tl;dr 13 | * This is a follow up to my [previous blog post](https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/) on Kerberos double hop and PowerShell remoting. 14 | * I have published some helper functions for working with **resource-based Kerberos constrained delegation** (**RB KCD**) and PowerShell remoting: `Enable-RBKCD`, `Disable-RBKCD`, `Get-RBKCD`. 15 | * Get the files and slides [on my GitHub here](https://github.com/GoateePFE/PshSummit2017). 16 | * RB KCD works with a limited set of commands and functions running under SYSTEM account in the kernel context. 17 | * RB KCD does not support WinRM / PowerShell remoting, because that runs under the NETWORK account. 18 | * For cases where RB KCD does not work you can nest two `Invoke-Command` statements to make the double hop. See helper function `Invoke-DoubleHop`. 19 | 20 | ## The Problem 21 | ### Classic Kerberos Double Hop 22 | I am on *ServerA*, connected to *ServerB* where I need to reach *ServerC*. 23 | I have permissions to ServerC, but I still get *Access Denied*. 24 | Default Kerberos rules prevent ServerB from passing credentials to ServerC. 25 | The most common examle is a user (ServerA) connected to a web server (ServerB/frontend) that needs to use the user's credentials to access a database server (ServerC/backend). 26 | In a [previous blog post](https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/) I described multiple popular (and not-so-popular) work-arounds. 27 | 28 | ### Scenario A: Jump Server 29 | From my workstation I connect to my jump server (tool server, etc. whatever you like to call it) via PowerShell remoting (`Enter-PSSession`, `Invoke-Command`). 30 | From that server I want to reach out and collect data from multiple other servers for a report. 31 | I am in the Administrators group on all of these servers, but I get an *Access Denied* when attempting to access them from my jump server. 32 | 33 | Why not connect directly to the servers? Perhaps I have limited network connectivity or restricted routing. 34 | Maybe it is a DMZ or a hosted environment. 35 | There are many legitimate scenarios why you may choose this approach. 36 | 37 | ### Scenario B: Remote Software Install 38 | Another popular scenario is installing software remotely. 39 | From my workstation (ServerA) I want to fan out to 50 servers (ServerB) and install an application whose source files are hosted on a file share (ServerC). 40 | Here again I will get *Access Denied* at the file share even though I know I have permissions. 41 | This is Kerberos double hop. 42 | 43 | ### Scenario X 44 | There are many more scenarios for Kerberos double hop. 45 | RB KCD will help with some of them. 46 | `Invoke-DoubleHop` should help with more of them. 47 | And some will likely have no other choice but to continue using *CredSSP* for the time being. 48 | You will need to experiment to see which commands are compatible with RB KCD (running as SYSTEM in kernel context). 49 | 50 | For example, from your workstation you connect to your SharePoint server with PowerShell remoting. 51 | The SharePoint cmdlets need to access a backend SQL server, but they fail. 52 | Typically CredSSP is the solution. 53 | I have some peers who have not been successful yet getting RB KCD to work with this case. 54 | I suspicion that it would need to be configured on service accounts and may work then. 55 | Let me know if you figure this one out. 56 | 57 | ## PowerShell and DevOps Global Summit 2017 58 | In a [previous blog post](https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/) I described the benefits of *resource-based Kerberos constrained delegation* and how it can apply to PowerShell remoting. 59 | It is not a complete solution, but it works for the key scenarios described above and a few others. 60 | The PowerShell documentation team took that article, tweaked it, and turned it into a documentation page [here](https://msdn.microsoft.com/en-us/powershell/scripting/setup/ps-remoting-second-hop). 61 | 62 | This week I presented the topic and demos at the **PowerShell and DevOps Global Summit 2017**. 63 | The demos files and slides are available [on my GitHub here](https://github.com/GoateePFE/PshSummit2017). 64 | 65 | ## Two Solutions, One Module 66 | I created a helper module for quickly configuring RB KCD and for cheating with nested `Invoke-Command` commands. 67 | 68 | ``` 69 | PS> Import-Module rbkcd.psm1 70 | 71 | PS> Get-Command -Module RBKCD 72 | 73 | CommandType Name Version Source 74 | ----------- ---- ------- ------ 75 | Function Disable-RBKCD 0.0 RBKCD 76 | Function Enable-RBKCD 0.0 RBKCD 77 | Function Get-RBKCD 0.0 RBKCD 78 | Function Invoke-DoubleHop 0.0 RBKCD 79 | ``` 80 | 81 | Here are some examples: 82 | ```PowerShell 83 | # Both ServerB and ServerC in the same domain. 84 | Enable-RBKCD -ServerB sb.proseware.com -ServerC sc.proseware.com -Credential (Get-Credential) 85 | 86 | # ServerB and ServerC in different domains. 87 | Enable-RBKCD -ServerB sb.proseware.com -ServerC ms1.alpineskihouse.com -DomainBCred (Get-Credential) -DomainCCred (Get-Credential) 88 | 89 | # See which identities are allowed to delegate to ServerC 90 | Get-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 91 | 92 | # Remove all identities allowed to delegate to ServerC 93 | Disable-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 94 | 95 | # For scenarios that do not work with RB KCD 96 | Invoke-DoubleHop -ServerB sb -ServerC sc -DomainBCred $DomainBCred -Scriptblock { 97 | dir \\sc\c$ 98 | } 99 | ``` 100 | 101 | While these functions were written to help with RB KCD for PowerShell remoting, they could be used for any other RB KCD scenario. 102 | Note that these only work with computer accounts. 103 | You could expand the code to work with service accounts or user accounts also. 104 | 105 | You can share these RB KCD articles and scripts with this short link: [http://aka.ms/pskdh](http://aka.ms/pskdh) 106 | 107 | ## Enjoy 108 | 109 | This is a bit of a niche topic, but lots of people struggle with it. Hopefully this was helpful. 110 | **Please use the comments below to help the community understand where this was helpful for you and where is was *not* helpful.** This is an on-going research project for me, and your feedback is valuable. 111 | -------------------------------------------------------------------------------- /RBKCD.md: -------------------------------------------------------------------------------- 1 | # Help for module RBKCD 2 | 3 | ## Disable-RBKCD 4 | 5 | ### Synopsis 6 | Removes all accounts allowed to delegate to ServerC 7 | 8 | ### Description 9 | Sets the msDS-AllowedToActOnBehalfOfOtherIdentity computer object attribute to $null (by using the aliased attribute PrincipalsAllowedToDelegateToAccount) 10 | 11 | ### Parameters 12 | 13 | -ServerC 14 | FQDN of ServerC 15 | 16 | Required? true 17 | Position? 1 18 | Default value 19 | Accept pipeline input? false 20 | Accept wildcard characters? false 21 | 22 | 23 | -DomainCCred 24 | Credential to edit the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only 25 | needs delegated authority to the computer object. 26 | Will prompt for credential if not provided 27 | 28 | Required? true 29 | Position? 2 30 | Default value (Get-Credential -Message 'DomainC credential') 31 | Accept pipeline input? false 32 | Accept wildcard characters? false 33 | 34 | 35 | ### Examples 36 | -------------------------- EXAMPLE 1 -------------------------- 37 | 38 | ``` 39 | PS C:\> Disable-RBKCD -ServerC sc.proseware.com 40 | 41 | ``` 42 | -------------------------- EXAMPLE 2 -------------------------- 43 | 44 | ``` 45 | PS C:\> Disable-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 46 | 47 | ``` 48 | 49 | ## Enable-RBKCD 50 | 51 | ### Synopsis 52 | Enables Resource-Based Kerberos Constrained Delegation for ServerB to access ServerC 53 | 54 | ### Description 55 | Enables Resource-Based Kerberos Constrained Delegation for one or more ServerB computers to access one or more ServerC computers. Optionally, these computers can reside in separate domains, requiring two sets of credentials for the command. 56 | 57 | ### Parameters 58 | 59 | -ServerB 60 | FQDN of ServerB. Accepts an array. 61 | 62 | Required? true 63 | Position? named 64 | Default value 65 | Accept pipeline input? false 66 | Accept wildcard characters? false 67 | 68 | 69 | -ServerC 70 | FQDN of ServerC. Accepts an array. 71 | 72 | Required? true 73 | Position? named 74 | Default value 75 | Accept pipeline input? false 76 | Accept wildcard characters? false 77 | 78 | 79 | -Credential 80 | Credential when both ServerB and ServerC are in the same domain. 81 | 82 | Required? true 83 | Position? named 84 | Default value 85 | Accept pipeline input? false 86 | Accept wildcard characters? false 87 | 88 | 89 | -DomainBCred 90 | Credential to query the domain of the ServerB computer account, also having admin rights on ServerB. 91 | 92 | Required? true 93 | Position? named 94 | Default value 95 | Accept pipeline input? false 96 | Accept wildcard characters? false 97 | 98 | 99 | -DomainCCred 100 | Credential to update the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only 101 | needs delegated authority to the computer object. 102 | 103 | Required? true 104 | Position? named 105 | Default value 106 | Accept pipeline input? false 107 | Accept wildcard characters? false 108 | 109 | 110 | ### Notes 111 | This code is still a work in progress. There are some obvious areas for optimization. 112 | 113 | ### Examples 114 | -------------------------- EXAMPLE 1 -------------------------- 115 | 116 | ``` 117 | PS C:\> Enable-RBKCD -ServerB sb.proseware.com -ServerC sc.proseware.com -Credential (Get-Credential) 118 | Both ServerB and ServerC in the same domain. 119 | 120 | ``` 121 | -------------------------- EXAMPLE 2 -------------------------- 122 | 123 | ``` 124 | PS C:\> Enable-RBKCD -ServerB sb.proseware.com -ServerC ms1.alpineskihouse.com -DomainBCred (Get-Credential) -DomainCCred (Get-Credential) 125 | ServerB and ServerC in different domains. 126 | 127 | ``` 128 | -------------------------- EXAMPLE 3 -------------------------- 129 | 130 | ``` 131 | PS C:\> Enable-RBKCD -ServerB sa.proseware.com,sb.proseware.com,sc.proseware.com -ServerC ms1.alpineskihouse.com,ms1.alpineskihouse.com -DomainBCred (Get-Credential) -DomainCCred (Get-Credential) 132 | Multiple ServerB and multiple ServerC in different domains. 133 | If passing multiples to either server parameter, they must be in the same domain. This is a limitation of the way the code is written. It is not a limitation of resource-based kerberos constrained delegation. 134 | 135 | ``` 136 | 137 | ## Get-RBKCD 138 | 139 | ### Synopsis 140 | Displays the identities allowed to delegate to ServerC 141 | 142 | ### Description 143 | Retrives the msDS-AllowedToActOnBehalfOfOtherIdentity computer object attribute which contains an ACL. Displays only the identity portion of the ACL. 144 | 145 | ### Parameters 146 | 147 | -ServerC 148 | FQDN of ServerC 149 | 150 | Required? true 151 | Position? 1 152 | Default value 153 | Accept pipeline input? false 154 | Accept wildcard characters? false 155 | 156 | 157 | -DomainCCred 158 | Credential to view the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only 159 | needs delegated authority to the computer object. 160 | Will prompt for credential if not provided 161 | 162 | Required? true 163 | Position? 2 164 | Default value (Get-Credential -Message 'DomainC credential') 165 | Accept pipeline input? false 166 | Accept wildcard characters? false 167 | 168 | 169 | ### Examples 170 | -------------------------- EXAMPLE 1 -------------------------- 171 | 172 | ``` 173 | PS C:\> Get-RBKCD -ServerC sc.proseware.com 174 | 175 | ``` 176 | -------------------------- EXAMPLE 2 -------------------------- 177 | 178 | ``` 179 | PS C:\> Get-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 180 | 181 | ``` 182 | 183 | ## Invoke-DoubleHop 184 | 185 | ### Synopsis 186 | Nested Invoke-Command from ServerB to ServerC 187 | 188 | ### Description 189 | Passes fresh credentials to ServerC Invoke-Command from a nested Invoke-Command on ServerB with $using:. 190 | 191 | ### Parameters 192 | 193 | -ServerB 194 | First hop computer 195 | 196 | Required? true 197 | Position? 1 198 | Default value 199 | Accept pipeline input? false 200 | Accept wildcard characters? false 201 | 202 | 203 | -ServerC 204 | Second hop computer 205 | 206 | Required? true 207 | Position? 2 208 | Default value 209 | Accept pipeline input? false 210 | Accept wildcard characters? false 211 | 212 | 213 | -DomainBCred 214 | Credentials to access ServerB 215 | 216 | Required? true 217 | Position? 3 218 | Default value 219 | Accept pipeline input? false 220 | Accept wildcard characters? false 221 | 222 | 223 | -DomainCCred 224 | Credentials to access ServerC. This can be omitted if both ServerB and ServerC are in the same domain. 225 | 226 | Required? false 227 | Position? 4 228 | Default value 229 | Accept pipeline input? false 230 | Accept wildcard characters? false 231 | 232 | 233 | -Scriptblock 234 | 235 | Required? true 236 | Position? 5 237 | Default value 238 | Accept pipeline input? false 239 | Accept wildcard characters? false 240 | 241 | 242 | ### Notes 243 | The output PSComputerName property reflects ServerB, while the output is actually from ServerC. 244 | 245 | ### Examples 246 | -------------------------- EXAMPLE 1 -------------------------- 247 | 248 | ``` 249 | PS C:\> Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 250 | dir \\dc\c$ 251 | } 252 | 253 | ``` 254 | -------------------------- EXAMPLE 2 -------------------------- 255 | 256 | ``` 257 | PS C:\> $p = @{ 258 | ServerB = 'sb' 259 | ServerC = 'dc1.alpineskihouse.com' 260 | DomainBCred = (Get-Credential) 261 | DomainCCred = (Get-Credential) 262 | } 263 | 264 | Invoke-DoubleHop @p -Scriptblock { 265 | dir C:\ 266 | } 267 | 268 | ``` 269 | -------------------------------------------------------------------------------- /RBKCD.psm1: -------------------------------------------------------------------------------- 1 | <############################################################################## 2 | Ashley McGlone 3 | Microsoft Premier Field Engineer 4 | April 2017 5 | http://aka.ms/GoateePFE 6 | 7 | This script is part of a demo of Kerberos Double Hop mitigations in 8 | PowerShell. Presented at the PowerShell and DevOps Global Summit 2017. 9 | http://aka.ms/pskdh 10 | 11 | LEGAL DISCLAIMER 12 | This Sample Code is provided for the purpose of illustration only and is not 13 | intended to be used in a production environment. THIS SAMPLE CODE AND ANY 14 | RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 15 | EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. We grant You a 17 | nonexclusive, royalty-free right to use and modify the Sample Code and to 18 | reproduce and distribute the object code form of the Sample Code, provided 19 | that You agree: (i) to not use Our name, logo, or trademarks to market Your 20 | software product in which the Sample Code is embedded; (ii) to include a valid 21 | copyright notice on Your software product in which the Sample Code is embedded; 22 | and (iii) to indemnify, hold harmless, and defend Us and Our suppliers from and 23 | against any claims or lawsuits, including attorneys’ fees, that arise or result 24 | from the use or distribution of the Sample Code. 25 | ##############################################################################> 26 | 27 | <# 28 | .SYNOPSIS 29 | Displays the identities allowed to delegate to ServerC 30 | .DESCRIPTION 31 | Retrives the msDS-AllowedToActOnBehalfOfOtherIdentity computer object attribute which contains an ACL. Displays only the identity portion of the ACL. 32 | .PARAMETER ServerC 33 | FQDN of ServerC 34 | .PARAMETER DomainCCred 35 | Credential to view the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only needs delegated authority to the computer object. 36 | Will prompt for credential if not provided 37 | .EXAMPLE 38 | Get-RBKCD -ServerC sc.proseware.com 39 | .EXAMPLE 40 | Get-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 41 | .LINK 42 | http://aka.ms/pskdh 43 | #> 44 | Function Get-RBKCD { 45 | param( 46 | [Parameter(Mandatory=$true)] 47 | [ValidatePattern('\w+\.\w+\.\w+')] 48 | [string] 49 | $ServerC, 50 | [Parameter(Mandatory=$true)] 51 | [PSCredential] 52 | $DomainCCred = (Get-Credential -Message 'DomainC credential') 53 | ) 54 | "Computers configured for resource-based Kerberos constrained delegation to $ServerC" 55 | (Get-ADComputer -Identity $ServerC.Substring(0,$ServerC.IndexOf('.')) -Credential $DomainCCred -Server $ServerC.Substring($ServerC.IndexOf('.')+1) -Properties 'msDS-AllowedToActOnBehalfOfOtherIdentity').'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access.IdentityReference.Value 56 | } 57 | 58 | 59 | <# 60 | .SYNOPSIS 61 | Removes all accounts allowed to delegate to ServerC 62 | .DESCRIPTION 63 | Sets the msDS-AllowedToActOnBehalfOfOtherIdentity computer object attribute to $null (by using the aliased attribute PrincipalsAllowedToDelegateToAccount) 64 | .PARAMETER ServerC 65 | FQDN of ServerC 66 | .PARAMETER DomainCCred 67 | Credential to edit the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only needs delegated authority to the computer object. 68 | Will prompt for credential if not provided 69 | .EXAMPLE 70 | Disable-RBKCD -ServerC sc.proseware.com 71 | .EXAMPLE 72 | Disable-RBKCD -ServerC sc.proseware.com -Credential (Get-Credential proseware\adminacct) 73 | .LINK 74 | http://aka.ms/pskdh 75 | #> 76 | Function Disable-RBKCD { 77 | param( 78 | [Parameter(Mandatory=$true)] 79 | [ValidatePattern('\w+\.\w+\.\w+')] 80 | [string] 81 | $ServerC, 82 | [Parameter(Mandatory=$true)] 83 | [PSCredential] 84 | $DomainCCred = (Get-Credential -Message 'DomainC credential') 85 | ) 86 | Set-ADComputer -Identity $ServerC.Substring(0,$ServerC.IndexOf('.')) -Credential $DomainCCred -Server $ServerC.Substring($ServerC.IndexOf('.')+1) -PrincipalsAllowedToDelegateToAccount $null 87 | } 88 | 89 | 90 | <# 91 | .SYNOPSIS 92 | Enables Resource-Based Kerberos Constrained Delegation for ServerB to access ServerC 93 | .DESCRIPTION 94 | Enables Resource-Based Kerberos Constrained Delegation for one or more ServerB computers to access one or more ServerC computers. Optionally, these computers can reside in separate domains, requiring two sets of credentials for the command. 95 | .PARAMETER ServerB 96 | FQDN of ServerB. Accepts an array. 97 | .PARAMETER ServerC 98 | FQDN of ServerC. Accepts an array. 99 | .PARAMETER Credential 100 | Credential when both ServerB and ServerC are in the same domain. 101 | .PARAMETER DomainBCred 102 | Credential to query the domain of the ServerB computer account, also having admin rights on ServerB. 103 | .PARAMETER DomainCCred 104 | Credential to update the ServerC computer account from the domain where ServerC resides. Can be a domain admin, but only needs delegated authority to the computer object. 105 | .EXAMPLE 106 | Enable-RBKCD -ServerB sb.proseware.com -ServerC sc.proseware.com -Credential (Get-Credential) 107 | Both ServerB and ServerC in the same domain. 108 | .EXAMPLE 109 | Enable-RBKCD -ServerB sb.proseware.com -ServerC ms1.alpineskihouse.com -DomainBCred (Get-Credential) -DomainCCred (Get-Credential) 110 | ServerB and ServerC in different domains. 111 | .EXAMPLE 112 | Enable-RBKCD -ServerB sa.proseware.com,sb.proseware.com,sc.proseware.com -ServerC ms1.alpineskihouse.com,ms1.alpineskihouse.com -DomainBCred (Get-Credential) -DomainCCred (Get-Credential) 113 | Multiple ServerB and multiple ServerC in different domains. 114 | If passing multiples to either server parameter, they must be in the same domain. This is a limitation of the way the code is written. It is not a limitation of resource-based kerberos constrained delegation. 115 | .NOTES 116 | This code is still a work in progress. There are some obvious areas for optimization. 117 | .LINK 118 | http://aka.ms/pskdh 119 | #> 120 | Function Enable-RBKCD { 121 | [CmdletBinding()] 122 | param( 123 | [Parameter(Mandatory=$true,ParameterSetName='1')] 124 | [Parameter(Mandatory=$true,ParameterSetName='2')] 125 | [ValidatePattern('\w+\.\w+\.\w+')] 126 | [string[]] 127 | $ServerB, 128 | [Parameter(Mandatory=$true,ParameterSetName='1')] 129 | [Parameter(Mandatory=$true,ParameterSetName='2')] 130 | [ValidatePattern('\w+\.\w+\.\w+')] 131 | [string[]] 132 | $ServerC, 133 | [Parameter(Mandatory=$true,ParameterSetName='1')] 134 | [PSCredential] 135 | $Credential, 136 | [Parameter(Mandatory=$true,ParameterSetName='2')] 137 | [PSCredential] 138 | $DomainBCred, 139 | [Parameter(Mandatory=$true,ParameterSetName='2')] 140 | [PSCredential] 141 | $DomainCCred 142 | ) 143 | If (!$PSBoundParameters.ContainsKey('DomainCCred')) {$DomainCCred = $DomainBCred = $Credential} 144 | 145 | # Split out the hostname and domain name portions of the FQDN where appropriate 146 | 147 | ForEach ($ServerCEach in $ServerC) { 148 | $C = Get-ADComputer -Identity $ServerCEach.Substring(0,$ServerCEach.IndexOf('.')) -Credential $DomainCCred -Server $ServerCEach.Substring($ServerCEach.IndexOf('.')+1) -Properties 'msDS-AllowedToActOnBehalfOfOtherIdentity' 149 | 150 | # We don't want to overwrite any pre-existing allowed delegations 151 | If ($C.'msDS-AllowedToActOnBehalfOfOtherIdentity') { 152 | $NullGuid = [GUID]'00000000-0000-0000-0000-000000000000' 153 | 154 | ForEach ($ServerBEach in $ServerB) { 155 | 156 | Write-Verbose "Allowing $ServerBEach to delegate to $ServerCEach" 157 | 158 | $B = Get-ADComputer -Identity $ServerBEach.Substring(0,$ServerBEach.IndexOf('.')) -Credential $DomainBCred -Server $ServerBEach.Substring($ServerBEach.IndexOf('.')+1) 159 | 160 | # Ran into difficulty appending computers to PrincipalsAllowedToDelegateToAccount. 161 | # Did this the hard way by directly updating the ACL stored in msDS-AllowedToActOnBehalfOfOtherIdentity. 162 | # There should be a better way to do this. 163 | $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $B.SID, 'GenericAll', 'Allow', $NullGuid, 'None', $NullGuid 164 | $C.'msDS-AllowedToActOnBehalfOfOtherIdentity'.AddAccessRule($ACE) 165 | 166 | $void = Invoke-Command -ComputerName $B.Name -Credential $DomainBCred -ScriptBlock { 167 | klist purge -li 0x3e7 168 | } 169 | } 170 | 171 | # Could not get the Instance parameter to set the value, so changed method. 172 | #Set-ADComputer -Instance $C -Credential $DomainCCred -Server $ServerC.Substring($ServerC.IndexOf('.')+1) 173 | Set-ADObject -Identity $C -Replace @{'msDS-AllowedToActOnBehalfOfOtherIdentity'=$C.'msDS-AllowedToActOnBehalfOfOtherIdentity'} -Credential $DomainCCred -Server $ServerCEach.Substring($ServerCEach.IndexOf('.')+1) 174 | 175 | } Else { 176 | 177 | # If there are no other current delegations 178 | $B = ForEach ($ServerBEach in $ServerB) { 179 | Write-Verbose "Allowing $ServerBEach to delegate to $ServerCEach" 180 | Get-ADComputer -Identity $ServerBEach.Substring(0,$ServerBEach.IndexOf('.')) -Credential $DomainBCred -Server $ServerBEach.Substring($ServerBEach.IndexOf('.')+1) 181 | } 182 | Set-ADComputer -Identity $C -PrincipalsAllowedToDelegateToAccount $B -Credential $DomainCCred -Server $ServerCEach.Substring($ServerCEach.IndexOf('.')+1) 183 | 184 | $void = Invoke-Command -ComputerName $B.Name -Credential $DomainBCred -ScriptBlock { 185 | klist purge -li 0x3e7 186 | } 187 | } 188 | } 189 | } 190 | 191 | 192 | <# 193 | .SYNOPSIS 194 | Nested Invoke-Command from ServerB to ServerC 195 | .DESCRIPTION 196 | Passes fresh credentials to ServerC Invoke-Command from a nested Invoke-Command on ServerB with $using:. 197 | .PARAMETER ServerB 198 | First hop computer 199 | .PARAMETER ServerC 200 | Second hop computer 201 | .PARAMETER DomainBCred 202 | Credentials to access ServerB 203 | .PARAMETER DomainCCred 204 | Credentials to access ServerC. This can be omitted if both ServerB and ServerC are in the same domain. 205 | .EXAMPLE 206 | Invoke-DoubleHop -ServerB sb -ServerC dc -DomainBCred $DomainBCred -Scriptblock { 207 | dir \\dc\c$ 208 | } 209 | .EXAMPLE 210 | $p = @{ 211 | ServerB = 'sb' 212 | ServerC = 'dc1.alpineskihouse.com' 213 | DomainBCred = (Get-Credential) 214 | DomainCCred = (Get-Credential) 215 | } 216 | Invoke-DoubleHop @p -Scriptblock { 217 | dir C:\ 218 | } 219 | .NOTES 220 | The output PSComputerName property reflects ServerB, while the output is actually from ServerC. 221 | .LINK 222 | http://aka.ms/pskdh 223 | #> 224 | Function Invoke-DoubleHop { 225 | [CmdletBinding()] 226 | param( 227 | [parameter(mandatory=$true)] 228 | [string] 229 | $ServerB, 230 | [parameter(mandatory=$true)] 231 | [string] 232 | $ServerC, 233 | [parameter(mandatory=$true)] 234 | [PSCredential] 235 | $DomainBCred, 236 | [PSCredential] 237 | $DomainCCred, 238 | [parameter(mandatory=$true)] 239 | [Scriptblock] 240 | $Scriptblock 241 | ) 242 | If (!$PSBoundParameters.ContainsKey('DomainCCred')) {$DomainCCred = $DomainBCred} 243 | Write-Warning 'PSComputerName property reflects ServerB, while the output is actually from ServerC.' 244 | 245 | Invoke-Command -ComputerName $ServerB -Credential $DomainBCred -Verbose -ScriptBlock { 246 | # The Scriptblock gets serialized to a string when used remotely. 247 | # Recast it as a scriptblock. 248 | # Yes, this is a violation of PowerShell security best practices. 249 | $sb2 = [scriptblock]::Create($using:Scriptblock) 250 | Invoke-Command -ComputerName $using:ServerC -Credential $using:DomainCCred -ScriptBlock $sb2 251 | } 252 | } 253 | --------------------------------------------------------------------------------