时时勤拂拭,勿使惹尘埃

TOC

Categories

Android(十)SEAndroid初探


0x1 SEAndroid简介

SEAndroid(Security-Enhanced Android),是将原本运用在Linux操作系统上的MAC强制存取控管套件SELinux,移植到Android平台上。可以用来强化Android操作系统对App的存取控管,建立类似沙箱的执行隔离效果,来确保每一个App之间的独立运作,也因此可以阻止恶意App对系统或其它应用程序的攻击。
SEAndroid在架构和机制上与SELinux完全一样,中心理念为:即使恶意应用获取了root权限,依然可以阻止应用的越权读取行为。考虑到移动设备的特点,所以移植到SEAndroid的只是SELinux的一个子集。

SEAndroid工作流程如下,程序访问资源时,会先向SEAndroid/SELinux发送请求,SEAndroid根据策略数据库进行策略分析,比对安全上下文,控制应用程序的资源存取。

0x2 SEAndroid策略

SEAndroid是一种基于安全策略的MAC安全机制。这种安全策略又是建立在对象的安全上下文的基础上的。这里所说的对象分为两种类型,一种称主体(Subject),一种称为客体(Object)。主体通常就是指进程,而客观就是指进程所要访问的资源,例如文件、系统属性等。
SEAndroid的安全检查覆盖了所有重要的方面包括了域转换、类型转换、进程相关操作、内核相关操作、文件目录相关操作、文件系统相关操作、对设备相关操作、对app相关操作、对网络相关操作、对IPC相关操作。
在用户空间中,SEAndroid包含有三个主要的模块,分别是安全上下文(Security Context)、安全策略(SEAndroid Policy)和安全服务(Security Server)。

0x21 SEAndroid工作模式

目前 SELinux 支持三种模式,分别如下:
  • enforcing:强制模式,代表 SELinux 运行中,且已经正确的开始限制 domain/type 了;
  • permissive:宽容模式:代表 SELinux 运行中,不过仅会有警告信息并不会实际限制 domain/type 的存取,这种模式可以运来作为 SELinux 的 debug 之用;
  • disabled:关闭,SELinux 并没有实际运行。
显示SEAndroid工作状态可以使用以下指令,输出结果为Enforcing,说明使用强制模式:
$ getenforce
Enforcing
设置SEAndroid工作模式可以使用以下指令,enforcing为1,permissive为0,但需要相应权限才能执行:

$ setenforce --help
usage: setenforce [enforcing|permissive|1|0]
Sets whether SELinux is enforcing (1) or permissive (0).
$ setenforce 1
setenforce: Could not set enforcing status to '1': Permission denied
$ setenforce 0
setenforce: Could not set enforcing status to '0': Permission denied

0x22 安全上下文(Security Context)

SEAndroid的安全上下文与SELinux基本一致,实际上就是一个附加在对象上的标签(Tag)。这个标签实际上就是一个字符串,它由四部分内容组成,分别是SELinux用户、SELinux角色、类型、安全级别,每一个部分都通过一个冒号来分隔,格式为user:role:type:sensitivity
通过ls -Z指令可以查看文件的安全上下文信息:

1|sailfish:/ $ ls -Z

u:object_r:cgroup:s0           acct         u:object_r:tmpfs:s0            mnt

u:object_r:rootfs:s0           bin          u:object_r:vendor_file:s0      odm

u:object_r:rootfs:s0           bugreports   u:object_r:oemfs:s0            oem

u:object_r:rootfs:s0           charger      u:object_r:proc:s0             proc

u:object_r:configfs:s0         config       u:object_r:system_file:s0      product

u:object_r:rootfs:s0           d            u:object_r:rootfs:s0           res

u:object_r:system_data_file:s0 data         u:object_r:rootfs:s0           sbin

u:object_r:rootfs:s0           default.prop u:object_r:rootfs:s0           sdcard

u:object_r:device:s0           dev          u:object_r:storage_file:s0     storage

u:object_r:rootfs:s0           dsp          u:object_r:sysfs:s0            sys

u:object_r:rootfs:s0           etc          u:object_r:system_file:s0      system

u:object_r:firmware_file:s0    firmware     u:object_r:vendor_file:s0      vendor

u:object_r:rootfs:s0           lost+found
通过ps -Z指令可以查看进程的安全上下文信息:

sailfish:/ $ ps -Z

LABEL                          USER           PID  PPID     VSZ    RSS WCHAN            ADDR S NAME

u:r:shell:s0                   shell         8987  8920    9256   1988 SyS_rt_si+ 7c60833e58 S sh

