EDITOR’S NOTE: We initially published this article before MITRE significantly updated ATT&CK data sources and components. As a result, we use the term “process command line” in this article to refer to the data source component that MITRE would later categorize as “command execution.”
Command line refers to the arguments that are passed to an executable process in Windows. It is useful information for defenders as it can reveal contextual clues about the execution of a suspicious process. For example, adversaries regularly supply malicious PowerShell code as command-line arguments via the -Command
and -EncodedCommand
parameters. For executables that support arguments, command-line context is incredibly valuable to defenders looking to identify malicious behavior and/or aid incident response.
Any user-mode process, even if it isn’t a dedicated console application (for example, a GUI application) can have associated command-line arguments. And while it is generally the case that if an application implements command-line parameters that they will be documented accordingly, this is not always the case. Many applications have undocumented command-line parameters.
Why focus on process command line?
Defenders and vendors rely on process command line to discern benign from suspicious or malicious activity because it is among the most omnipresent data sources on an endpoint. Process command line can tell us how an application was intended to be used and in some cases can supply us directly with adversary payloads. For example, adversaries often supply malicious encoded PowerShell commands directly at the command line using any of the -EncodedCommand
parameter variations. The way in which PowerShell eases post-exploitation abuse for adversaries also creates a unique and straightforward means of detecting malicious behavior based on process command line alone.
But this begs the question: what does legitimate PowerShell command-line activity look like?, which begs the follow-on question an adversary may pose: to what extent can I blend in with seemingly legitimate looking PowerShell command-line activity? So while you can be generally confident that known malicious evidence in the command line is malicious, you can’t always trust that non-malicious looking command line is not malicious activity in hiding.
What data sources are available to retrieve process command line?
The following data sources are either built into the operating system or are freely available to collect process command line. Note: This is a non-exhaustive list of data sources.
Windows Management Instrumentation (WMI)
Data source: Win32_Process Class
Relevant field[s]: CommandLine
Example retrieval:
Get-CimInstance -ClassName Win32_Process | Select-Object -Property CommandLine
wmic process list /format:csv
Example data:
PS C:\> Get-CimInstance -ClassName Win32_Process -Filter 'CommandLine = "Foo"' | Select ProcessId, ExecutablePath, CommandLine | Format-List
ProcessId : 2648
ExecutablePath : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
CommandLine : Foo
Windows Process Auditing
Data source: Windows Security Log Event ID 4688
Relevant field[s]: CommandLine
Example data:
A new process has been created.
Creator Subject:
Security ID: <REDACTED>
Account Name: <REDACTED>
Account Domain: <REDACTED>
Logon ID: 0x1103DA2
Target Subject:
Security ID: NULL SID
Account Name: -
Account Domain: -
Logon ID: 0x0
Process Information:
New Process ID: 0x1a40
New Process Name: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Token Elevation Type: %%1938
Mandatory Label: Mandatory Label\Medium Mandatory Level
Creator Process ID: 0x270
Creator Process Name: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process Command Line: Foo
Sysmon
Data source: Event ID 1: Process creation
Relevant field[s]: CommandLine
, ParentCommandLine
Example data:
Process Create:
RuleName:
UtcTime: 2021-03-09 21:15:45.985
ProcessGuid: {79703954-e581-6047-0000-0010cb1b2601}
ProcessId: 4516
Image: C:\Windows\System32\conhost.exe
FileVersion: 10.0.19041.746 (WinBuild.160101.0800)
Description: Console Window Host
Product: Microsoft® Windows® Operating System
Company: Microsoft Corporation
OriginalFileName: CONHOST.EXE
CommandLine: \??\C:\WINDOWS\system32\conhost.exe 0xffffffff -ForceV1
CurrentDirectory: C:\WINDOWS
User: <REDACTED>
LogonGuid: {79703954-e15d-6047-0000-0020a23d1001}
LogonId: 0x1103DA2
TerminalSessionId: 4
IntegrityLevel: Medium
Hashes: SHA1=9D48D4B78CBBFB22C9EE9070F713B35CD2A6A6EB
ParentProcessGuid: {79703954-e581-6047-0000-00105f1b2601}
ParentProcessId: 6720
ParentImage: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
ParentCommandLine: Foo
Where is process command line stored and how do adversaries retrieve it?
Process command-line information is stored within the ProcessParameters
field of the process environment block (PEB), a user-mode data structure present in all processes. Because it is a user-mode data structure, it is readily susceptible to adversary modification. Even kernel drivers responsible for populating security events have to retrieve the command line from the PEB in user mode.
There are no APIs for directly retrieving process command line from another process. The following APIs are often used to access the PEB directly:
- NtQueryInformationProcess: This function can be used to obtain the PEB address for a process. For example, the WMI Win32_Process class uses this function for command-line retrieval. There are also other available methods of obtaining the PEB address, including RtlGetCurrentPeb and inline assembly code.
- ReadProcessMemory: This function can be used to read memory from a process. Using this API would require knowledge of the offsets to the
CommandLine
field within theProcessParameters
structure or by linking against winternl.h.
Under what conditions does an adversary have control over the process command line?
If an adversary has already achieved arbitrary code execution, they have the ability to spawn a new process with the command-line arguments of their choosing. An adversary may supply custom command-line arguments with the following intentions:
- to supply legitimate command-line arguments to an executable that expects and will process the arguments
- to evade naive detection logic that might look for specific command-line strings
So in the scenario where an adversary already has arbitrary code execution, they have a large amount of control over the command line of the processes they spawn. You should never assume that an adversary is not tampering with command-line logging.
Under what conditions does an adversary not have control over process command line?
An adversary will not have direct control over process command line under the following conditions, among many others:
- A file is executed using its default file handler. For example, getting a victim to download and double click on a MSHTA
.hta
file would invoke the default file handler for that extension:mshta.exe <path to HTA file>
- An executable starts as a side effect of certain actions. For example, when the Add-Type cmdlet is called in PowerShell, assuming it is C# code being compiled, the C# compiler
csc.exe
is spawned as a child process with a predictable command line.
How can I simulate generation of process command line in order to perform sensor and detection validation?
Influencing process command line at process start
There are multiple APIs available to start a process with a custom command line, CreateProcess being one of the more common functions available. In order to test starting an executable with a command line, we developed a simple PowerShell wrapper to make testing easy.
PS C:\> Start-ProcessWithCommandLine -ApplicationName 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -CommandLine 'Foo'
ProcessId ExecutablePath CommandLine
--------- -------------- -----------
7032 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Foo
In the above example, what would have been a command line of C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
is Foo
instead. The ability to specify the command line at process start may not always be useful to an adversary because it would prevent their ability to supply legitimate command-line arguments. In the example above, while a powershell.exe
is masqueraded in the command line, no relevant arguments like -Command
or –EncodedCommand
were supplied, potentially limiting the value to an adversary.
Modifying process command line after process start
In order to modify process command line after process start, an adversary would need to directly access and modify the PEB of a running process. The Masquerade-PEB PowerShell function written by Ruben Boonen is available to perform test command-line modification via the PEB.
> . .\Masquerade-PEB.ps1
> $CurrentPowerShellProcess = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $PID"
> $CurrentPowerShellProcess.CommandLine
powershell.exe -NoProfile
> Masquerade-PEB -BinPath C:\Windows\explorer.exe
[?] PID 6236
[+] PebBaseAddress: 0x000000049470E000
[!] RtlEnterCriticalSection --> &Peb->FastPebLock
[>] Overwriting &Peb->ProcessParameters.ImagePathName: 0x0000014B554C2120
[>] Overwriting &Peb->ProcessParameters.CommandLine: 0x0000014B554C2130
[?] Traversing &Peb->Ldr->InLoadOrderModuleList doubly linked list
[>] Overwriting _LDR_DATA_TABLE_ENTRY.FullDllName: 0x0000014B554C2AF8
[>] Overwriting _LDR_DATA_TABLE_ENTRY.BaseDllName: 0x0000014B554C2B08
[!] RtlLeaveCriticalSection --> &Peb->FastPebLock
> $CurrentPowerShellProcess = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $PID"
> $CurrentPowerShellProcess.CommandLine
C:\Windows\explorer.exe
In the example above, powershell.exe -NoProfile
was replaced with C:\Windows\explorer.exe
. In this scenario, an adversary would have benefited from a process accepting the command-line arguments they supplied, but their evidence was then later concealed. While this scenario has the potential to buy additional evasion for an adversary, most process command-line log sources—including 4688 and Sysmon Event ID 1 events documented above—will capture the original command line prior to an adversary making modifications.
What can process command line reveal in isolation?
- It can offer a clue about the functionality of the running executable assuming the command line was not altered by an adversary.
- It can reveal the use of undocumented or underutilized command-line arguments that could potentially stand on their own as detection logic.
- Adversaries will sometimes start a process with no command-line arguments and use it as a target for process injection. For executables that expect command-line arguments, such an anomaly could serve as sufficient indication of suspicious behavior.
What can process command line reveal in relation to other data sources?
- The executable path of the process: Is the process executable filename present in the command line? Is it a full path, relative path, or just the filename? Does such a distinction tell us something? How often does the process command line not have the filename of the running executable? Could there be an opportunity to detect certain instances of adversary command line tampering?
- Binary metadata of the process executable: Does the command line correspond to the expected command-line arguments implemented in the process executable?
Conclusion
Just because an adversary can exert influence over command-line parameters does not mean that process command-line logging cannot be trusted. And just because an adversary can exert influence over command-line parameters doesn’t mean that they will. There are still plenty of opportunities to leverage process command line to detect suspicious and malicious behavior while also using it to baseline expected, legitimate behavior. Also, command-line logging that occurs at process start has the benefit of winning the race and retrieving the original process command line before an adversary can come around and cover their tracks after the fact, as is the case in the Masquerade-PEB
example above.
Our hope is that you now have a better understanding of what process command line looks like under the hood and how adversaries think about it in terms of evasion. Stay tuned for more deep dives into data sources in the coming months!