From d91732a07f1750ca5ff8f0529936401814ebc137 Mon Sep 17 00:00:00 2001 From: elsapet Date: Fri, 2 Feb 2024 12:44:04 +0200 Subject: [PATCH] feat(java): code injection rule --- rules/java/lang/code_injection_rule.yml | 51 +++++++++++++++++++ tests/java/lang/code_injection_rule/test.js | 18 +++++++ .../code_injection_rule/testdata/main.java | 37 ++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 rules/java/lang/code_injection_rule.yml create mode 100644 tests/java/lang/code_injection_rule/test.js create mode 100644 tests/java/lang/code_injection_rule/testdata/main.java diff --git a/rules/java/lang/code_injection_rule.yml b/rules/java/lang/code_injection_rule.yml new file mode 100644 index 000000000..15a51537d --- /dev/null +++ b/rules/java/lang/code_injection_rule.yml @@ -0,0 +1,51 @@ +imports: + - java_shared_lang_user_input + - java_shared_lang_instance +patterns: + - pattern: | + $.invokeFunction($<_>, $); + filters: + - variable: INVOCATION + detection: java_lang_code_injection_rule_invocation_instance + - variable: USER_INPUT + detection: java_shared_lang_user_input + scope: result + - pattern: | + $.invokeMethod($<_>, $<_>, $); + filters: + - variable: INVOCATION + detection: java_lang_code_injection_rule_invocation_instance + - variable: USER_INPUT + detection: java_shared_lang_user_input + scope: result +auxiliary: + - id: java_lang_code_injection_rule_invocation_instance + patterns: + - pattern: $; + filters: + - variable: INVOCATION + detection: java_shared_lang_instance + scope: cursor + filters: + - variable: JAVA_SHARED_LANG_INSTANCE_TYPE + regex: \A(javax\.script\.)?Invocable\z +languages: + - java +metadata: + description: Unsanitized user input in code generation + remediation_message: | + ## Description + + The use of external input in scripting functions is bad security practice as it could lead to code injection attacks, where an attacker passes malicious code, that is then run by the application with potentially harmful results. + + ## Remediations + + ❌ Never pass raw user input to functions and methods that are dynamically invoked + + ## References + + - [OWASP Code injection](https://owasp.org/www-community/attacks/Code_Injection) + cwe_id: + - 94 + id: java_lang_code_injection_rule + documentation_url: https://docs.bearer.com/reference/rules/java_lang_code_injection_rule diff --git a/tests/java/lang/code_injection_rule/test.js b/tests/java/lang/code_injection_rule/test.js new file mode 100644 index 000000000..974da3cbe --- /dev/null +++ b/tests/java/lang/code_injection_rule/test.js @@ -0,0 +1,18 @@ +const { + createNewInvoker, + getEnvironment, +} = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("code_injection_rule", () => { + const testCase = "main.java" + + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) +}) \ No newline at end of file diff --git a/tests/java/lang/code_injection_rule/testdata/main.java b/tests/java/lang/code_injection_rule/testdata/main.java new file mode 100644 index 000000000..516c05b94 --- /dev/null +++ b/tests/java/lang/code_injection_rule/testdata/main.java @@ -0,0 +1,37 @@ +package script; +import javax.script.*; + +public class Foo { + + public void bad(String script, HttpServletResponse response) throws Exception { + ScriptEngineManager factory = new ScriptEngineManager(); + ScriptEngine engine = factory.getEngineByName("javascript"); + + engine.eval(script); + Invocable invocable = (Invocable) engine; + + var foo = request.getParameter("foo"); + + // bearer:expected java_lang_code_injection_rule + String badFunc = (String) invocable.invokeFunction("myFunc", foo); + + Object obj = engine.get("obj"); + // bearer:expected java_lang_code_injection_rule + Object badMethod = invocable.invokeMethod(obj, "myFunc", foo); + } + + public void ok(String script) throws Exception { + ScriptEngineManager factory = new ScriptEngineManager(); + ScriptEngine engine = factory.getEngineByName("javascript"); + + engine.eval(script); + Invocable invocable = (Invocable) engine; + + // ok + String badFunc = (String) invocable.invokeFunction("myFunc", "safe"); + + // ok + Object obj = engine.get("obj"); + Object badMethod = invocable.invokeMethod(obj, "myFunc", "safe"); + } +}