简介
RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection)
代码注入
1.漏洞场景:Groovy代码注入
Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,常用于脚本开发和自动化任务
Groovy代码注入漏洞通常是由于未对用户输入进行适当的验证和过滤,导致恶意输入被直接执行为 Groovy脚本的一部分
public R vulGroovy(String payload) {
try {
GroovyShell shell = new GroovyShell();
Object result = shell.evaluate(payload);
if (result instanceof Process) {
Process process = (Process) result;
String output = getProcessOutput(process);
return R.ok("[+] Groovy代码执行,结果:" + output);
} else {
return R.ok("[+] Groovy代码执行,结果:" + result.toString());
}
} catch (Exception e) {
return R.error(e.getMessage());
}
}
private String getProcessOutput(Process process) {
StringBuilder output = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
} catch (Exception e) {
return "读取输出失败: " + e.getMessage();
}
return output.toString();
}
2.安全场景:Groovy脚本白名单
public R safeGroovy(String payload) {
List<String> trustedScripts = Arrays.asList(
"\"id\".execute()",
"\"ls\".execute()",
"\"whoami\".execute()"
);
if (!isTrustedScript(payload, trustedScripts)) {
return R.error("非法的脚本输入!");
}
try {
GroovyShell shell = new GroovyShell();
Object result = shell.evaluate(payload);
if (result instanceof Process) {
Process process = (Process) result;
String output = getProcessOutput(process);
return R.ok("[+] 执行受信任的脚本,结果:" + output);
} else {
return R.ok("[+] 执行受信任的脚本,结果:" + result.toString());
}
} catch (Exception e) {
return R.error(e.getMessage());
}
}
private boolean isTrustedScript(String script, List<String> trustedScripts) {
return trustedScripts.contains(script);
}
命令注入
1.漏洞场景:ProcessBuilder
public R vul1(String payload) throws IOException {
String[] command = {"sh", "-c",payload};
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process process = pb.start();
InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder output = new StringBuilder();
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
return R.ok(output.toString());
2.漏洞场景:Runtime.getRuntime().exec()
代码审计SINK点:
1、ProcessBuilder
2、Runtime.exec()
3、反射调用 ProcessImpl.start
public R vul2(String payload) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
Process proc = Runtime.getRuntime().exec(payload);
InputStream inputStream = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
sb.append(line);
}
return R.ok(sb.toString());
}
3.漏洞场景:ProcessImpl
安全编码规范:
1、限制执行权限:避免使用Runtime、ProcessBuilder等函数,即使使用这类函数也应确保执行命令的进程具有最小权限,避免提升到更高的权限级别。
2、避免直接拼接命令字符串:尽可能使用专门的API或库来处理系统任务,避免直接构建和执行命令字符串
3、输入验证:对所有用户输入进行严格验证,确保符合预期格式,建立白名单机制,仅允许合法的输入和命令类型
public R vul3(String payload) throws Exception {
// 获取 ProcessImpl 类对象
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
// 获取 start 方法
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
Process process = (Process) method.invoke(null, new String[]{payload}, null, null, null, false);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
return R.ok(output.toString());
}
}
4.安全场景:白名单限制
安全代码
// 验证命令是否在允许的列表中
if (!ALLOWED_COMMANDS.contains(payload)) {
return R.error("不允许执行该命令!");
}
// 可执行命令白名单
private static final List<String> ALLOWED_COMMANDS = Arrays.asList("ls", "date");