Files
NetAlertX/pholus/pholus3.py
2023-01-22 11:45:08 +11:00

1163 lines
70 KiB
Python
Executable File

#!/usr/bin/python
from scapy.all import *
import argparse
import re
import binascii
import random
import multiprocessing
import logging
import itertools
import codecs
import ipaddress
import os
import sys
import datetime
from scapy.utils import PcapWriter
sys.setrecursionlimit(30000)
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)#supress Scapy warnings`
runPath = os.path.dirname(os.path.abspath(__file__))
runPathTmp = runPath + "/.."
logPath = runPathTmp + '/front/log'
#===============================================================================
# UTIL
#===============================================================================
#-------------------------------------------------------------------------------
def timeNow():
return datetime.datetime.now().replace(microsecond=0)
def write_file (pPath, pText):
# Write the text depending using the correct python version
if sys.version_info < (3, 0):
file = io.open (pPath , mode='w', encoding='utf-8')
file.write ( pText.decode('unicode_escape') )
file.close()
else:
file = open (pPath, 'w', encoding='utf-8')
file.write (pText)
file.close()
# Empty the last run log file
write_file(logPath + "/pialert_pholus_lastrun.log", "")
def file_print(*args):
result = ''
file = open(logPath + "/pialert_pholus_lastrun.log", "a")
for arg in args:
result += str(arg)
print(result)
file.write(result + '\n')
file.close()
# Empty the last run log file
write_file(logPath + "/pialert_pholus_subp_pr.log", "")
# For separate logging of the multiprocess subprocess
def file_print_pr(*args):
result = ''
file = open(logPath + "/pialert_pholus_subp_pr.log", "a")
for arg in args:
result += str(arg)
print(result)
file.write(result + '\n')
file.close()
def sanitize_string(input):
if isinstance(input, bytes):
input = input.decode('utf-8')
value = b_to_str(re.sub('[^a-zA-Z0-9-_\s]', '', str(input)))
return value
#-------------------------------------------------------------------------------
NoneType = type(None)
def b_to_str(value):
# if value is of other type than string, convert to string
if value is None:
return str("")
elif isinstance(value, type(None)):
return str("")
elif isinstance(value, NoneType):
return str("")
elif isinstance(value, str):
return str(value+"")
elif isinstance(value, int):
b_to_str(str(value))
elif isinstance(value, bool):
b_to_str(str(value))
elif isinstance(value, bytes):
b_to_str(value.decode('utf-8'))
elif isinstance(value, list):
for one in value:
b_to_str(one)
else:
return str(value)
#-------------------------------------------------------------------------------
######################################
### OBTAIN THE SYSTEM IPV6 ADDRESS ###
######################################
def get_my_ipv6_addr(interface):
myip=""
try:
for ifaces in scapy.arch.linux.in6_getifaddr(): #in6_getifaddr() #return a list of IPs - ifaces, etc
if ifaces[2]==interface:
if not myip:
myip=ifaces[0]
elif myip[0:6] == "fe80::":
myip=ifaces[0]
return myip
except:
file_print("The interface",interface,"does not exist. Please, try again.")
exit(0)
######################################
### OBTAIN THE SYSTEM IPV4 ADDRESS ###
######################################
def get_my_ipv4_addr(interface):
myip=""
try:
myip=scapy.arch.get_if_addr(interface)
return myip
except:
file_print("The interface",interface,"does not exist. Please, try again.")
exit(0)
##########################
##### SNIFFER CLASS #####
##########################
class Sniffer():
def __init__ (self,filter,interface,sniffer_timeout,queue,dns,show_ttl,dos_ttl, conflict, ttl,d4, d6, target_mac, auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,hlimit,workstation,printer,googlecast,airtv,flood,flooding_timeout,flooding_interval, v4, v6):
file_print(">>>>>>> sniffer_args: ", filter," ",interface," ",sniffer_timeout," ",queue," ",dns," ",show_ttl," ",dos_ttl," ", conflict," ", ttl," ",d4," ", d6," ", target_mac," ", auto_fake_responses," ",source_IPv6," ", source_IPv4," ", target_mac1," ", target_mac2," ",source_mac," ",hlimit," ",workstation," ",printer," ",googlecast," ",airtv," ",flood," ",flooding_timeout," ",flooding_interval," ", v4," ", v6)
self.filter = filter
self.interface = interface
file_print(">>>>>>> sniffer_timeout: ", sniffer_timeout)
self.sniffer_timeout=sniffer_timeout
self.queue=queue
self.dns=dns
self.show_ttl=show_ttl
self.dos_ttl=dos_ttl
self.conflict=conflict
self.ttl=ttl
self.d4=d4
self.d6=d6
self.target_mac=target_mac
self.auto_fake_responses=auto_fake_responses
self.source_IPv6=source_IPv6
self.source_IPv4=source_IPv4
self.target_mac1=target_mac1
self.target_mac2=target_mac2
self.source_mac=source_mac
self.hlimit=hlimit
self.workstation=workstation
self.printer=printer
self.airtv=airtv
self.googlecast=googlecast
self.flood=flood
self.flooding_interval=flooding_interval
self.flooding_timeout=flooding_timeout
self.v4=v4
self.v6=v6
sniff(filter=self.filter, iface=self.interface, prn=self.handler, store=0, timeout=self.sniffer_timeout)
def handler(self,packets):
ext_handler(packets,self.queue,self.dns,self.show_ttl,1,self.dos_ttl,self.conflict, self.ttl,self.interface,self.d4,self.d6,self.target_mac,self.auto_fake_responses,self.source_IPv6,self.source_IPv4,self.target_mac1,self.target_mac2,self.source_mac,self.hlimit,self.workstation,self.printer,self.googlecast,self.airtv,self.flood,self.flooding_timeout,self.flooding_interval,self.v4,self.v6)
##################################
##### OFFLINE SNIFFER CLASS #####
##################################
class Sniffer_Offline():
def __init__ (self,interface,queue,show_ttl,d4, d6, target_mac,auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,hlimit):
file_print(">>>>>>> Timestamp 0.0210aa: ", timeNow())
self.interface = interface
self.queue=queue
self.show_ttl=show_ttl
self.d4=d4
self.d6=d6
self.target_mac=target_mac
self.auto_fake_responses=auto_fake_responses
self.source_IPv6=source_IPv6
self.source_IPv4=source_IPv4
self.target_mac1=target_mac1
self.target_mac2=target_mac2
self.source_mac=source_mac
self.hlimit=hlimit
sniff(filter="udp and (port 5353 or port 53)", offline=self.interface, prn=self.handler, timeout=1)
def handler(self,packets):
ext_handler(packets,self.queue,False,self.show_ttl,1,False,False,4500,self.interface,self.d4,self.d6,self.target_mac,False,self.source_IPv6,self.source_IPv4,self.target_mac1,self.target_mac2,self.source_mac,self.hlimit,False,False,False,False,False,10.0,0.1,True,False)
########################################################################
### THE HANDLER THAT THE TWO SNIFFERS CALL - THIS MAKES THE MAIN JOB ###
########################################################################
def ext_handler(packets,queue,unidns,show_ttl,print_res,dos_ttl,conflict,ttl,interface,d4,d6,target_mac,auto_fake_responses,source_IPv6,source_IPv4,target_mac1,target_mac2,source_mac,hlimit,workstation,printer,googlecast,airtv,flood,flooding_timeout,flodding_interval,v4,v6):
# file_print(">>>>>>> Timestamp 0.0210: ", timeNow())
file_print_pr(">>>>>>> Timestamp 0.0210: ", timeNow())
file_print_pr(">>>>>>> Test ")
dns_type = {12: "PTR", 28: "AAAA", 13: "HINFO",33: "SRV", 1: "A", 255: "* (ANY)", 16: "TXT", 15: "MX", 6: "SOA", 256: "URI", 5: "CNAME",39: "DNAME"}
Ether_src=packets.getlayer(Ether).src
IP_src=None
if packets.haslayer(IPv6):
IP_src=packets.getlayer(IPv6).src
elif packets.haslayer(IP):
IP_src=packets.getlayer(IP).src
else:
file_print(">>>>>>> Timestamp 0.021: ", timeNow())
file_print_pr(">>>>>>> Test 2")
res0= Ether_src + " | " + IP_src.ljust(27)
if packets.haslayer(DNS):
file_print_pr(">>>>>>> Test 4")
dns=packets.getlayer(DNS)
if (conflict or dos_ttl) and dns.ancount>0:
DNSBlocks = [ ]
DNSBlocks.append(dns.an)
if conflict:
new_DNS_packet=DNS(id=dns[DNS].id,qr=dns[DNS].qr,opcode=dns[DNS].opcode,aa=dns[DNS].aa,tc=dns[DNS].tc,rd=dns[DNS].rd,ra=dns[DNS].ra,z=dns[DNS].z,ad=dns[DNS].ad,cd=dns[DNS].cd,rcode=dns[DNS].rcode,qdcount=0,ancount=dns[DNS].ancount,nscount=0,arcount=0,qd=dns[DNS].qd)
if target_mac:
new_packet=Ether(src=source_mac,dst=target_mac)
else:
new_packet=Ether(src=source_mac,dst=packets[Ether].dst)
if packets.haslayer(IPv6):
if d6:
new_packet=new_packet/IPv6(src=source_IPv6,dst=d6,hlim=packets[IPv6].hlim)
else:
new_packet=new_packet/IPv6(src=source_IPv6,dst=packets[IPv6].dst,hlim=packets[IPv6].hlim)
else:
if d4:
new_packet=new_packet/IP(src=source_IPv4,dst=d4,ttl=packets[IP].ttl)
else:
new_packet=new_packet/IP(src=source_IPv4,dst=packets[IP].dst,ttl=packets[IP].ttl)
for p in DNSBlocks:
if isinstance(p,DNSRR):
new_DNS_packet=new_DNS_packet/p
elif dos_ttl:
new_DNS_packet=DNS(id=dns[DNS].id,qr=dns[DNS].qr,opcode=dns[DNS].opcode,aa=dns[DNS].aa,tc=dns[DNS].tc,rd=dns[DNS].rd,ra=dns[DNS].ra,z=dns[DNS].z,ad=dns[DNS].ad,cd=dns[DNS].cd,rcode=dns[DNS].rcode,qdcount=0,ancount=dns[DNS].ancount,nscount=0,arcount=dns[DNS].arcount,qd=dns[DNS].qd)
DNSBlocks.append(dns.ar)
if target_mac:
new_packet=Ether(src=source_mac,dst=target_mac)
else:
new_packet=Ether(src=packets[Ether].src,dst=packets[Ether].dst)
if packets.haslayer(IPv6):
if d6:
new_packet=new_packet/IPv6(src=packets[IPv6].src,dst=d6,hlim=packets[IPv6].hlim)
else:
new_packet=new_packet/IPv6(src=packets[IPv6].src,dst=packets[IPv6].dst,hlim=packets[IPv6].hlim)
else:
if d4:
new_packet=new_packet/IP(src=packets[IP].src,dst=d4,ttl=packets[IP].ttl)
else:
new_packet=new_packet/IP(src=packets[IP].src,dst=packets[IP].dst,ttl=packets[IP].ttl)
for p in DNSBlocks:
if isinstance(p,DNSRR):
new_p=DNSRR()
new_p.ttl=0
new_p.rrname=p.rrname
new_p.type=p.type
new_p.rclass=p.rclass
new_p.rdlen=p.rdlen
new_p.rdata=p.rdata
new_DNS_packet=new_DNS_packet/new_p
if unidns:
new_packet=new_packet/UDP(dport=53)/new_DNS_packet
else:
new_packet=new_packet/UDP(dport=5353,sport=5353)/new_DNS_packet
for x in range(0,2):#Send each packet twice
file_print_pr(">>>>>>> Test 6")
sendp(new_packet,iface=interface)
file_print_pr(">>>>>>> Test 6.1")
elif auto_fake_responses or (not (dos_ttl or conflict)):
## IF THIS IS A QUERY ##
file_print_pr(">>>>>>> Test 6.2")
if dns.opcode==0:
res0 = res0 + ""
if dns.qdcount>0:
DNSBlocks = [ ]
DNSBlocks.append(dns.qd)
for block in DNSBlocks:
while isinstance(block,DNSQR):
dnsqr=block.getlayer(DNSQR)
### IF WE NEED TO AUTO RESPOND WITH A FAKE | DOS RESPONSE ###
if auto_fake_responses:
myttl=int(ttl)
if isinstance(dnsqr.qname,bytes):
qname=dnsqr.qname.decode("utf-8")
else:
qname=dnsqr.qname
if isinstance(dnsqr.name,bytes):
name=dnsqr.name.decode("utf-8")
else:
name=dnsqr.name
if (("in-addr.arpa" in qname) or ("ip6.arpa" in name)) and workstation:
if unidns:
dns_packet=UDP(dport=53)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=0)/DNSRR(rrname=dnsqr.qname,ttl=myttl,rdata='mitsos.local',type="PTR")
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=0)/DNSRR(rrname=dnsqr.qname,ttl=myttl,rdata='mitsos.local',type="PTR")
elif ("_workstation._tcp." in qname) and workstation:
#qname=dnsqr.qname
if qname.endswith('.'):
qname=qname[:-1]
if unidns:
dns_packet=UDP(dport=53)/DNS(qr=1,aa=1,rd=0,ancount=3)/DNSRR(rrname="_workstation._tcp.local",ttl=myttl,rdata="mitsos._workstation._tcp.local",type="PTR",rclass=32769)/DNSRR(rrname=qname,ttl=myttl,type="TXT",rclass=32769)/DNSRR(rrname="mitsos.local",ttl=myttl,rdata=source_IPv4,type="A",rclass=32769)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=3)/DNSRR(rrname="_workstation._tcp.local",ttl=myttl,rdata="mitsos._workstation._tcp.local",type="PTR",rclass=32769)/DNSRR(rrname=qname,ttl=myttl,type="TXT",rclass=32769)/DNSRR(rrname="mitsos.local",ttl=myttl,rdata=source_IPv4,type="A",rclass=32769)
elif (("_pdl-datastream._tcp." in qname) or ("_ipp._tcp." in qname)) and printer:
#qname=dnsqr.qname
if qname.endswith('.'):
qname=qname[:-1]
#make the SRV additional record
port=9100
port='{0:016b}'.format(port)
port="{0:0>4X}".format(int(port, 2))
weight=0
weight='{0:016b}'.format(weight)
weight="{0:0>4X}".format(int(weight, 2))
priority=0
priority='{0:016b}'.format(priority)
priority="{0:0>4X}".format(int(priority, 2))
data=priority.decode("hex")+weight.decode("hex")+port.decode("hex")
#for explanation, check http://stackoverflow.com/questions/26933016/rdata-field-of-a-dns-sd-ptr-packet-sent-via-scapy-results-in-an-unknown-extended
sublabels = "HP10000.local".split(".") + [""]
label_format = ""
for s in sublabels:
label_format = '%s%dp' % (label_format, len(s) + 1)
label_data = struct.pack(label_format, *sublabels)
srv_rrname=data+label_data
txt_record=""
rdata=['txtvers=1','qtotal=1','pdl=application/vnd.hp-PCL','ty=MyOfficejet100000','product=(Trexa gureue)','priority=0','adminur=http://'+source_IPv4]
#file_print(type(rdata))
for r in rdata:
length=hex(len(r))[2:]
#check http://code.activestate.com/recipes/576617-converting-arbitrary-size-python-integers-to-packe/
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
pkt= DNSRR(rrname="MyOfficejet10000._pdl-datasream._tcp.local",type="TXT",ttl=myttl,rclass=32769,rdata=txt_record)
pkt.rdlen-=1
mylength=len(pkt.rrname)+12
dnsrr_packet=str(pkt)[0:mylength]+str(pkt)[mylength+1::]
pkt=dnsrr_packet
if unidns:
dns_packet=UDP(dport=53)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=3)/DNSRR(rrname=qname,ttl=myttl,rdata="MyOffice10000."+qname,type="PTR",rclass=32769)/DNSRR(rrname="HP10000.local",ttl=myttl,type="A",rclass=32769,rdata=source_IPv4)/DNSRR(rrname="MyOffice100000."+qname,ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/pkt
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=3)/DNSRR(rrname=qname,ttl=myttl,rdata="MyOffice10000."+qname,type="PTR",rclass=32769)/DNSRR(rrname="HP10000.local",ttl=myttl,type="A",rclass=32769,rdata=source_IPv4)/DNSRR(rrname="MyOffice100000."+qname,ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/pkt
elif ("_googlecast._tcp." in qname) and googlecast:
#qname=dnsqr.qname
if qname.endswith('.'):
qname=qname[:-1]
#make the SRV additional record
port=8009
port='{0:016b}'.format(port)
port="{0:0>4X}".format(int(port, 2))
weight=0
weight='{0:016b}'.format(weight)
weight="{0:0>4X}".format(int(weight, 2))
priority=0
priority='{0:016b}'.format(priority)
priority="{0:0>4X}".format(int(priority, 2))
data=priority.decode("hex")+weight.decode("hex")+port.decode("hex")
sublabels = "32799abf-18ea-631d-62ae-390515bb47c5.local".split(".") + [""]
label_format = ""
for s in sublabels:
label_format = '%s%dp' % (label_format, len(s) + 1)
label_data = struct.pack(label_format, *sublabels)
srv_rrname=data+label_data
txt_record=""
rdata=['id=32799abf-18ea-631d-62ae-390515bb47c5','rm=','ve=05','md=Chromecast Ultra','ic=/setup/icon.png','fn=LivingRoom','ca=4101','st=0','bs=FA8FCA7EO948','rs=0']
for r in rdata:
length=hex(len(r))[2:]
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
pkt= DNSRR(rrname="Chromecast-Ultra-32799abf-18ea-631d-62ae-390515bb47c5."+qname,type="TXT",ttl=myttl,rclass=32769,rdata=txt_record)
pkt.rdlen-=1
mylength=len(pkt.rrname)+12
dnsrr_packet=str(pkt)[0:mylength]+str(pkt)[mylength+1::]
pkt=dnsrr_packet
if unidns:
dns_packet=UDP(dport=53)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=3)/DNSRR(rrname=qname,ttl=myttl,rdata="Chromecast-Ultra-32799abf-18ea-631d-62ae-390515bb47c5."+qname,type="PTR")/pkt/DNSRR(rrname="ChromecastUltra."+qname,ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/DNSRR(rrname="32799abf-18ea-631d-62ae-390515bb47c5.local",ttl=myttl,type="A",rclass=32769,rdata=source_IPv4)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=1,arcount=3)/DNSRR(rrname=qname,ttl=myttl,rdata="Chromecast-Ultra-32799abf-18ea-631d-62ae-390515bb47c5."+qname,type="PTR")/pkt/DNSRR(rrname="ChromecastUltra."+qname,ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/DNSRR(rrname="32799abf-18ea-631d-62ae-390515bb47c5.local",ttl=myttl,type="A",rclass=32769,rdata=source_IPv4)
elif ("_airplay." in qname) and airtv:
#qname=dnsqr.qname
if qname.endswith('.'):
qname=qname[:-1]
txt_record=""
rdata=['model=J33AP']
for r in rdata:
length=hex(len(r))[2:]
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
pkt= DNSRR(rrname="Apple TV-mitsos._device-info._tcp.local",type="TXT",ttl=myttl,rclass=32769,rdata=txt_record)
pkt.rdlen-=1
mylength=len(pkt.rrname)+12
dnsrr_packet=str(pkt)[0:mylength]+str(pkt)[mylength+1::]
pkt=dnsrr_packet
txt_record=""
rdata=['deviceid=9C:20:7B:AD:6B:E4','features=0x5A7FFFF7,0xE','flags=0x44','model=AppleTV3,1','pk=ab69a89af6fe7ff1fd803f74c6681d786aff1e6bc52087e49cc8f22585916ccd','pi=a62a851e-d024-439f-9ee0-01ef1b23d6ca','srcvers=220.68','vv=2']
for r in rdata:
length=hex(len(r))[2:]
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
pkt2= DNSRR(rrname="Apple TV-mitsos._airplay._tcp.local",type="TXT",ttl=myttl,rclass=32769,rdata=txt_record)
pkt2.rdlen-=1
mylength=len(pkt2.rrname)+12
dnsrr_packet=str(pkt2)[0:mylength]+str(pkt2)[mylength+1::]
pkt2=dnsrr_packet
txt_record=""
rdata=['cn=0,1,2,3','da=true','et=0,3,5','ft=0x5A7FFFF7,0xE','md=0,1,2','am=AppleTV3,1','pk=ab69a89af6fe7ff1fd803f74c6681d786aff1e6bc52087e49cc8f22585916ccd','sf=0x44','tp=UDP','vn=65537','vs=220.68','vv=2']
for r in rdata:
length=hex(len(r))[2:]
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
pkt3= DNSRR(rrname="9C207BAD6BE4@Apple TV-mitsos._raop._tcp.local",type="TXT",ttl=myttl,rclass=32769,rdata=txt_record)
pkt3.rdlen-=1
mylength=len(pkt3.rrname)+12
dnsrr_packet=str(pkt3)[0:mylength]+str(pkt3)[mylength+1::]
pkt3=dnsrr_packet
#make the SRV additional record
port=7000
port='{0:016b}'.format(port)
port="{0:0>4X}".format(int(port, 2))
weight=0
weight='{0:016b}'.format(weight)
weight="{0:0>4X}".format(int(weight, 2))
priority=0
priority='{0:016b}'.format(priority)
priority="{0:0>4X}".format(int(priority, 2))
data=priority.decode("hex")+weight.decode("hex")+port.decode("hex")
sublabels = "Apple-TV.local".split(".") + [""]
label_format = ""
for s in sublabels:
label_format = '%s%dp' % (label_format, len(s) + 1)
label_data = struct.pack(label_format, *sublabels)
srv_rrname=data+label_data
if unidns:
dns_packet=UDP(dport=53)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=3,arcount=6)/DNSRR(rrname=qname,ttl=myttl,rdata="Apple TV-mitsos._device-info."+qname,type="PTR")/pkt/DNSRR(rrname="_raop._tcp.local",ttl=myttl,rdata="9C207BAD6BE4@Apple TV-mitsos._raop._tcp.local",type="PTR")/pkt2/pkt3/DNSRR(rrname="Apple TV-mitsos."+qname,ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/DNSRR(rrname="9C207BAD6BE4@Apple TV-mitsos._raop._tcp.local",ttl=myttl,type="SRV",rclass=32769,rdata=srv_rrname)/DNSRR(rrname="Apple-TV.local",ttl=myttl,rdata=source_IPv4,type="A",rclass=32769)/DNSRR(rrname="Apple-TV.local",ttl=myttl,rdata=source_IPv6,type="AAAA",rclass=32769)
else:
if isinstance(dnsqr.qname,bytes):
qname=dnsqr.qname.decode("utf-8")
else:
qname=dnsqr.qname
if qname.endswith('.'):
qname=qname[:-1]
#file_print("Query Name = ",qname," Type=",dnsqr.qtype)
if unidns:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=1)/DNSRR(rrname=qname,ttl=myttl,rdata=source_IPv4,type="A")
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0,ancount=1)/DNSRR(rrname=qname,ttl=myttl,rdata=source_IPv4,type="A")
file_print_pr(">>>>>>> Test 6.23")
send_packets(v4,v6,source_mac,target_mac1,target_mac2,source_IPv4,d4,source_IPv6,d6,interface,hlimit,dns_packet,False,10.0,0.1)#CHANGE DEFAULT VALUES
file_print_pr(">>>>>>> Test 6.24")
### END "IF WE NEED TO AUTO RESPOND WITH A FAKE RESPONSE
### NEXT LINES ARE ONLY USED TO PRINT RESULTS ###
if dnsqr.qclass==32769:
res = res0 + " | Question | "+dnsqr.qname.decode("utf-8") + " " + dns_type[dnsqr.qtype] +" QU Class:IN"
elif dnsqr.qclass==1:
res = res0 + " | Question | "+dnsqr.qname.decode("utf-8") + " "+ dns_type[dnsqr.qtype] + " QM Class:IN"
elif dnsqr.qclass==255:
res = res0 + " | Question | "+dnsqr.qname.decode("utf-8") + " "+ dns_type[dnsqr.qtype] + " QM Class:ANY"
else:
file_print("DNSQR:")
file_print("-----")
file_print(dnsqr.show())
file_print("DEBUGGING IS NEEDED")
exit(0)
if print_res==1:
file_print(res)
queue.put(res)
block = block.payload
if dns.arcount>0:
DNSBlocks = [ ]
DNSBlocks.append(dns.ar)
for block in DNSBlocks:
if block.haslayer(DNSRROPT):
while isinstance(block,DNSRROPT):#Somewhat equivalent: while not isinstance(an, NoPayload):
dnsrropt=block.getlayer(DNSRROPT)
#print "DNS OPT Resource Record"
if dnsrropt.rrname == ".":
rrname = "<Root>"
else:
rrname = dnsrropt.rrname
if dnsrropt.type==41:
ARtype="OPT"
else:
ARtype=str(dnsrropt.type)
res = res0 + " | Additional_Record | " + rrname.decode("utf-8") + " " + ARtype
file_print_pr(">>>>>>> Test 6.24")
if dnsrropt.haslayer(EDNS0TLV):
edns0tlv=dnsrropt.getlayer(EDNS0TLV)
if edns0tlv.optcode==4:
optcode="Reserved"
else:
optcode=str(edns0tlv.optcode)
res = res + " EDNS0TLV: " + optcode + " " + codecs.encode(edns0tlv.optdata, 'hex_codec').decode("utf-8")
if print_res==1:
file_print(res)
queue.put(res)
block = block.payload
elif block.haslayer(DNSRR):
while isinstance(block,DNSRR):#Somewhat equivalent: while not isinstance(an, NoPayload):
dnsrr=block.getlayer(DNSRR)
if dnsrr.rclass==32769:
str_res0 = str(b_to_str(res0)) + ""
str_rrname = str(b_to_str(dnsrr.rrname)) + ""
str_type = str(b_to_str(dns_type[dnsrr.type])) + ""
str_rdata = str(b_to_str(dnsrr.rdata)) + ""
res = str_res0 + " | DNS Resource Record | " + str_rrname + " " + str_type + " QU Class:IN " + str_rdata
elif dnsrr.rclass==1:
str_res0 = str(b_to_str(res0)) + ""
str_rrname = str(b_to_str(dnsrr.rrname)) + ""
str_type = str(b_to_str(dns_type[dnsrr.type])) + ""
str_rdata = str(b_to_str(dnsrr.rdata)) + ""
res = str_res0 + " | DNS Resource Record | " + str_rrname + " " + str_type + " QM Class:IN " + str_rdata
elif dnsrr.qclass==255:
str_res0 = str(b_to_str(res0)) + ""
str_qname = str(b_to_str(dnsrr.qname)) + ""
str_qtype = str(b_to_str(dns_type[dnsrr.qtype])) + ""
res = str_res0 + " | Question | " + str_qname + " " + str_qtype + " QM Class:ANY"
else:
file_print("DNSRR:")
file_print("-----")
file_print(dnsrr.show())
file_print("DEBUGGING IS NEEDED HERE")
exit(0)
if dnsrr.type==33:#SRV Record
str_res0 = str(b_to_str(res0)) + ""
str_rrname = str(b_to_str(dnsrr.rrname)) + ""
str_type = str(b_to_str(dns_type[dnsrr.type])) + ""
str_rclass = str(b_to_str(dnsrr.rclass)) + ""
priority=str(dnsrr.rdata)[0].encode("HEX")+str(dnsrr.rdata)[1].encode("HEX")
weight=str(dnsrr.rdata)[2].encode("HEX")+str(dnsrr.rdata)[3].encode("HEX")
port_number=str(dnsrr.rdata)[4].encode("HEX")+str(dnsrr.rdata)[5].encode("HEX")
res = str_res0 + " | Additional_Record | "+ str_rrname + " " + str_type+" " + str_rclass + " priority="+str(int(priority,16))+" weight="+str(int(weight,16))+" port="+str(int(port_number,16))+" target="+str(dnsrr.rdata)[6::]
else:
rdata=dnsrr.rdata
if isinstance(rdata,bytes):
rdata = rdata.decode("utf-8")
if "._tcp." not in rdata and "._udp." not in rdata:
if rdata == "_dhnap.":
rdata=rdata+"_tcp."
str_res0 = str(b_to_str(res0)) + ""
str_rrname = str(b_to_str(dnsrr.rrname)) + ""
str_type = str(b_to_str(dns_type[dnsrr.type])) + ""
str_rdata = str(b_to_str(dnsrr.rdata)) + ""
str_rclass = str(b_to_str(dnsrr.rclass)) + ""
res = str_res0 + " | Additional_Record | "+str_rrname + " " + str_type+" " + str_rclass + ' "' +str_rdata+'"'
if show_ttl:
res = res + " TTL:"+str(dnsrr.ttl)
if print_res==1:
file_print(res)
file_print_pr(">>>>>>> Test 6.27")
queue.put(res)
block = block.payload
file_print_pr(">>>>>>> Test 6.270")
if dns.ancount>0:
DNSBlocks = [ ]
DNSBlocks.append(dns.an)
for block in DNSBlocks:
file_print_pr(">>>>>>> Test 6.271")
while isinstance(block,DNSRR):
dnsrr=block.getlayer(DNSRR)
if dnsrr.rclass==1:
rclass="Class:IN"
else:
rclass="Class:"+str(dnsrr.rclass)
rdata=dnsrr.rdata
if isinstance(rdata,bytes):
rdata = rdata.decode("utf-8")
if dnsrr.type==33:#SRV Record
priority=str(dnsrr.rdata)[0].encode("HEX")+str(dnsrr.rdata)[1].encode("HEX")
weight=str(dnsrr.rdata)[2].encode("HEX")+str(dnsrr.rdata)[3].encode("HEX")
port_number=str(dnsrr.rdata)[4].encode("HEX")+str(dnsrr.rdata)[5].encode("HEX")
res = res0 + " | Answer | "+dnsrr.rrname + " " + dns_type[dnsrr.type]+" " + rclass + " priority="+str(int(priority,16))+" weight="+str(int(weight,16))+" port="+str(int(port_number,16))+" target="+str(dnsrr.rdata)[6::]
else:
if "._tcp." not in rdata and "._udp." not in rdata:
if rdata == "_dhnap.":
rdata=dnsrr.rdata+"_tcp."
if isinstance(rdata,list):
rdata = b" ".join(rdata).decode("utf-8")
res = res0 + " | Answer | "+dnsrr.rrname.decode("utf-8") + " " + dns_type[dnsrr.type]+" " + rclass + ' "' +rdata+'"'
file_print_pr(">>>>>>> Test 6.272004")
if show_ttl:
res = res + " TTL:"+str(dnsrr.ttl)
if print_res==1:
file_print(res)
queue.put(res)
block = block.payload
file_print_pr(">>>>>>> Test 6.272")
if dns.nscount>0:
file_print_pr(">>>>>>> Test 6.273")
DNSBlocks = [ ]
DNSBlocks.append(dns.ns)
for block in DNSBlocks:
file_print_pr(">>>>>>> Test 6.28")
while isinstance(block,DNSRR):
dnsrr=block.getlayer(DNSRR)
if dnsrr.rclass==1:
rclass="Class:IN"
else:
rclass="Class:"+str(dnsrr.rclass)
str_res0 = str(b_to_str(res0)) + ""
str_rrname = str(b_to_str(dnsrr.rrname)) + ""
str_type = str(b_to_str(dns_type[dnsrr.type])) + ""
str_rdata = str(b_to_str(dnsrr.rdata)) + ""
str_rclass = str(b_to_str(rclass)) + ""
res = str_res0 + " Auth_NS: "+str_rrname + " " +str_type+" " + str_rclass + ' "' +str_rdata+'"'
if show_ttl:
res = res + " TTL:"+str(dnsrr.ttl)
if print_res==1:
file_print(res)
file_print_pr(">>>>>>> Test 6.274")
queue.put(res)
block = block.payload
else:
file_print_pr(">>>>>>> Test 6.27200")
else:
file_print("not a DNS Query", dns.summary())
file_print_pr(">>>>>>> Test 6.272001")
else:
file_print_pr(">>>>>>> Test 6.2720055")
else:
file_print_pr(">>>>>>> Test 3")
file_print_pr(">>>>>>> Test 6.272005599")
########################################
########### REQUEST FUNCTION ###########
########################################
def requests(interface,v4,v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,d4,d6,hlimit,unidns,domain,query,types_of_queries,add_domain,query_class,flood,flooding_interval,flooding_timeout):
if add_domain:
file_print("Sending mdns requests")
domain_list = domain.split(",")
query_list = query.split(",")
if add_domain:
the_query=query_list[0]+"."+domain_list[0]
else:
types_of_queries="ALL"#implies that first a generic scan has beem performed
the_query=query_list[0]
dns_query=DNSQR(qname=the_query,qtype=types_of_queries,qclass=int(query_class))
for j in range(1,len(query_list)):
if add_domain:
the_query=query_list[j]+"."+domain_list[0]
else:
the_query=query_list[j]
dns_query=dns_query/DNSQR(qname=the_query,qtype=types_of_queries,qclass=int(query_class))
if add_domain:
for i in range(1,len(domain_list)):
for j in query_list:
the_query=j+"."+domain_list[i]
dns_query=dns_query/DNSQR(qname=the_query,qtype=types_of_queries,qclass=int(query_class))
if unidns:
dns_packet=UDP(dport=53)/DNS(qr=0,qd=dns_query)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=0,qd=dns_query)
send_packets(v4,v6,source_mac,target_mac1,target_mac2,source_IPv4,d4,source_IPv6,d6,interface,hlimit,dns_packet,flood,flooding_timeout,flooding_interval)
########################################
######## SEND PACKETS FUNCTION #########
########################################
def send_packets(v4,v6,source_mac,target_mac1,target_mac2,source_IPv4,dst_ipv4,source_IPv6,dst_ipv6,interface,hlimit,payload,flood,flooding_timeout,flooding_interval):
if v4 or not v6:
packet=IP(src=source_IPv4,dst=dst_ipv4,ttl=hlimit,proto="udp")/payload
if len(packet)>1500:
frags=fragment(packet)
packets=[]
for frag in frags:
pkt1=Ether(src=source_mac,dst=target_mac1)/frag
packets.append(pkt1)
if flood:
counter=0.0
file_print("Stop flooding after ",flooding_timeout," sec.")
while(counter<float(flooding_timeout)):
for packt in packets:
sendp(pakt,iface=interface)
counter+=float(flooding_interval)
time.sleep(float(flooding_interval))
else:
for pakt in packets:
sendp(pakt,iface=interface)
else:
pkt1=Ether(src=source_mac,dst=target_mac1)/packet
if flood:
counter=0.0
file_print("Stop flooding after ",flooding_timeout," sec.")
while(counter<float(flooding_timeout)):
sendp(pkt1,iface=interface)
counter+=float(flooding_interval)
time.sleep(float(flooding_interval))
else:
sendp(pkt1,iface=interface)
if v6:
packet=IPv6(src=source_IPv6,dst=dst_ipv6,hlim=hlimit)/payload
if len(packet)>1500:
frags2=fragment6(IPv6(src=source_IPv6,dst=dst_ipv6,hlim=hlimit)/IPv6ExtHdrFragment()/payload,1480)
packets=[]
for frag2 in frags2:
pkt2=Ether(src=source_mac,dst=target_mac2)/frag2
packets.append(pkt2)
if flood:
counter=0.0
file_print("Stop flooding after ",flooding_timeout," sec.")
while(counter<float(flooding_timeout)):
for packt in packets:
sendp(pakt,iface=interface)
counter+=float(flooding_interval)
time.sleep(float(flooding_interval))
else:
for packt in packets:
sendp(pkt2,iface=interface)
else:
pkt2=Ether(src=source_mac,dst=target_mac2)/packet
if flood:
counter=0.0
file_print("Stop flooding after ",flooding_timeout," sec.")
while(counter<float(flooding_timeout)):
sendp(pkt2,iface=interface)
counter+=float(flooding_interval)
time.sleep(float(flooding_interval))
else:
pkt2=Ether(src=source_mac,dst=target_mac2)/packet
sendp(pkt2,iface=interface)
##########################################################
### Create an IPv6 link local address from MAC address ###
##########################################################
def mac2ipv6(mac):
###Code from https://stackoverflow.com/questions/37140846/how-to-convert-ipv6-link-local-address-to-mac-address-in-python###
# only accept MACs separated by a colon
parts = mac.split(":")
# modify parts to match IPv6 value
parts.insert(3, "ff")
parts.insert(4, "fe")
parts[0] = "%x" % (int(parts[0], 16) ^ 2)
# format output
ipv6Parts = []
for i in range(0, len(parts), 2):
ipv6Parts.append("".join(parts[i:i+2]))
#ipv6 = "fe80::%s/64" % (":".join(ipv6Parts))
ipv6 = "fe80::%s" % (":".join(ipv6Parts))
return ipv6
########################################################
########################################################
def main():
parser = argparse.ArgumentParser(description='Pholus: An mdns testing tool')
parser.add_argument('interface', action="store", help="the network interface to use, or the file (if -rpcap switch is used).")
parser.add_argument('-rpcap','--readpcap', action="store_true", dest="rpcap", default=False, help="Read packets from a pcap file")
parser.add_argument('-dns', '--DNS', action="store_true", dest="dns", default=False, help="Use unicast DNS request; remember to define target address")
parser.add_argument('-4', '--v4', action="store_true", dest="v4", default=False, help="Send mdns request/response using IPv4.")
parser.add_argument('-6', '--v6', action="store_true", dest="v6", default=False, help="Send mdns request/response using IPv6.")
parser.add_argument('-hl', '--hlimit', action="store", dest="hlimit", default=255, type=int, help="The TTL (for IPv4) or Hop Limit (for IPv6).")
parser.add_argument('-rq', '--request', action="store_true", dest="request", default=False, help="Send mdns request.")
parser.add_argument('-rp', '--response', action="store_true", dest="response", default=False, help="Send unsolicired mdns response.")
parser.add_argument('-ll', '--link_local', action="store_true", dest="link_local", default=False, help="As IPv6 source address, use link local address instead of global address")
parser.add_argument('-s6', '--source_addr_v6', action="store", dest="source6", default=False, help="The IPv6 address of the sender (if you want to spoof it).")
parser.add_argument('-s4', '--source_addr_v4', action="store", dest="source4", default=False, help="The IPv4 address of the sender (if you want to spoof it).")
parser.add_argument('-d6', '--dest_addr_v6', action="store", dest="d6", default="ff02::fb", help="The IPv6 destination address of the mdns packets")
parser.add_argument('-d4', '--dest_addr_v4', action="store", dest="d4", default="224.0.0.251", help="The IPv4 destination address of the mdns packets")
parser.add_argument('-qtype', '--gtype', action="store", dest="qtype", default="ALL", help="qtype of mDNS query (e.g. PTR, etc.)")
parser.add_argument('-query', '--query', action="store", dest="query", default="_services._dns-sd._udp", help="Query/ies of the mDNS packet; it can be a comma-separated list")
parser.add_argument('-qclass', '--query_class', action="store", dest="q_class", default=1, help="The class of the query (e.g. QU vs QM)")
parser.add_argument('-qu', '--qu', action="store_true", dest="qu", default=False, help="Send a Uniqast (QU) question in Queries")
parser.add_argument('-dns_response', '--dns_response', action="store", dest="dns_response", default="", help="Responses of the mDNS packet; it can be a comma-separated list")
parser.add_argument('-sttl', '--show_ttl', action="store_true", dest="show_ttl", default=False, help="Display the DNS TTL information of the received packets.")
parser.add_argument('-rm', '--random-mac', action="store_true", dest="random_mac", default=False, help="Randomise the source MAC address.")
parser.add_argument('-tm', '--target_mac', action="store", dest="target_mac", default=False, help="The mac address of the target (optional).")
parser.add_argument('-sm', '--source_mac', action="store", dest="source_mac", default=False, help="The mac address of the source, e.g. for spoofing purposes (optional).")
parser.add_argument('-stimeout','--sniffer_timeout', action="store", dest="sniffer_timeout", default=5, help="The timeout (in seconds) when the integrated sniffer (IF used) will exit automatically.")
parser.add_argument('-domain','--domain', action="store", dest="domain", default="local", help="The domain to query; default:local")
parser.add_argument('-rdns_scanning', '--reverse_dns_scanning', action="store", dest="rdns_scanning", default=False, help="The IPv4 address subnet that we want to scan, e.g. 192.168.169.0/24")
parser.add_argument('-sscan', '--service_scanning', action="store_true", dest="service_scan", default=False, help="A service scan, initiated using _services._dns-sd._udp.local")
parser.add_argument('-ttl','--define_ttl', action="store", dest="ttl", default=4500, help="The TTL to be used in the DNS messages.")
parser.add_argument('-dos_ttl', '--DoS_zeroizing_ttl', action="store_true", dest="dos_ttl", default=False, help="DoS hosts by zeroizing the TTL value of the DNS packets.")
parser.add_argument('-conflict', '--send_conflicting_questions', action="store_true", dest="conflict", default=False, help="Send conflicting questions with the received ones.")
parser.add_argument('-afre', '--auto_fake_responses', action="store_true", dest="auto_fake_responses", default=False, help="Send automatically fake resposnes")
parser.add_argument('-printer', '--printer', action="store_true", dest="printer", default=False, help="fake responses for printer")
parser.add_argument('-airplay', '--airplay', action="store_true", dest="airtv", default=False, help="fake responses for AirPlay TV")
parser.add_argument('-workstation', '--workstation', action="store_true", dest="workstation", default=False, help="fake responses for workstation")
parser.add_argument('-googlecast', '--googlecast', action="store_true", dest="googlecast", default=False, help="fake responses for googlecast")
parser.add_argument('-fl','--flood', action="store_true", dest="flood", default=0, help="flood the targets")
parser.add_argument('-flooding-interval','--interval-of-flooding', action="store", dest="flooding_interval", default=1, help="the interval between packets when flooding the targets")
parser.add_argument('-ftimeout','--flooding_timeout', action="store", dest="flooding_timeout", default=200, help="The time (in seconds) to flood your target.")
values = parser.parse_args()
if values.rpcap:
file_print("Read packets from a pcap file")
if not os.path.isfile(values.interface):
file_print('[-] ' + values.interface + ' does not exist')
exit(0)
elif not os.access(values.interface, os.R_OK):
file_print('[-] ' + values.interface + ' access is denied')
exit(0)
file_print("Press Ctrl-C to exit and print the results")
q = multiprocessing.Queue()
file_print(">>>>>>> Timestamp 0.1: ", timeNow())
pr = multiprocessing.Process(target=Sniffer_Offline, args=(values.interface,q,values.show_ttl,values.d4, values.d6, values.target_mac, values.auto_fake_responses,values.source6,values.source4,values.target_mac,values.target_mac,values.source_mac,values.hlimit))
pr.start()
pr.join()
file_print(">>>>>>> Timestamp 0.2: ", timeNow())
results=[]
while not q.empty():
results.append(q.get())
myset=set(results)
results=list(myset)
results.sort()
file_print("\n*********************************************RESULTS*********************************************")
for r in results:
file_print(r)
exit(0)
else:
#####################################LETS DO SOME CHECKS FIRST TO SEE IF WE CAN WORK####################
if os.geteuid() != 0:
file_print("You must be root to run this script.")
exit(1)
conf.verb=0
#########################################DEFINE SOURCE ADDRESSES########################################
source_mac=None
if values.random_mac:
source_mac = ':'.join(map(lambda x: "%02x" % x, [ 0x00, 0x16, 0x3E, random.randint(0x00, 0x7F), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF) ]))
elif values.source_mac:
source_mac=values.source_mac
else:
try:
source_mac=get_if_hwaddr(values.interface)
except:
file_print("interface ",values.interface," does not exist")
exit(0)
if values.qu:
q_class=32769
else:
q_class=int(values.q_class)
if not values.source6:
source_IPv6=None
source_IPv6=get_my_ipv6_addr(values.interface)#Selects global IPv6 address, if available
if not source_IPv6 or values.random_mac or values.link_local: #If a random MAC is used, construct the corresponding IPv6 Link Local Address
source_IPv6 = mac2ipv6(source_mac)
else:
source_IPv6=values.source6
if not values.source4:
source_IPv4=get_my_ipv4_addr(values.interface)
else:
source_IPv4=values.source4
file_print("source MAC address:",source_mac,"source IPv4 Address:",source_IPv4,"source IPv6 address:",source_IPv6)
#########################################################################################################
if values.target_mac:
target_mac1=values.target_mac
target_mac2=values.target_mac
else:
target_mac2="33:33:00:00:00:02"
target_mac1="01:00:5e:00:00:fb"
############################################Sniffing requirements########################################
q = multiprocessing.Queue()
if values.dos_ttl or values.auto_fake_responses:
if values.auto_fake_responses:
file_print("Send fake responses to requests" )
if values.target_mac:
myfilter = "not ether src " + source_mac + " and not ether dst " + values.target_mac +" and udp and port 5353"
else:
myfilter = "not ether src " + source_mac + " and udp and port 5353"
elif values.target_mac:
file_print("Performing implicit DoS by sending automated spoofed DNS Answers with TTL=0" )
myfilter = "not ether dst " + values.target_mac + " and udp and port 5353"
else:
file_print("Performing implicit DoS by sending automated spoofed DNS Answers with TTL=0" )
myfilter = "udp and port 5353"
file_print("Sniffer filter is: ",myfilter)
file_print("I will sniff for ",values.sniffer_timeout," seconds, unless interrupted by Ctrl-C")
file_print("Press Ctrl-C to exit")
try:
file_print(">>>>>>> Timestamp 0.0210ab: ", timeNow())
Sniffer(myfilter, values.interface, float(values.sniffer_timeout),q,values.dns,values.show_ttl, values.dos_ttl, values.conflict, values.ttl,values.d4, values.d6, values.target_mac, values.auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,values.hlimit,values.workstation,values.printer,values.googlecast,values.airtv,values.flood,values.flooding_timeout,values.flooding_interval,values.v4,values.v6)
file_print(">>>>>>> Timestamp 0.0210abc: ", timeNow())
except KeyboardInterrupt:
file_print("Exiting on user's request 1")
exit(0)
exit(0)
myfilter = "not ether src " + source_mac + " and udp and port 5353"
file_print("Sniffer filter is: ",myfilter)
file_print("I will sniff for ",values.sniffer_timeout," seconds, unless interrupted by Ctrl-C")
pr = multiprocessing.Process(target=Sniffer, args=(myfilter, values.interface, float(values.sniffer_timeout),q,values.dns,values.show_ttl, values.dos_ttl, values.conflict, values.ttl,values.d4,values.d6, values.target_mac, values.auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2, source_mac,values.hlimit,values.workstation,values.printer,values.googlecast,values.airtv,values.flood,values.flooding_timeout,values.flooding_interval,values.v4,values.v6))
pr.daemon = True
file_print(">>>>>>> Timestamp 0.01: ", timeNow())
pr.start()
file_print(">>>>>>> Timestamp 0.02: ", timeNow())
file_print("------------------------------------------------------------------------")
time.sleep(1)#to make sure than sniffer has started before we proceed, otherwise you may miss some traffic
file_print(">>>>>>> Timestamp 0.03: ", timeNow())
##########################################################################################################
if values.request:
file_print(">>>>>>> Timestamp 1: ", timeNow())
requests(values.interface,values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,values.d4,values.d6,values.hlimit,values.dns,values.domain,values.query,values.qtype,True,q_class,values.flood,values.flooding_interval,values.flooding_timeout)
file_print(">>>>>>> Timestamp 2: ", timeNow())
elif values.response:
#qr=1=>Response, aa=1=>Server is an authority for the domain, rd=0=> Do not query recursively
file_print(">>>>>>> Timestamp 3: ", timeNow())
if values.dns:
dns_packet=UDP(dport=53)/DNS(qr=1,aa=1,rd=0)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=1,aa=1,rd=0)
file_print(">>>>>>> Timestamp 4: ", timeNow())
responses = values.dns_response.split(",")
no_of_answers=0
no_of_additional_records=0
dnsar=None
for r in responses:
values_of_responses = r.split("/")
dnsrr=DNSRR()
port=0
weight=0
priority=0
no_of_answers+=1
this_is_a_dns_ar=False
rdata=[]
for dns_values in values_of_responses:
#print dns_values
value = dns_values.split("==")
if value[0]=="Type":
dnsrr.type=value[1]
elif value[0]=="Name":
dnsrr.rrname=value[1]
elif value[0]=="Target":
rdata.append(value[1])
elif value[0]=="TTL":
dnsrr.ttl=int(value[1])
elif value[0]=="Flush":
if value[1]=="True":
dnsrr.rclass=32769
elif value[0]=="Priority":
priority=int(value[1])
elif value[0]=="Weight":
weight=int(value[1])
elif value[0]=="Port":
port=int(value[1])
elif value[0]=="AR":
if value[1]=="True":
no_of_additional_records+=1
this_is_a_dns_ar=True
if dnsrr.type==33:
port='{0:016b}'.format(port)
port="{0:0>4X}".format(int(port, 2))
weight='{0:016b}'.format(weight)
weight="{0:0>4X}".format(int(weight, 2))
priority='{0:016b}'.format(priority)
priority="{0:0>4X}".format(int(priority, 2))
data=priority.decode("hex")+weight.decode("hex")+port.decode("hex")
#http://stackoverflow.com/questions/26933016/rdata-field-of-a-dns-sd-ptr-packet-sent-via-scapy-results-in-an-unknown-extended
sublabels = rdata[0].split(".") + [""]
label_format = ""
for s in sublabels:
label_format = '%s%dp' % (label_format, len(s) + 1)
label_data = struct.pack(label_format, *sublabels)
dnsrr.rdata=data+label_data
elif dnsrr.type==16:
txt_record=""
for r in rdata:
length=hex(len(r))[2:]
#check http://code.activestate.com/recipes/576617-converting-arbitrary-size-python-integers-to-packe/
if len(r) > 255:
s=struct.Struct('I')# CHECK IT
else:
s=struct.Struct('B')
value=(len(r),)
packed_data=s.pack(*value)
txt_record=txt_record+packed_data+r
dnsrr.rdata=txt_record
##################
pkt=dnsrr
pkt.rdlen-=1
mylength=len(pkt.rrname)+12
dnsrr_packet=str(pkt)[0:mylength]+str(pkt)[mylength+1::]
##################
dnsrr=dnsrr_packet
else:
dnsrr.rdata=rdata[0]
if not this_is_a_dns_ar:
dns_packet=dns_packet/dnsrr
else:
if not dnsar:
dnsar=dnsrr
else:
dnsar=dnsar/dnsrr
if dnsar:
dns_packet=dns_packet/dnsar
dns_packet[DNS].ancount=no_of_answers-no_of_additional_records
dns_packet[DNS].arcount=no_of_additional_records
send_packets(values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,values.d4,source_IPv6,values.d6,values.interface,values.hlimit,dns_packet,values.flood,values.flooding_timeout,values.flooding_interval)
elif values.rdns_scanning:
file_print(">>>>>>> Timestamp 5: ", timeNow())
dns_query=None
ipn = ipaddress.ip_network(values.rdns_scanning)
for ip in ipn.hosts():
the_query = ip.reverse_pointer
if not dns_query:
dns_query=DNSQR(qname=the_query,qtype=values.qtype,qclass=values.q_class)
else:
dns_query=dns_query/DNSQR(qname=the_query,qtype=values.qtype,qclass=values.q_class)
if values.dns:
dns_packet=UDP(dport=53)/DNS(qr=0,qd=dns_query)
else:
dns_packet=UDP(sport=5353,dport=5353)/DNS(qr=0,qd=dns_query)
send_packets(values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,values.d4,source_IPv6,values.d6,values.interface,values.hlimit,dns_packet,values.flood,values.flooding_timeout,values.flooding_interval)
file_print(">>>>>>> Timestamp 6: ", timeNow())
elif values.service_scan:
file_print(">>>>>>> Timestamp 7: ", timeNow())
requests(values.interface,values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,values.d4,values.d6,values.hlimit,values.dns,values.domain,values.query,values.qtype,True,q_class,values.flood,values.flooding_interval,values.flooding_timeout)
file_print(">>>>>>> Timestamp 8: ", timeNow())
############################################################################################
############################################################################################
if pr:
try:
file_print(">>>>>>> Timestamp 6.1000: ", timeNow())
pr.join()
file_print(">>>>>>> Timestamp 6.2: ", timeNow())
except KeyboardInterrupt:
file_print("Exiting on user's request 2")
exit(0)
#### AFTER EXITING, PRINT THE RESULTS ####
results=[]
while not q.empty():
results.append(q.get())
if values.rdns_scanning:
targets=[]
q2 = multiprocessing.Queue()
file_print(">>>>>>> Timestamp 9: ", timeNow())
pr2 = multiprocessing.Process(target=Sniffer, args=(myfilter, values.interface, float(values.sniffer_timeout),q2,values.dns,values.show_ttl, values.dos_ttl,values.conflict, values.ttl,values.d4, values.d6, values.target_mac, values.auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,values.hlimit,values.workstation,values.printer,values.googlecast,values.airtv,values.flood,values.flooding_timeout,values.flooding_interval,values.v4,values.v6))
pr2.daemon = True
pr2.start()
time.sleep(1) #to make sure than sniffer has started before we proceed, otherwise you may miss some traffic
file_print(">>>>>>> Timestamp 10: ", timeNow())
for r in results:
r2=r.split(" ")
service=r2[7].strip('"')
if service.endswith('local.'):
service=service[:-6]
if service.endswith('.'):
service=service[:-1]
if (r2[1],service) not in targets:
targets.append((r2[1],service))
requests(values.interface,values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,values.d4,values.d6,values.hlimit,values.dns,values.domain,service,values.qtype,True,q_class,values.flood,values.flooding_interval,values.flooding_timeout)
if pr2:
try:
pr2.join()
except KeyboardInterrupt:
file_print("Exiting on user's request 3")
while not q2.empty():
results.append(q2.get())
elif values.service_scan:
targets=[]
q2 = multiprocessing.Queue()
file_print(">>>>>>> Timestamp 11: ", timeNow())
pr2 = multiprocessing.Process(target=Sniffer, args=(myfilter, values.interface, float(values.sniffer_timeout),q2,values.dns,values.show_ttl, values.dos_ttl,values.conflict, values.ttl,values.d4, values.d6, values.target_mac, values.auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,values.hlimit,values.workstation,values.printer,values.googlecast,values.airtv,values.flood,values.flooding_timeout,values.flooding_interval,values.v4,values.v6))
pr2.daemon = True
pr2.start()
time.sleep(1) #to make sure than sniffer has started before we proceed, otherwise you may miss some traffic
file_print(">>>>>>> Timestamp 12: ", timeNow())
for r in results:
r2=r.split(" ")
service=r2[7].strip('"')[:-1]
if (r2[1],service) not in targets:
file_print((r2[1],service))
targets.append((r2[1],service))
requests(values.interface,values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,values.d4,values.d6,values.hlimit,values.dns,values.domain,service,values.qtype,True,q_class,values.flood,values.flooding_interval,values.flooding_timeout)
if pr2:
try:
pr2.join()
except KeyboardInterrupt:
file_print("Exiting on user's request 4")
while not q2.empty():
results.append(q2.get())
targets2=[]
q3 = multiprocessing.Queue()
file_print(">>>>>>> Timestamp 13: ", timeNow())
pr3 = multiprocessing.Process(target=Sniffer, args=(myfilter, values.interface, float(values.sniffer_timeout),q3,values.dns,values.show_ttl, values.dos_ttl, values.conflict,values.ttl,values.d4, values.d6, values.target_mac, values.auto_fake_responses,source_IPv6, source_IPv4, target_mac1, target_mac2,source_mac,values.hlimit,values.workstation,values.printer,values.googlecast,values.airtv,values.flood,values.flooding_timeout,values.flooding_interval,values.v4,values.v6))
pr3.daemon = True
pr3.start()
time.sleep(1) #to make sure than sniffer has started before we proceed, otherwise you may miss some traffic
file_print(">>>>>>> Timestamp 14: ", timeNow())
for r in results:
r2=r.split(" ")
service=r2[4]
if service.endswith('local.'):
service=service[:-6]
if service.endswith('.'):
service=service[:-1]
if (r2[1],service) not in targets and (r2[1],service) not in targets2 and "_services._dns-sd._udp" not in service:
targets2.append((r2[1],service))
requests(values.interface,values.v4,values.v6,source_mac,target_mac1,target_mac2,source_IPv4,source_IPv6,values.d4,values.d6,values.hlimit,values.dns,values.domain,service,values.qtype,True,q_class,values.flood,values.flooding_interval,values.flooding_timeout)
if pr3:
try:
pr3.join()
except KeyboardInterrupt:
file_print("Exiting on user's request 5")
while not q3.empty():
results.append(q3.get())
file_print("\n*********************************************RESULTS*********************************************")
for r in results:
file_print(r)
if __name__ == '__main__':
main()