Compare commits

...

11 Commits

Author SHA1 Message Date
Nex
9be393e3f6 Bumped version 2021-10-14 19:59:09 +02:00
Nex
5f125974b8 Upgraded adb-shell 2021-10-14 10:10:38 +02:00
Nex
aa0f152ba1 Merge branch 'main' of github.com:mvt-project/mvt 2021-10-12 18:07:44 +02:00
Nex
169f5fbc26 Pyment to reST 2021-10-12 18:06:58 +02:00
tek
5ea3460c09 Minor documentation update 2021-10-12 12:20:50 +02:00
Nex
c38df37967 Merge pull request #183 from l0s/libimobiledevice-glue_not-found
Install libimobiledevice-glue from source
2021-10-11 11:13:18 +02:00
Nex
7f29b522fa Merge pull request #202 from vin01/main
Specify public key for PythonRSASigner
2021-10-11 11:12:27 +02:00
vin01
40b0da9885 Specify public key for PythonRSASigner 2021-10-08 21:36:49 +02:00
tek
94a8d9dd91 Fixes bug in adb handling 2021-09-29 18:16:33 +02:00
tek
963d3db51a Fixes a bug in android packages module 2021-09-29 17:59:50 +02:00
Carlos Macasaet
f4ba29f1ef Install libimobiledevice-glue from source
This installs libimobiledevice-glue from source as it appears it is no
longer available to `apt-get`.

Resolves: #182
2021-09-12 18:28:17 -07:00
11 changed files with 46 additions and 16 deletions

View File

@@ -38,12 +38,15 @@ RUN apt update \
# Build libimobiledevice
# ----------------------
RUN git clone https://github.com/libimobiledevice/libplist \
&& git clone https://github.com/libimobiledevice/libimobiledevice-glue \
&& git clone https://github.com/libimobiledevice/libusbmuxd \
&& git clone https://github.com/libimobiledevice/libimobiledevice \
&& git clone https://github.com/libimobiledevice/usbmuxd \
&& cd libplist && ./autogen.sh && make && make install && ldconfig \
&& cd ../libimobiledevice-glue && PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./autogen.sh --prefix=/usr && make && make install && ldconfig \
&& cd ../libusbmuxd && PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./autogen.sh && make && make install && ldconfig \
&& cd ../libimobiledevice && PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./autogen.sh --enable-debug && make && make install && ldconfig \
@@ -51,7 +54,7 @@ RUN git clone https://github.com/libimobiledevice/libplist \
&& cd ../usbmuxd && PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --runstatedir=/run && make && make install \
# Clean up.
&& cd .. && rm -rf libplist libusbmuxd libimobiledevice usbmuxd
&& cd .. && rm -rf libplist libimobiledevice-glue libusbmuxd libimobiledevice usbmuxd
# Installing MVT
# --------------

View File

