#!/usr/bin/env python3
"""
SMTP Fuzzer using JRSFuzz
by Javantea
Oct 11, 2015
Based on SMTP Grammar Fuzzer
by Javantea
Sept 14, 2015

For STARTTLS, see smtp_starttls_jrsfuzz1.py

TODO:
HELO
DATA
Headers
Body
MIME
advanced SMTP commands.
Handle errors returned by the server.
Monitors with GDB and ASAN integration.
"""
import jrsfuzz
import sys
import socket

def main():
	# This works on any server except those that require STARTTLS (suzy)
	data = b'EHLO a.altsci.com\r\nMAIL FROM: jvoss@altsci.com\r\nRCPT TO: jvoss@altsci.com\r\nQUIT\r\n'
	host, port = 'localhost', 25
	if len(sys.argv) > 1:
			host = sys.argv[1]
	#end if
	if len(sys.argv) > 2:
			port = int(sys.argv[2])
	#end if
	dest = (host, port)
	family, socktype = socket.AF_UNSPEC, socket.SOCK_STREAM
	gai = socket.getaddrinfo(host, port, family, socktype)
	
	if len(sys.argv) > 3:
		data = sys.argv[3]
	#end if
	lines_output = len(data) * 256
	print("%i outputs, %3.3f MB" % (lines_output, lines_output*len(data)/(1<<20)), file=sys.stderr)

	our_data = None
	for family, socktype, proto, canonname, addr in gai:
		try:
			s = socket.socket(family, socktype, proto)
			s.connect(addr)
		except Exception as e:
			print(e,)
			continue
		#end try
		our_data = (family, socktype, proto, canonname, addr)
		break
	#next family, socktype, proto, canonname, addr
	
	if our_data == None:
		print("Can't connect to dest", dest)
	#end if
	family, socktype, proto, canonname, addr = our_data
	
	header = s.recv(1024)
	print(header)
	prevResp = None
	for i in range(lines_output):
		x = jrsfuzz.JRSFuzz(data, i)
		# We might be sending 2 commands, but let it be.
		s = socket.socket(family, socktype, proto)
		s.connect(addr)
		header = s.recv(1024)
		print(header)
		try:
			s.send(x)
		except BrokenPipeError:
			print("Broken Pipe.", i, x)
		except ConnectionResetError:
			print("Conn Reset.", i, x)
		#end try
		try:
			resp = s.recv(1024)
		except ConnectionResetError:
			print("Conn Reset on recv.", i, x)
			resp = b''
		#end try
		print(resp)
		if resp != prevResp: print(i, x)
		prevResp = resp
		s.close()
	#next i
#end def main()

if __name__ == '__main__':
	main()
#end if