【湃哒星说安全】内网渗透技巧之RdpThief实践

0x00  背景

在实际渗透过程中,各种口令凭据的窃取是一种美妙的艺术。而我们发现,登录 RDP 会话的凭据权限都比较高,除却通过 lsass.exe 来窃取口令外,RdpThief 应用而生。本文主要结合工具 CobaltStrike 以及 RdpThief 进行测试实验,以及些许原理的说明。

0x01  测试实验

测试环境:Win7(172.16.203.131)、Win10(172.16.203.136)

测试工具:https://github.com/0x09AL/RdpThief

测试过程

首先,我们假设目标已成功上线,以 Win10 为例,执行命令 rdpthief_enable ,开启对进程 mstsc 的检测。

然后在目标机开启 RDP 客户端,输入登录需要的 Server 地址,用户名及口令。

下图红框处,可以看到当 CobaltStrike 检测到目标进程 mstsc 时,就会将 shellcode 注入到进程,通过 Hook Windows 系统 API 获取登录凭证,并将凭证写入到环境变量 temp 目录下的 data.bin 文件。

之后执行命令 rdpthief_disable ,停止对进程 mstsc 的检测;执行命令 rdpthief_dump,读取储存凭证的文件。

无论用户登录成功与否,凭证信息都会被记录下来。

0x02  原理说明

比较详细的原理,可以通过文章 https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/ 来了解。

Windows API  

因为我们整个过程的核心内容就是通过 Hook Windows 系统 API 来窃取 RDP 凭证。那么接下来,就利用工具 API monitor 监控进程 mstsc 来大概看一下,RDP 登录过程中涉及的几个比较重要的系统 API。

下图红框标出的是 Win10 监控进程 mstsc ,完整进行 RDP 成功登录过程中涉及到的 4 个主要的 API 函数。

首先是 CredReadW 函数,可以看到这个函数的第一次调用,就能获得 Server 地址 172.16.203.131。

然后是 SspiPrepareForCredRead 函数,可以看到这个函数的第二个参数 pszTargetName 也能获得 Server 地址。

接下来就是 CryptProtectMemory 函数,这个函数主要用来加密内存中的敏感信息。可以看到第一次调用的这个函数,其中包含明文用户名 Test 。

接下来第二次调用的时候,可以获得纯粹的密码明文 123456 。

接着是 CredIsMarshaledCredentialW 函数,可以看到这个函数只有一个参数,就是我们的用户名明文 Test 。

工具 RdpThief 主要利用的是以下 3 个 API 来拿到对应的信息:

CredIsMarshaledCredentialW  --> UsernameCryptProtectMemory --> PasswordSspiPrepareForCredRead --> ServerIP

但是在 Win7 中,这个过程并没有对 SspiPrepareForCredRead 函数的调用,而且整个调用过程看起来也没有 Win10 那么清晰明了。首先,仍然是 CredReadW 函数可以拿到 Server 地址 172.16.203.136 。接下来其实通过 CredPackAuthenticationBufferW 函数也能拿到用户名明文 Test 信息。

然后也可以通过 CredIsProtectedW 函数直接拿到明文密码 654321 信息。这个过程跟 Win10 是有区别的。

利用工具 RdpThief 在 Win7 进行测试实验的时候,没办法获取到 Server 地址,就是因为没有 SspiPrepareForCredRead 这个 API 。只需要修改工具代码,使其通过 CredReadW 函数来获取 Sever 地址就可以了。当然,根据上述监控 API 的调用过程,Win7 其实也能利用其他 API 函数来获取相应凭证。

Hook API

RdpThief 工具编写 hook API 的 DLL 文件,使用的是开源库 Detours ,操作和原理都很简单。下面笔者提供一个简单的 Hook MessageBox 的示例,已经写明注释,便于参考理解。

#include <Windows.h>
#include <iostream>
#include <detours.h>

static int(WINAPI * TrueMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBox;
int WINAPI _MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) {
     return TrueMessageBox(NULL, L"Hooked", L"Hooked", 0);
 }
int main()
{
DetourRestoreAfterWith(); // 恢复之前的状态
DetourTransactionBegin();  // 开始一个事务
DetourUpdateThread(GetCurrentThread()); // 更新当前线程信
DetourAttach(&(PVOID&)TrueMessageBox, _MessageBox); // 将拦截的函数 _MessageBox 附加到原函数 TrueMessageBox 的地址上
DetourTransactionCommit(); // 提交事务
MessageBox(NULL, L"We can't be hooked", L"Hello", 0); // Hooked --> _MessageBox
DetourTransactionBegin(); // 开始一个事务
DetourUpdateThread(GetCurrentThread()); // 更新当前线程信息
DetourDetach(&(PVOID&)TrueMessageBox, _MessageBox); // 解除 Hook ,将拦截的函数从原函数的地址解除
DetourTransactionCommit(); // 提交事务
}
 

RdpThief 工具的作者有提供编译 DLL 的源码。所以这里笔者建议,还是自己重新建个新项目,将代码修改后编译成 DLL 。然后通过 sRDI 工具将 DLL 转换成 shellcode ,使用作者提供的 cna 脚本。结合 CobaltStrike 工具,将 shellcode 注入到 mstsc 进程中,进行 RDP 登录凭证的窃取。

踩坑指南

因为笔者复现的过程,并没有像作者演示视频的那样顺利,所以特此将碰到的坑点记录如下:

首先最重要的,RdpThief 工具是使用 VS2015 编译成的(笔者猜测,并不确定是不是这个原因),所以测试环境需要有 Visual C++ 2015 Redistributable 或更高版本的支持。否则你永远也不知道,为什么你能注入进程,但就是获取不到数据。

然后,经过修改后的代码编译 DLL ,需要 Release 版。否则你一执行命令 rdpthief_enable ,就会看到目标 mstsc 进程瞬间被杀死。(依然不清楚根本原因。)

最后,其实是编码的问题,如果你不想最后 type 读取凭证文件看到整齐划一的空格或方框,那么建议在写文件的时候,使用 WideCharToMultiByte 函数将 Unicode 变成 ANSI。可能,强迫症患者还需要注意不同操作系统换行符的问题。(不追求完美主义者,这条可忽略。)

0x03  参考链接

https://github.com/monoxgas/sRDI

https://github.com/0x09AL/RdpThief

https://www.4hou.com/technology/21645.html

https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

湃哒星说安全

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值