forked from sighook/spoofcheck
/
spoofcheck.py
executable file
·231 lines (156 loc) · 6.81 KB
/
spoofcheck.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#! /usr/bin/env python3
import sys
from colorama import init as color_init
import emailprotectionslib.dmarc as dmarclib
import emailprotectionslib.spf as spflib
import logging
from libs.PrettyOutput import output_good, output_bad, \
output_info, output_error, output_indifferent
logging.basicConfig(level=logging.INFO)
def check_spf_redirect_mechanisms(spf_record):
redirect_domain = spf_record.get_redirect_domain()
if redirect_domain:
output_info(f"Processing an SPF redirect domain: {redirect_domain}")
return is_spf_record_strong(redirect_domain)
else:
return False
def check_spf_include_mechanisms(spf_record):
include_domain_list = spf_record.get_include_domains()
for include_domain in include_domain_list:
output_info(f"Processing an SPF include domain: {include_domain}")
strong_all_string = is_spf_record_strong(include_domain)
if strong_all_string:
return True
return False
def is_spf_redirect_record_strong(spf_record):
output_info(f"Checking SPF redirect domain: {spf_record.get_redirect_domain}")
redirect_strong = spf_record._is_redirect_mechanism_strong()
if redirect_strong:
output_bad("Redirect mechanism is strong.")
else:
output_indifferent("Redirect mechanism is not strong.")
return redirect_strong
def are_spf_include_mechanisms_strong(spf_record):
output_info("Checking SPF include mechanisms")
include_strong = spf_record._are_include_mechanisms_strong()
if include_strong:
output_bad("Include mechanisms include a strong record")
else:
output_indifferent("Include mechanisms are not strong")
return include_strong
def check_spf_include_redirect(spf_record):
other_records_strong = False
if spf_record.get_redirect_domain():
other_records_strong = is_spf_redirect_record_strong(spf_record)
if not other_records_strong:
other_records_strong = are_spf_include_mechanisms_strong(spf_record)
return other_records_strong
def check_spf_all_string(spf_record):
strong_spf_all_string = True
if spf_record.all_string:
if spf_record.all_string == "~all" or spf_record.all_string == "-all":
output_indifferent(f"SPF record contains an All item: {spf_record.all_string}")
else:
output_good(f"SPF record All item is too weak: {spf_record.all_string}")
strong_spf_all_string = False
else:
output_good("SPF record has no All string")
strong_spf_all_string = False
if not strong_spf_all_string:
strong_spf_all_string = check_spf_include_redirect(spf_record)
return strong_spf_all_string
def is_spf_record_strong(domain):
strong_spf_record = True
spf_record = spflib.SpfRecord.from_domain(domain)
if spf_record and spf_record.record:
output_info("Found SPF record:")
output_info(str(spf_record.record))
strong_all_string = check_spf_all_string(spf_record)
if not strong_all_string:
redirect_strength = check_spf_redirect_mechanisms(spf_record)
include_strength = check_spf_include_mechanisms(spf_record)
strong_spf_record = False
if redirect_strength or include_strength:
strong_spf_record = True
else:
output_good(f"{domain} has no SPF record!")
strong_spf_record = False
return strong_spf_record
def get_dmarc_record(domain):
dmarc = dmarclib.DmarcRecord.from_domain(domain)
if dmarc and dmarc.record:
output_info("Found DMARC record:")
output_info(str(dmarc.record))
return dmarc
def get_dmarc_org_record(base_record):
org_record = base_record.get_org_record()
if org_record:
output_info("Found DMARC Organizational record:")
output_info(str(org_record.record))
return org_record
def check_dmarc_extras(dmarc_record):
if dmarc_record.pct and dmarc_record.pct != str(100):
output_indifferent(f"DMARC pct is set to {dmarc_record.pct}% - might be possible")
if dmarc_record.rua:
output_indifferent(f"Aggregate reports will be sent: {dmarc_record.rua}")
if dmarc_record.ruf:
output_indifferent(f"Forensics reports will be sent: {dmarc_record.ruf}")
def check_dmarc_policy(dmarc_record):
policy_strength = False
if dmarc_record.policy:
if dmarc_record.policy == "reject" or dmarc_record.policy == "quarantine":
policy_strength = True
output_bad(f"DMARC policy set to {dmarc_record.policy}")
else:
output_good(f"DMARC policy set to {dmarc_record.policy}")
else:
output_good("DMARC record has no Policy")
return policy_strength
def check_dmarc_org_policy(base_record):
policy_strong = False
try:
org_record = base_record.get_org_record()
if org_record and org_record.record:
output_info("Found organizational DMARC record:")
output_info(str(org_record.record))
if org_record.subdomain_policy:
if org_record.subdomain_policy == "none":
output_good(f"Organizational subdomain policy set to {org_record.subdomain_policy}")
elif org_record.subdomain_policy == "quarantine" or org_record.subdomain_policy == "reject":
output_bad(f"Organizational subdomain policy explicitly set to {org_record.subdomain_policy}")
policy_strong = True
else:
output_info("No explicit organizational subdomain policy. Defaulting to organizational policy...")
policy_strong = check_dmarc_policy(org_record)
else:
output_good("No organizational DMARC record")
except dmarclib.OrgDomainException:
output_good("No organizational DMARC record")
except Exception as e:
logging.exception(e)
return policy_strong
def is_dmarc_record_strong(domain):
dmarc_record_strong = False
dmarc = get_dmarc_record(domain)
if dmarc and dmarc.record:
dmarc_record_strong = check_dmarc_policy(dmarc)
check_dmarc_extras(dmarc)
elif dmarc.get_org_domain():
output_info("No DMARC record found. Looking for organizational record...")
dmarc_record_strong = check_dmarc_org_policy(dmarc)
else:
output_good(f"{domain} has no DMARC record!")
return dmarc_record_strong
if __name__ == "__main__":
color_init()
spoofable = False
try:
domain = sys.argv[1]
spf_record_strong = is_spf_record_strong(domain)
dmarc_record_strong = is_dmarc_record_strong(domain)
if spf_record_strong and dmarc_record_strong:
output_bad(f"Spoofing not possible for {domain}")
else:
output_good(f"Spoofing possible for {domain}!")
except IndexError:
output_error(f"Usage: {sys.argv[0]} [DOMAIN]")