Compare commits

...
9 changed files with 86 additions and 21 deletions

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
name: Add issue to project name: Add issue to project
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/add-to-project@v0.5.0 - uses: actions/add-to-project@v2
with: with:
# You can target a project in a different organization # You can target a project in a different organization
# to the issue # to the issue
+3 -3
View File
@@ -11,13 +11,13 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: "3.10" python-version: "3.10"
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v10.0.0
with: with:
enable-cache: true enable-cache: true
- name: Install Dependencies - name: Install Dependencies
+5 -6
View File
@@ -36,10 +36,10 @@ jobs:
tag-suffix: "-android" tag-suffix: "-android"
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -47,7 +47,7 @@ jobs:
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: | flavor: |
@@ -61,13 +61,13 @@ jobs:
type=sha,format=long,suffix=${{ matrix.platform.tag-suffix }} type=sha,format=long,suffix=${{ matrix.platform.tag-suffix }}
# This step sets up some additional capabilities to generate the provenance and sbom attestations # This step sets up some additional capabilities to generate the provenance and sbom attestations
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v4
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
- name: Build and push Docker image - name: Build and push Docker image
id: push id: push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v7
with: with:
file: ${{ matrix.platform.dockerfile }} file: ${{ matrix.platform.dockerfile }}
context: . context: .
@@ -76,4 +76,3 @@ jobs:
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
provenance: mode=max provenance: mode=max
sbom: true sbom: true
+3 -3
View File
@@ -12,13 +12,13 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: "3.10" python-version: "3.10"
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v10.0.0
with: with:
enable-cache: true enable-cache: true
- name: Install Dependencies - name: Install Dependencies
+3 -3
View File
@@ -15,13 +15,13 @@ jobs:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v10.0.0
with: with:
enable-cache: true enable-cache: true
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6 uses: actions/setup-python@v7
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install Python dependencies - name: Install Python dependencies
+2 -2
View File
@@ -11,8 +11,8 @@ jobs:
update-ios-version: update-ios-version:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- uses: actions/setup-python@v6 - uses: actions/setup-python@v7
- name: Install script dependencies - name: Install script dependencies
run: python -m pip install "packaging==26.3" run: python -m pip install "packaging==26.3"
- name: Run script to fetch latest iOS releases from Apple RSS feed. - name: Run script to fetch latest iOS releases from Apple RSS feed.
+26 -3
View File
@@ -4,7 +4,7 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import re import re
from typing import Any, Dict, List from typing import Any, Dict, List, Optional
from mvt.android.utils import ROOT_PACKAGES from mvt.android.utils import ROOT_PACKAGES
from mvt.common.module_types import ModuleAtomicResult, ModuleSerializedResult from mvt.common.module_types import ModuleAtomicResult, ModuleSerializedResult
@@ -71,6 +71,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
"timestamp": "", "timestamp": "",
"first_install_time": "", "first_install_time": "",
"last_update_time": "", "last_update_time": "",
"installer": "",
"permissions": list(), "permissions": list(),
"requested_permissions": list(), "requested_permissions": list(),
} }
@@ -78,7 +79,14 @@ class DumpsysPackagesArtifact(AndroidArtifact):
in_runtime_permissions = False in_runtime_permissions = False
in_declared_permissions = False in_declared_permissions = False
in_requested_permissions = True in_requested_permissions = True
current_user: Optional[int] = None
first_install_times: Dict[Optional[int], str] = {}
runtime_permissions: Dict[Optional[int], List[Dict[str, Any]]] = {}
for line in output.splitlines(): for line in output.splitlines():
user_match = re.match(r"User (\d+):", line.strip())
if user_match:
current_user = int(user_match.group(1))
if in_install_permissions: if in_install_permissions:
if line.startswith(" " * 4) and not line.startswith(" " * 6): if line.startswith(" " * 4) and not line.startswith(" " * 6):
in_install_permissions = False in_install_permissions = False
@@ -102,7 +110,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
if "granted=" in lineinfo[1]: if "granted=" in lineinfo[1]:
granted = "granted=true" in lineinfo[1] granted = "granted=true" in lineinfo[1]
details["permissions"].append( runtime_permissions.setdefault(current_user, []).append(
{"name": permission, "granted": granted, "type": "runtime"} {"name": permission, "granted": granted, "type": "runtime"}
) )
if in_declared_permissions: if in_declared_permissions:
@@ -126,8 +134,10 @@ class DumpsysPackagesArtifact(AndroidArtifact):
details["version_code"] = line.split("=", 1)[1].strip() details["version_code"] = line.split("=", 1)[1].strip()
elif line.strip().startswith("timeStamp="): elif line.strip().startswith("timeStamp="):
details["timestamp"] = line.split("=")[1].strip() details["timestamp"] = line.split("=")[1].strip()
elif line.strip().startswith("installerPackageName="):
details["installer"] = line.split("=", 1)[1].strip()
elif line.strip().startswith("firstInstallTime="): elif line.strip().startswith("firstInstallTime="):
details["first_install_time"] = line.split("=")[1].strip() first_install_times[current_user] = line.split("=", 1)[1].strip()
elif line.strip().startswith("lastUpdateTime="): elif line.strip().startswith("lastUpdateTime="):
details["last_update_time"] = line.split("=")[1].strip() details["last_update_time"] = line.split("=")[1].strip()
elif line.strip() == "install permissions:": elif line.strip() == "install permissions:":
@@ -139,6 +149,19 @@ class DumpsysPackagesArtifact(AndroidArtifact):
elif line.strip() == "requested permissions:": elif line.strip() == "requested permissions:":
in_requested_permissions = True in_requested_permissions = True
if 0 in first_install_times:
details["first_install_time"] = first_install_times[0]
elif None in first_install_times:
details["first_install_time"] = first_install_times[None]
elif first_install_times:
details["first_install_time"] = next(iter(first_install_times.values()))
if 0 in runtime_permissions:
details["permissions"].extend(runtime_permissions[0])
elif None in runtime_permissions:
details["permissions"].extend(runtime_permissions[None])
elif runtime_permissions:
details["permissions"].extend(next(iter(runtime_permissions.values())))
return details return details
def parse_dumpsys_packages(self, output: str) -> List[Dict[str, Any]]: def parse_dumpsys_packages(self, output: str) -> List[Dict[str, Any]]:
@@ -25,6 +25,7 @@ class TestDumpsysPackagesArtifact:
== "com.samsung.android.provider.filterprovider" == "com.samsung.android.provider.filterprovider"
) )
assert dpa.results[0]["version_name"] == "5.0.07" assert dpa.results[0]["version_name"] == "5.0.07"
assert dpa.results[0]["first_install_time"] == "2008-12-31 16:00:00"
def test_ioc_check(self, indicator_file): def test_ioc_check(self, indicator_file):
dpa = DumpsysPackagesArtifact() dpa = DumpsysPackagesArtifact()
@@ -40,3 +41,43 @@ class TestDumpsysPackagesArtifact:
assert len(dpa.alertstore.alerts) == 0 assert len(dpa.alertstore.alerts) == 0
dpa.check_indicators() dpa.check_indicators()
assert len(dpa.alertstore.alerts) == 1 assert len(dpa.alertstore.alerts) == 1
def test_per_user_fields_use_primary_user(self):
details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
""" User 0: installed=true
firstInstallTime=2024-01-10 09:19:39
runtime permissions:
android.permission.CAMERA: granted=true
User 95: installed=false
firstInstallTime=1970-01-01 01:00:00
runtime permissions:
android.permission.CAMERA: granted=false
android.permission.RECORD_AUDIO: granted=false
"""
)
assert details["first_install_time"] == "2024-01-10 09:19:39"
runtime_permissions = [
permission
for permission in details["permissions"]
if permission["type"] == "runtime"
]
assert runtime_permissions == [
{
"name": "android.permission.CAMERA",
"granted": True,
"type": "runtime",
}
]
def test_per_user_fields_fall_back_when_user_zero_is_missing(self):
details = DumpsysPackagesArtifact.parse_dumpsys_package_for_details(
""" User 10: installed=true
firstInstallTime=2024-02-10 09:19:39
runtime permissions:
android.permission.CAMERA: granted=true
"""
)
assert details["first_install_time"] == "2024-02-10 09:19:39"
assert details["permissions"][-1]["name"] == "android.permission.CAMERA"
@@ -54,6 +54,8 @@ class TestBugreportAnalysis:
== "com.samsung.android.provider.filterprovider" == "com.samsung.android.provider.filterprovider"
) )
assert m.results[1]["package_name"] == "com.instagram.android" assert m.results[1]["package_name"] == "com.instagram.android"
assert m.results[0]["installer"] == ""
assert m.results[1]["installer"] == "com.android.vending"
assert len(m.results[0]["permissions"]) == 4 assert len(m.results[0]["permissions"]) == 4
assert len(m.results[1]["permissions"]) == 32 assert len(m.results[1]["permissions"]) == 32