NEW FEATURE
Cobalt PtaaS + DAST combines manual pentests and automated scanning for comprehensive application security.
NEW FEATURE
Cobalt PtaaS + DAST combines manual pentests and automated scanning for comprehensive application security.

From CSRF and File Upload to RCE - JAVA

Lukasz shares valuable learnings around how a pentester can turn a CSRF and file upload into a Remote Code Execution.

I have come across many interesting vulnerabilities throughout my offensive security career. In this post, I would like to share valuable learnings around how an individual can turn a CSRF and file upload into a Remote Code Execution. My goal is to share insights with the community around how to look for this vulnerability type.

TL;DR: Administrative actions performed by the user are vulnerable to CSRF attack. Privileged users can upload any file. There were at least two ways to define where that file could be uploaded. That leads to double RCE using the same attack vector.

Now let’s dive into my thought process to executing this attack:

During the initial testing stage, I focused on getting familiar with the application, identifying an underlying technology and understanding the application’s functionality. Any OSCP cert holder knows it by memory – enumeration. A word with a wide variety of meaning in the pentesting world.

When it comes to the technical aspects of web application, reconnaissance is a crucial step – a good starting point is the OWASP Testing Guide. Understanding an application from a business perspective can be achieved by reading application help files, analyzing customer documentation, and walking through an application following business processes. It’s useful to look at the business processes implemented by the application and identify possible gaps in the application logic.

When I went through the application, I was able to easily find a XSS vulnerability (thanks to Reflection – Burp Suite extension). When I verified underlying HTTP requests sent to the server in Burp, I noticed that not every POST request had a CSRF token added. Additionally, business processes were based on processing files: images, documents, and any other evidence files. Processing of these files, as expected, was combined with file upload.

Let’s summarize, I gathered the following information:

  • It was a Java application served by Apache Tomcat.
  • Application had many file upload functionalities.
  • Not every endpoint of the application had CSRF protection.
  • Multiple path disclosures provided location to where files are stored and application webroot is located.

I didn’t end the enumeration at that point. I already had some information about the application, but I was still missing information on how the application maps to the underlying filesystem on the server. Everything which is stored in the application webroot directory is available through the browser and can be discovered by visiting each application's functionality, reading Javascript files, performing bruteforce discovery or using a web archive. But where is the application webroot? With help here came verbose responses from the server. Successful and unsuccessful requests disclosed the location where the file was uploaded or at what Java file error occurred. Analysis of this information gave me information about application webroot and where the application stored files. The application stored image files in '/app/xxx/files/upload, document files in /app/xxx/webapp/tempand application webroot was/app/xxx/webapp`. I wondered if these path disclosures can be combined with file upload? So I started checking the file uploads and testing two things:

  • Can I upload any file? Observation: content of a file and its extension is not modified
  • Where is a file uploaded? Observation: as expected file is uploaded to /app/xxx/files/upload on filesystem

Additionally, I checked if it is possible to modify the path where files are uploaded and this was possible from the administrative panel. I confirmed that an administrator/privileged user can change the path where files are uploaded. The next step was to take a closer look at the request which is sent to the application which makes that change of the path. Previously I spotted lack of CSRF protection in the requests and the same pattern I noticed in that request. Quick test using Burp Repeater allowed me to confirm that it is vulnerable to CSRF attack.

Results were:

  • Image files could have any content and extension (unrestricted file upload)
  • Document files were uploaded to /app/xxx/webapp/temp, because they were instantly accessible from the web through a link like this: https://[application_url]/temp
  • Administrator can change location where document files are uploaded

So, I combined that into the following intelligence:

  • administrator could change location where files are uploaded,
  • administrator could upload any file as a image file and
  • filesystem location /app/xxx/webapp/temp is accessible from the web under the URL: https://[application_url]/temp/

I changed the location where the image files were uploaded to /app/xxx/webapp/temp and then uploaded a simple jsp webshell as an image file. The uploaded file was available at https://[application_url]/temp/cmd.jsp. That gave me the code execution on the system.

From CSRF and File Upload to RCE - JAVA

Picture 1: Webshell executing id command and confirming code execution on underlying server.

From that point I just needed to put it all together. I found a way to get a command execution (RCE), but it could only be done by a privileged user(administrator). I noticed before that the administrative requests were not protected by anti CSRF protection. First, I minimized my request by removing unrequired HTTP headers, fields and parameters. Then, I crafted a CSRF proof of concept page, and administrative actions were successfully performed.

At that point, it was not very difficult to draw an attack vector. I had XSS, CSRF on activities related to upload, and RCE via upload. An attacker could use reflected XSS or stored XSS and inject a code, which would trigger a CSRF attack and then get the RCE via upload. Also, an attacker could just send the link to a page, which would trigger CSRF and give RCE.

Let’s present potential attack scenario:

  1. An attacker could create a reflected XSS payload. This XSS payload could be base64 encoded.
  2. An attacker could send a link to a victim who has privileged access to the application (and would be logged in).
  3. XSS payload could be triggered by the victim. Javascript code from the XSS vulnerability could run in the context of a victim. CSRF attack could be performed from that Javascript code. Action performed by exploiting CSRF could make changes to the application (changing upload path and uploading a webshell).
  4. An attacker could then connect to the uploaded webshell. With uploaded webshell an attacker would be able to run any command with privileges of the user who ran the application. That would lead to compromise of the underlying system.

Blueprint of XXS payload (Javascript code) which can be used for that scenario:

function setPath()
{
    var request = new XMLHttpRequest();
    request.open("POST", ENDPOINT1, true);
    request.setRequestHeader("Content-Type", "application\/x-www-form-urlencoded");
    request.withCredentials = true;
    var body = PAYLOAD;
    request.send(body));
}
function sendFile()
{
    var formData = new FormData();
    var content = WEBSHELL_CONTENT;
    var blob = new Blob([content], { type: "text/html"});
    formData.append("file", blob, 'test.jsp’);
    var request2 = new XMLHttpRequest();
    request2.open("POST", ENDPOINT2);
    request2.send(formData);
}
setPath();
sendFile();
############

With code execution I read an application code (access to the source code) and checked what is going on under the hood on the server. This change blackbox approach to whitebox. That made further examination easier.

I went back to enumeration. I looked for new ways to achieve additional command execution. With endpoints and functionality already identified, I focused on the potentially dangerous functions. That didn’t give any success. Then I found out that there is an additional channel to communicate with the application through the REST API. I checked the application documentation and discovered that there is a REST API endpoint https://[application_url]/rest/uploadfile. This endpoint handles general file uploads and takes filename and filepath as parameters. I sent a basic request to the REST API, intercepted it and sent it to the Burp repeater. Then I started modifying it and applied required parameters from documentation. With a crafted request I was able to upload a file. But it didn’t give me the second code execution straightforwardly.

I was intrigued by the endpoint https://[application_url]/rest/uploadfile. With code execution I had access to the filesystem and I was able to read the source code of this endpoint written in Java. I read its code and found out that filepath was stripped from any path traversal techniques. And even if you can specify the filepath, the application needs to have write permissions in that filepath. I used previously obtained knowledge that a good upload location is /app/xxx/webapp/temp. Location /app/xxx/webapp/temp was used to store document files and was accessible from the web under the URL https://[application_url]/temp/. I modified my crafted request to the endpoint https://[application_url]/rest/uploadfile and put parameters filepath as /app/xxx/webapp/temp and file as content of simple jsp webshell. File was uploaded and I was able to access it at https://[application_url]/temp/cmd.jsp. That gave me the second code execution on the system.

Let sum up:

  • Endpoint https://[application_url]/rest/uploadfile allowed any file to be uploaded but had limitations around where it could be uploaded.
  • Location /app/xxx/webapp/temp can be used to write any files and was accessible from the web under the address https://[application_url]/temp/

Key Takeaways

From an offensive security perspective:

  • Analyze initial enumeration result. Sometimes you’ll notice a pattern that allows you to chain small bugs to get higher severity.
  • Drawing the potential attack scenario could help you present the impact and severity to the customer.
  • Any file upload functionalities should be tested intensively.
  • Think out of the box!

From a defensive security perspective:

  • Review impact and analyze reported findings. Security operations know more about an application and its environment than pentesters - it is possible to find additional vulnerabilities and impacts that pentesters were not even aware of.
  • Client side vulnerabilities (CSRF and XSS) could allow the attacker to perform action as an administrator.
  • Ensure that the user provided input is sanitized and encoded.
  • Limit file formats that users can upload.
  • Check uploaded files with AntiVirus.
  • Follow web application best practices.
  • Regularly perform pentesting to look for weaknesses.

Interested in learning more? Explore more about file upload vulnerabilities.

Back to Blog
About Lukasz Wierzbicki
Lukasz Wierzbicki has over 15 years of experience in Information Technology and Information Security. He has been a developer, administrator, devops specialist, security officer, team lead, and pentester with a focus in the financial and consulting industries. He holds a BSc and MSc in Software Engineering from the Warsaw University of Technology. Lukasz has experience in numerous security areas such as infrastructure penetration testing, security source code review, application and API security testing, mobile security testing, and code assisted penetration testing. More By Lukasz Wierzbicki
File Upload Vulnerabilities
This blog aims to demonstrate how applications can be compromised using simple file upload functionalities. Core Pentester Shubham Chaskar will show how to bypass common defense mechanisms and upload web shells.
Blog
Aug 24, 2022