From ec070ac541f86cfbbfa6f88afa8e19e7213fe6a2 Mon Sep 17 00:00:00 2001 From: nathanmartinszup <63246935+nathanmartinszup@users.noreply.github.com> Date: Tue, 14 Dec 2021 09:51:52 -0300 Subject: [PATCH] engine/java:feature - adding log4j remote code injection rule (#870) Signed-off-by: Nathan Martins --- .../services/engines/java/rule_manager.go | 3 +- internal/services/engines/java/rules.go | 20 ++ internal/services/engines/java/rules_test.go | 116 +++++++ internal/services/engines/java/sample_test.go | 294 ++++++++++++++++++ internal/services/engines/rules_test.go | 2 +- 5 files changed, 433 insertions(+), 2 deletions(-) diff --git a/internal/services/engines/java/rule_manager.go b/internal/services/engines/java/rule_manager.go index f17c8bbe8..5f845542a 100644 --- a/internal/services/engines/java/rule_manager.go +++ b/internal/services/engines/java/rule_manager.go @@ -26,7 +26,7 @@ func NewRules() *engines.RuleManager { } func extensions() []string { - return []string{".java"} + return []string{".java", ".xml", ".gradle"} } // Rules return all rules registred to Java engine. @@ -186,6 +186,7 @@ func Rules() []engine.Rule { NewRequestMappingMethodsNotPublic(), NewLDAPDeserializationNotDisabled(), NewDatabasesPasswordNotProtected(), + NewVulnerableRemoteCodeInjectionApacheLog4j(), } return append(java, jvm.Rules()...) } diff --git a/internal/services/engines/java/rules.go b/internal/services/engines/java/rules.go index 8a313f56e..cc86811e3 100644 --- a/internal/services/engines/java/rules.go +++ b/internal/services/engines/java/rules.go @@ -2594,3 +2594,23 @@ func NewDatabasesPasswordNotProtected() text.TextRule { }, } } + +func NewVulnerableRemoteCodeInjectionApacheLog4j() text.TextRule { + return text.TextRule{ + Metadata: engine.Metadata{ + ID: "HS-JAVA-150", + Name: "Remote code injection Apache Log4j", + Description: "Log4j versions prior to 2.15.0 are subject to a remote code execution vulnerability via the ldap JNDI parser. For more information checkout the CVE-2021-44228 (https://nvd.nist.gov/vuln/detail/CVE-2021-44228) advisory.", + Severity: severities.Critical.ToString(), + Confidence: confidence.Medium.ToString(), + }, + Type: text.OrMatch, + Expressions: []*regexp.Regexp{ + regexp.MustCompile(`compile.*group:.*org\.apache\.logging\.log4j.*name:.*log4j.*version:.*(('|")((2\.([0-9]\.|1[0-4]))|(1\.))).*('|")`), + regexp.MustCompile(`compile.*log4j.*(:((2\.([0-9]\.|1[0-4]))|(1\.))).*('|")`), + regexp.MustCompile(`(.*|\n).*org\.apache\.logging\.log4j.*(.*|\n).*.*log4j.*(.*|\n)*(version>((2\.([0-9]\.|1[0-4]))|(1\.)))(.*|\n)*`), + regexp.MustCompile(``), + regexp.MustCompile(`<(log4j2|log4j)\.version>.*((2\.([0-9]\.|1[0-4]))|(1\.)).*`), + }, + } +} diff --git a/internal/services/engines/java/rules_test.go b/internal/services/engines/java/rules_test.go index fd7822478..a6c84f3b1 100644 --- a/internal/services/engines/java/rules_test.go +++ b/internal/services/engines/java/rules_test.go @@ -472,6 +472,97 @@ func TestRulesVulnerableCode(t *testing.T) { }, }, }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: SampleMavenVulnerableHSJAVA150, + Findings: []engine.Finding{ + { + CodeSample: "org.apache.logging.log4j", + SourceLocation: engine.Location{ + Line: 11, + Column: 12, + }, + }, + }, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample2GradleVulnerableHSJAVA150, + Findings: []engine.Finding{ + { + CodeSample: "compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'", + SourceLocation: engine.Location{ + Line: 16, + Column: 4, + }, + }, + { + CodeSample: "compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'", + SourceLocation: engine.Location{ + Line: 17, + Column: 4, + }, + }, + { + CodeSample: "compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.0'", + SourceLocation: engine.Location{ + Line: 18, + Column: 4, + }, + }, + }, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample3GradleVulnerableHSJAVA150, + Findings: []engine.Finding{ + { + CodeSample: "compile 'org.slf4j:slf4j-log4j12:1.7.26'", + SourceLocation: engine.Location{ + Line: 23, + Column: 4, + }, + }, + }, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample4IvyVulnerableHSJAVA150, + Findings: []engine.Finding{ + { + CodeSample: "", + SourceLocation: engine.Location{ + Line: 15, + Column: 4, + }, + }, + { + CodeSample: "", + SourceLocation: engine.Location{ + Line: 16, + Column: 4, + }, + }, + }, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample5MavenVulnerableHSJAVA150, + Findings: []engine.Finding{ + { + CodeSample: "2.8.2", + SourceLocation: engine.Location{ + Line: 16, + Column: 8, + }, + }, + }, + }, } testutil.TestVulnerableCode(t, testcases) @@ -659,6 +750,31 @@ func TestRulesSafeCode(t *testing.T) { Rule: NewDatabasesPasswordNotProtected(), Src: SampleSafeHSJAVA149, }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: SampleMavenSafeHSJAVA150, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample2GradleSafeHSJAVA150, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample3GradleSafeHSJAVA150, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample4IvySafeHSJAVA150, + }, + { + Name: "HS-JAVA-150", + Rule: NewVulnerableRemoteCodeInjectionApacheLog4j(), + Src: Sample5MavenSafeHSJAVA150, + }, } testutil.TestSafeCode(t, testcases) } diff --git a/internal/services/engines/java/sample_test.go b/internal/services/engines/java/sample_test.go index 946d14489..af879cb81 100644 --- a/internal/services/engines/java/sample_test.go +++ b/internal/services/engines/java/sample_test.go @@ -891,5 +891,299 @@ public class Foo { Connection conn = DriverManager.getConnection("jdbc:derby:memory:myDB;create=true", "login", password); } } +` + + SampleMavenVulnerableHSJAVA150 = ` + + + 4.0.0 + Log4j2Example + Log4j2Example + 0.0.1-SNAPSHOT + + + + org.apache.logging.log4j + log4j-core + 2.8.2 + + + +` + + SampleMavenSafeHSJAVA150 = ` + + + 4.0.0 + Log4j2Example + Log4j2Example + 0.0.1-SNAPSHOT + + + + org.apache.logging.log4j + log4j-core + 2.15.0 + + + +` + + Sample2GradleVulnerableHSJAVA150 = ` +group 'com.lamarjs' +version '1.0-SNAPSHOT' + +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + + // SLF4J as a facade over Log4j2 required dependencies + compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0' + compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0' + compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.0' + + // Bridges from other logging implementations to SLF4J. Be careful not to bridge SLF4J itself to + compile group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.7.25' // JUL bridge + compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.25' // Apache Commons Logging (JCL) bridge + compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.25' // log4j1.2 bridge + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +` + + Sample2GradleSafeHSJAVA150 = ` +group 'com.lamarjs' +version '1.0-SNAPSHOT' + +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + + // SLF4J as a facade over Log4j2 required dependencies + compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.15.0' + compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.15.0' + compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.15.0' + + // Bridges from other logging implementations to SLF4J. Be careful not to bridge SLF4J itself to + compile group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.7.25' // JUL bridge + compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.25' // Apache Commons Logging (JCL) bridge + compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.25' // log4j1.2 bridge + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +` + + Sample3GradleVulnerableHSJAVA150 = ` +plugins { + id 'java' +} + +group 'com.epam.rp' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + + compile 'org.seleniumhq.selenium:selenium-server:3.141.59' + + compile 'org.testng:testng:6.13.1' + compile 'com.epam.reportportal:agent-java-testng:4.2.3' + + compile 'com.epam.reportportal:logger-java-log4j:4.0.1' + compile 'org.slf4j:slf4j-log4j12:1.7.26' +} + + +test { + useTestNG() { + useDefaultListeners = true + suites 'suites/amazon_test.xml' + } +} +` + + Sample3GradleSafeHSJAVA150 = ` +plugins { + id 'java' +} + +group 'com.epam.rp' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + + compile 'org.seleniumhq.selenium:selenium-server:3.141.59' + + compile 'org.testng:testng:6.13.1' + compile 'com.epam.reportportal:agent-java-testng:4.2.3' + + compile 'com.epam.reportportal:logger-java-log4j:4.0.1' + compile 'org.slf4j:slf4j-log4j12:2.15.0' +} + + +test { + useTestNG() { + useDefaultListeners = true + suites 'suites/amazon_test.xml + } +} +` + + Sample4IvyVulnerableHSJAVA150 = ` + + + + + + + + + + + + + + + + + + + + + + + + +` + + Sample4IvySafeHSJAVA150 = ` + + + + + + + + + + + + + + + + + + + + + + + + +` + + Sample5MavenVulnerableHSJAVA150 = ` + + 4.0.0 + + com.example.log4j + log4j-examples + 1.0-SNAPSHOT + jar + + log4j-examples + http://maven.apache.org + + + UTF-8 + 2.8.2 + + + + + org.apache.logging.log4j + log4j-api + ${log4j2.version} + + + org.apache.logging.log4j + log4j-core + ${log4j2.version} + + + junit + junit + 3.8.1 + test + + + +` + + Sample5MavenSafeHSJAVA150 = ` + + 4.0.0 + + com.example.log4j + log4j-examples + 1.0-SNAPSHOT + jar + + log4j-examples + http://maven.apache.org + + + UTF-8 + 2.15.0 + + + + + org.apache.logging.log4j + log4j-api + ${log4j2.version} + + + org.apache.logging.log4j + log4j-core + ${log4j2.version} + + + junit + junit + 3.8.1 + test + + + ` ) diff --git a/internal/services/engines/rules_test.go b/internal/services/engines/rules_test.go index 0d905f8b8..b63912e5d 100644 --- a/internal/services/engines/rules_test.go +++ b/internal/services/engines/rules_test.go @@ -67,7 +67,7 @@ func TestGetRules(t *testing.T) { { engine: "Java", manager: java.NewRules(), - expectedTotalRules: 180, + expectedTotalRules: 181, }, { engine: "Dart",