Ten Writeup - HackTheBox
Ten is a hard Linux box. The chain runs: nmap finds FTP, SSH, and Apache, signup.php provisions real FTP accounts with a personal vhost, subdomain fuzzing finds webdb.ten.vl which exposes the Pure-FTPd MySQL backing table via an Adminer-style browser with a one-click login, editing the dir and uid/gid columns escapes the FTP chroot and spoofs tyrell's Unix identity, writing an SSH key to tyrell's .ssh directory gives shell access, etcd running as root with no auth holds the customer URL values that remco templates into live Apache vhost config without sanitization, injecting a newline and a CustomLog pipe directive into etcd runs arbitrary shell commands as root on the next logged request.
Discovery
Port scan
PORT STATE SERVICE VERSION 21/tcp open ftp Pure-FTPd 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 80/tcp open http Apache httpd 2.4.52 |_http-title: Page moved.
index.php (Status: 200) [Size: 5131] signup.php (Status: 200) [Size: 4050]
signup.php is a self-service account provisioner. Submitting a domain name creates an FTP account and a vhost at domain.ten.vl.
Account Creation and Subdomain Discovery
OK Your personal account is ready to be used: Username: ten-6a9c0045 Password: 71e79f38 Personal Domain: test123.ten.vl You can use the provided credentials to upload your pages via ftp://ten.vl.
webdb [Status: 200, Size: 1685]
webdb.ten.vl is a database browser. Its "Guess credentials" button logs straight in to MySQL on 127.0.0.1:3306.
FTP Chroot Escape
Leaking FTP user table
Browse to the pureftpd.users table in webdb.ten.vl. The table stores each user's chroot directory path, uid, and gid as editable columns. Pure-FTPd reads these at login time, not from config, so editing them changes the effective jail and Unix identity for the next session.
Escaping the chroot
Edit the dir column for your own account in the webdb table editor and reconnect via FTP after each change:
# Step 1 - one level up:
dir = /srv/./
# ftp ls shows all customer directories
# Step 2 - root filesystem:
dir = /../
# ftp ls shows bin, boot, etc, home, root, srv...
Chroot is now at /. Browse /etc/passwd over FTP to find the real user:
tyrell:x:1000:1000:Tyrell W.:/home/tyrell:/bin/bash
/home/tyrell is mode drwxr-x--- owned by uid 1000. The provisioned FTP account has a different uid so access is denied. Edit uid and gid to 1000 in the webdb table editor and reconnect:
drwx------ .ssh -r-------- .user.txt
tyrell's home directory is readable. .ssh is writable with the spoofed uid. Plant an SSH key:
226 File successfully transferred
tyrell@ten:~$ whoami tyrell
Shell as tyrell.
Privilege Escalation
etcd + remco config injection
tcp LISTEN 127.0.0.1:2379
{"etcdserver":"3.5.13","etcdcluster":"3.5.0"}
root 1581 /usr/local/bin/etcd --name=etcd --listen-client-urls=http://0.0.0.0:2379
etcd runs as root with no authentication. It holds the customer URL values that drive the Apache vhost config via remco, a templating daemon that watches etcd keys and rewrites Apache config on every change:
/customers/ten-6a9c0045/url test123
{% for customer in lsdir("/customers") %}
{% if exists(printf("/customers/%s/url", customer)) %}
<VirtualHost *:80>
ServerName {{ getv(printf("/customers/%s/url",customer)) }}.ten.vl
DocumentRoot /srv/{{ customer }}/
</VirtualHost>
{% endif %}
{% endfor %}
The customer URL is interpolated directly into the template without sanitization. remco is root-owned with no User= directive. A newline in the etcd value injects arbitrary Apache directives. Apache's CustomLog supports piped logging via |/path/to/command, executing as root on every logged request.
Inject the directive:
OK
remco picks up the etcd change, rewrites the Apache config, and restarts Apache. Trigger a logged request to run the piped command:
root@ten:~# whoami root
Related
References
-
remco, the config templating daemon used to bridge etcd and Apache.
-
etcd v3 API, etcdctl usage reference.