SEC504: Hacker Tools, Techniques, and Incident Handling

Experience SANS training through course previews.
Learn MoreLet us help.
Contact usConnect, learn, and share with other cybersecurity professionals
Engage, challenge, and network with fellow CISOs in this exclusive community of security leaders
Become a member for instant access to our free resources.
Sign UpMission-focused cybersecurity training for government, defense, and education
Explore industry-specific programming and customized training solutions
Sponsor a SANS event or research paper
We're here to help.
Contact UsPowerShell is a powerful tool for threat hunting. Let's look at PowerShell threat hunting steps by assessing processes on Windows.
When performing threat hunting and live system analysis, I will often look at the processes running on the system. Often, a compromised system will run one or more processes that look suspicious, which gives us an opportunity to identify the threat.
Let's look at how we can use PowerShell to evaluate a running system. We'll focus on two primary PowerShell commands: [code]Get-Process[/code] and [code]Get-CimInstance[/code] using the [code]Win32_Process[/code] class. This first article will focus on using the PowerShell commands and collecting the data. In the second article, we'll look at applying these commands to investigate malicious code running on a Windows host.
PowerShell makes it easy to list processes using [code]Get-Process[/code]:
PS C:\Users\Sec504> Get-Process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
317 32 42576 107816 2.77 1520 1 chrome
310 33 103376 81224 2.98 1708 1 chrome
151 9 2008 6980 0.02 2660 1 chrome
209 13 6788 16640 0.05 4844 1 chrome
988 42 51576 114540 3.28 6368 1 chrome
...
We can investigate a specific process by supplying the process name as an argument:
PS C:\Users\Sec504> Get-Process explorer
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
2332 93 82448 134420 14.31 4808 1 explorer
Wildcards work too:
PS C:\Users\Sec504> Get-Process vm*
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
92 7 1328 920 0.03 6520 1 vm3dservice
445 23 8672 10872 3200 0 vmtoolsd
541 36 23796 28980 13.64 6356 1 vmtoolsd
In the [code]Get-Process[/code] output, we get several columns of detail for each process:
The defaults are useful, but perhaps more to system administrators than security analysts. Fortunately, [code]Get-Process[/code] offers more process details as well.
We can get a list of the process properties details available with [code]Get-Process[/code] using [code]Get-Member[/code]:
PS C:\Users\Sec504> Get-Process | Get-Member -MemberType Properties
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize64
PM AliasProperty PM = PagedMemorySize64
SI AliasProperty SI = SessionId
VM AliasProperty VM = VirtualMemorySize64
WS AliasProperty WS = WorkingSet64
__NounName NoteProperty string __NounName=Process
BasePriority Property int BasePriority {get;}
Container Property System.ComponentModel.IContainer Container {get;}
EnableRaisingEvents Property bool EnableRaisingEvents {get;set;}
...
For incident response investigations, I like to examine the following parameters for processes:
Here's where I get disappointed with [code]Get-Process[/code]: it offers a lot of useful information, but it also omits lots of useful details about processes. We can modify the columns retrieved to get specific properties using [code]Select-Object[/code]:
PS C:\Users\Sec504> Get-Process chrome | Select-Object -Property Name, Id, Path, WorkingSet64
Name Id Path WorkingSet64
---- -- ---- ------------
chrome 1520 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 110432256
chrome 1708 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 82894848
chrome 2660 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 7159808
chrome 4844 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 16973824
chrome 6368 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 117047296
chrome 7496 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 26345472
chrome 7528 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 26374144
Unfortunately, [code]Get-Process[/code] doesn't offer all of the detail we want. Fortunately, Microsoft also makes [code]Get-CimInstance[/code] available.
[code]Get-Process[/code] is good for simple interrogation of processes, but if you want detailed information, you'll want to use [code]Get-CimInstance[/code] instead with the [code]Win32_Process[/code] class.
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process
ProcessId Name HandleCount WorkingSetSize VirtualSize
--------- ---- ----------- -------------- -----------
0 System Idle Process 0 8192 8192
4 System 2471 36864 3985408
92 Registry 0 27586560 94515200
316 smss.exe 53 274432 2203359694848
424 csrss.exe 578 2191360 2203413659648
...
At first glance, [code]Get-CimInstance -Class Win32_Process[/code] returns information that is similar to that of [code]Get-Process[/code], but we can get a lot more process detail information from [code]Get-CimInstance[/code]:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Get-Member -MemberType Properties
TypeName: Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
ProcessName AliasProperty ProcessName = Name
VM AliasProperty VM = VirtualSize
WS AliasProperty WS = WorkingSetSize
Caption Property string Caption {get;}
CommandLine Property string CommandLine {get;}
CreationClassName Property string CreationClassName {get;}
...
Often I'll use the following set of parameters to collect information about running processes when I'm looking for threats on a Windows system:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Select-Object -Property Name, HandleCount, ProcessId, ParentProcessId, Path, CommandLine, WriteTransferCount, ReadTransferCount, WorkingSetSize
...
Name : chrome.exe
HandleCount : 317
ProcessId : 1520
ParentProcessId : 6368
Path : C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
CommandLine : "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --type=renderer
--display-capture-permissions-policy-allowed --lang=en-US --device-scale-factor=2
--num-raster-threads=1 --renderer-client-id=5 --launch-time-ticks=3385309652
--mojo-platform-channel-handle=2832
--field-trial-handle=1804,i,7538668890417119548,1058345838094988730,131072 /prefetch:1
WriteTransferCount : 22843548
ReadTransferCount : 2816643
WorkingSetSize : 110432256
...
[code]Get-CimInstance[/code] does not allow us to specify a process name as an argument like [code]Get-Process[/code] does. If you want to use [code]Get-CimInstance[/code] to return information about a specific process by name, you can add a [code]Where-Object[/code] command to the pipeline:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Select-Object -Property Name, HandleCount, ProcessId, ParentProcessId, Path, CommandLine, WriteTransferCount, ReadTransferCount, WorkingSetSize | Where-Object -Property Name -E "explorer.exe"
Name : explorer.exe
HandleCount : 2244
ProcessId : 4808
ParentProcessId : 4760
Path : C:\WINDOWS\Explorer.EXE
CommandLine : C:\WINDOWS\Explorer.EXE
WriteTransferCount : 89089
ReadTransferCount : 5787331
WorkingSetSize : 131350528
Let's look at an example of applying these PowerShell process-interrogation techniques: parent and child relationships. Using [code]Get-CimInstance[/code], we can identify the parent process ID ([code]ParentProcessId[/code]) for a given process. The parent process ID tells us the process that launched the process. Let's get the PID of the Chrome process first:
PS C:\Users\Sec504> Get-Process chrome |Select-Object -Property Name, Id
Name Id
---- --
chrome 1520
chrome 1708
chrome 2660
chrome 4844
chrome 6368
chrome 7496
chrome 7528
Here we see [code]Get-Process[/code] has identified 7 Chrome processes with different process ID values. Unfortunately, [code]Get-Process[/code] can't identify the parent process ID, so we turn to [code]Get-CimInstance[/code] for that:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Where-Object -Property Name -EQ chrome.exe | Select-Object Name, ProcessId, ParentProcessId
Name ProcessId ParentProcessId
---- --------- ---------------
chrome.exe 6368 4808
chrome.exe 2660 6368
chrome.exe 1708 6368
chrome.exe 7496 6368
chrome.exe 4844 6368
chrome.exe 7528 6368
chrome.exe 1520 6368
In this output we see that the first Chrome process has a process ID of 6368; all other Chrome processes are children of this first Chrome process since they all have process ID 6368 as their parent process ID.
That's great, but how do we identify the parent of process ID 6368? Just a slight modification to the [code]Get-CimInstance[/code] command gives us the answer:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Where-Object -Property ProcessId -EQ 4808 | Select-Object Name, ProcessId, ParentProcessId
Name ProcessId ParentProcessId
---- --------- ---------------
explorer.exe 4808 4760
After identifying process ID 4808 as the parent for the first Chrome process, we can identify the process name by changing the [code]Where-Object[/code] clause to filter on the [code]ProcessId[/code] field, revealing the parent process as [code]explorer.exe[/code]. We can repeat this process for Explorer as well:
PS C:\Users\Sec504> Get-CimInstance -Class Win32_Process | Where-Object -Property ProcessId -EQ 4760 | Select-Object Name, ProcessId, ParentProcessId
PS C:\Users\Sec504>
Notably here, Explorer has no parent. It's a special process launched by Userinit when a user logs in, and then Userinit exits. This makes Explorer an orphan process, revealing no parent information when we investigate the parent process ID.
We looked at the [code]Get-Process[/code] command as a tool to retrieve information about running processes. [code]Get-Process[/code] accepts a process name or wildcard, allowing us to quickly filter the results. This is convenient, but [code]Get-Process[/code] is also limited: it doesn't allow us to inspect several properties that are useful for incident response analysis.
We also looked at [code]Get-CimInstance[/code] using the [code]Win32_Process[/code] class. [code]Get-CimInstance[/code] can reveal valuable process properties for incident response analysts: path, command line, parent process ID, and more. Filtering is a little more complicated with [code]Get-CimInstance[/code], but the [code]Where-Object[/code] command helps out here.
Finally we looked at a practical investigation opportunity using [code]Get-CimInstance[/code], investigating the relationship between process ID and parent process ID. We'll continue to leverage this in the next article, where we use these process threat hunting skills on a compromised system to hunt our malware.
-Joshua Wright
Return to Getting Started With PowerShell
Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.
As Senior Technical Director at Counter Hack and SANS Faculty Fellow, Joshua has advanced cybersecurity through ethical penetration testing, uncovering critical vulnerabilities across Fortune 500 companies and national infrastructure providers.
Read more about Joshua Wright