#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
__author__ = 'Jesus Olmos (jolmos[4t]isecauditors[d0t]com,sha0[4t]badchecksum[d0t]net)'
__version__ = '0.1'

#UDP is quick to scan and bruteforce, next version with threads :)



import socket
import sys
import os
import re

class TftpClient:
	def __init__(self,timeout):
		#Opcodes
		self.PRQ = '\x00\x01'	#Read request
		self.WRQ = '\x00\x02'	#Write request
		self.DATA = '\x00\x03'	#Data
		self.ACK = '\x00\x04'	#ACK
		self.ERR = '\x00\x05'	#Error
		#Data
		self.header=''
		self.OK = '\x00\x03\x00\x01'
		self.ERR = '\x00\x05\x00\x02'
		#Error Codes
		self.UNDEFINED = '\x00\x00'
		self.NOT_FOUND = '\x00\x01'
		self.ACCESS_VIOLATION = '\x00\x02'
		self.DISK_FULL = '\x00\x03'
		self.ILLEGAL = '\x00\x04'
		self.UNKNOWN_ID = '\x00\x05'
		self.ALREADY_EXISTS = '\x00\x06'
		self.NO_SUCH_USER = '\x00\x07'
		self.NO_RESPONSE = '\x7a\x69'
		#Response
		self.ack = 0
		self.resp_error = 0
		self.resp_msg = ''
		#UDP Socket
		self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
		self.sock.settimeout(timeout)
		
	def get(self,filename,host):
		self.send(self.PRQ,filename,host)

	def put(self,filename,host):
		self.send(self.WRQ,filename,host)

	def send(self,opcode,filename,host):
		#packet = opcode+filename+'\x00NETASCII\x00'
		packet = opcode+filename+'\x00octet\x00blksize\x00512'
		self.sock.sendto(packet,(host,69))
		try:
			self.header = self.sock.recv(4)
		except:
			self.ack = 0
                        self.resp_error = self.NO_RESPONSE

	def parse(self,data):
		pass

	def end(self):
		self.sock.close()


class TftpAudit:	
	def __init__(self,timeout):
		self.tftp = TftpClient(timeout)
		self.NON_EXISTENT_FILENAME = 'adh4g21n'
		sys.stdout.flush()
		self.retorno = re.compile('\x0d|\x0a')
	
	def speech(self,msg):
		try:
			os.popen('echo '+msg+' | festival --tts','r')
		except:
			pass
		

	def check(self,host):
		sys.stdout.write('>> '+host)
		self.tftp.get(self.NON_EXISTENT_FILENAME, host)
		if self.tftp.resp_error != self.tftp.NO_RESPONSE:		
			self.speech('Service identified')
			sys.stdout.write('\tTFTP identified')
			if self.tftp.resp_error == self.tftp.ACCESS_VIOLATION:
				print '\tbut Denied!'
			elif self.tftp.ack:
				print '\tand is Readable!!'
			else:
				print '\tbut with errors!!'
		else:
			self.speech('No response')	
			print '\tNo response.'
		
	def scan(self,net):
		for octet in range(0,255):
			host = net+'.'+str(octet)
			sys.stdout.write('>> '+host)
			self.tftp.get(self.NON_EXISTENT_FILENAME, host)
			if self.tftp.resp_error != self.tftp.NO_RESPONSE:		
				self.speech('Service detected at '+host)
				sys.stdout.write('\tTFTP identified')
				if self.tftp.resp_error == self.tftp.ACCESS_VIOLATION:
					print '\tbut Denied!'
				elif self.tftp.ack:
					print '\tand is Readable!!'
				else:
					print '\tbut with errors!!'
			else:
				print '\tNo response.'
				
	def brute(self,host,wordlist):
		f = open(wordlist,'r')
		words = f.readlines()
		f.close()
		for w in words:
			w = self.retorno.sub('',w)
			print 	w
			self.tftp.get(w,host)
			if self.tftp.header == self.tftp.OK:
				print host+'/'+w

	def bof(self,host):
		evil=''
		for i in range(1,666):
			evil+='666'
		self.tftp.get(evil,host)
		
	def end(self):
		self.tftp.end()

	def usage(self):
		print sys.argv[0]+' <mode s:scan c:check b:bruteforce> <net/host> <wordlist>'
		print ' ej: '+sys.argv[0]+' s 192.168.3'
		print ' ej: '+sys.argv[0]+' c 192.168.3.44'
		print '     '+sys.argv[0]+' b 191.168.3.5 nombreficheros.txt'
		self.end()
		sys.exit(-1)

audit = TftpAudit(1)

if len(sys.argv) > 2:
	if sys.argv[1] == 's':
		if len(sys.argv) == 3:
			audit.scan(sys.argv[2])
		else:	
			audit.usage()

	elif sys.argv[1] == 'c':
		if len(sys.argv) == 3:	
			audit.check(sys.argv[2])
		else:
			audit.usage()
					
	elif sys.argv[1] == 'b':
		if len(sys.argv) == 4:
			audit.brute(sys.argv[2],sys.argv[3])
		else:
			audit.usage()

	else:
		audit.usage()
else:
	audit.usage()


audit.end()


