Constrained endpoint on specific user - powershell

I'm trying to create a PowerShell endpoint constraint that restricts an user to only execute the functions in a custom module I made.
The first thing I did is import-module mymodule.psm1 which allows me to run my modules fine withing my host system.
Then the following PS command creates the configuration file for the endpoint which allows the functions inside the brackets to be the only functions the user gets to execute.
New-PSSessionConfigurationFile -VisibleFunctions('Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon') -LanguageMode ‘ConstrainedLanguage’ –SessionType ‘RestrictedRemoteServer’ –Path ‘c:\test\helpdesk.pssc’
Then I register the endpoint with
Register-PSSessionConfiguration –Name ‘HelpDesk’ -ShowSecurityDescriptorUI –Path ‘c:\test\helpdesk.pssc’
and selected which user I want allow to have these constrains once the SecurityDescriptorUI pops up. Once I log into the user that I set up the constrains for with
Enter-PSSession -computername SRV1-AD -Credential $credential -ConfigurationName HelpDesk
These are the allowed cmdlets / functions that the user is allowed to execute. These are the default required cmdlets to allow remote connections into a system.
How can I allow my custom module to be the only functions the endpoint allows users to execute? or How can I import my module into configuration file so it executes every time the HelpDesk end point configuration is used. I know that in the configuration file there's a line to import modules but Import-Module is not actually a module an example of a module would be ActiveDirectory, if I'm able to find what module import-module is a part of I think I should be able to do a quick and dirty work around for this.
UPDATE
A dirty solution I found for this was to enter into the user's session and disable all cmdlets / functions except the ones I want to allowed for example import-module & Get-Command with import-module I can manually import my custom module and my functions will be the only ones visible to user. But this is not a perfect solution because this means that I would need to download my module into every system I want this to take effect and it's no longer a one to many solution. The ideal solution is to have my module locally stored, enter into a session with the registered end point and have my module already imported into the users account.
Enter-PSSession -computername SRV1-AD -Credential $credential -ConfigurationName HelpDesk
Further Update
User #prasoon-karunan-v suggested I used -ScriptsToProcess & FunctionDefinitions to import the module so I used the following command
New-PSSessionConfigurationFile -VisibleFunctions('Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon') -LanguageMode ‘ConstrainedLanguage’ –SessionType ‘RestrictedRemoteServer’ –Path ‘.\EndPoint.pssc’ -ScriptsToProcess C:\Users\Administrator\Desktop\Modules\ImportM.psm1
In the configuration file I also set the functions I want to use like so
# Functions defined in this session configuration
FunctionDefinitions = 'Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon'
When I tried to establish a session it would throw the following error
Then I thought maybe it's not working because were not telling the command to import anything were just pointing to the module file, so maybe I need to create a small script that imports the module then add it the configuration file. So that's exactly what I did I created a small script with just,
import-module C:\Modules\ImportM.psm1 and then I went over to the .pssc
file and added this script to the ScriptsToProcess but I get the following error after I try to establish a session to the constrained endpoint.
Language Mode is set to
LanguageMode = 'RestrictedLanguage'

use -ScriptsToProcess parameter, which can be used to import your custom module.
See below as well.
Get-Help New-PSSessionConfigurationFile -Parameter ScriptsToProcess
Get-Help New-PSSessionConfigurationFile -Parameter FunctionDefinitions
Update:
Be sure about the language mode to use,
see here

Related

Create and configuring Application Pool on IIS w10 and powershell 7.2

I'm trying to create a pool of applications with specific parameters using this code:
$currentAppPool = New-WebAppPool -Name myNeyAppPool
# Set pool specifications
$currentAppPool.AutoStart = "true"
$currentAppPool.ManagedRuntimeVersion = "No Managed Code"
$currentAppPool | Set-Item
I have several errors because setitem asks me for a path variable that it doesn't recognize. Set-Item: The input object cannot be bound because it did not contain the information required to bind all mandatory parameters: Path
I tried to give it the parameter -path IIS:\AppPools\myNeyAppPool but I get the message
Set-Item: Cannot find drive. A drive with the name 'IIS' does not exist
There are quite a few changes concerning the management of IIS in w10 via powershell 7, but little documentation seems to exist on the subject.
Is there anything help ?
Thks,
The provider "IIS:" is loaded when importing the webadministration module.
Providers before and after to load webadministration module
Do you have IIS role enabled in windows 10?
You can check the following link:
https://community.lansweeper.com/t5/installation/how-to-install-iis-internet-information-services/ta-p/64422
Which providers appear if you run the "Get-PSProvider" command?
First try running PowerShell as an administrator, and then the drive is provided by the WebAdministration module, so you need make sure install that module, you can install the module with the following PowerShell commands:
Import-Module ServerManager
Add-WindowsFeature Web-Scripting-Tools