@@ -22,7 +22,7 @@ adb backup -all
## Unpack the backup
In order to reliable unpack th [Android Backup Extractor (ABE)](https://github.com/nelenkov/android-backup-extractor) to convert it to a readable file format. Make sure that java is installed on your system and use the following command:
In order to unpack the backup, use [Android Backup Extractor (ABE)](https://github.com/nelenkov/android-backup-extractor) to convert it to a readable file format. Make sure that java is installed on your system and use the following command:
```bash
java -jar ~/path/to/abe.jar unpack backup.ab backup.tar
@@ -31,6 +31,8 @@ tar xvf backup.tar
If the backup is encrypted, ABE will prompt you to enter the password.
Alternatively, [ab-decrypt](https://github.com/joernheissler/ab-decrypt) can be used for that purpose.
## Check the backup
You can then extract SMSs containing links with MVT:

View File

@@ -32,5 +32,6 @@ mvt-ios check-backup --iocs ~/iocs/malware1.stix --iocs ~/iocs/malware2.stix2 /p
- The [Amnesty International investigations repository](https://github.com/AmnestyTech/investigations) contains STIX-formatted IOCs for:
- [Pegasus](https://en.wikipedia.org/wiki/Pegasus_(spyware)) ([STIX2](https://raw.githubusercontent.com/AmnestyTech/investigations/master/2021-07-18_nso/pegasus.stix2))
- [This repository](https://github.com/Te-k/stalkerware-indicators) contains IOCs for Android stalkerware including [a STIX MVT-compatible file](https://github.com/Te-k/stalkerware-indicators/blob/master/stalkerware.stix2).
Please [open an issue](https://github.com/mvt-project/mvt/issues/) to suggest new sources of STIX-formatted IOCs.

View File

@@ -41,7 +41,7 @@ class AndroidExtraction(MVTModule):
def _adb_check_keys():
"""Make sure Android adb keys exist."""
if not os.path.isdir(os.path.dirname(ADB_KEY_PATH)):
os.path.makedirs(os.path.dirname(ADB_KEY_PATH))
os.makedirs(os.path.dirname(ADB_KEY_PATH))
if not os.path.exists(ADB_KEY_PATH):
keygen(ADB_KEY_PATH)
@@ -56,7 +56,10 @@ class AndroidExtraction(MVTModule):
with open(ADB_KEY_PATH, "rb") as handle:
priv_key = handle.read()
signer = PythonRSASigner("", priv_key)
with open(ADB_PUB_KEY_PATH, "rb") as handle:
pub_key = handle.read()
signer = PythonRSASigner(pub_key, priv_key)
# If no serial was specified or if the serial does not seem to be
# a HOST:PORT definition, we use the USB transport.

View File

@@ -41,6 +41,9 @@ class Packages(AndroidExtraction):
return records
def check_indicators(self):
if not self.indicators:
return
root_packages_path = os.path.join("..", "..", "data", "root_packages.txt")
root_packages_string = pkg_resources.resource_string(__name__, root_packages_path)
root_packages = root_packages_string.decode("utf-8").split("\n")

View File

@@ -15,6 +15,8 @@ class IndicatorsFileBadFormat(Exception):
class Indicators:
"""This class is used to parse indicators from a STIX2 file and provide
functions to compare extracted artifacts to the indicators.
"""
def __init__(self, log=None):
@@ -37,6 +39,7 @@ class Indicators:
:param file_path: Path to the STIX2 file to parse
:type file_path: str
"""
self.log.info("Parsing STIX2 indicators file at path %s",
file_path)
@@ -82,6 +85,7 @@ class Indicators:
:type url: str
:returns: True if the URL matched an indicator, otherwise False
:rtype: bool
"""
# TODO: If the IOC domain contains a subdomain, it is not currently
# being matched.
@@ -153,6 +157,7 @@ class Indicators:
:type urls: list
:returns: True if any URL matched an indicator, otherwise False
:rtype: bool
"""
if not urls:
return False
@@ -171,6 +176,7 @@ class Indicators:
:type process: str
:returns: True if process matched an indicator, otherwise False
:rtype: bool
"""
if not process:
return False
@@ -196,6 +202,7 @@ class Indicators:
:type processes: list
:returns: True if process matched an indicator, otherwise False
:rtype: bool
"""
if not processes:
return False
@@ -213,6 +220,7 @@ class Indicators:
:type email: str
:returns: True if email address matched an indicator, otherwise False
:rtype: bool
"""
if not email:
return False
@@ -231,6 +239,7 @@ class Indicators:
:type file_path: str
:returns: True if the file path matched an indicator, otherwise False
:rtype: bool
"""
if not file_path:
return False

View File

@@ -23,8 +23,7 @@ class InsufficientPrivileges(Exception):
pass
class MVTModule(object):
"""This class provides a base for all extraction modules.
"""
"""This class provides a base for all extraction modules."""
enabled = True
slug = None
@@ -66,8 +65,7 @@ class MVTModule(object):
return cls(results=results, log=log)
def get_slug(self):
"""Use the module's class name to retrieve a slug
"""
"""Use the module's class name to retrieve a slug"""
if self.slug:
return self.slug
@@ -77,12 +75,13 @@ class MVTModule(object):
def check_indicators(self):
"""Check the results of this module against a provided list of
indicators.
"""
raise NotImplementedError
def save_to_json(self):
"""Save the collected results to a json file.
"""
"""Save the collected results to a json file."""
if not self.output_folder:
return
@@ -112,6 +111,7 @@ class MVTModule(object):
"""Serialize entry as JSON to deduplicate repeated entries
:param timeline: List of entries from timeline to deduplicate
"""
timeline_set = set()
for record in timeline:
@@ -141,8 +141,7 @@ class MVTModule(object):
self.timeline_detected = self._deduplicate_timeline(self.timeline_detected)
def run(self):
"""Run the main module procedure.
"""
"""Run the main module procedure."""
raise NotImplementedError
@@ -190,6 +189,7 @@ def save_timeline(timeline, timeline_path):
:param timeline: List of records to order and store
:param timeline_path: Path to the csv file to store the timeline to
"""
with io.open(timeline_path, "a+", encoding="utf-8") as handle:
csvoutput = csv.writer(handle, delimiter=",", quotechar="\"")

View File

@@ -268,6 +268,7 @@ class URL:
:type url: str
:returns: Domain name extracted from URL
:rtype: str
"""
# TODO: Properly handle exception.
try:
@@ -282,6 +283,7 @@ class URL:
:type url: str
:returns: Top-level domain name extracted from URL
:rtype: str
"""
# TODO: Properly handle exception.
try:
@@ -292,8 +294,11 @@ class URL:
def check_if_shortened(self) -> bool:
"""Check if the URL is among list of shortener services.
:returns: True if the URL is shortened, otherwise False
:rtype: bool
"""
if self.domain.lower() in SHORTENER_DOMAINS:
self.is_shortened = True
@@ -301,8 +306,7 @@ class URL:
return self.is_shortened
def unshorten(self):
"""Unshorten the URL by requesting an HTTP HEAD response.
"""
"""Unshorten the URL by requesting an HTTP HEAD response."""
res = requests.head(self.url)
if str(res.status_code).startswith("30"):
return res.headers["Location"]

View File

@@ -16,6 +16,7 @@ def convert_mactime_to_unix(timestamp, from_2001=True):
:param from_2001: bool: Whether to (Default value = True)
:param from_2001: Default value = True)
:returns: Unix epoch timestamp.
"""
if not timestamp:
return None
@@ -42,6 +43,7 @@ def convert_chrometime_to_unix(timestamp):
:param timestamp: Chrome timestamp as int.
:type timestamp: int
:returns: Unix epoch timestamp.
"""
epoch_start = datetime.datetime(1601, 1 , 1)
delta = datetime.timedelta(microseconds=timestamp)
@@ -55,6 +57,7 @@ def convert_timestamp_to_iso(timestamp):
:type timestamp: int
:returns: ISO timestamp string in YYYY-mm-dd HH:MM:SS.ms format.
:rtype: str
"""
try:
return timestamp.strftime("%Y-%m-%d %H:%M:%S.%f")
@@ -67,6 +70,7 @@ def check_for_links(text):
:param text: Any provided text.
:type text: str
:returns: Search results.
"""
return re.findall("(?P<url>https?://[^\s]+)", text, re.IGNORECASE)
@@ -92,6 +96,7 @@ def keys_bytes_to_string(obj):
:param obj: Object to convert from bytes to string.
:returns: Object converted to string.
:rtype: str
"""
new_obj = {}
if not isinstance(obj, dict):

View File

@@ -6,7 +6,7 @@
import requests
from packaging import version
MVT_VERSION = "1.2.10"
MVT_VERSION = "1.2.11"
def check_for_updates():
res = requests.get("https://pypi.org/pypi/mvt/json")

View File

@@ -26,7 +26,7 @@ requires = (
# iOS dependencies:
"iOSbackup>=0.9.912",
# Android dependencies:
"adb-shell>=0.4.0",
"adb-shell>=0.4.1",
"libusb1>=1.9.3",
)