Compare commits

..

14 Commits

Author SHA1 Message Date
Donncha Ó Cearbhaill
3d924e22ec Merge branch 'release/v2.4.0' 2023-07-21 12:17:32 +02:00
Donncha Ó Cearbhaill
ca3c1bade4 Bump version to v2.4.0
Bumping the minor version as we introduce some backwards-incompatible
API changes to module definition in #367.
2023-07-21 12:14:31 +02:00
Donncha Ó Cearbhaill
85877fd3eb Merge pull request #369 from mvt-project/move-indicator-checking
Move detection and alerts from run() to check_indicators()
2023-07-21 12:12:36 +02:00
Donncha Ó Cearbhaill
8015ff78e8 Fix black error 2023-07-21 12:10:45 +02:00
Donncha Ó Cearbhaill
1a07b9a78f Move syntax checking before unit tests 2023-07-21 11:30:59 +02:00
Donncha Ó Cearbhaill
0b88de9867 Move detection and alerts from run() to check_indicators() 2023-07-21 11:29:12 +02:00
Donncha Ó Cearbhaill
76d7534b05 Fix bug recording detections in WebkitResourceLoadStatistics module 2023-07-18 18:02:42 +02:00
Donncha Ó Cearbhaill
ae2ab02347 Merge pull request #367 from mvt-project/refactor-module-options
Add a module_options parameter to pass data from CLI to modules
2023-07-17 19:07:41 +02:00
Donncha Ó Cearbhaill
e2c623c40f Move --fast flag from being a top-level MVT module parameter to an option in a new module_options parameter 2023-07-17 18:52:35 +02:00
Christian Clauss
a6e1a3de12 Add GitHub Annotions to ruff output (#364)
* Add GitHub Annotions to ruff output
* Upgrade GitHub Actions
* No Py3.11
2023-07-15 14:42:13 +02:00
tek
e7270d6a07 Fixes import and adds test for PR 361 2023-07-10 22:55:22 +02:00
Niclas Schwarzlose
1968a0fca2 Improve appops parsing in dumpsys (#361)
Without this change the package doesn't get properly reset when a new
user starts.

See for example in this excerpt:

```
 1 |    Package com.android.bluetooth:
 2 |      READ_CONTACTS (allow):
 3 |        null=[
 4 |          Access: [pers-s] 2022-04-22 13:24:17.577 (-277d5h22m53s447ms)
 5 |        ]
 6 |      WAKE_LOCK (allow):
 7 |        null=[
 8 |          Access: [pers-s] 2023-01-24 17:45:49.712 (-1m21s312ms) duration=+3ms
 9 |        ]
10 |      GET_USAGE_STATS (default):
11 |        null=[
12 |          Reject: [pers-s]2022-04-22 13:23:53.964 (-277d5h23m17s60ms)
13 |        ]
14 |      BLUETOOTH_CONNECT (allow):
15 |        null=[
16 |          Access: [pers-s] 2022-04-22 13:23:53.988 (-277d5h23m17s36ms)
17 |        ]
18 |  Uid 1027:
19 |    state=pers
20 |    capability=LCMN
21 |    appWidgetVisible=false
22 |      LEGACY_STORAGE: mode=ignore
23 |    Package com.android.nfc:
24 |      WAKE_LOCK (allow):
25 |        null=[
26 |          Access: [pers-s] 2022-04-22 13:23:54.633 (-277d5h23m16s391ms) duration=+1s73ms
27 |        ]
```

Here the package "com.android.bluetooth" is not reset when in line 18,
so when "LEGACY_STORAGE:" in line 22 is encountered, it's added as
another permission to "com.android.bluetooth" with "access" set to
"ode=igno".

This PR fixes that by resetting the package whenever a new Uid is
encountered.

Co-authored-by: Niclas Schwarzlose <niclas.schwarzlose@reporter-ohne-grenzen.de>
2023-07-10 22:53:58 +02:00
Donncha Ó Cearbhaill
46cc54df74 Add information about public indicators and support avenues to documentation 2023-06-30 19:43:30 +02:00
Donncha Ó Cearbhaill
7046ff80d1 Add SMS read time in the MVT logs 2023-06-30 19:30:50 +02:00
104 changed files with 315 additions and 257 deletions

View File

@@ -16,12 +16,12 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10'] # , '3.11']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies

View File

@@ -1,21 +1,19 @@
name: Ruff
on: [push]
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
ruff_py3:
name: Ruff syntax check
runs-on: ubuntu-latest
steps:
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.9
architecture: x64
- name: Checkout
uses: actions/checkout@master
- name: Install Dependencies
run: |
pip install ruff
pip install --user ruff
- name: ruff
run: |
ruff check .
ruff --format=github .

View File

@@ -2,9 +2,10 @@ PWD = $(shell pwd)
check:
flake8
pytest -q
ruff check -q .
black --check .
pytest -q
clean:
rm -rf $(PWD)/build $(PWD)/dist $(PWD)/mvt.egg-info

View File

@@ -6,6 +6,9 @@
Mobile Verification Toolkit (MVT) is a tool to facilitate the [consensual forensic analysis](introduction.md#consensual-forensics) of Android and iOS devices, for the purpose of identifying traces of compromise.
It has been developed and released by the [Amnesty International Security Lab](https://www.amnesty.org/en/tech/) in July 2021 in the context of the [Pegasus Project](https://forbiddenstories.org/about-the-pegasus-project/) along with [a technical forensic methodology](https://www.amnesty.org/en/latest/research/2021/07/forensic-methodology-report-how-to-catch-nso-groups-pegasus/). It continues to be maintained by Amnesty International and other contributors.
In this documentation you will find instructions on how to install and run the `mvt-ios` and `mvt-android` commands, and guidance on how to interpret the extracted results.
## Resources

View File

@@ -12,6 +12,20 @@ Mobile Verification Toolkit (MVT) is a collection of utilities designed to facil
MVT is a forensic research tool intended for technologists and investigators. Using it requires understanding the basics of forensic analysis and using command-line tools. MVT is not intended for end-user self-assessment. If you are concerned with the security of your device please seek expert assistance.
## Indicators of Compromise
MVT supports using [indicators of compromise (IOCs)](https://github.com/mvt-project/mvt-indicators) to scan mobile devices for potential traces of targeting or infection by known spyware campaigns. This includes IOCs published by [Amnesty International](https://github.com/AmnestyTech/investigations/) and other research groups.
!!! warning
Public indicators of compromise are insufficient to determine that a device is "clean", and not targeted with a particular spyware tool. Reliance on public indicators alone can miss recent forensic traces and give a false sense of security.
Reliable and comprehensive digital forensic support and triage requires access to non-public indicators, research and threat intelligence.
Such support is available to civil society through [Amnesty International's Security Lab](https://www.amnesty.org/en/tech/) or [Access Nows Digital Security Helpline](https://www.accessnow.org/help/).
More information about using indicators of compromise with MVT is available in the [documentation](iocs.md).
## Consensual Forensics
While MVT is capable of extracting and processing various types of very personal records typically found on a mobile phone (such as calls history, SMS and WhatsApp messages, etc.), this is intended to help identify potential attack vectors such as malicious SMS messages leading to exploitation.

View File

@@ -145,12 +145,14 @@ def download_apks(ctx, all_apks, virustotal, output, from_file, serial, verbose)
@click.pass_context
def check_adb(ctx, serial, iocs, output, fast, list_modules, module, verbose):
set_verbose_logging(verbose)
module_options = {"fast_mode": fast}
cmd = CmdAndroidCheckADB(
results_path=output,
ioc_files=iocs,
module_name=module,
serial=serial,
fast_mode=fast,
module_options=module_options,
)
if list_modules:

View File

@@ -21,7 +21,7 @@ class CmdAndroidCheckADB(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
) -> None:
super().__init__(
target_path=target_path,
@@ -29,7 +29,7 @@ class CmdAndroidCheckADB(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
log=log,
)

View File

@@ -21,7 +21,7 @@ class CmdAndroidCheckAndroidQF(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
) -> None:
super().__init__(
@@ -30,7 +30,7 @@ class CmdAndroidCheckAndroidQF(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
hashes=hashes,
log=log,
)

View File

@@ -35,7 +35,7 @@ class CmdAndroidCheckBackup(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
) -> None:
super().__init__(
@@ -44,7 +44,7 @@ class CmdAndroidCheckBackup(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
hashes=hashes,
log=log,
)

View File

@@ -25,7 +25,7 @@ class CmdAndroidCheckBugreport(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
) -> None:
super().__init__(
@@ -34,7 +34,7 @@ class CmdAndroidCheckBugreport(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
hashes=hashes,
log=log,
)

View File

@@ -44,7 +44,7 @@ class AndroidExtraction(MVTModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -52,7 +52,7 @@ class AndroidExtraction(MVTModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -23,7 +23,7 @@ class ChromeHistory(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -31,7 +31,7 @@ class ChromeHistory(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysAccessibility(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysAccessibility(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysActivities(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysActivities(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -21,7 +21,7 @@ class DumpsysAppOps(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -29,7 +29,7 @@ class DumpsysAppOps(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysBatteryDaily(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysBatteryDaily(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysBatteryHistory(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysBatteryHistory(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -21,7 +21,7 @@ class DumpsysDBInfo(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -29,7 +29,7 @@ class DumpsysDBInfo(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -18,7 +18,7 @@ class DumpsysFull(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -26,7 +26,7 @@ class DumpsysFull(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class DumpsysReceivers(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class DumpsysReceivers(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -30,7 +30,7 @@ class Files(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -38,7 +38,7 @@ class Files(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -142,8 +142,10 @@ class Files(AndroidExtraction):
"Found %s files in primary Android tmp and media folders", len(self.results)
)
if self.fast_mode:
self.log.info("Flag --fast was enabled: skipping full file listing")
if self.module_options.get("fast_mode", None):
self.log.info(
"The `fast_mode` option was enabled: skipping full file listing"
)
else:
self.log.info("Processing full file listing. This may take a while...")
self.find_files("/")

View File

@@ -20,7 +20,7 @@ class Getprop(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -28,7 +28,7 @@ class Getprop(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -18,7 +18,7 @@ class Logcat(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -26,7 +26,7 @@ class Logcat(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -93,7 +93,7 @@ class Packages(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -101,7 +101,7 @@ class Packages(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -351,7 +351,7 @@ class Packages(AndroidExtraction):
result["timestamp"],
)
if not self.fast_mode:
if not self.module_options.get("fast_mode", None):
self.check_virustotal(packages_to_lookup)
self.log.info(

View File

@@ -17,7 +17,7 @@ class Processes(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,7 +25,7 @@ class Processes(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -17,7 +17,7 @@ class RootBinaries(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,11 +25,16 @@ class RootBinaries(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
def check_indicators(self) -> None:
for root_binary in self.results:
self.detected.append(root_binary)
self.log.warning('Found root binary "%s"', root_binary)
def run(self) -> None:
root_binaries = [
"su",
@@ -60,7 +65,6 @@ class RootBinaries(AndroidExtraction):
if "which: not found" in output:
continue
self.detected.append(root_binary)
self.log.warning('Found root binary "%s"', root_binary)
self.results.append(root_binary)
self._adb_disconnect()

View File

@@ -19,7 +19,7 @@ class SELinuxStatus(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class SELinuxStatus(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -65,7 +65,7 @@ class Settings(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -73,7 +73,7 @@ class Settings(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -49,7 +49,7 @@ class SMS(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -57,7 +57,7 @@ class SMS(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -24,7 +24,7 @@ class Whatsapp(AndroidExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -32,7 +32,7 @@ class Whatsapp(AndroidExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class AndroidQFModule(MVTModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Union[List[Dict[str, Any]], Dict[str, Any], None] = None,
) -> None:
@@ -27,7 +27,7 @@ class AndroidQFModule(MVTModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysAccessibility(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysAccessibility(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class DumpsysActivities(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class DumpsysActivities(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -17,7 +17,7 @@ class DumpsysAppops(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,7 +25,7 @@ class DumpsysAppops(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -24,7 +24,7 @@ class DumpsysPackages(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[List[Dict[str, Any]]] = None,
) -> None:
@@ -32,7 +32,7 @@ class DumpsysPackages(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -26,7 +26,7 @@ class DumpsysReceivers(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Union[List[Any], Dict[str, Any], None] = None,
) -> None:
@@ -34,7 +34,7 @@ class DumpsysReceivers(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -34,7 +34,7 @@ class Getprop(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -42,7 +42,7 @@ class Getprop(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -17,7 +17,7 @@ class Processes(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,7 +25,7 @@ class Processes(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class Settings(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class Settings(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -26,7 +26,7 @@ class SMS(AndroidQFModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -34,7 +34,7 @@ class SMS(AndroidQFModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -20,7 +20,7 @@ class BackupExtraction(MVTModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -28,7 +28,7 @@ class BackupExtraction(MVTModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -17,7 +17,7 @@ class SMS(BackupExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,7 +25,7 @@ class SMS(BackupExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class Accessibility(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class Accessibility(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class Activities(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class Activities(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class Appops(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class Appops(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -20,7 +20,7 @@ class BugReportModule(MVTModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -28,7 +28,7 @@ class BugReportModule(MVTModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class BatteryDaily(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class BatteryDaily(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -19,7 +19,7 @@ class BatteryHistory(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -27,7 +27,7 @@ class BatteryHistory(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -21,7 +21,7 @@ class DBInfo(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -29,7 +29,7 @@ class DBInfo(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -20,7 +20,7 @@ class Getprop(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -28,7 +28,7 @@ class Getprop(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -24,7 +24,7 @@ class Packages(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -32,7 +32,7 @@ class Packages(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class Receivers(BugReportModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class Receivers(BugReportModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -339,6 +339,17 @@ def parse_dumpsys_appops(output: str) -> List[Dict[str, Any]]:
if line.startswith(" Uid "):
uid = line[6:-1]
if entry:
perm["entries"].append(entry)
entry = {}
if package:
if perm:
package["permissions"].append(perm)
perm = {}
results.append(package)
package = {}
continue
if line.startswith(" Package "):
@@ -360,7 +371,7 @@ def parse_dumpsys_appops(output: str) -> List[Dict[str, Any]]:
}
continue
if line.startswith(" ") and line[6] != " ":
if package and line.startswith(" ") and line[6] != " ":
if entry:
perm["entries"].append(entry)
entry = {}

View File

@@ -21,7 +21,7 @@ class CmdCheckIOCS(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
) -> None:
super().__init__(
target_path=target_path,
@@ -29,7 +29,7 @@ class CmdCheckIOCS(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
log=log,
)

View File

@@ -28,7 +28,7 @@ class Command:
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
log: logging.Logger = logging.getLogger(__name__),
) -> None:
@@ -40,9 +40,13 @@ class Command:
self.ioc_files = ioc_files if ioc_files else []
self.module_name = module_name
self.serial = serial
self.fast_mode = fast_mode
self.log = log
# This dictionary can contain options that will be passed down from
# the Command to all modules. This can for example be used to pass
# down a password to decrypt a backup or flags which are need by some modules.
self.module_options = module_options if module_options else {}
# This list will contain all executed modules.
# We can use this to reference e.g. self.executed[0].results.
self.executed = []
@@ -172,7 +176,7 @@ class Command:
m = module(
target_path=self.target_path,
results_path=self.results_path,
fast_mode=self.fast_mode,
module_options=self.module_options,
log=module_logger,
)

View File

@@ -6,8 +6,8 @@
import json
import logging
import os
from typing import Any, Dict, Iterator, List, Optional, Union
from functools import lru_cache
from typing import Any, Dict, Iterator, List, Optional, Union
import ahocorasick
from appdirs import user_data_dir

View File

@@ -37,7 +37,7 @@ class MVTModule:
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[Dict[str, Any]] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Union[List[Dict[str, Any]], Dict[str, Any], None] = None,
) -> None:
@@ -59,7 +59,7 @@ class MVTModule:
self.file_path = file_path
self.target_path = target_path
self.results_path = results_path
self.fast_mode = fast_mode
self.module_options = module_options if module_options else {}
self.log = log
self.indicators = None
self.results = results if results else []

View File

@@ -3,12 +3,12 @@
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import cProfile
import datetime
import hashlib
import logging
import os
import re
import cProfile
from typing import Any, Iterator, Union
from rich.logging import RichHandler

View File

@@ -3,4 +3,4 @@
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
MVT_VERSION = "2.3.0"
MVT_VERSION = "2.4.0"

View File

@@ -219,13 +219,14 @@ def check_backup(
ctx, iocs, output, fast, list_modules, module, hashes, verbose, backup_path
):
set_verbose_logging(verbose)
module_options = {"fast_mode": fast}
cmd = CmdIOSCheckBackup(
target_path=backup_path,
results_path=output,
ioc_files=iocs,
module_name=module,
fast_mode=fast,
module_options=module_options,
hashes=hashes,
)
@@ -269,12 +270,14 @@ def check_backup(
@click.pass_context
def check_fs(ctx, iocs, output, fast, list_modules, module, hashes, verbose, dump_path):
set_verbose_logging(verbose)
module_options = {"fast_mode": fast}
cmd = CmdIOSCheckFS(
target_path=dump_path,
results_path=output,
ioc_files=iocs,
module_name=module,
fast_mode=fast,
module_options=module_options,
hashes=hashes,
)

View File

@@ -22,7 +22,7 @@ class CmdIOSCheckBackup(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
) -> None:
super().__init__(
@@ -31,7 +31,7 @@ class CmdIOSCheckBackup(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
hashes=hashes,
log=log,
)

View File

@@ -22,7 +22,7 @@ class CmdIOSCheckFS(Command):
ioc_files: Optional[list] = None,
module_name: Optional[str] = None,
serial: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
hashes: bool = False,
) -> None:
super().__init__(
@@ -31,7 +31,7 @@ class CmdIOSCheckFS(Command):
ioc_files=ioc_files,
module_name=module_name,
serial=serial,
fast_mode=fast_mode,
module_options=module_options,
hashes=hashes,
log=log,
)

View File

@@ -22,7 +22,7 @@ class BackupInfo(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -30,7 +30,7 @@ class BackupInfo(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -26,7 +26,7 @@ class ConfigurationProfiles(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -34,7 +34,7 @@ class ConfigurationProfiles(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -26,7 +26,7 @@ class Manifest(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -34,7 +34,7 @@ class Manifest(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -91,19 +91,6 @@ class Manifest(IOSExtraction):
if not result.get("relative_path"):
continue
if result["domain"]:
if (
os.path.basename(result["relative_path"])
== "com.apple.CrashReporter.plist"
and result["domain"] == "RootDomain"
):
self.log.warning(
"Found a potentially suspicious "
'"com.apple.CrashReporter.plist" file created in RootDomain'
)
self.detected.append(result)
continue
if not self.indicators:
continue

View File

@@ -27,7 +27,7 @@ class ProfileEvents(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class ProfileEvents(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -23,7 +23,7 @@ class IOSExtraction(MVTModule):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -31,7 +31,7 @@ class IOSExtraction(MVTModule):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -27,7 +27,7 @@ class Analytics(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class Analytics(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -23,7 +23,7 @@ class AnalyticsIOSVersions(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -31,7 +31,7 @@ class AnalyticsIOSVersions(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -17,7 +17,7 @@ class CacheFiles(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -25,7 +25,7 @@ class CacheFiles(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -22,7 +22,7 @@ class Filesystem(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -30,7 +30,7 @@ class Filesystem(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -57,7 +57,7 @@ class Filesystem(IOSExtraction):
self.detected.append(result)
# If we are instructed to run fast, we skip the rest.
if self.fast_mode:
if self.module_options.get("fast_mode", None):
continue
ioc = self.indicators.check_file_path_process(result["path"])

View File

@@ -27,7 +27,7 @@ class Netusage(NetBase):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class Netusage(NetBase):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class SafariFavicon(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class SafariFavicon(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -23,7 +23,7 @@ class ShutdownLog(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -31,7 +31,7 @@ class ShutdownLog(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class IOSVersionHistory(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class IOSVersionHistory(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -27,7 +27,7 @@ class WebkitIndexedDB(WebkitBase):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class WebkitIndexedDB(WebkitBase):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class WebkitLocalStorage(WebkitBase):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class WebkitLocalStorage(WebkitBase):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class WebkitSafariViewService(WebkitBase):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class WebkitSafariViewService(WebkitBase):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -27,7 +27,7 @@ class Applications(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class Applications(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class Calendar(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class Calendar(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -5,7 +5,7 @@
import logging
import sqlite3
from typing import Union
from typing import Union, Optional
from mvt.common.utils import convert_mactime_to_iso
@@ -25,7 +25,7 @@ class Calls(IOSExtraction):
file_path: str = None,
target_path: str = None,
results_path: str = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: list = [],
) -> None:
@@ -33,7 +33,7 @@ class Calls(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -26,7 +26,7 @@ class ChromeFavicon(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -34,7 +34,7 @@ class ChromeFavicon(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class ChromeHistory(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class ChromeHistory(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -25,7 +25,7 @@ class Contacts(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -33,7 +33,7 @@ class Contacts(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -27,7 +27,7 @@ class FirefoxFavicon(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class FirefoxFavicon(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -31,7 +31,7 @@ class FirefoxHistory(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -39,7 +39,7 @@ class FirefoxHistory(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -29,7 +29,7 @@ class IDStatusCache(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -37,7 +37,7 @@ class IDStatusCache(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -221,7 +221,7 @@ class InteractionC(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -229,7 +229,7 @@ class InteractionC(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class LocationdClients(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class LocationdClients(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class Datausage(NetBase):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class Datausage(NetBase):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class OSAnalyticsADDaily(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class OSAnalyticsADDaily(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -29,7 +29,7 @@ class SafariBrowserState(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -37,7 +37,7 @@ class SafariBrowserState(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -32,7 +32,7 @@ class SafariHistory(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -40,7 +40,7 @@ class SafariHistory(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -30,7 +30,7 @@ class Shortcuts(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -38,7 +38,7 @@ class Shortcuts(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class SMS(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,22 +36,38 @@ class SMS(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
def serialize(self, record: dict) -> Union[dict, list]:
text = record["text"].replace("\n", "\\n")
return {
"timestamp": record["isodate"],
"module": self.__class__.__name__,
"event": "sms_received",
"data": f"{record['service']}: {record['guid']} \"{text}\" "
f"from {record['phone_number']} ({record['account']})",
}
sms_data = f"{record['service']}: {record['guid']} \"{text}\" from {record['phone_number']} ({record['account']})"
return [
{
"timestamp": record["isodate"],
"module": self.__class__.__name__,
"event": "sms_received",
"data": sms_data,
},
{
"timestamp": record["isodate_read"],
"module": self.__class__.__name__,
"event": "sms_read",
"data": sms_data,
},
]
def check_indicators(self) -> None:
for message in self.results:
alert = "ALERT: State-sponsored attackers may be targeting your iPhone"
if message.get("text", "").startswith(alert):
self.log.warning(
"Apple warning about state-sponsored attack received on the %s",
message["isodate"],
)
if not self.indicators:
return
@@ -120,6 +136,7 @@ class SMS(IOSExtraction):
# We convert Mac's ridiculous timestamp format.
message["isodate"] = convert_mactime_to_iso(message["date"])
message["isodate_read"] = convert_mactime_to_iso(message["date_read"])
message["direction"] = (
"sent" if message.get("is_from_me", 0) == 1 else "received"
)
@@ -128,17 +145,9 @@ class SMS(IOSExtraction):
if not message.get("text", None):
message["text"] = ""
alert = "ALERT: State-sponsored attackers may be targeting your iPhone"
if message.get("text", "").startswith(alert):
self.log.warning(
"Apple warning about state-sponsored attack received on the %s",
message["isodate"],
)
else:
# Extract links from the SMS message.
message_links = check_for_links(message.get("text", ""))
message["links"] = message_links
# Extract links from the SMS message.
message_links = check_for_links(message.get("text", ""))
message["links"] = message_links
self.results.append(message)
cur.close()

View File

@@ -28,7 +28,7 @@ class SMSAttachments(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class SMSAttachments(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -54,6 +54,20 @@ class SMSAttachments(IOSExtraction):
f"has_user_info: {record['has_user_info']})",
}
def check_indicators(self) -> None:
for attachment in self.results:
if (
attachment["filename"].startswith("/var/tmp/")
and attachment["filename"].endswith("-1")
and attachment["direction"] == "received"
):
self.log.warning(
"Suspicious iMessage attachment %s on %s",
attachment["filename"],
attachment["isodate"],
)
self.detected.append(attachment)
def run(self) -> None:
self._find_ios_database(backup_ids=SMS_BACKUP_IDS, root_paths=SMS_ROOT_PATHS)
self.log.info("Found SMS database at path: %s", self.file_path)
@@ -101,19 +115,6 @@ class SMSAttachments(IOSExtraction):
attachment["has_user_info"] = attachment["user_info"] is not None
attachment["service"] = attachment["service"] or "Unknown"
attachment["filename"] = attachment["filename"] or "NULL"
if (
attachment["filename"].startswith("/var/tmp/")
and attachment["filename"].endswith("-1")
and attachment["direction"] == "received"
):
self.log.warning(
"Suspicious iMessage attachment %s on %s",
attachment["filename"],
attachment["isodate"],
)
self.detected.append(attachment)
self.results.append(attachment)
cur.close()

View File

@@ -49,7 +49,7 @@ class TCC(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -57,7 +57,7 @@ class TCC(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -28,7 +28,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -36,7 +36,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)
@@ -58,7 +58,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
if not self.indicators:
return
self.detected = {}
self.detected = []
for result in self.results:
ioc = self.indicators.check_domain(result["registrable_domain"])
if ioc:

View File

@@ -36,7 +36,7 @@ class WebkitSessionResourceLog(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -44,7 +44,7 @@ class WebkitSessionResourceLog(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

View File

@@ -27,7 +27,7 @@ class Whatsapp(IOSExtraction):
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
fast_mode: bool = False,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
@@ -35,7 +35,7 @@ class Whatsapp(IOSExtraction):
file_path=file_path,
target_path=target_path,
results_path=results_path,
fast_mode=fast_mode,
module_options=module_options,
log=log,
results=results,
)

Some files were not shown because too many files have changed in this diff Show More