我们在Java中使用
ProcessBuilder
在Linux机器上执行Python程序。
我们添加了 Checkmarx 建议的所有验证,然后尝试执行 Checkmarx 提供的以下示例。
public String executeSystemCommand_WithParameters(HttpServletRequest request)
throws ServletException, IOException {
String commandResult = "";
String userCommand = request.getParameter("Command");
userCommand = userCommand.replaceAll("[^A-Za-z0-9]", "");
try {
ProcessBuilder builder = new ProcessBuilder("/bin/sh/","-c", PROGRAM_NAME,
userCommand);
Map<String, String> environ = builder.environment();
setEnvironmentVars(environ);
Process subProc = builder.start();
BufferedReader irProcOutput = new BufferedReader(new
InputStreamReader(subProc.getInputStream()));
String line = null;
while ((line = irProcOutput.readLine()) != null)
commandResult += line;
irProcOutput.close();
} catch (Exception ex) {
handleExceptions(ex);
}
return commandResult;
}
然而,Checkmarx 提供的这个作为解决方案的样本也产生了同样的缺陷。 请告知以下程序中可以更改哪些内容,以便解决命令行注入漏洞。
在审查查询时,
replaceAll
不被视为命令注入的消毒剂。该文档可能已过时。
虽然在这种情况下
replaceAll
会清理命令注入,但问题是静态分析无法理解根据正则表达式规范从字符串中过滤出的内容。示例中的正则表达式会删除非字母数字字符,但如果它被视为消毒剂并且有人删除了正则表达式怎么办?
考虑以下代码:
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.ProcessBuilder;
import java.util.Map;
import org.owasp.esapi.Encoder;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.codecs.UnixCodec;
import org.owasp.esapi.codecs.Codec;
class Main {
private static Encoder _enc = ESAPI.encoder();
private static Codec _codec = new UnixCodec();
public static String executeSystemCommand_sortofsafe(HttpServletRequest request) {
String commandResult = "";
String userCommand = request.getParameter("Command");
userCommand = userCommand.replaceAll("[^A-Za-z0-9]", "");
try {
ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", userCommand);
Process subProc = builder.start();
BufferedReader irProcOutput = new BufferedReader(new InputStreamReader(subProc.getInputStream()));
String line = null;
while ((line = irProcOutput.readLine()) != null)
commandResult += line;
irProcOutput.close();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return commandResult;
}
public static String executeSystemCommand_samebutnotsafe(HttpServletRequest request) {
String commandResult = "";
String userCommand = request.getParameter("Command");
// modify the regex to thwart sanitization
userCommand = userCommand.replaceAll("", "");
try {
ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", userCommand);
Process subProc = builder.start();
BufferedReader irProcOutput = new BufferedReader(new InputStreamReader(subProc.getInputStream()));
String line = null;
while ((line = irProcOutput.readLine()) != null)
commandResult += line;
irProcOutput.close();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return commandResult;
}
public static String executeSystemCommand_safe(HttpServletRequest request) {
String commandResult = "";
String userCommand = request.getParameter("Command");
// This is verifiable by static analysis, not subject to regex changes.
userCommand = _enc.encodeForOS(_codec, userCommand);
try {
ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", userCommand);
Process subProc = builder.start();
BufferedReader irProcOutput = new BufferedReader(new InputStreamReader(subProc.getInputStream()));
String line = null;
while ((line = irProcOutput.readLine()) != null)
commandResult += line;
irProcOutput.close();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return commandResult;
}
}
方法
executeSystemCommand_sortofsafe
是记录示例的精确副本。在这种情况下,这是假阳性。
现在考虑方法
executeSystemCommand_samebutnotsafe
。代码是相同的,但正则表达式被删除。这会导致输入未被清理。如果 replaceAll
被视为消毒剂,这将是假阴性。静态分析不会运行带有示例有效负载的代码来了解正则表达式如何改变输入字符串。
方法
executeSystemCommand_safe
中显示了一种清理代码的方法。 EASPI 库用于生成可验证的清理方法。 EASPI 库不会受到会改变逻辑的本地代码更改的影响,就像正则表达式被错误(甚至恶意)修改时的情况一样。
如果您扫描此代码示例,您将看到 2 个流经
replaceAll
的命令注入结果,但您不会看到使用 ESAPI 的示例的结果。我验证了查询发现 Encoder.encodeForOS
作为消毒剂。