diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 91c0f338a63..83272cb8044 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -439,6 +439,7 @@ - [Android Enterprise Work Profile Bypass](mobile-pentesting/android-app-pentesting/android-enterprise-work-profile-bypass.md) - [Android Hce Nfc Emv Relay Attacks](mobile-pentesting/android-app-pentesting/android-hce-nfc-emv-relay-attacks.md) - [Android Physical Attacks](mobile-pentesting/android-app-pentesting/android-physical-attacks.md) + - [Android SELinux Domains, AVC Denials and Policy Manipulation](mobile-pentesting/android-app-pentesting/android-selinux-domains-and-policy-manipulation.md) - [Android Task Hijacking](mobile-pentesting/android-app-pentesting/android-task-hijacking.md) - [Android VPN Bypass](mobile-pentesting/android-app-pentesting/android-vpn-bypass.md) - [ADB Commands](mobile-pentesting/android-app-pentesting/adb-commands.md) diff --git a/src/mobile-pentesting/android-app-pentesting/README.md b/src/mobile-pentesting/android-app-pentesting/README.md index 4336bcabbff..2049f26ec8e 100644 --- a/src/mobile-pentesting/android-app-pentesting/README.md +++ b/src/mobile-pentesting/android-app-pentesting/README.md @@ -36,6 +36,10 @@ Sometimes it is useful to **modify application code** to access **hidden informa - [Android app-level virtualization / app cloning abuse & detection](android-application-level-virtualization.md) - [Shizuku Privileged API (ADB-based non-root privileged access)](shizuku-privileged-api.md) +{{#ref}} +android-selinux-domains-and-policy-manipulation.md +{{#endref}} + {{#ref}} ../../binary-exploitation/linux-kernel-exploitation/futex-pi-uaf-pipe-buffer-workqueue-usermodehelper.md {{#endref}} diff --git a/src/mobile-pentesting/android-app-pentesting/android-selinux-domains-and-policy-manipulation.md b/src/mobile-pentesting/android-app-pentesting/android-selinux-domains-and-policy-manipulation.md new file mode 100644 index 00000000000..f675a2cce42 --- /dev/null +++ b/src/mobile-pentesting/android-app-pentesting/android-selinux-domains-and-policy-manipulation.md @@ -0,0 +1,190 @@ +# Android SELinux Domains, AVC Denials and Policy Manipulation + +{{#include ../../banners/hacktricks-training.md}} + +Android SELinux is a second authorization boundary after the Linux UID sandbox. The techniques below are for rooted, `userdebug`/`eng`, or otherwise policy-modifiable research devices: they remove MAC restrictions **after** privileged access exists and are not an initial-access exploit.[[9]](#references) + +## From APK identity to process domain + +Android derives an application's process domain and data-file type from two policy inputs. `mac_permissions.xml` maps a signing identity (optionally refined by package name) to `seinfo`; `seapp_contexts` then matches `seinfo` together with selectors such as UID class, package name, privileged/ephemeral status, target SDK, and isolated/SDK-sandbox state. Its `domain` output labels the process, `type` labels the app data directory, and `levelFrom` derives MLS/MCS categories used for per-app separation.[[1]](#references)[[2]](#references)[[9]](#references) + +```text +APK certificate/package + -> mac_permissions.xml -> seinfo + -> seapp_contexts selectors + -> domain (process) + -> type + levelFrom (data directory and categories) +``` + +At installation, PackageManager delegates data-directory labeling to `installd`, which applies the selected object type. At launch, Zygote forks and calls `selinux_android_setcontext()` before application code executes, so the child enters its selected domain while the parent remains `zygote`.[[9]](#references) + +Inspect the effective mapping and runtime labels on the device as follows.[[1]](#references)[[9]](#references) + +```bash +adb shell cat /system/etc/selinux/plat_mac_permissions.xml +adb shell cat /system/etc/selinux/plat_seapp_contexts +adb shell ps -AZ | grep com.example.target +adb shell run-as com.example.target cat /proc/self/attr/current +adb shell ls -Zd /data/user/0/com.example.target # root usually required +``` + +Do not assume that raw line order alone determines the winner on current AOSP. Entries are sorted by a defined specificity precedence and apps are checked until the first match; fixed/longer `user` or `name` selectors outrank prefixes, specified `seinfo` outranks unspecified `seinfo`, and platform entries outrank vendor entries at the final precedence step.[[1]](#references) + +A package-specific mapping can therefore force a research APK into another existing domain on a policy-modifiable image. This changes the SELinux domain and data type, **not** its Linux UID, and the target domain must already exist with suitable policy rules.[[1]](#references)[[9]](#references) + +```text +user=_app seinfo=default name=com.example.research \ + domain=system_app type=system_app_data_file levelFrom=user +``` + +On production images, AVB/dm-verity and partitioned policy normally prevent directly replacing `/system/etc/selinux/plat_seapp_contexts`; use an explicitly modifiable lab image or a root framework's supported boot-time mechanism instead of assuming a remount is sufficient.[[9]](#references) + +## Turn AVC denials into policy tuples + +An AVC record directly describes the rejected tuple: permissions in `{ ... }`, source domain in `scontext`, target type/domain in `tcontext`, and object class in `tclass`. For example, the record below means the `shell` domain lacks `proc_mem:file { open read write }`; `permissive=0` means enforcement blocked the request.[[3]](#references)[[9]](#references) + +```text +avc: denied { open read write } for pid=8821 comm="exploit_poc" name="mem" + scontext=u:r:shell:s0 + tcontext=u:object_r:proc_mem:s0 + tclass=file permissive=0 +``` + +Collect a clean window while reproducing the operation. Availability of kernel logs differs between production and debug builds.[[3]](#references)[[9]](#references) + +```bash +adb shell su -c 'dmesg -w | grep "avc:"' +adb logcat -b all | grep 'avc:' +adb shell su -c 'cat /proc/kmsg' | grep 'avc:' +``` + +If an access fails without a visible AVC, check whether `dontaudit` suppresses it. Android builds of SETools can query the live binary policy; compare these rules with the failing source, target and class, and use a temporary per-domain permissive test only on an isolated lab device to collect the rest of the denial chain.[[8]](#references)[[9]](#references) + +```bash +adb push sesearch /data/local/tmp/ && adb shell chmod 755 /data/local/tmp/sesearch +adb shell /data/local/tmp/sesearch --dontaudit /sys/fs/selinux/policy \ + | grep -E '(^dontaudit shell |^dontaudit untrusted_app )' +adb shell su -c "magiskpolicy --live 'permissive shell'" +# Reproduce, collect AVCs, then restore enforcement: +adb shell su -c "magiskpolicy --live 'enforce shell'" +``` + +`audit2allow` is useful for translating captured denials, but its output is only a starting point: blindly applying it can grant sensitive kernel-memory or device access. Reduce every candidate to the exact source, target, class and permissions required by the PoC.[[3]](#references) + +```bash +adb pull /sys/fs/selinux/policy ./policy +adb logcat -b events -d | audit2allow -p ./policy +``` + +## File types, `chcon` and `restorecon` + +A PoC may have the correct UID and process domain but still fail because its executable or library has the wrong target type. Files copied to `/data/local/tmp` normally acquire a path-defined label such as `shell_data_file`; with root, `chcon` can temporarily select a type for which the caller has `execute`, `entrypoint`, `map`, or read permissions.[[4]](#references)[[9]](#references) + +```bash +adb push exploit_poc /data/local/tmp/ +adb shell su -c 'ls -Z /data/local/tmp/exploit_poc' +adb shell su -c 'chcon u:object_r:shell_exec:s0 /data/local/tmp/exploit_poc' +adb shell su -c 'ls -Z /data/local/tmp/exploit_poc' +``` + +This does not persist against `restorecon`, filesystem relabeling, or boot-time relabel logic. `restorecon` resolves the expected type from merged, regex-based `file_contexts` files, so always record the original label and restore it after testing.[[4]](#references)[[9]](#references) + +```bash +adb shell su -c 'restorecon -v /data/local/tmp/exploit_poc' +adb shell su -c 'cat /system/etc/selinux/plat_file_contexts' | grep '/data/local/tmp' +adb shell su -c 'cat /vendor/etc/selinux/vendor_file_contexts' | grep '/vendor/bin' +``` + +`procfs`, `sysfs` and `debugfs` use `genfscon` path mappings rather than persistent per-inode labels. Adding a mapping only assigns a target type; the test domain still requires the corresponding allow rule and object class.[[5]](#references)[[6]](#references)[[9]](#references) + +```bash +magiskpolicy --live 'genfscon proc /kallsyms u:object_r:proc_kallsyms:s0' +magiskpolicy --live 'allow myexploit_t proc_kallsyms file { open read getattr }' +``` + +## Test another domain with `runcon` + +Changing only the requested context is insufficient. A successful `runcon` test needs (1) caller-to-target `process { transition setexec }`, (2) target-domain `entrypoint` access to the executable type, and (3) permission for the target to use inherited ADB descriptors, sockets and terminal devices. The Linux UID is inherited separately, so `runcon ... id` can report UID 0 in a restricted SELinux domain.[[9]](#references) + +```bash +magiskpolicy --live 'allow magisk system_app process { transition dyntransition setexec }' +magiskpolicy --live 'allow system_app toolbox_exec file { entrypoint execute read open getattr map }' +magiskpolicy --live 'allow system_app adbd fd use' +magiskpolicy --live 'allow system_app adbd unix_stream_socket { read write }' +magiskpolicy --live 'allow system_app devpts chr_file { read write open getattr ioctl }' +adb shell su -c 'runcon u:r:system_app:s0 id' +``` + +Use the resulting context to answer one narrow question at a time, such as whether `cameraserver` can open a GPU node or an app domain can read a specific procfs object. Follow every new AVC rather than broadening the domain globally.[[9]](#references) + +## Live policy changes with `magiskpolicy` + +`magiskpolicy` parses binary/runtime policy and `--live` immediately loads the result into the kernel. Its policy language supports `allow`, `deny` (removing matching allow bits), audit controls, per-type permissive/enforcing state, new types and attributes, transitions, `genfscon`, and ioctl extended permissions.[[6]](#references)[[9]](#references) + +```bash +magiskpolicy --live 'allow shell proc_mem file { open read write getattr }' +magiskpolicy --live 'deny untrusted_app shell_data_file file execute' +magiskpolicy --live 'auditallow untrusted_app app_data_file file { read write }' +magiskpolicy --live 'permissive untrusted_app' +magiskpolicy --live 'enforce untrusted_app' +``` + +### Dedicated exploit-testing domain + +Prefer a dedicated domain over making `shell`, `untrusted_app`, or the whole device permissive. The executable label becomes the transition trigger: when `shell` executes a file labeled `myexploit_exec_t`, the `type_transition` selects `myexploit_t`. Add only the resources the PoC needs, then inspect the domain's AVCs.[[6]](#references)[[9]](#references) + +
+Create a minimal custom transition + +```bash +magiskpolicy --live 'type myexploit_t domain' +magiskpolicy --live 'permissive myexploit_t' +magiskpolicy --live 'type myexploit_exec_t file_type' +magiskpolicy --live 'type_transition shell myexploit_exec_t process myexploit_t' +magiskpolicy --live 'allow shell myexploit_t process transition' +magiskpolicy --live 'allow shell myexploit_exec_t file { open read getattr execute }' +magiskpolicy --live 'allow myexploit_t myexploit_exec_t file entrypoint' +magiskpolicy --live 'allow myexploit_t shell_data_file file { open read write map getattr }' +adb shell su -c 'chcon u:object_r:myexploit_exec_t:s0 /data/local/tmp/exploit_poc' +adb shell /data/local/tmp/exploit_poc +``` + +
+ +### Fine-grained ioctl filtering + +A basic `chr_file ioctl` allow can still be denied by SELinux extended permissions. Grant only the ioctl request values required by the driver PoC; `*` (equivalent to `0x0000-0xFFFF`) removes that fine-grained restriction for the selected source/target/class and is appropriate only for disposable testing environments.[[6]](#references)[[9]](#references) + +```bash +magiskpolicy --live 'allow shell gpu_device chr_file { open read write ioctl }' +magiskpolicy --live 'allowxperm shell gpu_device chr_file ioctl { 0x6601 0x6602 }' +# Broad laboratory-only alternative: +magiskpolicy --live 'allowxperm shell gpu_device chr_file ioctl *' +``` + +Live edits disappear after reboot or policy replacement. For repeatable Magisk testing, place reviewed statements in `/data/adb/modules//sepolicy.rule` so Magisk merges them during boot; avoid wildcard rules and keep the module disabled outside the lab.[[9]](#references) + +```text +allow my_daemon system_file file { open read getattr } +allow my_daemon init unix_stream_socket connectto +``` + +## Kernel-space injection: KernelSU + +KernelSU performs its built-in SELinux changes in kernel code against the active `policydb`. Its current rules create a permissive `su` domain, assign trusted/network attributes, grant broad access and ioctl xperms, and replace the active policy pointer after updating the policy structures. This differs from `magiskpolicy --live`, which loads a patched policy through the normal runtime-policy path.[[7]](#references)[[9]](#references) + +Because these mechanisms intentionally weaken mandatory access control, treat any unauthorized access to a root-framework policy channel as a sandbox-break amplifier: it can expose device nodes, Binder/Unix sockets, procfs/sysfs data, cross-domain tracing and privileged executable transitions even when the attacker already has UID 0.[[7]](#references)[[9]](#references) + +## References + +- [1] [AOSP `seapp_contexts` mapping and precedence](https://android.googlesource.com/platform/system/sepolicy/+/refs/heads/main/private/seapp_contexts) +- [2] [AOSP `mac_permissions.xml` signing identity to `seinfo` mapping](https://android.googlesource.com/platform/system/sepolicy/+/refs/heads/main/private/mac_permissions.xml) +- [3] [Android Open Source Project - Validate SELinux policy and analyze denials](https://source.android.com/docs/security/features/selinux/validate) +- [4] [AOSP `file_contexts` matching and `restorecon` use](https://android.googlesource.com/platform/system/sepolicy/+/refs/heads/main/private/file_contexts) +- [5] [AOSP `genfs_contexts` pseudo-filesystem labels](https://android.googlesource.com/platform/system/sepolicy/+/refs/heads/main/private/genfs_contexts) +- [6] [Magisk tools documentation - `magiskpolicy`](https://topjohnwu.github.io/Magisk/tools.html#magiskpolicy) +- [7] [KernelSU SELinux policy injection source](https://github.com/tiann/KernelSU/blob/main/kernel/selinux/rules.c) +- [8] [setools-android](https://github.com/xmikos/setools-android) +- [9] [Android SELinux Internals Part II - Domains, Denials, and Bypass with Root Tools](https://8ksec.io/android-selinux-internals-part-ii) + +{{#include ../../banners/hacktricks-training.md}}