Add support for check APK certificate hash IOCs (#557)

* Fix bug loading indicators which I introduced in 81b647b

* Add support for matching on APK certificate hash IOCs
This commit is contained in:
Donncha Ó Cearbhaill
2024-10-18 16:35:50 +02:00
committed by GitHub
parent 665806db98
commit 3afe218c7c
5 changed files with 74 additions and 4 deletions

View File

@@ -77,7 +77,6 @@ class Packages(AndroidQFModule):
if ioc:
result["matched_indicator"] = ioc
self.detected.append(result)
continue
for package_file in result.get("files", []):
ioc = self.indicators.check_file_hash(package_file["sha256"])
@@ -85,6 +84,18 @@ class Packages(AndroidQFModule):
result["matched_indicator"] = ioc
self.detected.append(result)
if "certificate" not in package_file:
continue
# The keys generated by AndroidQF have a leading uppercase character
for hash_type in ["Md5", "Sha1", "Sha256"]:
certificate_hash = package_file["certificate"][hash_type]
ioc = self.indicators.check_app_certificate_hash(certificate_hash)
if ioc:
result["matched_indicator"] = ioc
self.detected.append(result)
break
def run(self) -> None:
packages = self._get_files_by_pattern("*/packages.json")
if not packages:

View File

@@ -82,6 +82,7 @@ class Indicators:
"files_md5": [],
"files_sha1": [],
"files_sha256": [],
"app_cert_hashes": [],
"app_ids": [],
"ios_profile_ids": [],
"android_property_names": [],
@@ -107,7 +108,7 @@ class Indicators:
ioc_coll=collection,
ioc_coll_list=collection["domains"],
)
if key == "ipv4-addr:value":
elif key == "ipv4-addr:value":
# We treat IP addresses as simple domains here to ease checks.
self._add_indicator(
ioc=value.strip(),
@@ -145,6 +146,24 @@ class Indicators:
self._add_indicator(
ioc=value, ioc_coll=collection, ioc_coll_list=collection["files_sha256"]
)
elif key == "app:cert.md5":
self._add_indicator(
ioc=value,
ioc_coll=collection,
ioc_coll_list=collection["app_cert_hashes"],
)
elif key == "app:cert.sha1":
self._add_indicator(
ioc=value,
ioc_coll=collection,
ioc_coll_list=collection["app_cert_hashes"],
)
elif key == "app:cert.sha256":
self._add_indicator(
ioc=value,
ioc_coll=collection,
ioc_coll_list=collection["app_cert_hashes"],
)
elif key == "app:id":
self._add_indicator(
ioc=value, ioc_coll=collection, ioc_coll_list=collection["app_ids"]
@@ -155,7 +174,6 @@ class Indicators:
ioc_coll=collection,
ioc_coll_list=collection["ios_profile_ids"],
)
elif key == "android-property:name":
self._add_indicator(
ioc=value,
@@ -703,6 +721,29 @@ class Indicators:
return None
def check_app_certificate_hash(self, cert_hash: str) -> Union[dict, None]:
"""Check the provided cert hash against the list of indicators.
:param cert_hash: hash to check
:type cert_hash: str
:returns: Indicator details if matched, otherwise None
"""
if not cert_hash:
return None
for ioc in self.get_iocs("app_cert_hashes"):
if cert_hash.lower() == ioc["value"].lower():
self.log.warning(
'Found a known suspicious app certfificate with hash "%s" '
'matching indicators from "%s"',
cert_hash,
ioc["name"],
)
return ioc
return None
def check_app_id(self, app_id: str) -> Union[dict, None]:
"""Check the provided app identifier (typically an Android package name)
against the list of indicators.

View File

@@ -86,3 +86,19 @@ class TestAndroidqfPackages:
module.detected[0]["matched_indicator"]["value"]
== "31037a27af59d4914906c01ad14a318eee2f3e31d48da8954dca62a99174e3fa"
)
def test_packages_certificate_hash_ioc(self, module, indicators_factory):
module.indicators = indicators_factory(
app_cert_hashes=[
"c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730"
]
)
run_module(module)
assert len(module.detected) == 1
assert module.detected[0]["name"] == "com.malware.muahaha"
assert (
module.detected[0]["matched_indicator"]["value"]
== "c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730"
)

View File

@@ -212,7 +212,7 @@
"certificate": {
"Md5": "54d5b5aca1e7e76bb1a26c61a9381b93",
"Sha1": "4ba9d1f82adb7be841bcf53b03ddae857747199a",
"Sha256": "31037a27af59d4914906c01ad14a318eee2f3e31d48da8954dca62a99174e3fa",
"Sha256": "c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730",
"ValidFrom": "2021-01-15T22:03:53Z",
"ValidTo": "2051-01-15T22:03:53Z",
"Issuer": "C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android",

View File

@@ -37,6 +37,7 @@ def indicators_factory(indicator_file):
file_names=[],
processes=[],
app_ids=[],
app_cert_hashes=[],
android_property_names=[],
files_sha256=[],
):
@@ -50,6 +51,7 @@ def indicators_factory(indicator_file):
ind.ioc_collections[0]["app_ids"].extend(app_ids)
ind.ioc_collections[0]["android_property_names"].extend(android_property_names)
ind.ioc_collections[0]["files_sha256"].extend(files_sha256)
ind.ioc_collections[0]["app_cert_hashes"].extend(app_cert_hashes)
return ind