Compare commits

...

5 Commits

Author SHA1 Message Date
tek
e4e1716729 Bumped version 2022-01-20 15:28:42 +01:00
tek
083bc12351 Merge branch 'feature/check-file-path' 2022-01-20 15:19:37 +01:00
tek
cf6d392460 Adds more details on the download-iocs command 2022-01-20 13:29:50 +01:00
tek
95205d8e17 Adds indicators check to iOS TCC module 2022-01-18 17:12:20 +01:00
tek
38bb583a9e Improves management of file path indicators 2022-01-18 15:50:31 +01:00
11 changed files with 74 additions and 34 deletions

View File

@@ -41,6 +41,6 @@ export MVT_STIX2="/home/user/IOC1.stix2:/home/user/IOC2.stix2"
- [Predator from Cytrox](https://citizenlab.ca/2021/12/pegasus-vs-predator-dissidents-doubly-infected-iphone-reveals-cytrox-mercenary-spyware/) ([STIX2](https://raw.githubusercontent.com/AmnestyTech/investigations/master/2021-12-16_cytrox/cytrox.stix2))
- [This repository](https://github.com/Te-k/stalkerware-indicators) contains IOCs for Android stalkerware including [a STIX MVT-compatible file](https://raw.githubusercontent.com/Te-k/stalkerware-indicators/master/stalkerware.stix2).
You can automaticallly download the latest public indicator files with the command `mvt-ios download-iocs` or `mvt-android download-iocs`.
You can automaticallly download the latest public indicator files with the command `mvt-ios download-iocs` or `mvt-android download-iocs`. These commands download the list of indicators listed [here](https://github.com/mvt-project/mvt/blob/main/public_indicators.json) and store them in the [appdir](https://pypi.org/project/appdirs/) folder. They are then loaded automatically by mvt.
Please [open an issue](https://github.com/mvt-project/mvt/issues/) to suggest new sources of STIX-formatted IOCs.

View File

@@ -89,10 +89,6 @@ class Files(AndroidExtraction):
return
for result in self.results:
if self.indicators.check_file_name(result["path"]):
self.log.warning("Found a known suspicous filename at path: \"%s\"", result["path"])
self.detected.append(result)
if self.indicators.check_file_path(result["path"]):
self.log.warning("Found a known suspicous file at path: \"%s\"", result["path"])
self.detected.append(result)

View File

@@ -25,6 +25,7 @@ class Indicators:
self.ioc_processes = []
self.ioc_emails = []
self.ioc_files = []
self.ioc_file_paths = []
self.ioc_files_sha256 = []
self.ioc_app_ids = []
self.ios_profile_ids = []
@@ -109,6 +110,9 @@ class Indicators:
elif key == "file:name":
self._add_indicator(ioc=value,
iocs_list=self.ioc_files)
elif key == "file:path":
self._add_indicator(ioc=value,
iocs_list=self.ioc_file_paths)
elif key == "app:id":
self._add_indicator(ioc=value,
iocs_list=self.ioc_app_ids)
@@ -272,30 +276,26 @@ class Indicators:
return False
def check_file_name(self, file_path) -> bool:
"""Check the provided file path against the list of file indicators.
def check_file_name(self, file_name) -> bool:
"""Check the provided file name against the list of file indicators.
:param file_path: File path or file name to check against file
:param file_name: File name to check against file
indicators
:type file_path: str
:returns: True if the file path matched an indicator, otherwise False
:type file_name: str
:returns: True if the file name matched an indicator, otherwise False
:rtype: bool
"""
if not file_path:
if not file_name:
return False
file_name = os.path.basename(file_path)
if file_name in self.ioc_files:
return True
return False
# TODO: The difference between check_file_name() and check_file_path()
# needs to be more explicit and clear. Probably, the two should just
# be combined into one function.
def check_file_path(self, file_path) -> bool:
"""Check the provided file path against the list of file indicators.
"""Check the provided file path against the list of file indicators (both path and name).
:param file_path: File path or file name to check against file
indicators
@@ -307,7 +307,10 @@ class Indicators:
if not file_path:
return False
for ioc_file in self.ioc_files:
if self.check_file_name(os.path.basename(file_path)):
return True
for ioc_file in self.ioc_file_paths:
# Strip any trailing slash from indicator paths to match directories.
if file_path.startswith(ioc_file.rstrip("/")):
return True

View File

@@ -6,7 +6,7 @@
import requests
from packaging import version
MVT_VERSION = "1.4.4"
MVT_VERSION = "1.4.5"
def check_for_updates():

View File

@@ -83,7 +83,7 @@ class Manifest(IOSExtraction):
self.detected.append(result)
continue
if self.indicators.check_file_name(result["relative_path"]):
if self.indicators.check_file_path("/" + result["relative_path"]):
self.log.warning("Found a known malicious file at path: %s", result["relative_path"])
self.detected.append(result)
continue

View File

@@ -37,10 +37,6 @@ class Filesystem(IOSExtraction):
return
for result in self.results:
if self.indicators.check_file(result["path"]):
self.log.warning("Found a known malicious file name at path: %s", result["path"])
self.detected.append(result)
if self.indicators.check_file_path(result["path"]):
self.log.warning("Found a known malicious file path at path: %s", result["path"])
self.detected.append(result)

View File

@@ -34,12 +34,19 @@ class ShutdownLog(IOSExtraction):
return
for result in self.results:
if self.indicators.check_file_path(result["client"]):
self.log.warning("Found mention of a known malicious file \"%s\" in shutdown.log",
result["client"])
self.detected.append(result)
continue
for ioc in self.indicators.ioc_processes:
parts = result["client"].split("/")
if ioc in parts:
self.log.warning("Found mention of a known malicious process \"%s\" in shutdown.log",
ioc)
self.detected.append(result)
continue
def process_shutdownlog(self, content):
current_processes = []

View File

@@ -41,13 +41,13 @@ class LocationdClients(IOSExtraction):
def serialize(self, record):
records = []
for ts in self.timestamps:
if ts in record.keys():
for timestamp in self.timestamps:
if timestamp in record.keys():
records.append({
"timestamp": record[ts],
"timestamp": record[timestamp],
"module": self.__class__.__name__,
"event": ts,
"data": f"{ts} from {record['package']}"
"event": timestamp,
"data": f"{timestamp} from {record['package']}"
})
return records
@@ -61,7 +61,31 @@ class LocationdClients(IOSExtraction):
proc_name = parts[len(parts)-1]
if self.indicators.check_process(proc_name):
self.log.warning("Found a suspicious process name in LocationD entry %s",
result["package"])
self.detected.append(result)
continue
if "BundlePath" in result:
if self.indicators.check_file_path(result["BundlePath"]):
self.log.warning("Found a suspicious file path in Location D: %s",
result["BundlePath"])
self.detected.append(result)
continue
if "Executable" in result:
if self.indicators.check_file_path(result["Executable"]):
self.log.warning("Found a suspicious file path in Location D: %s",
result["Executable"])
self.detected.append(result)
continue
if "Registered" in result:
if self.indicators.check_file_path(result["Registered"]):
self.log.warning("Found a suspicious file path in Location D: %s",
result["Registered"])
self.detected.append(result)
continue
def _extract_locationd_entries(self, file_path):
with open(file_path, "rb") as handle:

View File

@@ -66,6 +66,15 @@ class TCC(IOSExtraction):
"data": msg
}
def check_indicators(self):
if not self.indicators:
return
for result in self.results:
if self.indicators.check_process(result["client"]):
self.log.warning("Found malicious process in TCC database: %s", result["client"])
self.detected.append(result)
def process_db(self, file_path):
conn = sqlite3.connect(file_path)
cur = conn.cursor()

View File

@@ -5,27 +5,32 @@
import logging
from mvt.common.indicators import Indicators
from mvt.common.module import run_module
from mvt.ios.modules.mixed.tcc import TCC
from ..utils import get_backup_folder
class TestManifestModule:
def test_manifest(self):
class TestTCCtModule:
def test_tcc(self):
m = TCC(base_folder=get_backup_folder(), log=logging, results=[])
run_module(m)
assert len(m.results) == 11
assert len(m.timeline) == 11
assert len(m.detected) == 0
assert m.results[0]["service"] == "kTCCServiceUbiquity"
assert m.results[0]["client"] == "com.apple.Preferences"
assert m.results[0]["auth_value"] == "allowed"
def test_manifest_2(self):
def test_tcc_detection(self, indicator_file):
m = TCC(base_folder=get_backup_folder(), log=logging, results=[])
ind = Indicators(log=logging)
ind.parse_stix2(indicator_file)
m.indicators = ind
run_module(m)
assert len(m.results) == 11
assert len(m.timeline) == 11
assert len(m.detected) == 0
assert m.results[0]["service"] == "kTCCServiceUbiquity"
assert m.results[0]["auth_value"] == "allowed"
assert len(m.detected) == 1
assert m.detected[0]["service"] == "kTCCServiceLiverpool"
assert m.detected[0]["client"] == "Launch"