From 1e36568e44034ac3753eeb1b5229bdd1148babcd Mon Sep 17 00:00:00 2001 From: geoffrey Date: Fri, 21 Jun 2024 17:13:51 +0200 Subject: [PATCH] Analyse hash and dns --- config.py | 1 - dnsinformations.py | 40 +++++---- hashing.py | 38 +++++++++ main.py | 202 ++++++++++++++++++++++++++++++++++++++------- vt.py | 76 +++++++++++++++-- 5 files changed, 298 insertions(+), 59 deletions(-) create mode 100644 hashing.py diff --git a/config.py b/config.py index 80b9c95..77679ff 100644 --- a/config.py +++ b/config.py @@ -12,7 +12,6 @@ VT_ATTRIBUTES_MAPPING = { 'ip': 'str' } -#DNS_QUERIES_TYPE = ('A', 'MX', 'TXT') DNS_QUERIES_TYPE = { 'A': 'address', 'MX': ['exchange', 'preference'], diff --git a/dnsinformations.py b/dnsinformations.py index 77a59e5..6921415 100644 --- a/dnsinformations.py +++ b/dnsinformations.py @@ -20,37 +20,35 @@ class DNSInformations: report['updated_date'] = w.updated_date report['ns'] = w.name_servers report['admin_name'] = w.admin_name + report['registrar'] = w.registrar return report def resolver(self): report = dict() - n = dns.name.from_text(self._fqdn) - s = self._fqdn.split(".") - l = len(s) - fqdn = f"{s[l - 2]}.{s[l - 1]}" - print(fqdn) - o = dns.name.from_text(fqdn) - if n.relativize(o): - print(True) - - for t in DNS_QUERIES_TYPE.keys(): report[t] = self._resolving(self._fqdn, t, DNS_QUERIES_TYPE[t]) return report def _resolving(self, fqdn, t, attr): report = list() - res_query = dns.resolver.resolve(fqdn, t) - for rdata in res_query: - if isinstance(attr, list): - data = dict() - for a in attr: - data[a] = getattr(rdata, a) - report.append(data) - else: - report.append({ - attr: getattr(rdata, attr) - }) + try: + res_query = dns.resolver.resolve(fqdn, t) + for rdata in res_query: + if isinstance(attr, list): + data = dict() + for a in attr: + data[a] = getattr(rdata, a) + report.append(data) + else: + report.append({ + attr: getattr(rdata, attr) + }) + except dns.resolver.NoAnswer: + pass + except dns.resolver.NXDOMAIN: + report.append({'error': 'Domain not exist'}) + except dns.resolver.NoNameservers: + report.append({'error': 'Domain not exist'}) return report diff --git a/hashing.py b/hashing.py new file mode 100644 index 0000000..efa5063 --- /dev/null +++ b/hashing.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import hashlib + + +class Hash: + def __init__(self): + pass + + def hashMd5(self, f): + md5 = hashlib.md5() + with open(f, "rb") as data: + md5.update(data.read()) + return md5.hexdigest() + + def hashSha1(self, f): + sha1 = hashlib.sha1() + with open(f, "rb") as data: + sha1.update(data.read()) + return sha1.hexdigest() + + def hashSha256(self, f): + sha256 = hashlib.sha256() + with open(f, "rb") as data: + sha256.update(data.read()) + return sha256.hexdigest() + + def hashSha384(self, f): + sha384 = hashlib.sha384() + with open(f, "rb") as data: + sha384.update(data.read()) + return sha384.hexdigest() + + def hashSha512(self, f): + sha512 = hashlib.sha512() + with open(f, "rb") as data: + sha512.update(data.read()) + return sha512.hexdigest() diff --git a/main.py b/main.py index d1697b8..3dc046b 100644 --- a/main.py +++ b/main.py @@ -2,19 +2,33 @@ # -*- coding: utf-8 -*- from argparse import ArgumentParser -import requests -import re from config import VT_ATTRIBUTES_MAPPING from vt import VT from dnsinformations import DNSInformations as DNS +import ipaddress +from datetime import datetime +from hashing import Hash +from os.path import exists def checkArguments(): parser = ArgumentParser(description="baoSOC") parser.add_argument('-c', '--config', help='Config file') - parser.add_argument('--hash', help='Hash file', action='store_true') - parser.add_argument('--dns', help='Get domain name information') + parser.add_argument('--dns', help='Get domain name information', action="store_true") + # For dns command parser.add_argument('--dnsattacks', help='Parse DNS pcap file') + parser.add_argument('--domain', help='Get domain name information') + parser.add_argument('--host', help='Get domain name information') + parser.add_argument('--ip', help='Get IP information') + # For hash command + parser.add_argument('--hash', help='Hash file', action='store_true') + parser.add_argument('--scanvt', help='If specified, scan the hash with VirusTotal', action='store_true') + parser.add_argument('--md5', help='Hash file') + parser.add_argument('--sha1', help='Hash file') + parser.add_argument('--sha256', help='Hash file') + parser.add_argument('--sha384', help='Hash file') + parser.add_argument('--sha512', help='Hash file') + return parser.parse_args() def usage(): @@ -25,8 +39,20 @@ def usage(): print("Usage: main.py [COMMAND]") print("-c PATH, --config PATH\t\tConfig file - mandatory") print("--hash FILE\t\t\tHash the file and check in VirusTotal") - print("--dns FQDN\t\t\tGet information regarding the domain with whois and VirusTotal") - print("--dnsattacks FILE\t\t\tParse the DNS pcap file and identify some DNS attacks") + print("--dns \t\t\t\tGet information regarding the domain with whois and VirusTotal") + print("--dnsattacks FILE\t\tParse the DNS pcap file and identify some DNS attacks") + + print("\n--dns command:") + print("\t --domain FQDN\t\tScan and get domain information") + print("\t --host HOST\t\tScan and get host information") + print("\t --ip IP\t\tScan and get IP information") + + print("\n--hash command:") + print("\t --md5 FILE\t\tGet the MD5 hash of the file") + print("\t --sha1 FILE\t\tGet the SHA256 of the file") + print("\t --sha256 FILE\t\tGet the SHA256 of the file") + print("\t --sha384 FILE\t\tGet the SHA384 of the file") + print("\t --sha512 FILE\t\tGet the SHA512 of the file") def mainMenu(): print("\n baoSOC ") @@ -74,35 +100,151 @@ def main(): print("Failed to read the config file") exit(0) - #vt = VT(config['api_key']) - #report = list() - #print(vt.getIPVirusTotal("1.1.1.1", report)) + report = dict() + # Analyse DNS if args.dns: - dns = DNS(config['api_key'], args.dns) + if args.domain: + _parsingDomain(config, args.domain, report) + if args.host: + pass + if args.ip: + _parsingIP(config, args.ip, report) + # Analyse hash + if args.hash: + h = Hash() + dispatcher = { + "MD5": h.hashMd5, + "SHA1": h.hashSha1, + "SHA256": h.hashSha256, + "SHA384": h.hashSha384, + "SHA512": h.hashSha512, + } + if args.md5: + hashType = "MD5" + filename = args.md5 + if args.sha1: + hashType = "SHA1" + filename = args.sha1 + if args.sha256: + hashType = "SHA256" + filename = args.sha256 + if args.sha384: + hashType = "SHA384" + filename = args.sha384 + if args.sha512: + hashType = "SHA512" + filename = args.sha512 + + if not exists(filename): + print(f"File {filename} do not exist") + else: + res = dispatcher[hashType](filename) + print(f"{hashType} hash: {res}") - print("IP Informations:\n") - report = dns.resolver() - for key in report.keys(): - print(f"{key}: ") - for entry in report[key]: - for subkey in entry.keys(): - value = entry[subkey] - if isinstance(value, bytes): - value = value.decode() - print(f"\t{subkey}: {value}") + res = "6548eec09f4d8bc6514bee3e5452541c" + if args.scanvt: + _parsingHash(config, res, report) - print("\nReport with Whois:\n") - report = dns.whois() - for key in report.keys(): - if isinstance(report[key], list): - print(f"{key}:") - for value in report[key]: - print(f"\t{value}") - else: - print(f"{key}: {report[key]}") +def _parsingHash(config, h, report): + report = dict() + vt = VT(config['api_key']) + + vt.getRateFromHash(h, report) + print("\n----------------------") + print("| VirusTotal |") + print("----------------------") + + if 'error' in report: + print("Error, can not find any informations") + return + + # File + print("\nFile information:") + f = report['results']['file'] + print(f"\tMD5: {f['md5']}") + print(f"\tSHA1: {f['sha1']}") + print(f"\tMagic: {f['magic']}") + print(f"\tFile type: {f['filetype']}") + print(f"\tSize: {f['size']}") + print(f"\tExtension: {f['extension']}") + print(f"\tFirst seen: {f['first_seen']}") + print(f"\tLast analysis: {f['last_analysis']}") + + # Vendors + vendors = report['results']['vendors'] + print("\nVendors:") + print(f"\tTotal vendors: {vendors['total_vendors']}") + print(f"\tCategorized as malicious: {vendors['total_malicious']}\n") + for key in vendors['result']: + print(f"\t{key}: {vendors['result'][key]}") + +def _parsingIP(config, ip, report): + # Check if it's an IP address + vt = VT(config['api_key']) + try: + ip_obj = ipaddress.ip_address(ip) + except ValueError: + print("The IP is not valid") + return + + report['ip'] = dict() + report['ip'] = vt.getIPVirusTotal(ip) + + if 'error' not in report['ip']: + print("----------------------------") + print("| IP Informations |") + print("----------------------------") + for vt in VT_ATTRIBUTES_MAPPING.keys(): + try: + vtAttributes = VT_ATTRIBUTES_MAPPING[vt] + if 'date' in vtAttributes: + value = datetime.fromtimestamp(int(report['ip'][vt])) + else: + value = report['ip'][vt] + print(f"{vt}: {value}") + except KeyError: + print(f"Cannot find the key {vt}") + +def _parsingDomain(config, fqdn, report): + vt = VT(config['api_key']) + dns = DNS(config['api_key'], fqdn) + + print("----------------------") + print("| resolving |") + print("----------------------") + report['resolving'] = dns.resolver() + for key in report['resolving'].keys(): + print(f"{key}: ") + for entry in report['resolving'][key]: + for subkey in entry.keys(): + value = entry[subkey] + if isinstance(value, bytes): + value = value.decode() + print(f"\t{subkey}: {value}") + + print("\n----------------------") + print("| whois |") + print("----------------------") + report['whois'] = dns.whois() + report_whois = report['whois'] + for key in report_whois.keys(): + if isinstance(report_whois[key], list): + print(f"{key}:") + for value in report_whois[key]: + print(f"\t{value}") + else: + print(f"{key}: {report_whois[key]}") + + print("\n----------------------") + print("| VirusTotal |") + print("----------------------") + report['vt'] = dict() + vt.getDomainReport(fqdn, report['vt']) + report_vt = report['vt'] + for key in report_vt: + print(f"{key}: {report_vt[key]}") - print("\nReport with VirusTotal:\n") if __name__ == "__main__": main() diff --git a/vt.py b/vt.py index 76b44e1..6514461 100644 --- a/vt.py +++ b/vt.py @@ -1,16 +1,18 @@ #!/ur/bin/env python3 import requests +from config import VT_ATTRIBUTES_MAPPING +from datetime import datetime class VT: def __init__(self, api_key): self._url = "https://www.virustotal.com/api/v3" self._headers = { - 'x-apki-key': api_key, + 'x-apikey': api_key, } - def getIPVirusTotal(self, ip, report): + def getIPVirusTotal(self, ip): res = requests.get( f"{self._url}/ip_addresses/{ip}", headers=self._headers @@ -33,16 +35,76 @@ class VT: data[entry] = vt[entry] except KeyError: data[entry] = 'Unknown' + return data - report.append(data) + def getDomainReport(self, fqdn, report): + res = requests.get( + f"{self._url}/domains/{fqdn}", + headers=self._headers + ) + + js = res.json() + report['reputation'] = js['data']['attributes']['reputation'] + report['last_update'] = \ + datetime.fromtimestamp(js['data']['attributes']['last_update_date']) + + # Get number of security vendors + report['total_vendors'] = 0 + report['clean'] = 0 + report['unrated'] = 0 + report['malicious'] = 0 + vendors = js['data']['attributes']['last_analysis_results'] + + for entry in vendors: + report['total_vendors'] += 1 + if vendors[entry]['result'] == 'clean': + report['clean'] += 1 + elif vendors[entry]['result'] == 'unrated': + report['unrated'] += 1 + elif vendors[entry]['result'] == 'malicious': + report['malicious'] += 1 def getRateFromHash(self, h, report): headers = self._headers - headers['resource'] = h res = requests.get( - f"{self._url}/file/report", - headers=headers + f"{self._url}/files/{h}", + headers=self._headers ).json() - data = dict() + if 'error' in res: + report["error"] = "Can not find the result" + return + + attributes = res['data']['attributes'] + report['results'] = dict() + report['results']['file'] = dict() + report['results']['file']['magic'] = attributes['magic'] + report['results']['file']['sha1'] = attributes['sha1'] + report['results']['file']['md5'] = attributes['md5'] + report['results']['file']['filetype'] = attributes['detectiteasy']['filetype'] + report['results']['file']['size'] = attributes['size'] + report['results']['file']['extension'] = attributes['type_extension'] + report['results']['file']['first_seen'] = \ + datetime.fromtimestamp(attributes['first_seen_itw_date']) + report['results']['file']['last_analysis'] = \ + datetime.fromtimestamp(attributes['last_analysis_date']) + + # Identify vendors + report['results']['vendors'] = dict() + report['results']['vendors']['total_vendors'] = 0 + report['results']['vendors']['total_malicious'] = 0 + report['results']['vendors']['result'] = dict() + report['results']['vendors']['result']['undetected'] = 0 + results = res['data']['attributes']['last_analysis_results'] + for entry in results: + report['results']['vendors']['total_vendors'] += 1 + if results[entry]['category'] == 'undetected': + report['results']['vendors']['result']['undetected'] += 1 + else: + result = results[entry]['result'] + if result not in report['results']['vendors']['result']: + report['results']['vendors']['result'][result] = 0 + report['results']['vendors']['result'][result] += 1 + report['results']['vendors']['total_malicious'] += 1 +