-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathspf-ip.py
55 lines (52 loc) · 2.57 KB
/
spf-ip.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
from recon.core.module import BaseModule
from recon.mixins.resolver import ResolverMixin
import dns.resolver
class Module(BaseModule, ResolverMixin):
meta = {
'name': 'Sender Policy Framework (SPF) Record Retriever',
'author': 'Jim Becher (@jimbecher, [email protected])',
'description': 'Retrieves the SPF IPv4 records for a domain. Updates the \'hosts\' and/or \'netblocks\' tables with the results.',
'comments': (
'This module reads domains from the domains table and retrieves the IP addresses and/or netblocks',
'of the SPF records associated with each domain. The addresses are then stored in the hosts',
'and/or netblocks table.'
),
'query': 'SELECT DISTINCT domain FROM domains WHERE domain IS NOT NULL',
}
def module_run(self, domains):
max_attempts = 3
resolver = self.get_resolver()
answers = ""
for domain in domains:
attempt = 0
while attempt < max_attempts:
try:
answers = resolver.query(domain, 'TXT')
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
self.verbose('%s => No record found.' % (domain))
except dns.resolver.Timeout:
self.verbose('%s => Request timed out.' % (domain))
attempt += 1
continue
except (dns.resolver.NoNameservers):
self.verbose('%s => Invalid nameserver.' % (domain))
else:
for txtrecord in answers:
if "v=spf" in txtrecord.to_text():
resp = txtrecord.to_text()
words = resp.split()
for item in words:
if "ip4" in item:
ipaddr = item.split(':', 1)[1]
if "/" in ipaddr:
self.output(ipaddr)
self.add_netblocks(ipaddr)
else:
self.output(ipaddr)
self.add_hosts(ip_address=ipaddr)
elif "a:" in item:
spfhost = item.split(':', 1)[1]
self.output(spfhost)
self.add_hosts(host=spfhost)
# break out of the loop
attempt = max_attempts