mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-04 17:06:35 +02:00
Support rotated iOS shutdown logs (#834)
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from mvt.common.module import DatabaseNotFoundError
|
||||||
from mvt.common.module_types import (
|
from mvt.common.module_types import (
|
||||||
ModuleAtomicResult,
|
ModuleAtomicResult,
|
||||||
ModuleResults,
|
ModuleResults,
|
||||||
@@ -17,6 +18,7 @@ from ..base import IOSExtraction
|
|||||||
|
|
||||||
SHUTDOWN_LOG_PATH = [
|
SHUTDOWN_LOG_PATH = [
|
||||||
"private/var/db/diagnostics/shutdown.log",
|
"private/var/db/diagnostics/shutdown.log",
|
||||||
|
"private/var/db/diagnostics/shutdown.*.log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -132,10 +134,17 @@ class ShutdownLog(IOSExtraction):
|
|||||||
self.results = sorted(self.results, key=lambda entry: entry["isodate"])
|
self.results = sorted(self.results, key=lambda entry: entry["isodate"])
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
self._find_ios_database(root_paths=SHUTDOWN_LOG_PATH)
|
if self.file_path:
|
||||||
self.log.info("Found shutdown log at path: %s", self.file_path)
|
shutdown_log_paths = [self.file_path]
|
||||||
|
else:
|
||||||
|
shutdown_log_paths = sorted(
|
||||||
|
self._get_fs_files_from_patterns(SHUTDOWN_LOG_PATH)
|
||||||
|
)
|
||||||
|
|
||||||
if not self.file_path:
|
if not shutdown_log_paths:
|
||||||
return
|
raise DatabaseNotFoundError("unable to find any shutdown log files")
|
||||||
with open(self.file_path, "r", encoding="utf-8") as handle:
|
|
||||||
self.process_shutdownlog(handle.read())
|
for shutdown_log_path in shutdown_log_paths:
|
||||||
|
self.log.info("Found shutdown log at path: %s", shutdown_log_path)
|
||||||
|
with open(shutdown_log_path, "r", encoding="utf-8") as handle:
|
||||||
|
self.process_shutdownlog(handle.read())
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ def indicators_factory(indicator_file):
|
|||||||
domains=[],
|
domains=[],
|
||||||
emails=[],
|
emails=[],
|
||||||
file_names=[],
|
file_names=[],
|
||||||
|
file_paths=[],
|
||||||
processes=[],
|
processes=[],
|
||||||
app_ids=[],
|
app_ids=[],
|
||||||
app_cert_hashes=[],
|
app_cert_hashes=[],
|
||||||
@@ -47,6 +48,7 @@ def indicators_factory(indicator_file):
|
|||||||
ind.ioc_collections[0]["domains"].extend(domains)
|
ind.ioc_collections[0]["domains"].extend(domains)
|
||||||
ind.ioc_collections[0]["emails"].extend(emails)
|
ind.ioc_collections[0]["emails"].extend(emails)
|
||||||
ind.ioc_collections[0]["file_names"].extend(file_names)
|
ind.ioc_collections[0]["file_names"].extend(file_names)
|
||||||
|
ind.ioc_collections[0]["file_paths"].extend(file_paths)
|
||||||
ind.ioc_collections[0]["processes"].extend(processes)
|
ind.ioc_collections[0]["processes"].extend(processes)
|
||||||
ind.ioc_collections[0]["app_ids"].extend(app_ids)
|
ind.ioc_collections[0]["app_ids"].extend(app_ids)
|
||||||
ind.ioc_collections[0]["android_property_names"].extend(android_property_names)
|
ind.ioc_collections[0]["android_property_names"].extend(android_property_names)
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT Authors.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
from mvt.common.module import run_module
|
||||||
|
from mvt.ios.modules.fs.shutdownlog import ShutdownLog
|
||||||
|
|
||||||
|
|
||||||
|
def _shutdown_log_entry(pid: int, client: str, timestamp: int) -> str:
|
||||||
|
return (
|
||||||
|
f"remaining client pid: {pid} ({client})\n"
|
||||||
|
f"SIGTERM: [{timestamp}]\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestShutdownLog:
|
||||||
|
def test_discovers_rotated_shutdown_logs(self, tmp_path):
|
||||||
|
diagnostics_path = tmp_path / "private/var/db/diagnostics"
|
||||||
|
diagnostics_path.mkdir(parents=True)
|
||||||
|
(diagnostics_path / "shutdown.log").write_text(
|
||||||
|
_shutdown_log_entry(100, "/usr/libexec/first", 1_700_000_000),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
(diagnostics_path / "shutdown.0.log").write_text(
|
||||||
|
_shutdown_log_entry(200, "/usr/libexec/second", 1_700_000_001),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
module = ShutdownLog(target_path=str(tmp_path))
|
||||||
|
run_module(module)
|
||||||
|
|
||||||
|
assert {result["client"] for result in module.results} == {
|
||||||
|
"/usr/libexec/first",
|
||||||
|
"/usr/libexec/second",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_file_path_indicator_matches_client_with_trailing_uuid(
|
||||||
|
self, indicators_factory
|
||||||
|
):
|
||||||
|
executable_path = "/usr/sbin/filecoordinationd"
|
||||||
|
client = f"{executable_path}/123e4567-e89b-12d3-a456-426614174000"
|
||||||
|
module = ShutdownLog(
|
||||||
|
results=[
|
||||||
|
{
|
||||||
|
"isodate": "2023-11-14 22:13:20.000000",
|
||||||
|
"pid": "100",
|
||||||
|
"client": client,
|
||||||
|
"delay": 0.0,
|
||||||
|
"times_delayed": 0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
module.indicators = indicators_factory(file_paths=[executable_path])
|
||||||
|
|
||||||
|
module.check_indicators()
|
||||||
|
|
||||||
|
assert len(module.alertstore.alerts) == 1
|
||||||
|
assert module.alertstore.alerts[0].matched_indicator.value == executable_path
|
||||||
Reference in New Issue
Block a user