10000 PSReadLine Evasion · Issue #1 · scrt/PowerChell · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

PSReadLine Evasion #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tang77 opened this issue Feb 20, 2025 · 8 comments
Closed

PSReadLine Evasion #1

tang77 opened this issue Feb 20, 2025 · 8 comments
Labels
enhancement New feature or request wontfix This will not be worked on

Comments

@tang77
Copy link
tang77 commented Feb 20, 2025

Hello Clément,

Super article as always 👍

Lors d'un engagement redteam récent, j'ai remarqué que les EDR(s) étaient en monitoring aussi sur le module PSReadLine notamment sur le history handler/file output. (Pas cool de se faire toper après bypass AMSI/ETW et se faire avoir juste à cause de l'historique de commande lol).

Je suggère l'ajout suivant :

$type = [Microsoft.PowerShell.PSConsoleReadLine]
$options = $type.GetField("_options","NonPublic,Instance")
$instance = $type.GetField("_singleton", "Static,NonPublic").GetValue($null)
$options.SetValue($instance, $null)

Before :
Image

After :

Image

@cla-ocd
Copy link
Collaborator
cla-ocd commented Mar 3, 2025

Hello! Thanks for the comment, and sorry for the late response, I realized that I hadn't enabled notifications for this repo.

I wasn't aware of such a detection. Is there a good online resource (article, blog post, thread, forum) that mentions or discusses this in more detail?

@tang77
Copy link
Author
tang77 commented Mar 4, 2025

Hello !

I haven't come across resources mentioned this fact (maybe on X somewhere ?), but from personal OpSec experience with some past engagement.

Not tested on all EDRs in the market, but currently aware that BitDefender is snooping on ConsoleHost_history.txt to search for keyword such as Invoke-* ... :)

My previous script is a bit agressive though as I was wiping all the PsReadLine options, you could just disable the history handler this way :
Set-PSReadLineOption -AddToHistoryHandler { return $false }

Cheers!

@cla-ocd
Copy link
Collaborator
cla-ocd commented Mar 4, 2025

OK, thanks for the update. In that case, it might be worth digging a little bit deeper in that direction. I'll see what I can do.

Do you know if this kind of detection is included in the free version of BitDefender? Second, are you aware of any specific keyword that it detects, so that I can easily test?

@tang77
Copy link
Author
tang77 commented Mar 4, 2025

Not sure if it is included in free version, but I'm sure other EDRs are having similar tactics to keep an eye on the command you typed.

For testing, I suggest, disable AMSI/ETWI/scriptlogging, then use the classic noisy keywords : Invoke-Mimikatz, Invoke-winPEAS..

@cla-ocd
Copy link
Collaborator
cla-ocd commented Mar 6, 2025

I created a new Windows VM, installed Bitdefender EDR, started PowerChell, and used known commands such as Invoke-Mimikatz. There is no apparent detection on the endpoint, I can't see any relevant alert in the admin dashboard either.

I repeated the same steps with powershell.exe. There is no apparent detection on the endpoint, just the typical AMSI error message. However, this time, the command invocation Invoke-Mimikatz can be observed in the dashboard. Indeed in generates one high severity alert with the message "Antimalware Scan Interface has detected suspicious activity.".

So I can't see an evident sign that the console history is leveraged for additional detection.

@tang77
Copy link
Author
tang77 commented Mar 8, 2025

Weird, might depend on the policy enforced ? I've tried for TrendMicro EDR as well, this is not triggering blocking action, though in the dashboard it gathers all the previous command from the console history. Might be worth to investigate others one if you have time.

From my perspective, this is similar to some kind of "command logging" and can be used to monitor for malicious actions. So feel free to implement or close the issue as you want. Though, I'm keeping this trick under the hood to avoid from stupid IOCs ;)

@cla-ocd cla-ocd added the enhancement New feature or request label Apr 15, 2025
@cla-ocd
Copy link
Collaborator
cla-ocd commented May 21, 2025

I investigated this a bit further.

As it turns out, the type Microsoft.PowerShell.PSConsoleReadLine is not implemented in a "common" .Net assembly, but comes from a built-in PowerShell module: PSReadLine.

PS C:\Users\Admin> [Microsoft.PowerShell.PSConsoleReadLine].Assembly

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Program Files\WindowsPowerShell\Modules\PSReadLine\2.0.0\Microsoft.PowerShell.PSReadLine.dll

Contrary to PowerShell, though, I don't load default built-in modules in PowerChell. Therefore the PSConsoleReadLine type does not exist.

Image

One of the side effects is that there is actually no console history being logged. So, I have nothing to patch here. I checked my console history file while using PowerChell, and indeed, nothing is logged. No wonder why I was unable to reproduce the behavior...

Nonetheless, the issue could arise if the module PSReadLine were to be loaded either directly or indirectly at some point. To address this, I could preemptively load the module and patch it.

By the way, about the "patch" itself, You can do something like this. It's less "invasive" and way easier to implement in C/C++ than setting the console history handler.

# Method 1: Simple use
Set-PSReadLineOption -HistorySaveStyle SaveNothing

# Method 2: Same as 1 but "manual"
$options = [Microsoft.PowerShell.PSConsoleReadLine]::GetOptions()
$options.HistorySaveStyle = [Microsoft.PowerShell.HistorySaveStyle]::SaveNothing

# Method 3: Reflection
$ConsoleReadLineOptions = [Microsoft.PowerShell.PSConsoleReadLine]::GetOptions()
$ConsoleReadLineOptionsType = $ConsoleReadLineOptions.GetType()
$HistorySaveStyleProperty = $ConsoleReadLineOptionsType.GetProperty("HistorySaveStyle")
$HistorySaveStyleProperty.SetValue($ConsoleReadLineOptions, 2)

Still need to work a bit more on this. I need to find out if there is more to importing PowerShell modules than just loading an assembly. But I wanted to share this bit of (interesting?) information.

@cla-ocd
Copy link
Collaborator
cla-ocd commented May 22, 2025

Conclusion...

There is indeed more to importing a PowerShell module than just loading its assembly. The work required to do that goes beyond the point of this project, whilst it can be achieved with just a few lines of PowerShell in the console.

According to the documentation, the point of the PSReadLine module is to bring a bash-like user experience to PowerShell v3+. Therefore, it's not something that's strictly required for the PowerShell console to work. It's more of a convenience.

To load the module, and prevent commands from being logged to the history file, one could do the following.

Import-Module PSReadLine
Set-PSReadLineOption -HistorySaveStyle SaveNothing

Image

@cla-ocd cla-ocd added the wontfix This will not be worked on label May 22, 2025
@cla-ocd cla-ocd closed this as completed May 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants
0