Skip to content

Move .NET method invocation logging to after the needed type conversion is done for method arguments - #24853

Closed
Dongbo Wang (daxian-dbw) wants to merge 2 commits into
PowerShell:masterfrom
daxian-dbw:memberInvokeLog
Closed

Dongbo Wang (daxian-dbw) wants to merge 2 commits into
PowerShell:masterfrom
daxian-dbw:memberInvokeLog

Conversation

@daxian-dbw

Copy link
Copy Markdown
Member

PR Summary

This PR is to fix a MSRC report about a bug in the .NET method logging implementation. The report is not considered a vulnerability, so I'm submitting the fix in GitHub.

The .NET method invocation logging is currently called before PowerShell does any of the needed type conversion for the method arguments, and it results in inaccurate information being logged to AMSI.

The fix is to move .NET method invocation logging to after the needed type conversion is done for method arguments.
The following is the comparison between before and after the fix when turning on the console logging for the AMSI notification feature:

Before the fix -- it logs .GetType(<Foo>)

C:\>pwsh -noprofile
PowerShell 7.4.6
PS C:\>
class Foo {
>>     [string] ToString() {
>>         return "System.Management.Automation." + ([char[]]@(0x41, 0x6D, 0x73, 0x69, 0x55, 0x74, 0x69, 0x6C, 0x73) -join "")
>>     }
>> }
PS C:\>
$utilTypeName = [Foo]::new()

=== Amsi notification report content ===
<Foo>.new()
=== Amsi notification report success: True ===

=== Amsi notification report content ===
<System.Object>.new()
=== Amsi notification report success: True ===
PS C:\>
$utilType = [PSObject].Assembly.GetType($utilTypeName)

=== Amsi notification report content ===
<System.Reflection.RuntimeAssembly>.GetType(<Foo>)
=== Amsi notification report success: True ===
PS C:\>
exit

After the fix -- it logs .GetType(<System.Management.Automation.AmsiUtils>)

C:\>E:\arena\source\PowerShell\src\powershell-win-core\bin\Debug\net9.0\win7-x64\publish\pwsh.exe -noprofile
PowerShell 7.5.0-preview.3-197-g36740ab4a21a1cd51f8cd795f295a86aa5c91d34
PS C:\>
class Foo {
>>     [string] ToString() {
>>         return "System.Management.Automation." + ([char[]]@(0x41, 0x6D, 0x73, 0x69, 0x55, 0x74, 0x69, 0x6C, 0x73) -join "")
>>     }
>> }
PS C:\>
$utilTypeName = [Foo]::new()

=== Amsi notification report content ===
<Foo>.new()
=== Amsi notification report success: True ===

=== Amsi notification report content ===
<System.Object>.new()
=== Amsi notification report success: True ===
PS C:\>
$utilType = [PSObject].Assembly.GetType($utilTypeName)

=== Amsi notification report content ===
<System.Reflection.RuntimeAssembly>.GetType(<System.Management.Automation.AmsiUtils>)
=== Amsi notification report success: True ===
PS C:\>
exit

PR Context

PowerShell 7.3 added a new feature that will log any .NET method calls and provide it to the IAntimalwareProvider2.Notify call. As an example running the following will result in the string below being provided to the AMSI provider to check before running

$foo = 'bar'
[Console]::WriteLine($foo)
<System.Console>.WriteLine(<bar>)

This allows antimalware providers registered with AMSI to be able to detect the runtime values provided to .NET methods even if they are obfuscated in the code and missed by any static analysis of the scriptblock text being run.

A bug in the implementation means that the provided args in the LogMemberInvocation method that builds the string to provide to AMSI are the ones before they are casted when actually invoking them.

For any .NET method that accepts a string we can now provide a custom class with a ToString method that returns the value we want to provide to the .NET call but the AMSI notify string value will just be the class name. With this we can now bypass the checks that may be in place to stop things like the below which would typically be picked up by AMSI due to the presence of the keyword AmsiUtils in the string.

[PSObject].Assembly.GetType("System.Management.Automation.AmsiUtils")

Repro Steps

Run the following PowerShell script

class Foo {
    [string] ToString() {
        return "System.Management.Automation." + ([char[]]@(0x41, 0x6D, 0x73, 0x69, 0x55, 0x74, 0x69, 0x6C, 0x73) -join "")
    }
}
$utilTypeName = [Foo]::new()
$utilType = [PSObject].Assembly.GetType($utilTypeName)

The type name string provided at runtime to GetType is System.Management.Automation.AmsiUtils but AMSI will see the following in the member invocation log, masking the true intention of the call.

<System.Reflection.RuntimeAssembly>.GetType(<Foo>)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 1 out of 1 changed files in this pull request and generated no comments.

@daxian-dbw

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 4 pipeline(s).

@daxian-dbw

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@microsoft-github-policy-service microsoft-github-policy-service Bot removed the Review - Needed The PR is being reviewed label Feb 13, 2025
@daxian-dbw

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@daxian-dbw

Copy link
Copy Markdown
Member Author

/azp run PowerShell-CI-macos, PowerShell-CI-Linux, PowerShell-CI-Windows, PowerShell-CI-static-analysis, PSResourceGet ACR, PowerShell-Windows-Packaging-CI

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@daxian-dbw

Copy link
Copy Markdown
Member Author

Superseded by #25022

@microsoft-github-policy-service

microsoft-github-policy-service Bot commented Feb 15, 2025 •

Copy link
Copy Markdown
Contributor

📣 Hey Dongbo Wang (@daxian-dbw), how did we do? We would love to hear your feedback with the link below! 🗣️

🔗 https://aka.ms/PSRepoFeedback

@daxian-dbw
Dongbo Wang (daxian-dbw) deleted the memberInvokeLog branch February 15, 2025 00:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants