From fe4672907c326ee314fbea34985457515ba9dd72 Mon Sep 17 00:00:00 2001
From: TISSERAND Pacome
Date: Mon, 4 Sep 2023 11:41:15 +0200
Subject: [PATCH] adding BIMI record retrival
---
libs/bimi.py | 18 ++++++++++++++++++
libs/dns.py | 12 +++++++-----
libs/logic.py | 0
libs/report.py | 5 ++++-
spoofy.py | 9 +++++----
test.py | 0
6 files changed, 34 insertions(+), 10 deletions(-)
create mode 100755 libs/bimi.py
mode change 100644 => 100755 libs/dns.py
mode change 100644 => 100755 libs/logic.py
mode change 100644 => 100755 libs/report.py
mode change 100644 => 100755 spoofy.py
mode change 100644 => 100755 test.py
diff --git a/libs/bimi.py b/libs/bimi.py
new file mode 100755
index 0000000..3b1b66f
--- /dev/null
+++ b/libs/bimi.py
@@ -0,0 +1,18 @@
+import dns.resolver
+
+
+def get_bimi_record(domain, dns_server):
+ """Returns the BIMI record for a given domain."""
+ try:
+ resolver = dns.resolver.Resolver()
+ resolver.nameservers = [dns_server, '1.1.1.1', '8.8.8.8']
+ query_result = resolver.resolve('default._bimi.' + domain, 'TXT')
+ for record in query_result:
+ if 'v=BIMI' in str(record):
+ return record
+ return None
+ except:
+ return None
+
+
+
diff --git a/libs/dns.py b/libs/dns.py
old mode 100644
new mode 100755
index 5e13f94..0fe823f
--- a/libs/dns.py
+++ b/libs/dns.py
@@ -1,6 +1,6 @@
import dns.resolver
import socket
-from . import spf, dmarc
+from . import spf, dmarc, bimi
def get_soa_record(domain):
@@ -24,25 +24,27 @@ def get_soa_record(domain):
def get_dns_server(domain):
"""Finds the DNS server that serves the domain and returns it, along with any SPF or DMARC records."""
SOA = get_soa_record(domain)
- spf_record = dmarc_record = partial_spf_record = partial_dmarc_record = None
+ spf_record = dmarc_record = partial_spf_record = partial_dmarc_record = bimi_record = None
if SOA:
spf_record = spf.get_spf_record(domain, SOA)
dmarc_record = dmarc.get_dmarc_record(domain, SOA)
+ bimi_record = bimi.get_bimi_record(domain, SOA)
if spf_record and dmarc_record:
- return SOA, spf_record, dmarc_record
+ return SOA, spf_record, dmarc_record, bimi_record
for ip_address in ['1.1.1.1', '8.8.8.8', '9.9.9.9']:
spf_record = spf.get_spf_record(domain, ip_address)
dmarc_record = dmarc.get_dmarc_record(domain, ip_address)
+ bimi_record = bimi.get_bimi_record(domain, SOA)
if spf_record and dmarc_record:
- return ip_address, spf_record, dmarc_record
+ return ip_address, spf_record, dmarc_record, bimi_record
if spf_record:
partial_spf_record = spf_record
if dmarc_record:
partial_dmarc_record = dmarc_record
- return '1.1.1.1', partial_spf_record, partial_dmarc_record
+ return '1.1.1.1', partial_spf_record, partial_dmarc_record, bimi_record
def get_txt_record(domain, record_type):
diff --git a/libs/logic.py b/libs/logic.py
old mode 100644
new mode 100755
diff --git a/libs/report.py b/libs/report.py
old mode 100644
new mode 100755
index b73a091..8c56c74
--- a/libs/report.py
+++ b/libs/report.py
@@ -48,7 +48,7 @@ def write_to_excel(data):
df.to_excel(file_name, index=False)
-def printer(domain, subdomain, dns_server, spf_record, spf_all, spf_includes, dmarc_record, p, pct, aspf, sp, fo, rua, spoofable):
+def printer(domain, subdomain, dns_server, spf_record, spf_all, spf_includes, dmarc_record, p, pct, aspf, sp, fo, rua, bimi_record, spoofable):
"""This function is a utility function that takes in various parameters related to the
results of DMARC and SPF checks and outputs the results to the console in a human-readable format.
@@ -96,6 +96,9 @@ def printer(domain, subdomain, dns_server, spf_record, spf_all, spf_includes, dm
f"Aggregate reports will be sent to: {rua}" if rua else "No DMARC aggregate report location found.")
else:
output_warning("No DMARC record found.")
+
+ if(bimi_record):
+ output_info(f"BIMI record : {bimi_record}")
if spoofable in [0, 1, 2, 3, 4, 5, 6, 7, 8]:
if spoofable == 8:
diff --git a/spoofy.py b/spoofy.py
old mode 100644
new mode 100755
index 0bbd33d..7f4206d
--- a/spoofy.py
+++ b/spoofy.py
@@ -17,7 +17,7 @@ def process_domain(domain, output):
spf_all = spf_includes = p = pct = aspf = sp = fo = rua = None
subdomain = bool(tldextract.extract(domain).subdomain)
with print_lock:
- dns_server, spf_record, dmarc_record = dns.get_dns_server(domain)
+ dns_server, spf_record, dmarc_record, bimi_record = dns.get_dns_server(domain)
if spf_record:
spf_all = spf.get_spf_all_string(spf_record)
spf_includes = spf.get_spf_includes(domain)
@@ -30,13 +30,14 @@ def process_domain(domain, output):
data = [{'DOMAIN': domain, 'SUBDOMAIN': subdomain, 'SPF': spf_record, 'SPF MULTIPLE ALLS': spf_all,
'SPF TOO MANY INCLUDES': spf_includes, 'DMARC': dmarc_record, 'DMARC POLICY': p,
'DMARC PCT': pct, 'DMARC ASPF': aspf, 'DMARC SP': sp, 'DMARC FORENSIC REPORT': fo,
- 'DMARC AGGREGATE REPORT': rua, 'SPOOFING POSSIBLE': spoofable}]
+ 'DMARC AGGREGATE REPORT': rua, 'BIMI_RECORD': bimi_record, 'SPOOFING POSSIBLE': spoofable}]
report.write_to_excel(data)
else:
with print_lock:
report.printer(domain, subdomain, dns_server, spf_record, spf_all, spf_includes, dmarc_record, p, pct, aspf,
- sp, fo, rua, spoofable)
- except:
+ sp, fo, rua, bimi_record, spoofable)
+ except Exception as e:
+ raise e
with print_lock:
report.output_error(
f"Domain {domain} is offline or format cannot be interpreted.")
diff --git a/test.py b/test.py
old mode 100644
new mode 100755