
Hands-on lab demonstrating Apache Struts2 OGNL injection (CVE-2017-5638) with step-by-step system analysis, exploitation, sandbox bypass, and post-exploitation techniques for penetration testing education.

After starting the container, Struts2 logs show that the application loads familiar configuration files such as struts-default.xml, struts-plugin.xml, and struts.xml. This confirms that the framework in use is Apache Struts2.

A notable point lies in the line:
Choosing bean (jakarta) for (org.apache.struts2.dispatcher.multipart.MultiPartRequest)
This line indicates that Struts2 is choosing the Jakarta multipart parser (multipart upload data analyzer) to handle requests of type multipart/form-data, which is commonly encountered in file upload functionality.
This is a crucial signal when analyzing S2-045 / CVE-2017-5638, since this vulnerability is related to the process where Struts2 handles errors when parsing multipart requests, especially with an invalid Content-Type header.
However, this log only proves that the application uses Struts2 and a Jakarta-style multipart handler. It is not yet sufficient to conclude that the application is definitely vulnerable. To confirm, we need to determine the version of struts2-core and compare it against the affected version range.



When accessing the web service using curl, the response headers show that the application is running on Jetty 9.2.11.v20150529. This information helps identify the environment running the application (servlet container), but does not directly reveal the version of Struts2.
The web interface returns the Struts2 Showcase - Fileupload sample page, with an upload form using:
method="POST" enctype="multipart/form-data" action="/upload.action"
This matches the earlier log where Struts2 chose jakarta for MultiPartRequest: the application indeed has a file upload handling flow via multipart/form-data.
⇒ Thinking: The endpoint /upload.action uses multipart/form-data, matching the mechanism Struts2 processes via Jakarta MultiPartRequest. This is a sign that strengthens the suspicion of S2-045/CVE-2017-5638, but we need to determine the Struts2 version before concluding the application is vulnerable. Next, deeper verification is still needed regarding the version of struts2-core and how the application handles errors when receiving an invalid Content-Type.
After identifying that the application has an upload endpoint using multipart/form-data, the next analysis step is to find the actual version of Struts2. This is crucial because previous signs only showed that the application has a mechanism related to multipart upload, which is not yet sufficient to conclude it is vulnerable.

After identifying the correct container serving Endpoint 8001, checking the libraries is performed directly inside the container project1-lab01-1.
The result found the struts2-core file:
/root/.m2/repository/org/apache/struts/struts2-core/2.3.30/struts2-core-2.3.30.jar
From this path, we can determine that the application is using Apache Struts2 2.3.30.

Comparing this with the published CVE-2017-5638 / S2-045 vulnerability, it affects many older Struts2 versions, including the 2.3.x branch before the patch. When combined with:
Framework: Apache Struts2 Version: 2.3.30 Multipart parser: Jakarta Endpoint: /upload.action Content-Type: multipart/form-data
The analysis condition chain becomes clearer:
`Struts2 Version 2.3.30 < Version 2.3.32
However, from an analysis perspective, a vulnerable version is only evidence of the potential to be affected. To confirm on a behavioral level, we need to send an anomalous multipart request and observe the response/logs to see if it enters the error handling branch of the Struts2 multipart parser.
⇒ Thinking: At this point, it is no longer just about identifying the framework; version 2.3.30 confirms the application lies within the affected version range of S2-045/CVE-2017-5638. The remaining step is to verify the multipart error handling behavior to complete the chain of evidence.

We need to check if requests sent to /upload.action really go through the Struts2 multipart processing mechanism. Here, I use the curl command with the -F option to test the handling mechanism. And the returned result is broken down into parts:
`
⇒ A valid request proves that /upload.action indeed goes through the multipart upload mechanism because curl -F generates multipart/form-data and the server can parse each part of the request.


After sending a request declaring Content-Type as multipart/form-data but with a body that does not conform to the multipart structure, the server still returns HTTP 200 OK. However, the ContentType, FileName, File, and Caption fields are all empty. Checking the Docker logs, we notice that there is no boundary (separator string between parts in multipart), and the client still receives HTTP 200 OK. However, Struts2 actually encountered an error while processing the request.
This proves the chain of evidence:
Faulty multipart request → Struts2 wraps request → MultiPartRequestWrapper is called → JakartaMultiPartRequest parses request → FileUploadException due to missing boundary
⇒ Matches the components related to S2-045/CVE-2017-5638. Thus, the condition chain is more complete: vulnerable version, Jakarta parser, upload endpoint, and the faulty request goes into the correct multipart processing branch.