# Watermelon

Recently, I participated in the [Blackhat MEA 2024 Qualification CTF](https://ctftime.org/event/2430), where I tackled a web challenge named “**Watermelon**.” This challenge was relatively straightforward but enjoyable. Here’s a step-by-step breakdown of how I solved it.

#### <mark style="color:yellow;">Challenge Overview</mark>

The challenge provided a file named `app.py`, which sets up the challenge API for managing users and their uploaded files. It includes basic security checks for file access and an admin-specific endpoint.

{% file src="<https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FDfbM4MLGSvqUjde39LgB%2Fapp.py?alt=media&token=7ad02660-038e-4166-a8f2-ef60314b95ec>" %}
Given file
{% endfile %}

#### <mark style="color:yellow;">User Registration</mark>

Upon reviewing the `app.py` file, I discovered the user registration process:

```python
@app.post("/register")
def register():
    if not request.json or not "username" in request.json or not "password" in request.json:
        return jsonify({"Error": "Please fill all fields"}), 400
    
    username = request.json['username']
    password = request.json['password']

    if User.query.filter_by(username=username).first():
        return jsonify({"Error": "Username already exists"}), 409

    new_user = User(username=username, password=password)
    db.session.add(new_user)
    db.session.commit()

    return jsonify({"Message": "User registered successfully"}), 201
```

Here, I noted that I needed to make a POST request containing a username and password to register a user account. Following this, I registered my own user account successfully.

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2Fjj4H68zdWTB3kMH9oSDd%2Fwatermelon-1.png?alt=media&#x26;token=b0ec1c3b-d4e9-46bb-bede-e51f60b5c52d" alt=""><figcaption><p>Request and Response for user registration</p></figcaption></figure>

#### <mark style="color:yellow;">User Login</mark>

After registration, I could log into the user account, which involved a process similar to registration:

```python
@app.post("/login")
def login():
    if not request.json or not "username" in request.json or not "password" in request.json:
        return jsonify({"Error": "Please fill all fields"}), 400
    
    username = request.json['username']
    password = request.json['password']

    user = User.query.filter_by(username=username, password=password).first()
    if not user:
        return jsonify({"Error": "Invalid username or password"}), 401
    
    session['user_id'] = user.id
    session['username'] = user.username
    return jsonify({"Message": "Login successful"}), 200
```

With the user account registered, I was able to log in successfully.

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FruCS32BJx7Pa29t71tSn%2Fwatermelon-2.png?alt=media&#x26;token=d5379644-0cee-4dfc-b61d-8f301d7806b0" alt=""><figcaption><p>Request for user login</p></figcaption></figure>

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FrGw7ohfEn7OXn70mohtw%2Fwatermelon-3.png?alt=media&#x26;token=65dfcbeb-7872-4ee5-91a7-0b6113e7556d" alt=""><figcaption><p>Login confirmation</p></figcaption></figure>

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2F6JOxlm3j2pQmgeN4QSqr%2Fwatermelon-4.png?alt=media&#x26;token=ae83ad86-f150-4b2e-af6e-9fc71cd698b5" alt=""><figcaption><p>User profile</p></figcaption></figure>

#### <mark style="color:yellow;">File Upload</mark>

Next, I explored the file upload functionality, which was also detailed in the `app.py` file:

```python
@app.route("/upload", methods=["POST"])
@login_required
def upload_file():
    if 'file' not in request.files:
        return jsonify({"Error": "No file part"}), 400
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({"Error": "No selected file"}), 400
    
    user_id = session.get('user_id')
    if file:
        blocked = ["proc", "self", "environ", "env"]
        filename = file.filename

        if filename in blocked:
            return jsonify({"Error":"Why?"})

        user_dir = os.path.join(app.config['UPLOAD_FOLDER'], str(user_id))
        os.makedirs(user_dir, exist_ok=True)

        file_path = os.path.join(user_dir, filename)

        file.save(f"{user_dir}/{secure_filename(filename)}")
        
        new_file = File(filename=secure_filename(filename), filepath=file_path, user_id=user_id)
        db.session.add(new_file)
        db.session.commit()
        
        return jsonify({"Message": "File uploaded successfully", "file_path": file_path}), 201

    return jsonify({"Error": "File upload failed"}), 500
```

I successfully uploaded several files and was able to retrieve their file paths. However, I couldn’t find the flag at this stage. This led me to consider performing LFI by manipulating the filename.

#### <mark style="color:yellow;">Exploiting LFI</mark>

I renamed one of my uploaded files to `../../app.py` and uploaded it. This worked, allowing me to read the `app.py` file hosted on the challenge server. Within this file, I discovered the credentials for the admin user.

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FkpiU1kKmfOXC9u8o4CNZ%2Fwatermelon-5.png?alt=media&#x26;token=8e7952be-210f-48e4-939d-060a8dceed55" alt=""><figcaption><p>Successful file upload</p></figcaption></figure>

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FiTE7c8RImG3mHF0Smdh2%2Fwatermelon-6.png?alt=media&#x26;token=2822718e-5c19-4fbb-a59f-e0936c65bf52" alt=""><figcaption><p>Uploaded file details</p></figcaption></figure>

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FfYAgZhYO6gTe2816Wsk4%2Fwatermelon-7.png?alt=media&#x26;token=fc2f6a63-2d07-4b09-b12d-00592a9932c1" alt=""><figcaption><p>Admin credentials found via LFI</p></figcaption></figure>

#### <mark style="color:yellow;">Accessing the Admin Account</mark>

Using the found credentials, I logged into the admin account. Once inside, I navigated to the `/admin` directory and successfully located the flag.

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2Fsg9H3WZ2n4pgJHiMbuUn%2Fwatermelon-8.png?alt=media&#x26;token=20d5f340-d2da-4b0e-93f3-9f1b3e5af245" alt=""><figcaption><p>Request for login into the admin account</p></figcaption></figure>

<figure><img src="https://1587335382-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkNnZYAWVfMtLd97hhReo%2Fuploads%2FivUl0qdJuoYz6fb43ZTo%2Fwatermelon-9.png?alt=media&#x26;token=404099cb-d8a9-4d31-a1f6-1e6f2908d08b" alt=""><figcaption><p>Flag found</p></figcaption></figure>

So, that was all about that challenge. See you in some other blog. PEACE!
