.NET | 详解通过Win32函数实现本地提权
01阅读须知
此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他方面
02Windows权限控制
LookupPrivilegeValue 是 Windows API 的一个函数,主要用于获取权限的 LUID,结合其他 API(如 AdjustTokenPrivileges),可实现精细化的权限控制。
2.1 LookupPrivilege
LookupPrivilegeValue 用于检索指定系统中某个权限的局部唯一标识符 (LUID)。LUID 是权限的内部表示形式,用于后续的权限管理操作,例如启用或禁用权限。
通过这个函数,你可以将权限的名字(如 SeDebugPrivilege)转换为 LUID,这一步通常是权限操作的必要前提,具体代码如下所示。
[DllImport("advapi32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupPrivilegeValue(
[MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
[MarshalAs(UnmanagedType.LPTStr)] string lpName,
out LUID lpLuid
);
声明这是一个 P/Invoke 函数,来自 advapi32.dll 动态链接库,该库包含与高级 Windows 安全相关的功能,指定如何在托管代码和非托管代码之间转换字符串。LPTStr 使得字符串在运行时会根据 CharSet 决定是 ANSI 还是 Unicode。
以下是一个完整的 C# 示例,展示如何使用 LookupPrivilegeValue 函数获取权限的 LUID,代码如下所示。
using System;
using System.Runtime.InteropServices;
class Program
{
// 引用 LUID 结构体
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
// P/Invoke 声明 LookupPrivilegeValue
[DllImport("advapi32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupPrivilegeValue(
[MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
[MarshalAs(UnmanagedType.LPTStr)] string lpName,
out LUID lpLuid
);
static void Main()
{
// 要查询的权限名称
string privilegeName = "SeDebugPrivilege";
// 用于接收 LUID
LUID luid;
// 调用 LookupPrivilegeValue
if (LookupPrivilegeValue(null, privilegeName, out luid))
{
Console.WriteLine($"Privilege Name: {privilegeName}");
Console.WriteLine($"LUID: {luid.HighPart:X8}{luid.LowPart:X8}");
}
else
{
// 获取错误码
int error = Marshal.GetLastWin32Error();
Console.WriteLine($"Failed to lookup privilege. Error Code: {error}");
}
}
}
privilegeName 指定了目标权限,例如 SeDebugPrivilege,调用 LookupPrivilegeValue,传入系统名称(null 表示本地系统)和权限名称。成功时,返回权限的 LUID,可以用于后续权限管理操作。
2.2 AdjustTokenPrivilege
AdjustTokenPrivileges 是 Windows API 的一个函数,用于启用或禁用指定访问令牌中的一组权限。这是操作系统权限管理的重要功能,通过它可以动态调整进程或线程的权限。以下是 AdjustTokenPrivileges 的 P/Invoke 声明
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
uint BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength
);
TokenHandle 是一个访问令牌的句柄(通常是当前进程或线程的令牌),DisableAllPrivileges 参数表示指定是否禁用所有权限。以下代码演示如何启用当前进程的 SeDebugPrivilege。
using System;
using System.Runtime.InteropServices;
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public uint PrivilegeCount;
public LUID Luid;
public uint Attributes;
}
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LookupPrivilegeValue(
string lpSystemName,
string lpName,
out LUID lpLuid
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken(
IntPtr ProcessHandle,
uint DesiredAccess,
out IntPtr TokenHandle
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
uint BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength
);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
const uint TOKEN_QUERY = 0x0008;
const uint SE_PRIVILEGE_ENABLED = 0x00000002;
static void Main()
{
// 获取当前进程的令牌
IntPtr tokenHandle;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out tokenHandle))
{
Console.WriteLine("Failed to open process token.");
return;
}
// 查找 SeDebugPrivilege 的 LUID
LUID luid;
if (!LookupPrivilegeValue(null, "SeDebugPrivilege", out luid))
{
Console.WriteLine("Failed to lookup privilege.");
return;
}
// 设置权限状态
TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES
{
PrivilegeCount = 1,
Luid = luid,
Attributes = SE_PRIVILEGE_ENABLED
};
// 调整权限
if (!AdjustTokenPrivileges(tokenHandle, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
{
Console.WriteLine("Failed to adjust token privileges.");
}
else
{
Console.WriteLine("SeDebugPrivilege enabled successfully.");
}
}
}
上述代码通过使用 OpenProcessToken 获取当前进程的访问令牌,再调用 AdjustTokenPrivileges 启用或禁用指定权限。
03工具实现
Sharp4Token.exe 正是基于这种机制开发的一款本地提权工具。通过搜寻目标系统中可用的高权限令牌,并模拟或替换当前进程的令牌,成功实现权限提升。该工具广泛应用于渗透测试和红队模拟中,是攻击者在本地环境下提权的强大武器。
通过捕获并利用高权限令牌(如 NT AUTHORITY\SYSTEM),将普通用户权限提升至管理员甚至系统级别,并使用高权限令牌直接启动具有管理员或系统权限的命令提示符。工具的基本使用方式如下:
Sharp4Token execute "NT AUTHORITY\SYSTEM" cmd true
参数"NT AUTHORITY\SYSTEM",表示目标令牌的用户标识,通常是高权限账户,如 SYSTEM 或 Administrator。
工具通过调用 Windows API,例如 OpenProcess 和 OpenProcessToken,枚举系统中所有正在运行的进程,并尝试打开其访问令牌,使用高权限令牌,通过调用 ImpersonateLoggedOnUser 或 SetTokenInformation 实现当前进程权限的提升。
05.NET安全星球
dot.Net安全矩阵星球已成为中国.NET安全领域最知名、最活跃的技术知识库之一,从.NET Framework到.NET Core,从Web应用到PC端软件应用,并且每日分享.NET安全技术干货以及交流解答各类技术等问题,社区中发布很多高质量的.NET安全资源,可以说市面上很少见,都是干货。
星球文化始终认为授人以鱼不如授人以渔!加入星球后可以跟星主和嘉宾们一对一提问交流,20+个专题栏目涵盖了点、线、面、体等知识面,助力师傅们快速成长!其中主题包括.NET Tricks、漏洞分析、内存马、代码审计、预编译、反序列化、webshell免杀、命令执行、C#工具库等等。
我们倾力打造专刊、视频等配套学习资源,循序渐进的方式引导加深安全攻防技术提高以及岗位内推等等服务。
.NET 免杀WebShell
.NET 反序列化漏洞
.NET 安全防御绕过
.NET 内网信息收集
.NET 本地权限提升
.NET 内网横向移动
.NET 目标权限维持
.NET 数据外发传输
这些阶段所涉及的工具集不仅代表了当前.NET安全领域的最前沿技术,更是每一位网络安全爱好者不可或缺的实战利器。
文章涉及的工具已打包,请加/入/后下/载:https://wx.zsxq.com/group/51121224455454