Compare commits

...
Author SHA1 Message Date
Janik Besendorf 4fb6260c56 Fix intrusion log event ID parsing 2026-06-11 17:11:15 +02:00
besendorf 1e67a343ca Document network access options (#808) 2026-06-05 20:27:42 +02:00
tesandbesendorf 0a8da50c2b fix: enforce NETWORK_ACCESS_ALLOWED and timeout on URL.unshorten (#800)
Co-authored-by: besendorf <janik@besendorf.org>
2026-06-05 20:20:34 +02:00
4 changed files with 87 additions and 2 deletions

No files matched your search

+19 -1
View File
@@ -34,6 +34,25 @@ It is also possible to load STIX2 files automatically from the environment varia
export MVT_STIX2="/home/user/IOC1.stix2:/home/user/IOC2.stix2"
```
## Network Access
When checking URL indicators, MVT follows recognized shortened URLs with an
HTTP `HEAD` request. The following environment variables control these
requests:
- `MVT_NETWORK_ACCESS_ALLOWED` enables or disables network requests. It defaults
to `true`. Set it to `false` to prevent MVT from attempting to resolve
shortened URLs.
- `MVT_NETWORK_TIMEOUT` sets the request timeout in seconds. It defaults to
`15`.
For example, to run IOC checks without resolving shortened URLs:
```bash
MVT_NETWORK_ACCESS_ALLOWED=false mvt-ios check-iocs \
--iocs ~/iocs/malware.stix2 /path/to/iphone/output/
```
## STIX2 Support
So far MVT implements only a subset of [STIX2 specifications](https://docs.oasis-open.org/cti/stix/v2.1/csprd01/stix-v2.1-csprd01.html):
@@ -55,4 +74,3 @@ You can automaticallly download the latest public indicator files with the comma
Please [open an issue](https://github.com/mvt-project/mvt/issues/) to suggest new sources of STIX-formatted IOCs.
@@ -264,6 +264,7 @@ SECURITY_EVENT_TAGS = {
}
SECURITY_EVENT_METADATA_KEYS = {
"event_id",
"event_time",
"event_type",
"timestamp",
+15 -1
View File
@@ -3,11 +3,16 @@
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
import logging
from typing import Optional
import requests
from tld import get_tld
from .config import settings
log = logging.getLogger(__name__)
SHORTENER_DOMAINS = [
"0rz.tw",
"1drv.ms",
@@ -375,7 +380,16 @@ class URL:
def unshorten(self) -> Optional[str]:
"""Unshorten the URL by requesting an HTTP HEAD response."""
res = requests.head(self.url)
if settings.NETWORK_ACCESS_ALLOWED is False:
log.info(
"Network access disabled (MVT_NETWORK_ACCESS_ALLOWED=False), "
"skipping unshorten for %s",
self.url,
)
return ""
res = requests.head(self.url, timeout=settings.NETWORK_TIMEOUT)
if str(res.status_code).startswith("30"):
return res.headers["Location"]
+52
View File
@@ -143,6 +143,58 @@ def test_check_intrusion_logs_parses_core_and_unknown_security_events(
assert "Please open an issue on GitHub" in caplog.text
def test_check_intrusion_logs_treats_event_id_as_security_event_metadata(
tmp_path, caplog
):
_write_ndjson(
tmp_path / "intrusion.txt",
[
{
"security_event": {
"event_id": 191,
"event_time": 1_700_000_002_000_000_000,
"keyguard_dismiss_auth_attempt": {
"success": True,
"method_strength": 0,
},
}
},
{
"security_event": {
"event_id": 192,
"event_time": 1_700_000_003_000_000_000,
"keyguard_dismissed": {},
}
},
],
)
with caplog.at_level(logging.WARNING):
cmd = CmdAndroidCheckIntrusionLogs(target_path=str(tmp_path))
cmd.run()
security_module = next(
module for module in cmd.executed if isinstance(module, SecurityEvent)
)
assert security_module.event_type_counts == {
"keyguard_dismiss_auth_attempt": 1,
"keyguard_dismissed": 1,
}
assert [event["event_id"] for event in security_module.results] == [191, 192]
keyguard_events = {
event["event"]: event
for event in cmd.timeline
if event["event"]
in {"keyguard_dismiss_auth_attempt", "keyguard_dismissed"}
}
assert "Auth attempt: Success" in keyguard_events[
"keyguard_dismiss_auth_attempt"
]["data"]
assert keyguard_events["keyguard_dismissed"]["data"] == "Keyguard dismissed"
assert "unknown intrusion logging security event type(s): event_id" not in caplog.text
def test_check_intrusion_logs_cli_lists_modules(tmp_path):
_write_ndjson(tmp_path / "intrusion.txt", [])