u:r:shell:s0                   shell         9666  8987   11724   2200 0          7192d327b8 R ps
u:object_r:system_data_file:s0为例,这些标记代表含义如下:
  • user:安全上下文的第一列为SELinux用户,在SEAndroid中的user只有一个就是u。
  • role:第二列表示SELinux角色,在SEAndroid中的role有两个,分别为r和object_r。
  • type:第三列为type类型,SEAndroid中共定义了139种不同的type。
  • security level:第四列为安全级别,由敏感性(Sensitivity)和类别(Category)两部分内容组成的,格式为sensitivity[:category_set]category_set可选。
安全上下文中最重要的部分就是第三列的type,type是整个SEAndroid中最重要的一个参量,所有的policy都围绕这一参量展开,所以为系统中每个文件标记上合适的type就显得极为重要。而SELinux用户、SELinux角色和安全级别都几乎可以忽略不计的。
在SEAndroid中,我们通常将用来标注文件的安全上下文中的类型称为file_type,而用来标注进程的安全上下文的类型称为domain,并且每一个用来描述文件安全上下文的类型都将file_type设置为其属性,每一个用来进程安全上下文的类型都将domain设置为其属性。

0x23 SEAndroid配置文件

四种类型的对象的安全上下文,分别是App进程、App数据文件、系统文件和系统属性。这四种类型对象的安全上下文通过四个文件来描述:mac_permissions.xml、seapp_contexts、file_contexts和property_contexts,这几个文件通常在/sys/fs/selinux(早期版本)或/etc/selinux/目录下:

$ ls -ahlZ

ls: ./plat_hwservice_contexts: Permission denied

ls: ./plat_mac_permissions.xml: Permission denied

total 536K

drwxr-xr-x  3 root root u:object_r:system_file:s0            4.0K 2009-01-01 16:00 .

drwxr-xr-x 17 root root u:object_r:system_file:s0            4.0K 2009-01-01 16:00 ..

drwxr-xr-x  2 root root u:object_r:system_file:s0            4.0K 2009-01-01 16:00 mapping

-rw-r--r--  1 root root u:object_r:sepolicy_file:s0            65 2009-01-01 16:00 plat_and_mapping_sepolicy.cil.sha256

-rw-r--r--  1 root root u:object_r:file_contexts_file:s0      23K 2009-01-01 16:00 plat_file_contexts

-rw-r--r--  1 root root u:object_r:property_contexts_file:s0 6.5K 2009-01-01 16:00 plat_property_contexts

-rw-r--r--  1 root root u:object_r:seapp_contexts_file:s0    1.2K 2009-01-01 16:00 plat_seapp_contexts

-rw-r--r--  1 root root u:object_r:sepolicy_file:s0          0.9M 2009-01-01 16:00 plat_sepolicy.cil

-rw-r--r--  1 root root u:object_r:service_contexts_file:s0   14K 2009-01-01 16:00 plat_service_contexts

0x3 规则分析

AOSP提供的所有Android策略文件都在源码路径external/sepolicy目录下面,在编译完成之后一共会生成如下个module:

0x31 sepolicy

sepolicy 其主要用于配置进程的安全上下文用来控制进程访问内核资源(文件,端口等等)策略和设置虚拟文件系统的安全上下文,系统启动之后,会由init进程在 /sys/fs /selinux中安装一个selinux虚拟文件系统,接着再加载SEAndroid安全策略到内核空间的selinux lsm模块中去。
sepolicy文件其实就是SEAndroid的安全策略配置文件,里面有所有进程的权限配置,进程只能进行它的权限规定内的操作。这个文件root权限也删不掉,把这个文件的内容dump出来后会发现里面有好多条规则,看两条例子:
allow untrusted_app system_app_data_file : file { read }     
allow zygote sdcard_type : file { read write creat rename }
它的具体格式为:allow Domain Type : Class { Permission } (Domain 是指进程的type)
通过这个格式解读上面的两条规则就是:
  1. 允许 untrusted_app类型的进程对 system_app_data_file类型的文件进行read。
  2. 允许zygote类型的进程对sdcard_type的file进行 read write creat rename。
所以MAC控制方式是这个样子的:
当一个进程去操作一个文件的时候,系统会去检测这个进程和文件的上下文,看看这个进程的所属的type有没有对这个的文件的type操作的权限。比如:zygote如果要去读sdcard上的一个文件,这个文件的type为sdcard,zygote的type(Domain)为zygote, 系统去检测看看发现这条规则 allow zygote sdcard_type : file { read write creat rename }。那么这个操作就会被允许执行。zygote要是想删除一个sdcard上的文件,系统发现对应的规则里没有delete,那么就会被deny。

