Watermelon

I will list here the functions and classes that might be interesting for us :

Path of the database & File Class

app.py
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db' 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = secrets.token_hex(20)
app.config['UPLOAD_FOLDER'] = 'files'


db = SQLAlchemy(app)

class File(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(255), nullable=False)
    filepath = db.Column(db.String(255), nullable=False)
    uploaded_at = db.Column(db.DateTime, nullable=False, default=db.func.current_timestamp())
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

    user = db.relationship('User', backref=db.backref('files', lazy=True))

Admin check

Upload function

File view function

Flag print

So basically this app doesn't have UI, you need to register using burp or curl, then login and upload a file.

But where is the vulnerability? We can only read the flag if we somehow read the environment variable FLAG or by going to admin page.

Looking at these few lines in the upload function :

Firstly, a user_dir is created with our id in the upload folder which is files so files/2.

then it calls the os.path.join to join the user_dir directory with our file name and put it in file_path variable.

Then it inserts file_path in the database.

We can also access it with its id in the database as stated in File view func :

Taking a look at os.path.joinarrow-up-right documentation :

If a segment is an absolute path (which on Windows requires both a drive and a root), then all previous segments are ignored and joining continues from the absolute path segment.

So if we uploaded our file with a name like : /etc/passwd

the os.path.join function will ignore the files/2 and upload our file with the same name.

Great, let's do it :

Screenshot (193)

And we got it :

Screenshot (196)

Now how do we get the flag? There are many ways to get it.

Examples:

1

Read process environment

Set the filename to /proc/1/environ and download it.

Screenshot (197)

You can retrieve the flag from the environment contents.

Screenshot (198)
2

Download the SQLite DB

Set the filename to /app/instance/db.db, then download the DB and open it with any DB viewer to get the admin password. Use that to access /admin.

Screenshot (199)
Screenshot (200)
3

Read source file and secret key

Set the filename to /app/app.py and read the SECRET_KEY. With that you can create your own admin cookie using tools like flask-unsign and access /admin.

Last updated