POP3 leaks its identity in the first line and its abilities in one command. The greeting banner often names the implementation, and if the server supports APOP it embeds a per-connection timestamp token right there in the greeting. CAPA lists whether STARTTLS (STLS) is offered, which SASL mechanisms exist, and whether UIDL/TOP are available. The USER/PASS two-step is also a username oracle on servers that distinguish "no such user" from "bad password". All of this is unauthenticated.
Fingerprint first#
The server sends a +OK greeting on connect. On an APOP-capable server the greeting contains a <...> token, the timestamp used for the APOP digest.
nc <target> 110
+OK POP3 mail.corp.local v2020.1 server ready <1896.697170952@mail.corp.local>
CAPA
+OK Capability list follows
TOP
USER
UIDL
SASL PLAIN LOGIN
STLS
APOP
.
Read this:
- The greeting string frequently names the product (
qpopper,Courier,Dovecot ready). A<token@host>present in the greeting means APOP is offered and gives you the challenge if you want to attack it. STLSmeans STARTTLS is available on 110; its absence on a cleartext port meansUSER/PASSwill cross the wire in plaintext (useful to know for sniffing, and for whether the server forces TLS).SASLlists theAUTHmechanisms;UIDLandTOPconfirm you can list unique IDs and peek at headers during mailbox access.
On 995 wrap it in TLS:
openssl s_client -connect <target>:995 -quiet
CAPA
Username validation#
Classic POP3 implementations answer USER by itself with +OK regardless, then reveal the account's existence at the PASS step or via timing. Where the server (or the SASL back end behind it) returns a distinct error for an unknown user, the login becomes a user oracle.
nc <target> 110
USER bob
+OK
PASS x
-ERR [AUTH] Authentication failed. # account exists, bad password
USER nobody
+OK
PASS x
-ERR [SYS/PERM] No such user. # account does not exist (older servers)
Modern Dovecot normalizes both to the same message and adds delay, killing the wording differential, so fall back to timing: a server that validates the user before hashing the password answers a known account more slowly than an unknown one.
for u in $(cat users.txt); do
t=$( { /usr/bin/time -f %e sh -c \
"printf 'USER $u\r\nPASS x\r\nQUIT\r\n' | openssl s_client -connect <target>:995 -quiet 2>/dev/null >/dev/null"; } 2>&1 )
echo "$u $t"
done | sort -k2 -n
Legacy qpopper and older Courier are where explicit "no such user" wording survives; sort the timing output for the modern uniform servers.
Follow-on#
Carry the validated usernames and the APOP token/SASL list into authentication, and the banner's product/version into server exploitation.