PicoGym Random Writeups
Because of my imminent work in a Red team, I wanted to practice a bit with some CTF challenges.
I tried hackthebox, but I didn’t liked it because is too guided and “step by step”. I then went over to PicoCTF’s PicoGym. Even if it’s for high school students, I find it quite good.
Web Exploitation
Search Source - 100p
The developer of this website mistakenly left an important artifact in the website source, can you find it? The website is here
Even before opening the website we can assume that we’ll need to inspect the source code, in order to find something useful. The website is something related to a yoga course?
it’s just a pretty generic landing page. Let’s see the source code!
index.html
is quite regular: some imports for bootrstrap and font-awesome in the head tag, and nothing really worth in the body except for this comment:
<!-- six_box
end six_box The flag is not here but keep digging :)-- >
Let’s keep digging!
The flag is not in this file, so let’s start from the imports in the head:
Every .css file is minified, except for
style.css
and responsive.css
. If we search for the keyword pico
in style.css
we get our flag:
This was quite easy, let’s spice it up a bit!
Most Cookies - 150p
Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:52134/
Okay, just from the description we know that
- The challenge is about cookies
- The target is written using Flask, which I should know a bit of!
- We have the source code!!
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()
Our goal is to manipulate the value of the session variable very_auth
. If its value is admin
we will obtain the 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
How can we do that? We can edit the very_auth
session variable when we enter the biscuit name.
When I studied web-development at school, the teacher told us that session data are stored server-side. Well, that’s not (always) true.
As we can read on the Flask doc
If you have set Flask.secret_key (or configured it from SECRET_KEY) you can use sessions in Flask applications. A session makes it possible to remember information from one request to another. The way Flask does this is by using a signed cookie. The user can look at the session contents, but can’t modify it unless they know the secret key, so make sure to set that to something complex and unguessable.
So, if we have the secret key, we can craft a custom session data that has the very_auth
value set to admin
.
Guess what? we don’t exactly know which is the secret key of the remote web server, but we know how that’s chosen: it’s a random choice between the elements of the cookie_name
list. We have a valid and signed session data cookie (we can take it using firefox developer tools): Let’s bruteforce!
The first result on google is this library: Flask-Unsign. It has a really really nice cli switch: --wordlist
. Let’s transform our cookie_names
python list in a plain text list with one cookie name per line, and run the following command
$ flask-unsign --wordlist wordlist.txt --unsign --cookie "eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.Zg7W6Q.LoCgUmlDHGcM-NioGVQ5kOeSr7o" --no-literal-eval
After a really short time…
Our flask secret key is peanut butter
!
Now, always with flask-unsign, we can craft the custom cookie, use it to replace the real one, and get our flag!
$ flask-unsign --sign --cookie "{'very_auth':'admin'}" --secret 'peanut butter'
Which outputs
eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.Zg7aaA.Hug5ru08NmxhFE-UsfUMOH9zzwg
and if we do the “cookie substitution”
We get the flag! This one was fun!
Irish-Name-Repo 1 - 300p
There is a website running at https://jupiter.challenges.picoctf.org/problem/50009/ (link) or http://jupiter.challenges.picoctf.org:50009. Do you think you can log us in? Try to see if you can login!
The website is a sort of static website about… irish actors? those websites are weird.
Anyway, there’s not a lot to do except the admin login page. Even the login page is quite simple, but if we analyze the code we can find something interesting: an hidden input named debug
<input type="hidden" name="debug" value="0">
If we use the firefox inspector to change the value to 1, we can see the username, the password and a SQL query, probably the one used for the login check.
Is this just a way to push us into an SQL injection?
Yes.
After the “Most cookies”, this challenge has been a bit disappointing considering that it had twice as many points.
Irish-Name-Repo 2 - 350p
Same website of Irish Name Repo 1 but “improved”. If i try the same injection as before it doesn’t work because it detects the sql injection.
But if I try with just admin' --
(the condition is just the admin user exists) it works. done.
Irish-Name-Repo 3 - 400p
Again, same, but the username field is no more. The debug input is still there. If i try to inject ' OR 1=1 --
the debug output is weird:
be
? I didn’t wrote be
! but this can maybe be ROT13?
Yes, it is. If the SQL injection has ‘be’ instead of ‘or’ it should work. And it does.
400 points for this? really?
Created on 4/4/2024 - Last updated on 4/4/2024