父进程欺骗DidierStevens(二)

admin 2024年8月3日15:38:43评论5 views字数 4431阅读14分46秒阅读模式

获取访问令牌DEBUG权限

getCurrentProcess 函数 (processthreadsapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess

    检索当前进程的伪句柄。伪句柄是一个特殊常量,此句柄具有对进程对象的PROCESS_ALL_ACCESS访问权限。

HANDLE GetCurrentProcess();

OpenProcessToken 函数 (processthreadsapi.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken

    OpenProcessToken 函数打开与进程关联的访问令牌。如果正在检查的进程是由其他帐户启动的,则检查过程需要启用SE_DEBUG_NAME特权(必须提供此常量才能调试和调整另一帐户拥有的进程的内存)。

BOOL OpenProcessToken(  [in]  HANDLE  ProcessHandle,  [in]  DWORD   DesiredAccess,  [out] PHANDLE TokenHandle);
参数 作用
[in] ProcessHandle 打开访问令牌的进程句柄。进程必须具有PROCESS_QUERY_LIMITED_INFORMATION访问权限。
[in] DesiredAccess 指定访问掩码,该掩码指定访问令牌的请求访问类型。
[out] TokenHandle 指向句柄的指针,该句柄标识函数返回时新打开的访问令牌。

lookupPrivilegeValueA 函数 (winbase.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluea

    LookupPrivilegeValue 函数检索本地唯一标识符 (LUID) 指定系统上用于本地表示指定特权名称。

BOOL LookupPrivilegeValueA(  [in, optional] LPCSTR lpSystemName,  [in]           LPCSTR lpName,  [out]          PLUID  lpLuid);
参数 作用
[in, optional] lpSystemName 指向以 null 结尾的字符串的指针,该字符串指定检索特权名称的系统的名称。如果指定了空字符串,则该函数将尝试在本地系统上查找特权名称。
[in] lpName 指向以 null 结尾的字符串的指针,该字符串指定权限的名称。
[out] lpLuid 指向一个变量的指针,该变量接收 LUID,lpSystemName 参数指定的系统上的权限是已知的。

TOKEN_PRIVILEGES结构 (winnt.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-token_privileges

    TOKEN_PRIVILEGES 结构包含有关访问令牌的一组特权的信息。

typedef struct _TOKEN_PRIVILEGES {  DWORD               PrivilegeCount;  LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
参数 作用
PrivilegeCount 必须将其设置为 Privileges 数组中的条目数。
Privileges 指定 LUID_AND_ATTRIBUTES 结构的数组。每个结构都包含特权的 LUID 和属性。若要获取与 LUID 关联的特权的名称,请调用 LookupPrivilegeName 函数,并将 LUID 的地址作为 lpLuid 参数的值传递。

Privileges特权的属性可以是以下值的组合:

特权值 含义
SE_PRIVILEGE_ENABLED 权限已启用。
SE_PRIVILEGE_ENABLED_BY_DEFAULT 默认情况下,权限处于启用状态。
SE_PRIVILEGE_REMOVED 用于删除特权。
SE_PRIVILEGE_USED_FOR_ACCESS 用于获取对对象或服务的访问权限。

LUID_AND_ATTRIBUTES 结构(winnt.h)

    官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-luid_and_attributes

    LUID_AND_ATTRIBUTES 结构表示 LUID(本地唯一标识符) 及其属性。

typedef struct _LUID_AND_ATTRIBUTES {  LUID  Luid;  DWORD Attributes;} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
参数 作用
Luid 指定 LUID 值。
Attributes 指定 LUID 的属性。此值最多包含 32 个一位标志。其含义取决于 LUID 的定义和使用。

adjustTokenPrivileges 函数 (securitybaseapi.h)

官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges

    AdjustTokenPrivileges 函数启用或禁用指定访问令牌中的特权。启用或禁用访问令牌中的特权需要TOKEN_ADJUST_PRIVILEGES访问权限。

BOOL AdjustTokenPrivileges(  [in]            HANDLE            TokenHandle,  [in]            BOOL              DisableAllPrivileges,  [in, optional]  PTOKEN_PRIVILEGES NewState,  [in]            DWORD             BufferLength,  [out, optional] PTOKEN_PRIVILEGES PreviousState,  [out, optional] PDWORD            ReturnLength);
参数 作用
[in] TokenHandle 包含要修改的权限的访问令牌的句柄。句柄必须具有TOKEN_ADJUST_PRIVILEGES令牌的访问权限。如果 PreviousState 参数不为 NULL,则句柄还必须具有TOKEN_QUERY访问权限。
[in] DisableAllPrivileges 指定函数是否禁用令牌的所有特权。如果此值为 TRUE,则函数将禁用所有特权并忽略 NewState 参数。如果为 FALSE,则函数根据 NewState 参数指向的信息修改权限。
[in, optional] NewState 指向 TOKEN_PRIVILEGES 结构的指针,该结构指定特权及其属性的数组。如果 DisableAllPrivileges 参数为 FALSE, 则 AdjustTokenPrivileges 函数将启用、禁用或删除令牌的这些特权。
[in] BufferLength 指定 PreviousState 参数指向的缓冲区的大小(以字节为单位)。如果 PreviousState 参数为 NULL,则此参数可以为 零。
[out, optional] PreviousState 指向缓冲区的指针,该缓冲区由 函数填充TOKEN_PRIVILEGES 结构,该结构包含函数修改的任何特权的先前状态。 如果 TOKEN_PRIVILEGES 的 PrivilegeCount 成员为零,则此函数未更改任何特权。此参数可以为 NULL。
[out, optional] ReturnLength 指向变量的指针,该变量接收 PreviousState 参数指向的缓冲区的所需大小(以字节为单位)。如果 PreviousState 为 NULL,此参数可以为 NULL。

源码分析

    要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以了。

  1. 首先要通过OpenProcessToken获取到当前进程GetCurrentProcess的访问令牌;

  2. 再用LookupPrivilegeValue获取SE_DEBUG_NAME对应的luid数值;

  3. 设置访问令牌的特权属性SE_PRIVILEGE_ENABLED;

  4. 通过AdjustTokenPrivileges启用luid对应的权限。

BOOL CurrentProcessAdjustToken(void){    HANDLE hToken;    TOKEN_PRIVILEGES sTP;    // 1. 首先要通过OpenProcessToken获取到当前进程GetCurrentProcess的访问令牌    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))    {        // 2. 再用LookupPrivilegeValue获取SE_DEBUG_NAME对应的luid数值           if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sTP.Privileges[0].Luid))        {            CloseHandle(hToken);            return FALSE;        }        // 3. 设置访问令牌的特权属性SE_PRIVILEGE_ENABLED,其用luid对应的权限        sTP.PrivilegeCount = 1;        sTP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;        // 4. 通过AdjustTokenPrivileges启用luid对应的权限        if (!AdjustTokenPrivileges(hToken, 0, &sTP, sizeof(sTP), NULL, NULL))        {            CloseHandle(hToken);            return FALSE;        }        CloseHandle(hToken);        return TRUE;    }    return FALSE;}

参考

[1]https://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/

原文始发于微信公众号(蟹堡安全团队):父进程欺骗--DidierStevens(二)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月3日15:38:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   父进程欺骗DidierStevens(二)https://cn-sec.com/archives/3028583.html

发表评论

匿名网友 填写信息