0x32 file_contexts

file_contexts模块用于设置打包在ROM里面的文件的安全上下文。其是由external/sepolicy/file_contexts文件编译而成。
例如在build systemimage时会将这个file_contexts文件路径传递给命令make_ext4fs时,就会根据它设置的规则给打包在 system.img里面的文件关联安全上下文。这样就获得了一个关联有安全上下文的system.img镜像文件了。
通过fastboot命令将system.img刷入system分区mount到/system目录之后,因为设置了相应的安全上下文,这样就能控制进程访问system目录下相关文件.

0x33 seapp_contexts和mac_permissions.xml

seapp_contexts是负责设置APP数据文件的安全上下文,mac_permissions.xml是负责设置APP进程的安全上下文.
路径: external/sepolicy/mac_permissons.xml
文件mac_permissions.xml给不同签名的App分配不同的seinfo字符串,例如,在AOSP源码环境下编译并且使用平台签名的App获得的seinfo为“platform”,使用第三方签名安装的App获得的seinfo签名为”default”。这个seinfo描述的是其实并不是安全上下文中的Type,它是用来在另外一个文件seapp_contexts中查找对应的type的。
路径:external/sepolicy/seapp_context
sisSystemServer=true domain=system_server
user=system domain=system_app type=system_app_data_file
user=bluetooth domain=bluetooth type=bluetooth_data_file
user=nfc domain=nfc type=nfc_data_file
user=radio domain=radio type=radio_data_file
user=shared_relro domain=shared_relro
user=shell domain=shell type=shell_data_file
user=_isolated domain=isolated_app
user=_app seinfo=platform domain=platform_app type=app_data_file
user=_app domain=untrusted_app type=app_data_file
例如,于使用平台签名的App来说,它的seinfo为platform。用户空间的SecurityServer(比如installd)在为它查找 对应的Type时,使用的user输入为_app。这样在seapp_contexts文件中,与它匹配的一行即为:user=_app seinfo=platform domain=platform_app type=app_data_file 这样就可以知道,使用平台签名的App所运行在的进程domain为platform_app,并且它的数据文件的file_typeapp_data_file

0x34 property_contexts

在Android系统中,有一种特殊的资源——属性,App通过读写它们能够获得相应的信息,以及控制系统的行为,因此,SEAndroid也需要对它们进行保护。这意味着Android系统的属性也需要关联有安全上下文。
路径:external/sepolicy/property_contexts
##########################
# property service keys
#
#
net.rmnet               u:object_r:net_radio_prop:s0
net.gprs                u:object_r:net_radio_prop:s0
net.ppp                 u:object_r:net_radio_prop:s0
...
属性的安全上下文与文件的安全上下文是类似的,将属性net.rmnet设置为u:object_r:net_radio_prop:s0, 意味着只有有权限访问type为net_radio_prop的资源的进程才可以访问这个属性。

0x35 service_contexts

在AndroidL系统中,还将服务(属于进程或线程)也作为一种资源来定义,给其定义对应的安全上下文,用来保护服务不被恶意进程访问.
路径:external/sepolicy/service_contexts
...
window                                    u:object_r:system_server_service:s0
*                                         u:object_r:default_android_service:s0
服务的安全上下文同样与文件的安全上下文是类似的,将window服务设置为u:object_r:system_server_service:s0,意味着只有有权限访问type为system_server_service的资源的进程才可以访问这个服务。

0x4 攻击案例

0x41 绕过SEAndroid几个方法

由于SELinux引入android不久,还有很多不完善的地方。在DEFCON 21上,来自viaForensics的Pau Oliva就演示了几个方法来绕过SEAndroid
  1. 用恢复模式(recovery)刷回permissive模式的镜像
  2. Su超级用户没有设置SELinux模式权限,但是system user系统用户可以。
  3. Android通过/system/app/SEAndroidManager.apk来设置SELinux模式,所以只要在recovery模式下将其删除就可以绕过
  4. 在Android启动时直接操作内核内存,通过将内核里的unix_ioctl符号改写成reset_security_ops重置LSM(Linux Security Modules)

0x42 Fastboot 中将SELinux 更改为 Permissive 模式

这个问题是一加手机 3/3T Bootloader 漏洞,允许在 Fastboot 中将SELinux 更改为 Permissive 模式。
fastboot oem selinux permissive
...
OKAY [  0.045s]
finished. total time: 0.047s
....
OnePlus3:/ $ getenforce
Permissive
OnePlus3:/ $

0x5 参考

一加手机 3/3T Bootloader 存在漏洞(允许在 Fastboot 中将SELinux 更改为 Permissive 模式)