package testcode.command; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import javax.servlet.http.HttpServletRequest; public abstract class CommandInjection { public static HttpServletRequest req; //Could be override at any time. (tainted) public static void main(String[] args) throws IOException { String input = args.length > 0 ? args[0] : ";cat /etc/passwd"; List<String> cmd = Arrays.asList("ls", "-l", input); //Runtime exec() Runtime r = Runtime.getRuntime(); r.exec("ls -l " + input); r.exec("ls -l " + input, null); r.exec("ls -l " + input, null, null); r.exec(cmd.toArray(new String[cmd.size()])); r.exec(cmd.toArray(new String[cmd.size()]), null); r.exec(cmd.toArray(new String[cmd.size()]), null, null); //ProcessBuilder new ProcessBuilder() .command("ls", "-l", input) .start(); new ProcessBuilder() .command(cmd) .start(); } public void bad(String tainted) throws IOException { StringBuilder builder = new StringBuilder("<" + tainted + ">"); builder.insert(3, tainted).append(""); builder.reverse(); StringBuilder builder2 = new StringBuilder("xxx"); builder2.append("").append(builder); String safe = "yyy"; String unsafe = safe.replace("y", builder2.toString()); Runtime.getRuntime().exec(unsafe.toLowerCase().substring(1).intern()); } public void good() throws IOException { String hardcoded = "constant"; boolean b = "xxx".equals(hardcoded); StringBuilder builder = new StringBuilder("<" + hardcoded + ">"); builder.insert(3, hardcoded).append(""); builder.reverse(); StringBuilder builder2 = b ? new StringBuilder("xxx") : new StringBuilder(8); builder2.append("").append(builder); String safe = "yyy"; String unsafe = safe.replace("y", builder2.toString()); Runtime.getRuntime().exec(unsafe.toLowerCase().substring(1).intern()); } public void badWithException() throws Exception { String data = ""; File file = new File("C:\\data.txt"); FileInputStream streamFileInput; InputStreamReader readerInputStream; BufferedReader readerBuffered; try { streamFileInput = new FileInputStream(file); readerInputStream = new InputStreamReader(streamFileInput, "UTF-8"); readerBuffered = new BufferedReader(readerInputStream); data = readerBuffered.readLine(); } catch (IOException ex) { } Runtime.getRuntime().exec(data); } public void badInterMethod() throws Exception { Runtime.getRuntime().exec(taintSource("")); } public void goodInterMethod() throws Exception { Runtime.getRuntime().exec(safeSource(0)); } public void badWithTaintSink() throws Exception { taintSink("safe", req.getHeader("x")); } private void taintSink(String param1, String param2) throws Exception { Runtime.getRuntime().exec(param1 + " safe " + param2); } public void badWithDoubleTaintSink() throws Exception { taintSinkTransfer(req.getParameter("y")); } public void taintSinkTransfer(String str) throws Exception { taintSink2(str.toLowerCase()); } public static void taintSink2(String param) throws Exception { Runtime.getRuntime().exec(param); } public void badCombo() throws Exception { String str = taintSourceDouble().toUpperCase(); str = str.concat("aaa" + "bbb"); comboSink(new StringBuilder(str).substring(1)); } public void comboSink(String str) throws Exception { Runtime.getRuntime().exec(str); } public void badTransfer() throws IOException { String tainted = req.getParameter("zzz"); Runtime.getRuntime().exec(combine("safe", tainted)); } public void goodTransfer() throws IOException { String safe = "zzz"; Runtime.getRuntime().exec(combine("safe", safe)); } public void interClass() throws IOException { Runtime.getRuntime().exec(MoreMethods.tainted()); Runtime.getRuntime().exec((new MoreMethods()).safe()); } public void unconfiguredObject() throws IOException { Runtime.getRuntime().exec(parametricUnknownSource("safe, but result unknown")); } public void stringArrays(String param) throws Exception { Runtime.getRuntime().exec(transferThroughArray(taintSource(""))); Runtime.getRuntime().exec(transferThroughArray("const" + param)); Runtime.getRuntime().exec(transferThroughArray("const")); } public void lists(String param) throws Exception { Runtime.getRuntime().exec(transferThroughList(taintSource(""), 0)); Runtime.getRuntime().exec(transferThroughList("const" + param, 0)); Runtime.getRuntime().exec(transferThroughList("const", 0)); } abstract void unknown(String str, String s); abstract void unknown(StringBuilder sb); public void testUnknown() throws IOException { String str = "xx"; unknown(str, ""); Runtime.getRuntime().exec(str); StringBuilder sb = new StringBuilder("xx"); unknown(sb); Runtime.getRuntime().exec(sb.toString()); } public void testListIterator() throws IOException { Runtime.getRuntime().exec(transferListIteratorIndirect("safe")); Runtime.getRuntime().exec(transferListIteratorIndirect(taintSourceDouble())); Runtime.getRuntime().exec(transferThroughListIterator("safe")); Runtime.getRuntime().exec(transferThroughListIterator(taintSourceDouble())); } public void unknownSubmethod(String unknown) throws IOException { Runtime.getRuntime().exec(new MoreMethods().safeParentparametricChild(unknown)); Runtime.getRuntime().exec(new SubClass().safeParentparametricChild(unknown)); } public void sinkWithSafeInput(String str) throws IOException { Runtime.getRuntime().exec(str); } public void safeCall() throws IOException { sinkWithSafeInput("safe"); } private String transferThroughArray(String in) { String[] strings = new String[3]; strings[0] = "safe1"; strings[1] = in; strings[2] = "safe2"; // whole array is tainted, index is not important String str = "safe3" + strings[1].trim(); return str.split("a")[0]; } private String transferThroughList(String in, int index) { LinkedList<String> list = new LinkedList<String>(); list.add(System.getenv("")); // taints the list list.clear(); // makes the list safe again list.add(1, "xx"); list.addFirst(in); // can taint the list list.addLast("yy"); list.push(in); return list.element() + list.get(index) + list.getFirst() + list.getLast() + list.peek() + list.peekFirst() + list.peekLast() + list.poll() + list.pollFirst() + list.pollLast() + list.pop() + list.remove() + list.remove(index) + list.removeFirst() + list.removeLast() + list.set(index, "safe") + list.toString(); } private String transferThroughListIterator(String str) { List<String> list = new LinkedList<String>(); ListIterator<String> listIterator = list.listIterator(); listIterator.add(str); return listIterator.next(); } private String transferListIteratorIndirect(String str) { List<String> list = new LinkedList<String>(); // not able to transfer this, set as UNKNOWN even if str is SAFE ListIterator<String> listIterator = list.listIterator(); listIterator.add(str); return list.get(0); } public String parametricUnknownSource(String str) { return str + new Object().toString() + "xx"; } public String taintSource(String param) throws IOException { File file = new File("C:\\data.txt"); FileInputStream streamFileInput; InputStreamReader readerInputStream; BufferedReader readerBuffered; streamFileInput = new FileInputStream(file); readerInputStream = new InputStreamReader(streamFileInput, "UTF-8"); readerBuffered = new BufferedReader(readerInputStream); return param + readerBuffered.readLine(); } public String taintSourceDouble() throws IOException { return taintSource("safe, but result will be tainted") + safeSource(1); } public String safeSource(long number) { String safe = 3.14 + (number * 2) + "xx".toUpperCase() + null + Integer.toString(7); safe.concat(new Double(10.0).toString() + Long.toHexString(number)); StringBuilder sb = new StringBuilder(safe).insert(1, 'c'); sb.append(new Integer(0)).append(Double.valueOf("1.0")); // object taint transfer return sb + String.valueOf(true) + 0.1f + new String(); } public String combine(String x, String y) { StringBuilder sb = new StringBuilder("safe"); sb.append((Object) x); HashSet<String> set = new HashSet<String>(); set.add("ooo"); set.add(sb.append("x").append("y").toString().toLowerCase()); for (String str : set) { if (str.equals(y.toLowerCase())) { return str + String.join("-", set) + String.join("a", "b", "c"); } } return new StringBuilder(String.format("%s", y)).toString().trim() + "a".concat("aaa"); } public void call() throws IOException { MoreMethods.sink(req.getHeader("test")); } public void callInterface(InterfaceWithSink obj1) throws IOException { InterfaceWithSink obj2 = getNewMoreMethods(); if (obj2.hashCode() % 2 == 0) { System.out.println(obj2.toString()); } // just to confuse the analysis a bit unknown(new StringBuilder().append(obj2)); obj2.sink2(req.getHeader("test")); obj1.sink2(req.getHeader("test")); // should not be reported } public InterfaceWithSink getNewMoreMethods() { return new MoreMethods(); } }