A proof-of-concept aimed at creating a PowerShell console in C/C++, with all the security features patched or disabled: Antimalware Scan Interface (AMSI), Script Block logging, Module logging, Transcription, Execution Policy, and Constrained Language Mode (CLM).
- Open the solution file
PowerChell.sln
with Visual Studio (you must have the Windows SDK installed). - In the toolbar, select
RELEASE-EXE
if you want to build the executable (.exe) file, orRELEASE-DLL
if you want to build the DLL. In both cases, the target configuration will bex64
because this is the only supported platform. - In the top bar, click
Build > Build Solution
to build the project.
You should be able to run the executable straight away:
C:\Users\Dummy\Downloads>PowerChell.exe
Windows PowerChell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Users\Dummy\Downloads> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.26100.2161
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.26100.2161
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
As for the DLL, you can use the following command:
rundll32 PowerChell.dll,Start
In the command above, Start
is the name of a dummy function. It exists only to prevent rundll32
from complaining about not finding the entry point. You can very well specify any entry point you want. It will work as long as you don't close the error dialog.
You can also execute a PowerShell command like this:
C:\Users\Dummy\Downloads>PowerChell.exe -c "$PSVersionTable"
+-----------------------------------+
| POWERSHELL STANDARD OUTPUT STREAM |
+-----------------------------------+
Name Value
---- -----
PSVersion 5.1.26100.3624
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.26100.3624
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
This also works with the DLL, albeit less convient because you won't see the result:
rundll32 PowerChell.dll,Start -c "$PSVersionTable"
In PowerShell v3+, Microsoft added a built-in module named PSReadLine
to bring a bash-like experience to the PowerShell console. PowerChell doesn't load any module by design, so if you want to enable features such as syntax highlighting and other goodies that this module implements, you need to load it manually.
However, this has a side effect in regard to detection by EDR. In doing so, you will also enable PowerShell command logging to the current uesr's console history file %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
. This file is actively monitored by some security solutions (see issue #1).
To load this module, and disable console history, you should do the following.
Import-Module PSReadLine
Set-PSReadLineOption -HistorySaveStyle SaveNothing
- If you open any of the source files and Visual Studio is screaming at you because it can't find the
mscorlib
stuff, that's expected. You need to build the solution at least once. It will generate themscorlib.tlh
file automatically. - The code of the DLL will likely need to be adapted if you want it to work properly using DLL sideloading.
- Clément Labro
- Mastodon: https://infosec.exchange/@itm4n
- GitHub: https://github.com/itm4n
There would be many resources, blog posts, and tools to credit. Unfortunately, I haven't kept track of all them, but here are the main ones.
Tools
- https://github.com/calebstewart/bypass-clm
- https://github.com/anonymous300502/Nuke-AMSI
- https://github.com/OmerYa/Invisi-Shell
- https://github.com/leechristensen/UnmanagedPowerShell
- https://github.com/racoten/BetterNetLoader
- https://gist.github.com/Arno0x/386ebfebd78ee4f0cbbbb2a7c4405f74 (
loadDotNetAssemblyFromMemory.cpp
) - https://gist.github.com/tandasat/e595c77c52e13aaee60e1e8b65d2ba32 (
KillETW.ps1
)
Blog posts