diff --git a/bin/contentctl_project/contentctl_core/application/factory/ba_factory.py b/bin/contentctl_project/contentctl_core/application/factory/ba_factory.py index 1f8077d3e7..393c3e29c8 100644 --- a/bin/contentctl_project/contentctl_core/application/factory/ba_factory.py +++ b/bin/contentctl_project/contentctl_core/application/factory/ba_factory.py @@ -1,12 +1,17 @@ import os import sys +from webbrowser import get + + from pydantic import ValidationError +from pydantic.error_wrappers import ErrorWrapper from dataclasses import dataclass -from typing import Tuple +from typing import Sequence, Tuple import pathlib from bin.contentctl_project.contentctl_core.domain.entities.enums.enums import SecurityContentType +from bin.contentctl_project.contentctl_core.domain.entities.detection_tags import DetectionTags from bin.contentctl_project.contentctl_core.application.builder.basic_builder import BasicBuilder from bin.contentctl_project.contentctl_core.application.builder.detection_builder import DetectionBuilder from bin.contentctl_project.contentctl_core.application.builder.story_builder import StoryBuilder @@ -43,13 +48,13 @@ class BAFactory(): if len(validation_errors) != 0: - print(f"There were [{len(validation_errors)}] error(s) found while parsing security_content") - for ve in validation_errors: - file_path = ve[0] - error = ve[1] - print(f'\nValidation Error for file [{file_path}]:\n{str(error)}') - raise(Exception("Error(s) validating Security Content")) - + print(f"There were [{len(validation_errors)}] error(s) found while parsing security_content") + for ve in validation_errors: + file_path = ve[0] + error = ve[1] + print(f'\nValidation Error for file [{file_path}]:\n{str(error)}') + #raise(Exception("Error(s) validating Security Content")) + @@ -82,6 +87,22 @@ class BAFactory(): self.input_dto.director.constructDetection(self.input_dto.detection_builder, file, [], [], [], self.output_dto.tests, {}, [], []) detection = self.input_dto.detection_builder.getObject() Utils.add_id(self.ids, detection, file) + + tag_and_nist_errors = [] + + if detection.tags.cis20 == None: + error = TypeError(f"Detection Tags missing cis20 field") + tag_and_nist_errors.append(ErrorWrapper(error, loc="cis20")) + + if detection.tags.nist == None: + error = TypeError(f"Detection Tags missing nist field") + tag_and_nist_errors.append(ErrorWrapper(error, loc="nist")) + + if len(tag_and_nist_errors) > 0: + raise ValidationError( tag_and_nist_errors , DetectionTags) + + + if not detection.deprecated and not detection.experimental: self.output_dto.detections.append(detection) elif type == SecurityContentType.unit_tests: diff --git a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py index 89a5ad5e02..125ff45910 100644 --- a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py +++ b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py @@ -43,10 +43,26 @@ class DetectionTags(BaseModel): @validator('cis20') def tags_cis20(cls, v, values): - pattern = 'CIS [0-9]{1,2}' + pattern = '^CIS ([0-9]|1[0-9]|20)$' #DO NOT match leading zeroes and ensure no extra characters before or after the string for value in v: if not re.match(pattern, value): - raise ValueError('CIS controls are not following the pattern CIS xx: ' + values["name"]) + raise ValueError(f"CIS control '{value}' is not a valid Control ('CIS 1' -> 'CIS 20'): {values['name']}") + return v + + @validator('nist') + def tags_nist(cls, v, values): + # Sourced Courtest of NIST: https://www.nist.gov/system/files/documents/cyberframework/cybersecurity-framework-021214.pdf (Page 19) + IDENTIFY = [f'ID.{category}' for category in ["AM", "BE", "GV", "RA", "RM"] ] + PROTECT = [f'PR.{category}' for category in ["AC", "AT", "DS", "IP", "MA", "PT"]] + DETECT = [f'DE.{category}' for category in ["AE", "CM", "DP"] ] + RESPOND = [f'RS.{category}' for category in ["RP", "CO", "AN", "MI", "IM"] ] + RECOVER = [f'RC.{category}' for category in ["RP", "IM", "CO"] ] + ALL_NIST_CATEGORIES = IDENTIFY + PROTECT + DETECT + RESPOND + RECOVER + + + for value in v: + if not value in ALL_NIST_CATEGORIES: + raise ValueError(f"NIST Category '{value}' is not a valid category") return v @validator('confidence') diff --git a/detections/experimental/endpoint/ssa___disable_defender_antivirus_registry.yml b/detections/experimental/endpoint/ssa___disable_defender_antivirus_registry.yml index cdf5bb40e0..e095104073 100644 --- a/detections/experimental/endpoint/ssa___disable_defender_antivirus_registry.yml +++ b/detections/experimental/endpoint/ssa___disable_defender_antivirus_registry.yml @@ -34,6 +34,7 @@ tags: analytic_story: - IcedID automated_detection_testing: passed + cis20: [] confidence: 70 context: - Source:Endpoint @@ -47,6 +48,7 @@ tags: mitre_attack_id: - T1562.001 - T1562 + nist: [] observable: - name: dest type: Hostname diff --git a/detections/experimental/endpoint/ssa___excessive_number_of_office_files_copied.yml b/detections/experimental/endpoint/ssa___excessive_number_of_office_files_copied.yml index a6889f6abe..dc4e181c39 100644 --- a/detections/experimental/endpoint/ssa___excessive_number_of_office_files_copied.yml +++ b/detections/experimental/endpoint/ssa___excessive_number_of_office_files_copied.yml @@ -27,6 +27,7 @@ references: [] tags: analytic_story: - Insider Threat + cis20: [] confidence: 80 context: - Source:Endpoint @@ -39,6 +40,7 @@ tags: message: High number of files copied mitre_attack_id: - T1048.003 + nist: [] observable: - name: dest_user_id type: User diff --git a/detections/experimental/endpoint/ssa___high_file_deletion_frequency.yml b/detections/experimental/endpoint/ssa___high_file_deletion_frequency.yml index 4e432359a4..23047ce93d 100644 --- a/detections/experimental/endpoint/ssa___high_file_deletion_frequency.yml +++ b/detections/experimental/endpoint/ssa___high_file_deletion_frequency.yml @@ -35,6 +35,7 @@ tags: analytic_story: - Clop Ransomware - Insider Threat + cis20: [] confidence: 80 context: - Source:Endpoint @@ -47,6 +48,7 @@ tags: message: High frequency file deletion activity detected on host $Computer$ mitre_attack_id: - T1485 + nist: [] observable: - name: user type: User diff --git a/detections/experimental/network/ssl_certificates_with_punycode.yml b/detections/experimental/network/ssl_certificates_with_punycode.yml new file mode 100644 index 0000000000..187241d58c --- /dev/null +++ b/detections/experimental/network/ssl_certificates_with_punycode.yml @@ -0,0 +1,66 @@ +name: SSL Certificates with Punycode +id: 696694df-5706-495a-81f2-79501fa11b90 +version: 1 +date: '2022-11-01' +author: Michael Haag, Splunk +type: Hunting +datamodel: [] +description: The following analytic utilizes the Certificates Datamodel to look for punycode domains, starting with xn--, found in the SSL issuer email domain. + The presence of punycode here does not equate to evil, therefore we need to decode the punycode to determine what it translates to. Remove the CyberChef recipe as needed and decode manually. + Note that this is not the exact location of the malicious punycode to trip CVE-2022-3602, but a method to at least identify fuzzing occurring on these email paths. + What does evil look like? it will start with +search: '| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) + as lastTime from datamodel=Certificates.All_Certificates by All_Certificates.SSL.ssl_issuer_email_domain All_Certificates.SSL.ssl_issuer All_Certificates.SSL.ssl_subject_email All_Certificates.SSL.dest All_Certificates.SSL.src All_Certificates.SSL.sourcetype All_Certificates.SSL.ssl_subject_email_domain + | `drop_dm_object_name("All_Certificates.SSL")` + | eval punycode=if(like(ssl_issuer_email_domain,"%xn--%"),1,0) + | where punycode=1 + | cyberchef infield="ssl_issuer_email_domain" outfield="convertedPuny" jsonrecipe="[{"op":"From Punycode","args":[true]}]" + | table ssl_issuer_email_domain convertedPuny ssl_issuer ssl_subject_email dest src sourcetype ssl_subject_email_domain + | `ssl_certificates_with_punycode_filter`' +how_to_implement: Ensure data is properly being ingested into the Certificates datamodel. If decoding the of interest, the CyberChef app is needed https://splunkbase.splunk.com/app/5348. If decoding is not needed, remove the cyberchef lines. +known_false_positives: False positives may be present if the organization works with international businesses. Filter as needed. +references: + - https://www.splunk.com/en_us/blog/security/nothing-puny-about-cve-2022-3602.html + - https://www.openssl.org/blog/blog/2022/11/01/email-address-overflows/ + - https://community.emergingthreats.net/t/out-of-band-ruleset-update-summary-2022-11-01/117 + - https://github.com/corelight/CVE-2022-3602/tree/master/scripts +tags: + analytic_story: + - OpenSSL CVE-2022-3602 + asset_type: Network + cis20: + - CIS 3 + - CIS 5 + - CIS 16 + confidence: 30 + context: + - Source:IPS + dataset: [] + impact: 50 + kill_chain_phases: + - Reconnaissance + - Delivery + message: A x509 certificate has been identified to have punycode in the SSL issuer email domain on $dest$. + mitre_attack_id: + - T1573 + nist: + - DE.CM + observable: + - name: dest + type: Hostname + role: + - Victim + product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud + required_fields: + - All_Certificates.SSL.ssl_issuer_email_domain + - All_Certificates.SSL.ssl_issuer + - All_Certificates.SSL.ssl_subject_email + - All_Certificates.SSL.dest + - All_Certificates.SSL.src + - All_Certificates.SSL.sourcetype + - All_Certificates.SSL.ssl_subject_email_domain + risk_score: 15 + security_domain: network diff --git a/detections/experimental/network/zeek_x509_certificate_with_punycode.yml b/detections/experimental/network/zeek_x509_certificate_with_punycode.yml new file mode 100644 index 0000000000..36dee9950c --- /dev/null +++ b/detections/experimental/network/zeek_x509_certificate_with_punycode.yml @@ -0,0 +1,61 @@ +name: Zeek x509 Certificate with Punycode +id: 029d6fe4-a5fe-43af-827e-c78c50e81d81 +version: 1 +date: '2022-11-03' +author: Michael Haag, Splunk +type: Hunting +datamodel: [] +description: The following analytic utilizes the Zeek x509 log. Modify the zeek_x509 macro with your index and sourcetype as needed. You will need to ensure the full x509 is logged as the potentially malicious punycode is nested under subject alternative names. + In this particular analytic, it will identify punycode within the subject alternative name email and other fields. Note, that OtherFields is meant to be BOOL (true,false), therefore we may never see xn-- in that field. + Upon identifying punycode, manually copy and paste, or add CyberChef recipe to query, and decode the punycode manually. +search: '`zeek_x509` + | rex field=san.email{} "\@(?xn--.*)" + | rex field=san.other_fields{} "\@(?xn--.*)" + | stats values(domain_detected) by basic_constraints.ca source host + | `zeek_x509_certificate_with_punycode_filter`' +how_to_implement: The following analytic requires x509 certificate data to be logged entirely. In particular, for CVE-2022-3602, the punycode will be within the leaf certificate. The analytic may be modified to look for all xn--, or utilize a network IDS/monitoring tool like Zeek or Suricata to drill down into cert captured. Note for Suricata, the certificate is base64 encoded and will need to be decoded to capture the punycode (punycode will need to be decoded after). +known_false_positives: False positives may be present if the organization works with international businesses. Filter as needed. +references: + - https://community.emergingthreats.net/t/out-of-band-ruleset-update-summary-2022-11-01/117 + - https://github.com/corelight/CVE-2022-3602/tree/master/scripts + - https://docs.zeek.org/en/master/logs/x509.html + - https://www.splunk.com/en_us/blog/security/nothing-puny-about-cve-2022-3602.html + - https://www.openssl.org/blog/blog/2022/11/01/email-address-overflows/ + - https://docs.zeek.org/en/master/scripts/base/init-bare.zeek.html#type-X509::SubjectAlternativeName +tags: + analytic_story: + - OpenSSL CVE-2022-3602 + asset_type: Network + cis20: + - CIS 3 + - CIS 5 + - CIS 16 + confidence: 30 + context: + - Source:IPS + dataset: [] + impact: 50 + kill_chain_phases: + - Reconnaissance + - Delivery + message: A x509 certificate has been identified to have punycode in the subject alternative name on $dest$. + mitre_attack_id: + - T1573 + nist: + - DE.CM + observable: + - name: dest + type: Hostname + role: + - Victim + product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud + required_fields: + - domain_detected + - basic_constraints.ca + - source + - host + risk_score: 15 + security_domain: network diff --git a/macros/zeek_x509.yml b/macros/zeek_x509.yml new file mode 100644 index 0000000000..243f259ac0 --- /dev/null +++ b/macros/zeek_x509.yml @@ -0,0 +1,4 @@ +definition: sourcetype="zeek:x509:json" +description: customer specific splunk configurations(eg- index, source, sourcetype). + Replace the macro definition with configurations for your Splunk Environmnent. +name: zeek_x509 diff --git a/stories/openssl_cve_2022_3602.yml b/stories/openssl_cve_2022_3602.yml new file mode 100644 index 0000000000..4bac0bdf80 --- /dev/null +++ b/stories/openssl_cve_2022_3602.yml @@ -0,0 +1,36 @@ +name: OpenSSL CVE-2022-3602 +id: 491e00c9-998b-4c64-91bb-d8f9c79c1f4c +version: 1 +date: '2022-11-02' +author: Michael Haag, splunk +description: OpenSSL recently disclosed two vulnerabilities CVE-2022-3602 and CVE-2022-3786. CVE-2022-3602 is a X.509 Email Address 4-byte Buffer Overflow where puny code is utilized. This only affects OpenSSL 3.0.0 - 3.0.6. +narrative: A buffer overrun can be triggered in X.509 certificate verification, + specifically in name constraint checking. Note that this occurs after + certificate chain signature verification and requires either a CA to + have signed a malicious certificate or for an application to continue + certificate verification despite failure to construct a path to a trusted + issuer. An attacker can craft a malicious email address in a certificate + to overflow an arbitrary number of bytes containing the . character + (decimal 46) on the stack. This buffer overflow could result in a crash + (causing a denial of service). + In a TLS client, this can be triggered by connecting to a malicious + server. In a TLS server, this can be triggered if the server requests + client authentication and a malicious client connects. + Users of OpenSSL 3.0.0 - 3.0.6 are encouraged to upgrade to 3.0.7 as soon as possible. If you obtain your copy of OpenSSL from your Operating System vendor or other third party then you should seek to obtain an updated version from them as soon as possible. + SSL Certificates with Punycode will identify SSL certificates with Punycode. Note that it does not mean it will capture malicious payloads. + If using Zeek, modify the Zeek x509 certificate with punycode to match your environment. + We found during this exercise that the FULL x509 with SAN must be captured and stored, decoded, in order to query against it. +references: + - https://www.openssl.org/blog/blog/2022/11/01/email-address-overflows/ + - https://github.com/advisories/GHSA-h8jm-2x53-xhp5 + - https://community.emergingthreats.net/t/out-of-band-ruleset-update-summary-2022-11-01/117 + - https://github.com/corelight/CVE-2022-3602/tree/master/scripts +tags: + analytic_story: OpenSSL CVE-2022-3602 + category: + - Adversary Tactics + product: + - Splunk Enterprise + - Splunk Enterprise Security + - Splunk Cloud + usecase: Advanced Threat Detection