From a048e71197938b4e9600c5f7e7c6adf753404ac7 Mon Sep 17 00:00:00 2001 From: Bobby Richter <403231+secretrobotron@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:51:28 +0100 Subject: [PATCH] Company name and cert event fixes 1. Moved common SSL event functions to common_ssl_cert.py 2. Change sfp_crt and sfp_sslcert accordingly. 3. Allowed sfp_company to grab the O= portion of cert subject as full name (not limited to 3 words) fixes #1749 --- modules/common_ssl_cert.py | 47 ++++++++++++++++++++++++++++++++++++++ modules/sfp_company.py | 40 ++++++++++++++++++++------------ modules/sfp_crt.py | 40 ++------------------------------ modules/sfp_sslcert.py | 44 +++-------------------------------- 4 files changed, 77 insertions(+), 94 deletions(-) create mode 100644 modules/common_ssl_cert.py diff --git a/modules/common_ssl_cert.py b/modules/common_ssl_cert.py new file mode 100644 index 0000000000..b446eec778 --- /dev/null +++ b/modules/common_ssl_cert.py @@ -0,0 +1,47 @@ +from spiderfoot import SpiderFootEvent + +def process_ssl_cert_events(spiderfoot_plugin, cert, root_event): + eventName = root_event.eventType + + if cert.get('issued'): + new_event = SpiderFootEvent('SSL_CERTIFICATE_ISSUED', cert['issued'], spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + + if cert.get('issuer'): + new_event = SpiderFootEvent('SSL_CERTIFICATE_ISSUER', cert['issuer'], spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + + if eventName != "IP_ADDRESS" and cert.get('mismatch'): + new_event = SpiderFootEvent('SSL_CERTIFICATE_MISMATCH', ', '.join(cert.get('hosts')), spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + + for san in set(cert.get('altnames', list())): + domain = san.replace("*.", "") + + if spiderfoot_plugin.getTarget().matches(domain, includeChildren=True): + new_event_type = 'INTERNET_NAME' + if spiderfoot_plugin.opts['verify'] and not spiderfoot_plugin.sf.resolveHost(domain) and not spiderfoot_plugin.sf.resolveHost6(domain): + spiderfoot_plugin.debug(f"Host {domain} could not be resolved") + new_event_type += '_UNRESOLVED' + else: + new_event_type = 'CO_HOSTED_SITE' + + new_event = SpiderFootEvent(new_event_type, domain, spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + + if spiderfoot_plugin.sf.isDomain(domain, spiderfoot_plugin.opts['_internettlds']): + if new_event_type == 'CO_HOSTED_SITE': + new_event = SpiderFootEvent('CO_HOSTED_SITE_DOMAIN', domain, spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + else: + new_event = SpiderFootEvent('DOMAIN_NAME', domain, spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + + if cert.get('expired'): + new_event = SpiderFootEvent("SSL_CERTIFICATE_EXPIRED", cert.get('expirystr', 'Unknown'), spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) + return + + if cert.get('expiring'): + new_event = SpiderFootEvent("SSL_CERTIFICATE_EXPIRING", cert.get('expirystr', 'Unknown'), spiderfoot_plugin.__name__, root_event) + spiderfoot_plugin.notifyListeners(new_event) \ No newline at end of file diff --git a/modules/sfp_company.py b/modules/sfp_company.py index 9db067d46a..43b221c9e5 100644 --- a/modules/sfp_company.py +++ b/modules/sfp_company.py @@ -15,7 +15,6 @@ from spiderfoot import SpiderFootEvent, SpiderFootPlugin - class sfp_company(SpiderFootPlugin): meta = { @@ -56,6 +55,8 @@ def handleEvent(self, event): srcModuleName = event.module eventData = event.data + found_company_names = list() + # Various ways to identify companies in text # Support up to three word company names with each starting with # a capital letter, allowing for hyphens brackets and numbers within. @@ -95,8 +96,17 @@ def handleEvent(self, event): try: if eventName == "SSL_CERTIFICATE_ISSUED": eventData = eventData.split("O=")[1] - except Exception: + + # Try to get O= as easy company name + o_match = re.search(r"(.+)[,]", eventData) + + if o_match: + company_name = o_match.groups()[0] + found_company_names.append(company_name) + eventData = eventData[len(company_name):] + except Exception as e: self.debug("Couldn't strip out 'O=' from certificate issuer, proceeding anyway...") + self.debug(e) # Find chunks of text containing what might be a company name first. # This is to avoid running very expensive regexps on large chunks of @@ -116,7 +126,6 @@ def handleEvent(self, event): offset = m + len(pat) m = eventData.find(pat, offset) - myres = list() for chunk in chunks: for pat in pattern_match_re: matches = re.findall(pattern_prefix + "(" + pat + ")" + pattern_suffix, chunk, re.MULTILINE | re.DOTALL) @@ -141,22 +150,23 @@ def handleEvent(self, event): self.info("Found company name: " + fullcompany) - if fullcompany in myres: + if fullcompany in found_company_names: self.debug("Already found from this source.") continue - myres.append(fullcompany) + found_company_names.append(fullcompany) - if "AFFILIATE_" in eventName: - etype = "AFFILIATE_COMPANY_NAME" - else: - etype = "COMPANY_NAME" + if "AFFILIATE_" in eventName: + etype = "AFFILIATE_COMPANY_NAME" + else: + etype = "COMPANY_NAME" - evt = SpiderFootEvent(etype, fullcompany, self.__name__, event) - if event.moduleDataSource: - evt.moduleDataSource = event.moduleDataSource - else: - evt.moduleDataSource = "Unknown" - self.notifyListeners(evt) + for company_name in found_company_names: + evt = SpiderFootEvent(etype, company_name, self.__name__, event) + if event.moduleDataSource: + evt.moduleDataSource = event.moduleDataSource + else: + evt.moduleDataSource = "Unknown" + self.notifyListeners(evt) # End of sfp_company class diff --git a/modules/sfp_crt.py b/modules/sfp_crt.py index 92f3be8284..f88fbf607b 100644 --- a/modules/sfp_crt.py +++ b/modules/sfp_crt.py @@ -17,6 +17,7 @@ from spiderfoot import SpiderFootEvent, SpiderFootPlugin +from modules.common_ssl_cert import process_ssl_cert_events class sfp_crt(SpiderFootPlugin): @@ -216,43 +217,6 @@ def handleEvent(self, event): evt = SpiderFootEvent("SSL_CERTIFICATE_RAW", str(cert_text), self.__name__, event) self.notifyListeners(evt) - sans = cert.get('altnames', list()) - - if not sans: - continue - - for san in sans: - if san.lower() == event.data.lower(): - continue - domains.append(san.lower().replace("*.", "")) - - if self.opts['verify'] and len(domains) > 0: - self.info(f"Resolving {len(set(domains))} domains ...") - - for domain in set(domains): - if domain in self.results: - continue - - if not self.sf.validHost(domain, self.opts['_internettlds']): - continue - - if self.getTarget().matches(domain, includeChildren=True, includeParents=True): - evt_type = 'INTERNET_NAME' - if self.opts['verify'] and not self.sf.resolveHost(domain) and not self.sf.resolveHost6(domain): - self.debug(f"Host {domain} could not be resolved") - evt_type += '_UNRESOLVED' - else: - evt_type = 'CO_HOSTED_SITE' - - evt = SpiderFootEvent(evt_type, domain, self.__name__, event) - self.notifyListeners(evt) - - if self.sf.isDomain(domain, self.opts['_internettlds']): - if evt_type == 'CO_HOSTED_SITE': - evt = SpiderFootEvent('CO_HOSTED_SITE_DOMAIN', domain, self.__name__, event) - self.notifyListeners(evt) - else: - evt = SpiderFootEvent('DOMAIN_NAME', domain, self.__name__, event) - self.notifyListeners(evt) + process_ssl_cert_events(self, cert, event) # End of sfp_crt class diff --git a/modules/sfp_sslcert.py b/modules/sfp_sslcert.py index dcc06ccb7b..78a1d34ca4 100644 --- a/modules/sfp_sslcert.py +++ b/modules/sfp_sslcert.py @@ -14,6 +14,7 @@ from spiderfoot import SpiderFootEvent, SpiderFootPlugin +from modules.common_ssl_cert import process_ssl_cert_events class sfp_sslcert(SpiderFootPlugin): @@ -128,47 +129,8 @@ def handleEvent(self, event): rawevt = SpiderFootEvent("SSL_CERTIFICATE_RAW", cert['text'], self.__name__, event) self.notifyListeners(rawevt) - if cert.get('issued'): - evt = SpiderFootEvent('SSL_CERTIFICATE_ISSUED', cert['issued'], self.__name__, event) - self.notifyListeners(evt) - - if cert.get('issuer'): - evt = SpiderFootEvent('SSL_CERTIFICATE_ISSUER', cert['issuer'], self.__name__, event) - self.notifyListeners(evt) - - if eventName != "IP_ADDRESS" and cert.get('mismatch'): - evt = SpiderFootEvent('SSL_CERTIFICATE_MISMATCH', ', '.join(cert.get('hosts')), self.__name__, event) - self.notifyListeners(evt) - - for san in set(cert.get('altnames', list())): - domain = san.replace("*.", "") - - if self.getTarget().matches(domain, includeChildren=True): - evt_type = 'INTERNET_NAME' - if self.opts['verify'] and not self.sf.resolveHost(domain) and not self.sf.resolveHost6(domain): - self.debug(f"Host {domain} could not be resolved") - evt_type += '_UNRESOLVED' - else: - evt_type = 'CO_HOSTED_SITE' + process_ssl_cert_events(self, cert, event) - evt = SpiderFootEvent(evt_type, domain, self.__name__, event) - self.notifyListeners(evt) - - if self.sf.isDomain(domain, self.opts['_internettlds']): - if evt_type == 'CO_HOSTED_SITE': - evt = SpiderFootEvent('CO_HOSTED_SITE_DOMAIN', domain, self.__name__, event) - self.notifyListeners(evt) - else: - evt = SpiderFootEvent('DOMAIN_NAME', domain, self.__name__, event) - self.notifyListeners(evt) - - if cert.get('expired'): - evt = SpiderFootEvent("SSL_CERTIFICATE_EXPIRED", cert.get('expirystr', 'Unknown'), self.__name__, event) - self.notifyListeners(evt) - return - - if cert.get('expiring'): - evt = SpiderFootEvent("SSL_CERTIFICATE_EXPIRING", cert.get('expirystr', 'Unknown'), self.__name__, event) - self.notifyListeners(evt) + # End of sfp_sslcert class