如何使用CODASM编码Payload并降低熵值

admin 2024年9月17日16:04:31评论16 views字数 7159阅读23分51秒阅读模式

如何使用CODASM编码Payload并降低熵值

关于CODASM

CODASM是一款针对Payload的编码工具,该工具针对红蓝队研究人员设计,可以帮助我们对Payload执行编码操作并显著降低Payload的熵值。

如何使用CODASM编码Payload并降低熵值

该工具允许您将任意数据编码为伪 ASM 指令,并将其编译到二进制文件的 .text 部分。

开销为 80-120%(例如 380KB CS shellcode => 870KB CODASM 有效负载)。

功能介绍

Payload(尤其是 shellcode)具有相当高的熵,在编译后的二进制文件中的大多数位置看起来都不合适。CODASM 旨在将Payload隐藏在已经具有高熵的位置:.text包含二进制文件编译代码的部分。为此,CODASM 将生成良性 shellcode,并支持嵌入任意Payload。

CODASM 是一个 Python 脚本,可以生成以下内容:

1、良性的 shellcode,用于任意Payload;

2、一个 C 头文件,你可以在程序中使用它将 shellcode 嵌入到二进制文件中,并在运行时检索它;

对于编码Payload,CODASM 执行以下操作:

1、生成有效 x86_64 函数;

2、将Payload字节嵌入到指令操作数中(例如mov eax, <4 bytes of payload>);

3、对嵌入的Payload字节进行异或加密;

为了解码Payload,生成的 C 头文件执行以下操作:

1、解析单个指令,直到检索到所需数量的Payload字节:

2、检测单个指令,确定它们是否包含Payload字节;

3、如果指令包含Payload字节,则提取并解密它们;

工具要求

Python 3

工具安装

由于该工具基于Python 3开发,因此我们首先需要在本地设备上安装并配置好最新版本的Python 3环境。

接下来,广大研究人员可以直接使用下列命令将该项目源码克隆至本地:

git clone https://github.com/NVISOsecurity/codasm
工具使用
usage: codasm.py [-h] -i INPUT [-oa OUT_ASM] [-ob OUT_BIN] [-oc OUT_C] [-op OUT_P] [--rng RNG] [-vbmin VAL_BYTES_MIN] [-vbmax VAL_BYTES_MAX] [-vbch VAL_BYTES_CHANCE] [-v]CODASM encoding utilityoptions:  -h, --help           显示此帮助消息并退出  -i INPUT, --input INPUT                        要编码为ASM/二进制指令的输入文件的路径  -oa OUT_ASM, --out-asm OUT_ASM                        将生成的ASM指令写入的路径  -ob OUT_BIN, --out-bin OUT_BIN                       将生成的二进制指令写入的路径  -oc OUT_C, --out-c OUT_C                        将生成的CODASM解码器写入的路径  -op OUT_P, --out-p OUT_P                        将嵌入式Payload写入的路径  --rng RNG     用于随机化的rng种子(异或密钥、有效载荷指令顺序、解码操作顺序)  -vbmin VAL_BYTES_MIN, --val-bytes-min VAL_BYTES_MIN                        编码到单个方法中的最小字节数(默认值64)  -vbmax VAL_BYTES_MAX, --val-bytes-max VAL_BYTES_MAX                        编码到单个方法中的最大字节数(默认256)  -vbch VAL_BYTES_CHANCE, --val-bytes-chance VAL_BYTES_CHANCE                        操作成为编码数据而不是虚拟数据的机会(0.1-0.9,默认值0.1)  -v, --verbose   输出详细程度(0-3,默认值0)Note: ASM output is meant to be used for manual reference, not for compiling!
使用样例

1、准备 shellcode (例如 CS/BR shellcode) 并另存为shellcode.bin;

2、使用 CODASM 对 shellcode 进行编码:

./codasm.py --i shellcode.bin -oc codasmloader.h

3、复制codasmloader.h到您最喜欢的加载器或独立的最小加载器中(例如/demo/codasm.c);

4、确保decode在调用 shellcode 之前调用 CODASM:

/* ~snip CODASM decode~*/#include <stdlib.h>// "INTEXT" macro ensures that the payload is pleced into the `.text` sectionINTEXT uint8_t payload[5978] = {    0x50, 0x53, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, /* ... */};int main() {    uint64_t xor_key = 0xFFFDA6803A51E3FB; // Generated by CODASM    uint8_t* input = (uint8_t*)payload;    uint8_t* output = (uint8_t*)malloc(sizeof(payload));    uint32_t output_length = 0xac4;    int32_t res = 0;    if ((res = decode(input, sizeof(payload), output, output_length, xor_key)) < 0)        return 1; // Some doo-doo happened, investigate value of res    // You successfully recovered the payload, do something fun with it here :)    return 0;}