Powershell JEA Security hole with commands embedded in functions?

This seems bonkers so I'm hoping I didn't find a big security gap... I have Powershell JEA (just enough administration) successfully set up on a server to allow only certain administrative functions. Specifically, I don't have the "net" command allowed at all. If I do the below:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
net stop "My windows service"
}
Then I get the error below as expected:
The term 'net.exe' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and
try again.
+ CategoryInfo : ObjectNotFound: (net.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
BUT, if I wrap my "net.exe" usage inside a function, it actually works:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
function StopService($servicename) {
net stop "$($servicename)"
}
StopService "My windows service"
}
The above does not throw an error and actually stops the service. WTF?
This is more than the "net" command. Another example: "Out-File" is not allowed. The below code fails:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
"hacked you" | Out-File C:\test.txt
}
With the error:
The term 'Out-File' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and
try again.
+ CategoryInfo : ObjectNotFound: (Out-File:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : vxcazdev01
But if I do it this way, it works:
Invoke-Command -computername MYSERVER -configurationname MYCONFIG -scriptblock {
function DoIt() {
"hacked you" | Out-File C:\test.txt
}
DoIt
}
Why is this happening? Am I missing something? The JEA project on github is now read-only so I can't open an issue there.
Edit to add: the same problem happens if I use Enter-PSSession instead of Invoke-Command.
Edit to add relevant session config pieces: My session config file only has a few customizations from the default file produced by the New-PSSessionConfigurationFile command:
SessionType = 'Default'
RunAsVirtualAccount = $true
RoleDefinitions = #{
'MYDOMAIN\MYADGROUP' = #{ RoleCapabilities = 'MyCustomRole' }
}
MYADGROUP is the only group my test user is a member of. And then this is registered on the server like so:
Register-PSSessionConfiguration -Path "C:\Program Files\WindowsPowerShell\Modules\MyJEAModule\VSM.pssc" -Name 'MYCONFIG' -Force
I'm just going to answer this question myself with the answer: security hole by design.
The documentation says this:
The body (script block) of custom functions runs in the default language mode for the system and isn't subject to JEA's language constraints.
It's rather surprising, to me at least, that JEA will let you lock down actions on a server in security sandbox, but as soon as one writes their own custom functions they have full administrative rights to the machine and have broken out of the box. Allowing or restricting the creation of custom functions via the language mode is one thing, but bypassing the set security permissions is another. In my opinion, user-written custom functions should be subject to full security limitations; custom functions written in the role capabilities files should have full admin rights as the documentation indicates.
The other answer by HAL9256 is great, but it describes the benefits of JEA, which is not the topic of this post.
I wouldn't say that it's a security hole, it's that you are clearly demonstrating what could happen on a system when you have not set up a fully secured configuration. Microsoft even states JEA doesn't protect against admins because "they could simply RDP in and change the configuration". We need the correct combination of SessionType and RoleDefinitions, and that they are meant for two different configurations.
Your example demonstrates a configuration setup where, even though we lock the front door of the house, we started off with a house that had all the windows and doors open. It is fully possible to get in through the back door, or reach through a window and unlock the front door, thus demonstrating the fruitlessness of locking the front door. For example, I don't need to run net stop I could just do a taskkill instead, or..., or..., etc.
Let's look at the overview of what JEA is designed for:
Reduce the number of administrators on your machines using virtual accounts or group-managed service accounts to perform privileged actions on behalf of regular users.
Limit what users can do by specifying which cmdlets, functions, and external commands they can run.
Better understand what your users are doing with transcripts and logs that show you exactly which commands a user executed during their session.
Reduce the number of administrators
We can use JEA to remove people from the local administrators group, or larger Domain Admin groups. They can then selectively get elevated Administrator rights when needed through Virtual Accounts.
If we set it up with the SessionType = 'Default' this enables all language features. We essentially can have a Jr. Technical Analyst without Domain Admin rights, without Local Admin rights, log on, and do Administrative duties. This is what the session type is meant for.
Limit what users can do
If we set it up with the SessionType = 'Default' this enables all language features. In mode it doesn't matter what commands we limit, all the doors and windows are open and we can pretty much do whatever we want. One rule in Windows is that there is always 3-4 different ways to do something. You just can't plug all the holes when everything is wide open.
#MathiasR.Jessen is right, the only way to Limit what users can do is to first lock down the system. Setting SessionType = 'RestrictedRemoteServer' locks down the session to:
Sessions of this type operate in NoLanguage mode and only have access
to the following default commands (and aliases):
Clear-Host (cls, clear)
Exit-PSSession (exsn, exit)
Get-Command (gcm)
Get-FormatData
Get-Help
Measure-Object (measure)
Out-Default
Select-Object (select)
No PowerShell providers are available, nor are any external programs
(executables or scripts).
This starts us out with a completely locked up house. We then selectively enable the needed commands. Ideally we should pre-create custom functions so that the custom function is the only thing they can run, they are technically not even allowed to execute the commands inside the function at all, it's all handled by the Virtual Account.
What you did was essentially exploiting this custom function capability, by "cheating" and creating our own "custom function" that will run in the Virtual Account scope, and not your own, which is why it was able to run "non-allowed" functions, and you were not. If the SessionType = 'RestrictedRemoteServer', you wouldn't be able to create scripts or custom functions like demonstrated, and hence, the "hole" would not be there.
Better understand what your users are doing
Finally the other benefit for JEA is that it can record a transcript of all the commands that are run. This might be needed for audit reasons or fed into a SIEM solution or to find out how your Jr. Technical Analyst messed up your system ;-).

