Challenge Description
- Difficulty : Medium
- Points : 250
- Categoty : Web
Walkthrough
The Meme Generator website allows you generate a Meme by seaching a term on any one of the 3 below search engines.
- DuckDuckGo
- Search Encrypt
When searching on any of the search engines, the search URL would look like this.
# Google
https://google.com/?q=<MEME_SEARCH_TERM>
# DuckDuckGo
https://DuckDuckGo.com/?q=<MEME_SEARCH_TERM>
# Search Encrypt
https://searchencrypt.com/?q=<MEME_SEARCH_TERM>
# General Format
https://<SEARCH_ENGINE>.com/?q=<MEME_SEARCH_TERM>
The backend server prepends https://
and appends .com
to the search engine we specify to form the search query.
The following multipart POST request is sent to the backend API endpoint /api/generate
when generating a Meme.
We also have the source code of the Meme Generator logic by going to /source
.
import utils
from flask import Flask, render_template, request
import os import
html app = Flask(name)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/api/generate", methods = ["POST"])
def generate():
search_engine = request.form.get("search_engine")
query = request.form.get("query")
if not (search_engine and query):
return "", 400
utils.take_screenshot(search_engine, query)
utils.make_meme()
return "", 200
@app.route("/source")
def source():
with open(file, "r") as f:
return f"<pre><code>{html.escape(f.read())}</code></pre>", 200
@app.route("/flag")
def flag():
# TODO: Fix typo
if request.remote_addr == "127.0.0.1" and request.url.startswith("http://l0calhost"):
return os.getenv("FLAG"), 200
return "Nice try", 200
app.run("0.0.0.0", 8080)
After reviewing the code, it is clear that, in order to get the flag, we should make the backend server issue a request to the /flag
endpoint and the URL should start with http://l0calhost
.
Vulnerability #1 - SSRF in Search Engine Field
We have a very obvious Server Side Request Forgery in the search engine multipart form data field. We can specify any domain name omitting the TLD part. For example, if we want to make the backend server issue a request to https://example.com
, we would specify only example
as the search engine. So, to get a callback on burp collaborator, set the search engine as follows.
<collaborator_unique_id>.oastify
Somehow, I couldn’t come up with a way to exploit this to get the flag.
Vulnerability #2 - JavaScript Injection in Search Term
I noticed that the we can inject arbitrary JavaScript in the search term and would get evaluated by the chrome engine. I specified the following search term to see if the search term is evaluated in some way.
query
string :abc" + " test
If my theory was right I would get a Meme with abc test
as search term.
And to my surprise, the search term was indeed abc test
.
I had doubts at this point whether is it Python code injection or JavaScript code injection. To confirm my doubts, I tried the following payload which will form a search query containing current date. I used JavaScript Date()
function in the query
string as follows.
abc" + Date() + " test"
Voila, the Meme showed search term as abc <Current Date> test
.
If we want to redirect the Chrome headless browser to arbitrary URLs, we will need access to JavaScript objects such as document
or window
.
Confirming access to window.location
object with following query string.
abc " + window.location + " test
The meme now shows the window.location
value in the search field.
Now that I had arbitrary JavaScript execution and have access to JavaScript window
object, I can make the Chrome browser redirect to any URL. To confirm this, I used following query
string which will redirect the Chrome headless browser to http://example.com
.
abc"; window.location="http://example.com"; var s = "test
The generated meme showed that we have successfull redirection to https://example.com
.
Finally, its time to get the flag. Sending the following payload satisfied all conditions and gave the flag.
abc"; window.location="http://l0calhost.localhost:8080/flag"; var s = "test
Flag: BlackHatMEA{196:15:b15003a794eec95eb3d93f3ee55398d81c4ed0ab}