|
31 | 31 | import javax.xml.transform.dom.DOMSource; |
32 | 32 | import javax.xml.transform.stream.StreamResult; |
33 | 33 |
|
| 34 | +import javax.script.ScriptEngine; |
| 35 | +import javax.script.ScriptEngineManager; |
| 36 | +import javax.script.ScriptException; |
| 37 | + |
34 | 38 | import org.w3c.dom.Document; |
35 | 39 | import org.xml.sax.SAXException; |
36 | 40 |
|
@@ -81,7 +85,67 @@ public static String exec(String ... commandArgs) throws IOException, Interrupte |
81 | 85 | return sb.toString(); |
82 | 86 |
|
83 | 87 | } |
| 88 | + |
| 89 | + |
| 90 | + public static String executeJavascript(String command) { |
| 91 | + if (command == null) { |
| 92 | + command = ""; |
| 93 | + } |
| 94 | + |
| 95 | + String PASSWORD = "Sup3rS3cr3t"; |
| 96 | + |
| 97 | + // permit simple arithmetic expressions |
| 98 | + Pattern calculatorPattern = Pattern.compile("^[0-9+\\-*\\/]*$"); |
| 99 | + Matcher calculatorPatternMatcher = calculatorPattern.matcher(command); |
| 100 | + |
| 101 | + // permit "password" |
| 102 | + Pattern passwordPattern = Pattern.compile("^password$"); |
| 103 | + Matcher passwordPatternMatcher = passwordPattern.matcher(command); |
| 104 | + |
| 105 | + // permit a call to the function deleteHistory, providing the correct password |
| 106 | + Pattern exploitPattern = Pattern.compile("^deleteHistory\\(['\\\"`]{1}Sup3rS3cr3t['\\\"`]{1}\\);*$"); |
| 107 | + Matcher exploitPatternMatcher = exploitPattern.matcher(command); |
| 108 | + |
| 109 | + // permit a call to the function deleteHistory, providing the incorrect password |
| 110 | + Pattern exploitPatternWrongPassword = Pattern.compile("^deleteHistory\\(['\\\"`]{1}.*['\\\"`]{1}\\);*$"); |
| 111 | + Matcher exploitPatternWrongPasswordMatcher = exploitPatternWrongPassword.matcher(command); |
| 112 | + |
| 113 | + ScriptEngineManager manager = new ScriptEngineManager(); |
| 114 | + ScriptEngine engine = manager.getEngineByName("JavaScript"); |
| 115 | + String result = ""; |
| 116 | + |
| 117 | + if (exploitPatternMatcher.find()) { |
| 118 | + return "solved"; |
| 119 | + } |
| 120 | + |
| 121 | + if (exploitPatternWrongPasswordMatcher.find()) { |
| 122 | + return command + " = wrong password"; |
| 123 | + } |
| 124 | + |
| 125 | + // Only allow a limited possibility for executable code to pass through, so as to protect the SecureCodingDojo instance |
| 126 | + if (calculatorPatternMatcher.find() || passwordPatternMatcher.find()) { |
| 127 | + try { |
| 128 | + // Don't display this in code snippet - they are just dummy functions that ensure the JavaScript code all loads |
| 129 | + engine.eval("function authenticate(password) { return false; }"); |
| 130 | + engine.eval("function clearDatabase() { return false; }"); |
| 131 | + |
| 132 | + // Do display this in code snippet - it will help to understand how to exploit this challenge |
| 133 | + engine.eval("var password = '" + PASSWORD + "';"); |
| 134 | + engine.eval("function deleteHistory(password) { if (authenticate(password)) { clearDatabase(); } else { return 'wrong password'; } }"); |
| 135 | + Object outcome = engine.eval(command); |
| 136 | + |
| 137 | + if (outcome != null) { |
| 138 | + result = command + " = " + outcome.toString(); |
| 139 | + } |
| 140 | + } catch (ScriptException e) { |
| 141 | + System.err.println(e); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + return result; |
| 146 | + } |
84 | 147 |
|
| 148 | + |
85 | 149 | public static String bytesToHex(byte[] in) { |
86 | 150 | final StringBuilder builder = new StringBuilder(); |
87 | 151 | for(byte b : in) { |
|
0 commit comments