diff --git a/rules/java/lang/crlf_injection.yml b/rules/java/lang/crlf_injection.yml new file mode 100644 index 000000000..07791a3eb --- /dev/null +++ b/rules/java/lang/crlf_injection.yml @@ -0,0 +1,110 @@ +patterns: + - pattern: | + $.$($<...>$$<...>) + filters: + - variable: UNSANITIZED_USER_INPUT + detection: java_lang_log_dynamic_input + scope: result + - not: + variable: UNSANITIZED_USER_INPUT + detection: java_lang_log_sanitized_dynamic_input + scope: result + - not: + variable: UNSANITIZED_USER_INPUT + detection: java_lang_log_dynamic_bundle_input + scope: result + - variable: METHOD + values: + - config + - debug + - entering + - error + - exiting + - fine + - finer + - finest + - info + - log + - logp + - logrb + - severe + - throwing + - trace + - warn + - variable: LOG + values: + - log + - logger +auxiliary: + - id: java_lang_log_dynamic_bundle_input + patterns: + - pattern: $<_> + "bundle" + - id: java_lang_log_dynamic_input + patterns: + - pattern: $.$() + filters: + - variable: REQUEST + values: + - req + - request + - variable: REQUEST_METHOD + values: + - getCookies + - getHeader + - getQueryString + - getRequestURI + - getRequestURL + - getAttribute + - getInputStream + - getParameter + - getParameterMap + - getParameterNames + - getParameterValues + - getReader + - getHeaderNames + - getPart + - getParts + - id: java_lang_log_sanitized_dynamic_input + patterns: + - pattern: $<_>.$($, $<_>); + filters: + - variable: METHOD + values: + - replace + - replaceAll + - variable: SOURCE + string_regex: "\\r\\n|\\\\r\\\\n" + - pattern: $<_>.$($, $<_>).$($, $<_>); + filters: + - variable: METHOD + values: + - replace + - replaceAll + - variable: CR + string_regex: "\\r|\\\\r" + - variable: LF + string_regex: "\\n|\\\\n" +languages: + - java +metadata: + description: "Possible CLRF injection detected." + remediation_message: | + ## Description + + A CRLF (Carriage Return Line Feed) injection occurs when an attacker injects a sequence of line termination characters into a log message, allowing them to forge log entries. + + ## Remediations + + ✅ Strip any carriage return and line feed characters from user input data before logging it. + + ```java + logger.info(userInput.replaceAll("[\r\n]+", "")); + ``` + + ## Resources + - [OWASP CRLF Injection] (https://owasp.org/www-community/vulnerabilities/CRLF_Injection) + - [OWASP logging cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html) + cwe_id: + - 93 + id: java_lang_crlf_injection + documentation_url: https://docs.bearer.com/reference/rules/java_lang_crlf_injection diff --git a/tests/java/lang/crlf_injection/test.js b/tests/java/lang/crlf_injection/test.js new file mode 100644 index 000000000..19ecb0824 --- /dev/null +++ b/tests/java/lang/crlf_injection/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("crlf_injection", () => { + 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/crlf_injection/testdata/main.java b/tests/java/lang/crlf_injection/testdata/main.java new file mode 100644 index 000000000..79855fff7 --- /dev/null +++ b/tests/java/lang/crlf_injection/testdata/main.java @@ -0,0 +1,29 @@ +package inject; + +import javax.servlet.http.HttpServletRequest; +import java.util.logging.*; + +public class CRLFInjection extends HttpServlet { + public void javaUtilLogging(HttpServletRequest req, HttpServletResponse res) { + String dangerous = req.getParameter("test"); + String okay = "some known string"; + + logger = Logger.getLogger(Log.class); + logger.setLevel(Level.ALL); + + // bearer:expected java_lang_crlf_injection + logger.info(dangerous); + // bearer:expected java_lang_crlf_injection + logger.info(dangerous.replace("hello", "world")); + // bearer:expected java_lang_crlf_injection + logger.info(dangerous.replace('\n', "")); + // bearer:expected java_lang_crlf_injection + logger.info(dangerous.replaceAll("\r", "")); + + // okay + logger.config("hello world" + okay); + logger.info(dangerous.replace('\r', ' ').replace('\n', ' ')); + logger.logrb(Level.INFO, safe, safe, dangerous + "bundle", safe); + logger.fine(dangerous.replaceAll("[\r\n]+", "")); + } +} \ No newline at end of file