PowerShell - ActiveDirectory Module

I need the ability to have users run a script that requires the ActiveDirectory module. I copied over the following:
"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ActiveDirectory", "Microsoft.ActiveDirectory.Management.resources.dll", "Microsoft.ActiveDirectory.Management.dll".
The script runs two Get-ADUser commands, 1 without the -Server parameter and the other with. The issue is that the former is working but the latter is not.
Is there another module that I need to copy over?
I don't like the idea of installing administrative tools for non-admins. Even if you could get away with copying files and not doing the full-blown RSAT installation. Not the least of reasons is you are dramatically increasing the attack surface for malicious actors. The better solution is (Just Enough Administration) JEA, or a philosophically similar approach.
JEA / Contrained endpoints can get complicated, but a summary of what you can do looks something like this:
New-PSSessionConfigurationFile -Path 'C:\PSSessionConfigs\DemoPSEndpointConfig.pssc' -ModulesToImport ActiveDirectory -VisibleCmdlets "Get-ADUser"
Register-PSSessionConfiguration -Path 'C:\PSSessionConfigs\DemoPSEndpointConfig.pssc' -ShowSecurityDescriptorUI -Name DemoPSEndPoint
Run these commands on a system that has the ActiveDirectory module (likely the whole RSAT component) installed, it doesn't need to be a Domain Controller. It will create a new PowerShell remoting endpoint configuration that exposes only the commands you wish. The Register-PSSessionConfiguration command will display a security dialog where you can permission which users you want to allow to connect, you want to grant them read & execute permission. Once that's done, you can get the results with an Invoke-Command command like this:
Invoke-Command -ComputerName <ServerName> -ConfigurationName DemoPSEndPoint -ScriptBlock { Get-ADUser <UserName> }
You can add the -Server parameter in the command without issue. You can expand the cmdlets you are allowing in the New-PSSessionConfiguration command.
Again this is very much a summary of a more complex topic but should be enough to get what you want.
Personally, I don't use configuration files as much as I use startup scripts. I think the latter is more flexible. You can get some information about that here. If you really want to dig into this there are references at the end of the article including a link to the PowerShell JEA documentation. There's also a link to some of the MVP articles I used to develop my own endpoints.
The ActiveDirectory module is dependent on the RSAT (remote server administration tool). This is avalible to install/activate through powershell: https://mikefrobbins.com/2018/10/03/use-powershell-to-install-the-remote-server-administration-tools-rsat-on-windows-10-version-1809/
With this installed you automatically also get the Activedirectory module installed.

Import Module with an different user account