5、编译你的加载器;

6、确保生成的二进制文件删除所有调试信息;

工具运行演示
# Input file$ cat test.txtmy secret message# Encode & generate C file$ ./codasm.py -i test.txt -ob test.bin -oa test.asm -oc test.c# Generated mashine code$ xxd test.bin00000000: 5053 5152 4150 4151 4152 4153 4154 4155  PSQRAPAQARASATAU00000010: 4156 4157 4883 ec28 751b 757f c705 5696  AVAWH..(u.u...V.00000020: 44e9 6df6 61d6 84c0 488d 0d91 9e02 2640  D.m.a...H.....&@00000030: 32ff b91b 8052 f975 8283 f99c 85c9 7513  2....R.u......u.00000040: 4883 c428 415f 415e 415d 415c 415b 415a  H..(A_A^A]AA[AZ00000050: 4159 4158 5a59 5b68 c3cc                 AYAXZY[X..# Generated ASM$ cat test.asmpush rax...push r15sub RSP, 0x28jnz 0x1Bjnz 0x7Fmov 0xE9449656,0xD661F66Dtest al,allea 0x26029E91xor dil,dilmov ecx,0xF952801Bjnz 0x82cmp ecx,0x9Ctest ecx,ecxjnz 0x13add RSP, 0x28pop r15...pop raxretn; Padding# Prepare generated C file for compilation$ sed -i "s//* Generated.*//" test.c$ sed -i "s/Sample usage://" test.c$ sed -i "s/}*//}/" test.c# Minimal program in C file:$ tail -n 30 test.c#endif // CODASM_DECODE#include <stdlib.h>INTEXT uint8_t payload[90] = {    0x50, 0x53, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, /* ... */int main() {    uint64_t xor_key = 0xFBE38A21E5760676;    uint8_t* input = (uint8_t*)payload;    uint8_t* output = (uint8_t*)malloc(sizeof(payload));    uint32_t output_length = 0x11;    int32_t res = 0;    if ((res = decode(input, sizeof(payload), output, output_length, xor_key)) < 0)        return 1; // Some doo-doo happened, investigate value of res    // You successfully recovered the payload, do something fun with it here :)    return 0;}# Compile using MINGW$ x86_64-w64-mingw32-gcc test.c -o test.exe# Find generated ASM in compiled EXE:$ objdump -d test.exe...0000000140002da0 <payload>:   140002da0: 50                    push   %rax   ...   140002db2: 41 57                 push   %r15   140002db4: 48 83 ec 28           sub    $0x28,%rsp   140002db8: 75 1b                 jne    140002dd5 <payload+0x35>   140002dba: 75 7f                 jne    140002e3b <main+0x41>   140002dbc: c7 05 56 96 44 e9 6d movl   $0xd661f66d,-0x16bb69aa(%rip)        # 12944c41c <__size_of_stack_reserve__+0x12924c41c>   140002dc3: f6 61 d6   140002dc6: 84 c0                 test   %al,%al   140002dc8: 48 8d 0d 91 9e 02 26 lea    0x26029e91(%rip),%rcx        # 16602cc60 <.debug_ranges+0x25fde970>   140002dcf: 40 32 ff              xor    %dil,%dil   140002dd2: b9 1b 80 52 f9        mov    $0xf952801b,%ecx   140002dd7: 75 82                 jne    140002d5b <decode+0x4f>   140002dd9: 83 f9 9c              cmp    $0xffffff9c,%ecx   140002ddc: 85 c9                 test   %ecx,%ecx   140002dde: 75 13                 jne    140002df3 <payload+0x53>   140002de0: 48 83 c4 28           add    $0x28,%rsp   140002de4: 41 5f                 pop    %r15   ...   140002df7: 58                    pop    %rax   140002df8: c3                    ret       140002df9: cc                    int3...

嵌入的payload在IDA中如下所示:

如何使用CODASM编码Payload并降低熵值

检测

您可以使用以下 YARA 规则来潜在地检测嵌入 CODASM 生成的输出的 PECOFF 文件。您可以在代码块下方找到规则的简要说明:

import "pe"import "math"private rule IsPE{    meta:        description = "Tests whether the file starts with the MZ header."        author = "Moritz Thomas"        date = "2024-07-24"    condition:        uint16(0) == 0x5A4D}private rule ExampleUsage{    meta:        description = "Detects malloc and invoking the decode function, passing in references to the .data section"        author = "Moritz Thomas"        date = "2024-07-24"    strings:        $AllocDecode = {            8b 0d ?? ?? ?? ??   // MOV ECX, dword ptr [DAT_1400fb070]            89 4c 24 ??         // MOV dword ptr [RSP + 0x3c], ECX            e8 ?? ?? ?? ??      // CALL MSVCRT.DLL::malloc                               // ECX = DAT_1400fb070                               // [RSP + 0x3c] = ECX                               // malloc()            8b 15 ?? ?? ?? ??   // MOV EDX, dword ptr [DAT_1400fb080]            44 8b 4c 24 ??      // MOV R9D, dword ptr [RSP + 0x3c]                               // EDX = DAT_1400fb080                               // R9D = [RSP + 0x3c]            48 8d 0d ?? ?? ?? ?? // LEA RCX, [FUN_140001460]            48 89 c3            // MOV RBX, RAX            48 8b 05 ?? ?? ?? ?? // MOV RAX, qword ptr [DAT_1400fb090]            49 89 d8            // MOV R8, RBX            48 89 44 24 ??      // MOV qword ptr [RSP + 0x20], RAX                               // RCX = &FUN_140001460                               // RBX = RAX                               // RAX = DAT_1400fb090                               // R8 = RBX                               // [RSP + 0x20] = RAX            e8 ?? ?? ?? ??      // CALL FUN_1400f9cf0                               // FUN_1400f9cf0()            89 c2               // MOV EDX, EAX            85 c0               // TEST EAX, EAX            79 13               // JNS LAB_1400fac7b                               // EDX = EAX                               // if (EAX >= 0) goto LAB_1400fac7b            48 8d 0d ?? ?? ?? ?? // LEA RCX, [LAB_1400fc0e3]            e8 ?? ?? ?? ??      // CALL FUN_1400faae0                               // RCX = &LAB_1400fc0e3                               // FUN_1400faae0()            b8 01 00 00 00      // MOV EAX, 0x1            eb ??               // JMP !AB_1400faca3                               // EAX = 1                               // goto LAB_1400faca3            83 f8 42            // CMP EAX, 0x42            75 ??               // JNZ LAB_1400fac8a                               // if (EAX != 0x42) goto LAB_1400fac8a            b9 22 00 00 00      // MOV ECX, 0x22            e8 ?? ?? ?? ??      // CALL FUN_140001460                               // ECX = 0x22                               // FUN_140001460()        }        // if (iVar2 == 0x42) FUN_140001460(0x22, 0x42);        $PseudoCall= {            83 f8 42          // CMP EAX, 0x42            75 ??             // JNZ LAB_1400FACA3            b9 22 00 00 00    // MOV ECX, 0x22            e8 ?? ?? ?? ??    // CALL FUN_140001460        }    condition:        IsPE and $AllocDecode and $PseudoCall}private rule Decode{    meta:        description = "Detects parameter validation (null-checks), returning -2 and performing a pseudo call RBX(22h)"        author = "Moritz Thomas"        date = "2024-07-24"    strings:        $NullTest = {            48 85 c9 // TEST    param_1,param_1            74 ??    // JZ      LAB_1400f9d76            4d 85 c0 // TEST    param_3,param_3            74 ??    // JZ      LAB_1400f9d76        }        $ReturnMinusTwo = {            b8 fe ff ff ff  // MOV  EAX,0xfffffffe        }        $PseudoCall = {            b9 22 00 00 00  // MOV  ECX,0x22            ff d3           // CALL RBX        }    condition:        IsPE and $NullTest and $ReturnMinusTwo and $PseudoCall}private rule PEAnalysis{    meta:        description = "Detects PE files with very large .text sections (>=90%) that have reasonable entropy (5.0 < e(.text) < 7.0)."        author = "Moritz Thomas"        date = "2024-07-24"    condition:        IsPE and // Check for MZ header        for any i in (0..pe.number_of_sections - 1) : (            pe.sections[i].name == ".text"  and            pe.sections[i].raw_data_size > (filesize * 0.9) and            math.in_range(                math.entropy(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size),                5.0, 7.0            )        )}rule CODASMed{    condition:        ExampleUsage or (Decode and PEAnalysis)}
许可证协议

本项目的开发与发布遵循MIT开源许可协议。

项目地址

CODASM

https://github.com/NVISOsecurity/codasm

原文始发于微信公众号(FreeBuf):如何使用CODASM编码Payload并降低熵值

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月17日16:04:31
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   如何使用CODASM编码Payload并降低熵值https://cn-sec.com/archives/3176040.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息