Thursday, 5 July 2018

Locking down remote Powershell users access with restrained endpoints

The aim of this tutorial is to ensure that a restrictive session configuration is applied for specific users when they login remotely to a server via powershell and limit them to specific commands (applying a default deny all approach.) In addition all commands will be executed by a service account since we do not want our users to process any administrative rights on the server / domain.

We'll apply this using a Powershell Session Configuration - this is a type of policy that is executed  when you login via Powershell / PSSession to a remote computer.

The default session configuration carries very few restrictions and allows the users to run all sorts of potentially dangerous commands - for example: Stop-Service and so on.

We will also make use of 'proxy commands' - these allow us implement (or expand) our our own functions. For example the following command:

Get-Service Spooler | Restart-Service

could be implemented as a custom function:

Restart-SpoolerService

This provide us with two benefits:

- We can write complex / chained commands more concisely

- But more importantly it provides granular control on what exactly can be executed. For example simply restricting the a normal cmdlet e.g. Get-User would allow a user to execute the following:

Get-User -Identity userA
Get-User -Identity userB

While we might want to allow access to userA's information - we don't necessarily want to provide access to userB's information - so instead the proxy command can encapsulate 'Get-User -Identity userA'.

i.e. The proxy command 'Get-UserA' == 'Get-User -Identity userA'.

We'll start by firstly creating a new session configuration:

Note: We can use the 'New-PSSessionConfiguration' cmdlet to generate a session configuration for us - however in this example we will be manually creating it - so firstly save a file named C:\scripts\restricted_session_config.ps1 with the following:

$RequiredCommands = @("Get-Command", "Get-FormatData", "Out-Default", "Select-Object", "out-file", "Measure-Object", "Exit-PSSession" )
$ExecutionContext.SessionState.Applications.Clear()
$ExecutionContext.SessionState.Scripts.Clear()
Get-Command -CommandType Cmdlet, alias, function | ?{$RequiredCommands -notcontains $_.Name} | %{$_.Visibility="Private"}
$ExecutionContext.SessionState.LanguageMode="RestrictedLanguage"

This will limit the commands to: Get-Command, Get-FormatData, Out-Default, Select-Object, out-file, Measure-Object and Exit-PSSession.

We'll now need to register our new session config with:

Register-PSSessionConfiguration -Name "RestrictedUser" -StartupScript C:\scripts\restricted_session_config.ps1

Note: If you need to perform administrative operations on the server we will need to apply delegated administration - this simply means we will have a dedicated service account that has the appropriate administrative rights. When users connect to the powershell session all operations will be executed under this user account - to do this we'd issue the following instead:

Register-PSSessionConfiguration -Name "RestrictedUser" -StartupScript C:\scripts\restricted_session_config.ps1 -RunAsCredential 'server01\serviceaccount' -Force

If we now remote into the above server and run 'Get-PSSessionConfiguration' we should now see it listed.

The next step is to ensure that our limited user has the appropriate permissions on the session configuration -

Set-PSSessionConfiguration "RestrictedUser" -ShowSecurityDescriptorUI

This opens up an GUI ACL window where we will add our limited user and ensure they ONLY have 'Execute' permissions!

We need to specify the session configuration (from the client side) when connecting otherwise it will attempt to apply the default session configuration (that is only available to local administrators by default and as a result will deny access to the user.):

Enter-PSSession -ConfigurationName "RestrictedUser" <server-name>

or alternatively we can set the local variable 'PSSessionConfigurationName':

$PSSessionConfigurationName = "RestrictedUser"

We can quickly verify the policy has been applied by issuing:

Get-Commands

The final step is to create our proxy commands - so we need to append the following to our 'restricted_session_config.ps1' file on the server:

Function Hello-Function{
  Write-Output "Hello World"
}

NOTE: Make sure you add the 'Hello Function' into the 'RequiredCommands' section within the session configuration script as well!

To test connect to the server:

Enter-PSSession <server-name> -ConfigurationName RestrictedUser

and finally test the function:

Hello-Function