Are you able to import a module through PowerShell with a different user account? I am specifically attempting to import the ActiveDirectory module with a different account to the currently logged in one.
I don't want to go all out for the console though because I am attempting to use the current Outlook process to send an email after the part of the code is done, and if the entire console is elevated it will give a COM error (instance of PowerShell and Outlook are not elevated together).
The SMTP way of sending an email or through Send-Mail won't work as even though I can ping the SMTP server, I get the below error message, which from what I've read is because I am unable to communicate with the SMTP server appropriately?
Exception calling "Send" with "1" argument(s): "Failure sending mail."
At C:\Users\\Desktop\SCRIPT.ps1:64 char:9
+ $SMTP.Send($MSG)
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SmtpException
You can't import a module with a different account as it doesn't work this way. You need to run the individual commands themselves with alternative credentials.
As you mentioned AD I've used Get-ADUser as an example but a lot of powershell commands have a Credential or PSCredential parameter of some kind, check the documentation to find out.
$Credentials = Get-Credential
Get-ADUser JohnSmith -Properties DistinguishedName -Credential $Credentials
This above example will prompt for credentials, but you can also save them in the script instead on entering them every time.
NOTE: Saving credentials in a file isn't secure so be careful what credentials you save and where you store them!
$Username = "DomainUserName"
$Password = "PlainPassword" | ConvertTo-SecureString -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($Username ,$Password)
There are also other ways to save credentials, but that's too much to go into here.
The AD module for powershell is a wrapper around much of the .NET framework's System.DirectoryServices namespace of code.
.NET in turn is wrapped on top of the older COM ADSI component.
Because of this, it is possible to use windows cached credentials to handle the AD work without using the -Credential option.
If you cache a Windows Domain credential prior to running the script, the AD cmdlets will use those cached credentials to authenticate to the DC. Of course, there's no requirement to remove the cached credential...but realize it's static. if the password changes in the domain, you need to re-cache the cred.
The management of domain creds can be done by command line as well using the cmdkey.exe program that is present since Win7. Using this command line tool, you could set the windows credential just before you run your script, then remove the credential after.
Note that the use of the cached creds is based solely on the server name that the cmdlet will attempt to communicate. If you are not specifying a DC in your cmdlet calls, then it will use the %logonserver% environment variable.
The critical piece then is that the servername used by ADSI must match exactly in the credential cache. If the short name (server01) is used, then that must be in the cache. If the full dns name is used (server01.domain.com), then that must be in the cache. If you feel that your script may change to another server, then that server must be in the cache.

Powershell 3.0: Using my local profile and modules in remote PSSessions

I need my local $profile located on my local PC to be loaded automatically when I PSRemote into other computers. My $profile also imports a few local modules (available only on my local PC). So, I need my $profile to be enhanced so that my modules can be still be imported (regardless where my $profile is loaded).
I spent a lot of time trying to get this to work; but see a lot of inconsistent information posted (probably because the differences between PS2 and PS3). Everything I tried, resulted in some kind of error.
I was hoping someone would help me with a dummy-proof working example of how to do this. The only thing that actually works is a basic: enter-pssession -ComputerName RemoteServerName. I did try to at least get my local profile to load in a remote session (see below), but that didn't work either; let alone loading the modules imported in the profile file.
Register-PSSessionConfiguration -Name MyLocalProfile -StartupScript $Profile
Enter-PSSession -ComputerName REMOTESERVERNAME -ConfigurationName 'MyLocalProfile'
Gives error:
Enter-PSSession : Connecting to remote server REMOTESERVERNAME failed with the following error message : The WS-Management service cannot process the request. Cannot find the MyLocalProfile session configuration in the WSMan: drive on the REMOTESERVERNAME computer.
I even tried:
Register-PSSessionConfiguration -Name MyLocalProfile `
-StartupScript \\MYLocalPC\profile$\Microsoft.PowerShell_profile.ps1
But, but it still produced the same error. Not sure why it should be this hard to do something that most people would most likely want to happen by default.
Short answer: You're doing it incorrectly, and it's impossible to do it that way.
Long Answer:
From the Enter-PSSession page on MSDN, a line stands out:
The session configuration for a session is located on the remote computer. If the specified session configuration does not exist on the remote computer, the command fails.
Therefor you will have to Invoke-Command the Register-PSSessionConfiguration before creating the new session.