Introduction
Building upon the last technique for bypassing AppLocker default rules, this blog post aims to add another technique for bypassing CLM and executing PowerShell code.
As per Microsoft’s own definition:
PowerShell Constrained Language is a language mode of PowerShell designed to support day-to-day administrative tasks, yet restrict access to sensitive language elements that can be used to invoke arbitrary Windows APIs.
The language mode will be automatically be set to ConstrainedLanguage
when AppLocker is enforcing rules against PowerShell scripts (the same goes for WDAC), offering another security barrier for PS-based tradecraft.
After enabling the default rules, one can observe the restrictions in place. Using Powercat as an example, one would notice that it won’t return the expected connection, as it makes use of various .NET and COM objects.
Cruising Through Custom Runspaces
PowerShell commands run in a runspace. To host PowerShell in your application, you must create a System.Management.Automation.Runspaces.Runspace object.
In Windows, the powershell.exe application is essentially a GUI wrapper handling input and output from inside a managed DLL. When executed, it’ll call the System.Management.Automation
DLL and create a runspace.
This means that you can also create such PowerShell runspaces in custom applications, in which the current language mode won’t be enforced.
An example of creating custom runspaces can be found on Microsoft’s documentation.
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Command");
ps.Invoke();
rs.Close();
While this example works beautifully, it has an ugly limitation, which is that the command is hardcoded inside the AddCommand
method. Another issue is that, with custom AppLocker rules, you may not be able to drop this into an allowed directory.
Evade, Fetch & Run
Those details can be crucial for making such techniques viable, let’s then explore ways for solving those limitations.
The first can be easily fixed by fetching the commands from arguments, a local/remote location.
// Fetch command from text file
string text = File.ReadAllText("command.txt");
string cmd = text;
ps.AddScript(cmd);
// Fetch command from command line arguments
string cmd = args[0];
ps.AddScript(cmd);
Now for the former, an AppLocker bypass technique can be employed, such as using the InstallUtil LOLBAS. Note that for this the argument approach might not work, as the Uninstall method doesn’t seem to accept arguments.
[RunInstallerAttribute(true)]
public class AppLockerUninstall : System.Configuration.Install.Installer {
public override void Uninstall(System.Collections.IDictionary savedState) {
string text = File.ReadAllText("command.txt");
string cmd = text;
ps.AddScript(cmd);
}
}
As a demonstration, the tool will print the current Language Mode into a text file.
Lastly, another example for fetching and running the Powercat tool, that was previously shown to be blocked by the Language Mode.
References and Further Reading
0 Comments