PowerShell Basics–Recommendations when Importing Modules
In the last blog post we covered the basics of importing Modules and PSSnapins to extend the shell, this provides us great flexibility in terms of expandability but at the same time depending on how we have configured our system this can pose functional and security risks. The main risk is a module overwriting another module function or cmdlet. Lets demonstrate why it is important to be aware of this, lets start with 2 simple modules with the same function that returns a date for us to use for naming log files:
Lets look at what happens when we import both modules in a default configuration of PowerShell with Execution Policy not set to restricted:
As we can see both modules loaded with no errors shown, but when we look at the function we see that by typing only the name we only have the function from the latest module that was imported available to us.
PowerShell allows us to access each element in a module be it a function, cmdlet, workflow ..etc by using the module name so we could call the functions directly from each module. But lets be honest not many people use it this way:
If we use the –Verbose parameter when loading the modules we will see that nothing is shown to tell use that something is wrong:
This is because for PowerShell this is normal behavior. If we do not want to replace a command with the other we use the –NoClobber parameter when we load a module, it will not show any message telling you a that a conflict was avoided unless you use the –Verbose parameter (I wish it would show a warning message):
In PowerShell v3 this is more of a danger since Modules are loaded automatically. We can control in PowerShell v3 the behavior of the autoloading thru the variable $PSModuleAutoLoadingPreference
- All - Modules are imported automatically on first-use.
- ModuleQualified - Modules are imported automatically only when a user uses the module-qualified name of a command in the module <Module Name>\<Cmdlet Name>
- None - Automatic importing of modules is disabled in the session. To import a module, use the Import-Module cmdlet.
$PSModuleAutoLoadingPreference = "ModuleQualified"
One way to counter this would be to set default parameters to the Import-Module command, this is done by setting the values of the parameters for specific commands in $PSDefaultParameterValues the variable is a dictionary where we set up the values where the key is <Module Name>:<Parameter> = <Default Value>:
$PSDefaultParameterValues.('Import-Module:Verbose') = $true $PSDefaultParameterValues.('Import-Module:NoClobber') = $true
Now when we try to load a module with Import-Module it will apply this values to it:
Now I know many of you are thinking “Why should I worry about this?” here is an evil example, lets say an attacker or malware has been able to get on your system, and you manage say Exchange, AD and/or Sharepoint server from your machine via PowerShell, many times you will use the Get-Credential cmdlet to enter alternate credentials because you are security conscious and have separation of privileges and use a separate account for administration so token abuse is minimized. What would happen if the attacker created a module in a hidden folder and hidden files in your system module path that would look like this:
As you can see the code replaces the Get-Credential cmdlet and if verbose is given it will return the clear text credential and password entered, an attacker would just save this to file, email them or do a post request somewhere, heck he could even do a DNS query with each as the host filed to a DNS he controls and exfil the information out of your network. This would look like so when ran:
And when we enter the credentials:
I hope you have found the blogpost useful and informative and thank you for reading it.