def test_software_update(self): with open(str(root_dir / "test_data" / "SoftwareUpdate.exe"), "rb") as f: fingerprinter = AuthenticodeFingerprinter(f) fingerprinter.add_authenticode_hashers(hashlib.sha1) hashes = fingerprinter.hash() # Sanity check that the authenticode hash is still correct self.assertEqual( binascii.hexlify(hashes['sha1']).decode('ascii'), '978b90ace99c764841d2dd17d278fac4149962a3') pefile = SignedPEFile(f) # This should not raise any errors. signed_datas = list(pefile.signed_datas) # There may be multiple of these, if the windows binary was signed multiple # times, e.g. by different entities. Each of them adds a complete SignedData # blob to the binary. For our sample, there is only one blob. self.assertEqual(len(signed_datas), 1) signed_data = signed_datas[0] self.assertEqual(signed_data._rest_data, b'\0') signed_data.verify() # should work as well pefile.verify()
def test_0d8c_valid(self): with open( str(root_dir / "test_data" / "0d8c2bcb575378f6a88d17b5f6ce70e794a264cdc8556c8e812f0b5f9c709198" ), "rb") as f: pefile = SignedPEFile(f) pefile.verify()
def test_pciide(self): with open(str(root_dir / "test_data" / "pciide.sys"), "rb") as f: pefile = SignedPEFile(f) signed_datas = list(pefile.signed_datas) self.assertEqual(len(signed_datas), 1) signed_data = signed_datas[0] signed_data.verify() pefile.verify()
def test_3a7de393a36ca8911cd0842a9a25b058_valid_different_contenttype( self): """uses a different contenttype, 1.2.840.113549.1.9.16.1.4 instead of Data""" with open( str(root_dir / "test_data" / "3a7de393a36ca8911cd0842a9a25b058"), "rb") as f: pefile = SignedPEFile(f) pefile.verify()
def test_0d8c_valid(self): with open( str(root_dir / "test_data" / "0d8c2bcb575378f6a88d17b5f6ce70e794a264cdc8556c8e812f0b5f9c709198" ), "rb") as f: pefile = SignedPEFile(f) pefile.verify( trusted_certificate_store=TRUSTED_CERTIFICATE_STORE_NO_CTL)
def test_jameslth_revoked(self): """this certificate is revoked""" with open(str(root_dir / "test_data" / "jameslth"), "rb") as f: pefile = SignedPEFile(f) with self.assertRaises(VerificationError): pefile.verify(verification_context_kwargs={ 'allow_fetching': True, 'revocation_mode': 'hard-fail' })
def test_sw_reporter(self): """Test for SHA256 hashes used in sig""" with open(str(root_dir / "test_data" / "software_reporter_tool.exe"), "rb") as f: pefile = SignedPEFile(f) signed_datas = list(pefile.signed_datas) self.assertEqual(len(signed_datas), 1) signed_data = signed_datas[0] signed_data.verify() pefile.verify()
def test_19e8_valid_within_period(self): with open( str(root_dir / "test_data" / "19e818d0da361c4feedd456fca63d68d4b024fbbd3d9265f606076c7ee72e8f8.ViR" ), "rb") as f: pefile = SignedPEFile(f) pefile.verify( verification_context_kwargs={ 'timestamp': datetime.datetime(2013, 1, 1, tzinfo=datetime.timezone.utc) })
def test_19e8_expired(self): with open( str(root_dir / "test_data" / "19e818d0da361c4feedd456fca63d68d4b024fbbd3d9265f606076c7ee72e8f8.ViR" ), "rb") as f: pefile = SignedPEFile(f) self.assertRaises(VerificationError, pefile.verify)
def test_modified_pciide_fails(self): with open(str(root_dir / "test_data" / "pciide.sys"), "rb") as f: data = bytearray(f.read()) data[1024] = 3 bt = io.BytesIO(data) pefile = SignedPEFile(bt) signed_datas = list(pefile.signed_datas) self.assertEqual(len(signed_datas), 1) self.assertRaises(AuthenticodeVerificationError, signed_datas[0].verify) self.assertRaises(AuthenticodeVerificationError, pefile.verify)
def add_authenticode_hashers(self, *hashers): """Specialized method of :meth:`add_hashers` to add hashers with ranges limited to those that are needed to calculate the hash of signed PE Files. """ pefile = SignedPEFile(self.file) omit = pefile.get_authenticode_omit_sections() if omit is None: return False ranges = [] start = 0 for start_length in sorted(omit.values()): ranges.append(Range(start, start_length.start)) start = sum(start_length) ranges.append(Range(start, self._filelength)) self.add_hashers(*hashers, ranges=ranges, description='authentihash') return True
def main(): data_file = sys.argv[1] try: with open(data_file, 'rb') as objf: pefile = SignedPEFile(objf) try: pefile.verify() except AuthenticodeVerificationError: print("could not verify cert") except Exception as error: print("error with verify") print(error.__class__.__name__ + ": " + error.message) return {} for signed_data in pefile.signed_datas: print(signed_data.signer_info.program_name) for cert in signed_data.certificates: print(cert) except Exception as error: print("Gen error") print(error.__class__.__name__ + ": " + error.message)
def test_potential_chains(self): with open( str(root_dir / "test_data" / "19e818d0da361c4feedd456fca63d68d4b024fbbd3d9265f606076c7ee72e8f8.ViR" ), "rb") as f: pefile = SignedPEFile(f) for signed_data in pefile.signed_datas: context = VerificationContext(TRUSTED_CERTIFICATE_STORE, signed_data.certificates) potential_chains = list( signed_data.signer_info.potential_chains(context)) self.assertEqual(len(potential_chains), 2)
def parse_certificates(data): # set up string io as we get data buffer = BytesIO() buffer.write(data) buffer.seek(0) try: pefile = SignedPEFile(buffer) signed_datas = list(pefile.signed_datas) except (SignedPEParseError, SignerInfoParseError, AuthenticodeParseError, VerificationError, CertificateVerificationError, SignerInfoVerificationError, AuthenticodeVerificationError) as e: logging.info(f"signify threw error {e} when processing PE file") return {} cert_list = [] signer_list = [] counter_signer_list = [] for signed_data in signed_datas: try: certs = signed_data.certificates for cert in certs: asn1 = cert.to_asn1crypto issuer = asn1.issuer.native cert_dict = { "country_name": issuer.get("country_name"), "organization_name": issuer.get("organization_name"), "organizational_unit_name": issuer.get("organizational_unit_name"), "common_name": issuer.get("common_name"), "serial_number": str(cert.serial_number), "issuer_dn": cert.issuer_dn, "subject_dn": cert.subject_dn, "valid_from": cert.valid_from.isoformat(), "valid_to": cert.valid_to.isoformat(), # "signature_algorithim": cert.signature_algorithm } cert_list.append(cert_dict) signer_dict = { 'issuer': signed_data.signer_info.issuer_dn, 'serial': str(signed_data.signer_info.serial_number), 'program_name': signed_data.signer_info.program_name, 'more_info': signed_data.signer_info.more_info } # signer information signer_list.append(signer_dict) if signed_data.signer_info.countersigner: counter_signer_dict = { 'issuer_dn': signed_data.signer_info.countersigner.issuer_dn, 'serial_number': str(signed_data.signer_info.countersigner.serial_number), 'signing_time': signed_data.signer_info.countersigner.signing_time. isoformat() } counter_signer_list.append(counter_signer_dict) except SignedPEParseError: logging.debug("no certificate in signed data") security_dict = { 'certificates': cert_list, 'signers': signer_list, 'counter_signers': counter_signer_list } try: pefile.verify() security_dict["verification"] = True except Exception as e: security_dict['verification'] = False security_dict['verification_error'] = str(e) return security_dict
def test_simple(self): with open(str(root_dir / "test_data" / "simple"), "rb") as f: pefile = SignedPEFile(f) self.assertRaises(SignedPEParseError, list, pefile.signed_datas) self.assertRaises(SignedPEParseError, pefile.verify)
def test_2A6E(self): with open(str(root_dir / "test_data" / "___2A6E.tmp"), "rb") as f: pefile = SignedPEFile(f) self.assertRaises(VerificationError, pefile.verify)
def test_whois_valid_countersignature_rfc3161(self): """whois includes a 1.3.6.1.4.1.311.3.3.1 type countersignature""" with open(str(root_dir / "test_data" / "whois.exe"), "rb") as f: pefile = SignedPEFile(f) pefile.verify()
def test_zonealarm_rfc3161_different_hash_and_digest_algorithms(self): """this tests a RFC3161 sample that has distinct hash and digest algorithms""" with open(str(root_dir / "test_data" / "zonealarm.exe"), "rb") as f: pefile = SignedPEFile(f) pefile.verify()
def test_7z1900_invalid_cve2020_0601(self): # This tests against CVE-2020-0601 with open(str(root_dir / "test_data" / "7z1900-x64_signed.exe"), "rb") as f: pefile = SignedPEFile(f) self.assertRaises(VerificationError, pefile.verify)
def test_solwarwinds_valid_countersignature_rfc3161(self): # Solarwinds includes a 1.3.6.1.4.1.311.3.3.1 type countersignature with open(str(root_dir / "test_data" / "SolarWinds.exe"), "rb") as f: pefile = SignedPEFile(f) pefile.verify()
def test_jameslth_valid_when_revocation_not_checked(self): # this certificate is revoked with open(str(root_dir / "test_data" / "jameslth"), "rb") as f: pefile = SignedPEFile(f) pefile.verify()