1
mirror of https://github.com/mvt-project/mvt synced 2025-10-21 22:42:15 +02:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Donncha Ó Cearbhaill
ac157a4421 WIP: Add inital scoffolding for multiple alerting levels in MVT 2023-11-28 13:38:58 +01:00
Rory Flynn
fb52f73556 Automatically add issues to development board (#428) 2023-11-27 14:10:54 +01:00
r-tx
acc950377f docker tweaks (#424)
Co-authored-by: r-tx <r-tx@users.noreply.github.com>
2023-11-27 12:53:03 +01:00
Rory Flynn
c8a0327768 Allow PR coverage comment to fail if running on a fork (#427) 2023-11-27 12:39:18 +01:00
Rory Flynn
1d075abde9 Make MVTModule.get_slug() a classmethod (#418) 2023-11-22 10:37:38 +01:00
7 changed files with 171 additions and 11 deletions

View File

@@ -0,0 +1,19 @@
name: Add issue to project
on:
issues:
types:
- opened
- reopened
jobs:
add-to-project:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v0.5.0
with:
# You can target a project in a different organization
# to the issue
project-url: https://github.com/orgs/mvt-project/projects/1
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}

View File

@@ -42,8 +42,9 @@ jobs:
- name: Test with pytest and coverage
run: pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=mvt tests/ | tee pytest-coverage.txt
- name: Pytest coverage comment
continue-on-error: true # Workflows running on a fork can't post comments
uses: MishaKav/pytest-coverage-comment@main
if: github.event_name == 'pull_request'
with:
pytest-coverage-path: ./pytest-coverage.txt
junitxml-path: ./pytest.xml
junitxml-path: ./pytest.xml

View File

@@ -57,12 +57,12 @@ RUN git clone https://github.com/libimobiledevice/libplist \
# Installing MVT
# --------------
RUN pip3 install mvt
RUN pip3 install git+https://github.com/mvt-project/mvt.git@main
# Installing ABE
# --------------
RUN mkdir /opt/abe \
&& wget https://github.com/nelenkov/android-backup-extractor/releases/download/20210709062403-4c55371/abe.jar -O /opt/abe/abe.jar \
&& wget https://github.com/nelenkov/android-backup-extractor/releases/download/master-20221109063121-8fdfc5e/abe.jar -O /opt/abe/abe.jar \
# Create alias for abe
&& echo 'alias abe="java -jar /opt/abe/abe.jar"' >> ~/.bashrc

138
mvt/common/alerting.py Normal file
View File

@@ -0,0 +1,138 @@
# 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 enum import Enum
class AlertLevel(Enum):
"""
informational: Rule is intended for enrichment of events, e.g. by tagging them. No case or alerting should be triggered by such rules because it is expected that a huge amount of events will match these rules.
low: Notable event but rarely an incident. Low rated events can be relevant in high numbers or combination with others. Immediate reaction shouldnt be necessary, but a regular review is recommended.
medium: Relevant event that should be reviewed manually on a more frequent basis.
high: Relevant event that should trigger an internal alert and requires a prompt review.
critical: Highly relevant event that indicates an incident. Critical events should be reviewed immediately.
"""
INFORMATIONAL = 0
LOW = 10
MEDIUM = 20
HIGH = 30
CRITICAL = 40
class AlertStore(object):
"""
Track all of the alerts and detections generated during an analysis.
Results can be logged as log messages or in JSON format for processing by other tools.
"""
def __init__(self) -> None:
self.alerts = []
def add_alert(
self, level, message=None, event_time=None, event=None, ioc=None, detected=True
):
"""
Add an alert to the alert store.
"""
self.alerts.append(
Alert(
level=level,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
)
def informational(
self, message=None, event_time=None, event=None, ioc=None, detected=False
):
self.add_alert(
AlertLevel.INFORMATIONAL,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
def low(self, message=None, event_time=None, event=None, ioc=None, detected=False):
self.add_alert(
AlertLevel.LOW,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
def medium(
self, message=None, event_time=None, event=None, ioc=None, detected=False
):
self.add_alert(
AlertLevel.MEDIUM,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
def high(self, message=None, event_time=None, event=None, ioc=None, detected=False):
self.add_alert(
AlertLevel.HIGH,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
def critical(
self, message=None, event_time=None, event=None, ioc=None, detected=False
):
self.add_alert(
AlertLevel.CRITICAL,
message=message,
event_time=event_time,
event=event,
ioc=ioc,
detected=detected,
)
class Alert(object):
"""
An alert generated by an MVT module.
"""
def __init__(self, level, message, event_time, event, ioc, detected):
self.level = level
self.message = message
self.event_time = event_time
self.event = event
self.ioc = ioc
self.detected = detected
def __repr__(self):
return f"<Alert level={self.level} message={self.message} event_time={self.event_time} event={self.event}>"
def __str__(self):
return f"{self.level} {self.message} {self.event_time} {self.event}"
def to_log(self):
return f"{self.level} {self.message} {self.event_time} {self.event}"
def to_json(self):
return {
"level": self.level,
"message": self.message,
"event_time": self.event_time,
"event": self.event,
"ioc": self.ioc,
"detected": self.detected,
}

View File

@@ -53,7 +53,7 @@ class CmdCheckIOCS(Command):
if self.module_name and iocs_module.__name__ != self.module_name:
continue
if iocs_module().get_slug() != name_only:
if iocs_module.get_slug() != name_only:
continue
log.info(

View File

@@ -74,12 +74,13 @@ class MVTModule:
log.info('Loaded %d results from "%s"', len(results), json_path)
return cls(results=results, log=log)
def get_slug(self) -> str:
@classmethod
def get_slug(cls) -> str:
"""Use the module's class name to retrieve a slug"""
if self.slug:
return self.slug
if cls.slug:
return cls.slug
sub = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", self.__class__.__name__)
sub = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", cls.__name__)
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", sub).lower()
def check_indicators(self) -> None:

View File

@@ -63,9 +63,10 @@ class SMS(IOSExtraction):
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"],
self.alerts.medium(
f"Apple warning about state-sponsored attack received on the {message['isodate']}",
event_time=message["isodate"],
event=message,
)
if not self.indicators: