每个 Java 应用都有一个 Runtime 类的实例, 一般需要使用 shell 时调用它,从而可以在 POSIX 中 使用/bin/sh 或者在Windows 平台中使用cmd.exe。 当参数中包含以空格、双引号或者其他以一/开头 的用来表示分支的字符时,就可能发生参数注入攻击。任何源于程序受信边界之外的字符串数据,在当 前平台作为命令来执行之前,都应经过净化。
对于净化传递给 Runtime,exec() 方法的非受信数据的情况,示例1给出了不规范用法(Java 语言) 示例。示例2给出了规范用法(Java 语言)示例。
示例1(Windows):class DirList {public static void main(String[] args) throws Exception {String dir = System.getProperty("dir");Runtime rt = Runtime.getRuntime();Process proc = rt.exec("cmd.exe /C dir"+ dir);int result = proc.waitFor();if (result!= 0){System.out.printIn("process error:"+ result);InputStream in =(result ==0)? proc.getInputStream():proc.getErrorStream();int c;while((c = in.read())!=- 1){System.out.print((char)c);}
该代码示例使用dir命令列出目录列表。这是通过 Runtime.exec() 方法调用 Windows 的 dir命令来实现的。因为Runtime.exec() 方法接受源于运行环境的未经净化的数据,所以这些代码会引起命令 注入攻击。
攻击者可以通过以下命令利用该程序:
java-Ddir='dummy &.echo bad'Java
该命令实际上执行的是两条命令:
cmd.exe /C dir dummy &. echo bad
第一条命令会列出并不存在的dummy文件夹,并且在控制台上输出 bad。
示例2(净化):if(!Pattern.matches("[0-9A-Za-z@.]+",dir)){//..}
这个符合规范的代码实例会对非受信的用户输入进行净化,只允许白名单中的字符出现在参数中,并传给 Runtime.exec()方法,其他所有的字符都会被排除掉。