Once I had adb access it was obvious it was very limited so, let’s get root. After some digging what seemed to be the easiest option was to change adb shell’s id to 0. How do we do that?
The goal is to change our ADB shell’s user ID from 2000 (shell) to 0 (root).
Every process in Linux has a task_struct kernel
structure, which contains a pointer to a cred (credentials)
structure. The cred struct stores the process’s uid, gid,
and other permissions. The shell user’s uid is 2000 (hex:
0x000007d0). If we find this struct in memory and zero it
out, the shell becomes root.
The approach is a memory search-and-overwrite:
bgrep -B32 6164626400 mem.dump > bgrep.outcat bgrep.out |cut -d: -f2|tr -d ' '|sed '/^\\/d' > bgrep.out.20x to all the linescat bgrep.out.2 |xargs -n 1 bash -c 'xxd -c8 -s "$(( $0-32 ))" -l 48 mem.dump; echo "\n"'3624a650: 0000 0000 0000 0000 ........
3624a658: 40a2 933e 0000 ffff @..>....
3624a660: 40a2 933e 0000 ffff @..>....
3624a668: 0000 0000 0000 0000 ........
3624a670: 6164 6264 0065 722f adbd.er/
3624a678: 3000 0000 0000 0000 0.......
40a2 933e→0x3e93a240 this is the address of
the cred structxxd -c 8 -s $(( 0x3e93a240)) dump_0x4M.bin |less3e93a240: 1c00 0000 d007 0000 ........
3e93a248: d007 0000 d007 0000 ........
3e93a250: d007 0000 d007 0000 ........
3e93a258: d007 0000 d007 0000 ........
3e93a260: d007 0000 3f00 0000 ....?...
> mdw 0x7e93a240 32
0x7e93a240: 00000024 000007d0 000007d0 000007d0 000007d0 000007d0 000007d0 000007d0
0x7e93a260: 000007d0 0000003f 00000000 00000000 00000000 00000000 00000000 00000000
0x7e93a280: 000000c0 00000000 00000000 00000000 00000000 00000000 43e45700 ffff0000
0x7e93a2a0: 00000000 00000000 00000000 00000000 00000000 00000000 362e2e80 ffff0000
> mww 0x7e93a244 00000000
> mww 0x7e93a248 00000000
adb shell id → Should give you rootI did script out most of these steps so it wasn’t so manual. ### Bypassing SELinux
Even with root, SELinux (Security-Enhanced Linux) blocks most useful
actions. SELinux enforces a policy that says what each process is
allowed to do , our shell context (u:r:shell:s0) is highly
restricted even as uid 0.
We need to patch the kernel function avc_denied(). This
function is called whenever an SELinux policy check fails , it’s what
generates the “avc: denied” log messages and returns the
-EACCES error. If we make it always return 0
(success) instead, every SELinux check passes.
avc_denied We want to change the orr
that sets the error return to orr w0, wzr, wzr , which sets
the return to 0 (success). We change
orr w0, wzr, #xffffffff3 to orr w0, wzr, wzr.
From opcode: 321c77e0 to opcode 0x2A1F03E0
ffff80001053beb8 <avc_denied>:
ffff80001053beb8: d100c3ff sub sp, sp, #0x30
ffff80001053bebc: a9027bfd stp x29, x30, [sp, #32]
ffff80001053bec0: 910083fd add x29, sp, #0x20
ffff80001053bec4: 37000127 tbnz w7, #0, ffff80001053bee8 <avc_denied+0x30>
ffff80001053bec8: 3940040c ldrb w12, [x0, #1]
ffff80001053becc: f9400bab ldr x11, [x29, #16]
ffff80001053bed0: 2a0303ea mov w10, w3
ffff80001053bed4: 2a0203e8 mov w8, w2
ffff80001053bed8: 2a0103e9 mov w9, w1
ffff80001053bedc: 340000ac cbz w12, ffff80001053bef0 <avc_denied+0x38>
ffff80001053bee0: 3940416c ldrb w12, [x11, #16]
ffff80001053bee4: 3700006c tbnz w12, #0, ffff80001053bef0 <avc_denied+0x38>
ffff80001053bee8: 321c77e0 orr w0, wzr, #0xfffffff3 ≪PATCH
ffff80001053beec: 1400000f b ffff80001053bf28 <avc_denied+0x70>
ffff80001053bef0: f9400800 ldr x0, [x0, #16]
ffff80001053bef4: b9400d6b ldr w11, [x11, #12]
ffff80001053bef8: b90013e7 str w7, [sp, #16]
ffff80001053befc: 320003e1 orr w1, wzr, #0x1
ffff80001053bf00: 2a0403e2 mov w2, w4
ffff80001053bf04: 2a0503e3 mov w3, w5
ffff80001053bf08: 2a0603e4 mov w4, w6
ffff80001053bf0c: 2a0903e5 mov w5, w9
ffff80001053bf10: 2a0803e6 mov w6, w8
ffff80001053bf14: 2a0a03e7 mov w7, w10
ffff80001053bf18: f90007ff str xzr, [sp, #8]
ffff80001053bf1c: b90003eb str w11, [sp]
ffff80001053bf20: 97fffeb2 bl ffff80001053b9e8 <avc_update_node>
ffff80001053bf24: 2a1f03e0 mov w0, wzr
ffff80001053bf28: a9427bfd ldp x29, x30, [sp, #32]
ffff80001053bf2c: 9100c3ff add sp, sp, #0x30
ffff80001053bf30: d65f03c0 ret
Finding the patch location: The kernel doesn’t use KASLR (Kernel Address Space Layout Randomization) on this device, which means the kernel code is always loaded at the same address every boot. This makes our job much easier.
We search for the function in the RAM dump using a unique byte
sequence E0771c320f000014 which corresponds to two
consecutive instructions in avc_denied
321c77e0 orr w0, wzr, #0xfffffff3 # sets return value to -EACCES (permission denied)
1400000f b <exit> # jumps to function exit
Search using perl
/usr/bin/perl -0777 -ne '
while (/(\xE0\x77\x1c\x32\x0f\x00\x00\x14){1}/g) {
$match = substr($_, $-[0], $+[0]-$-[0]);
printf "%d:%s\n", $-[0], unpack("H*",$match)
}
' mem.dumpAdd our offset:
# Example output from the perl search above:
# 9682664:e0771c320f000014
printf "0x%x\n" $((0x40000000 + 9682664))
# Result: 0x4093bee8Applying the patch in OpenOCD:
> mdw 0x4093bee8 4
0x4093bee8: 321c77e0 1400000f ...
> mww 0x4093bee8 0x2A1F03E0
> mdw 0x4093bee8 4
0x4093bee8: 2a1f03e0 1400000f ...
Verify SELinux is now permissive by checking the ADB log:
adb logcat | grep avc
# You'll see "permissive=1" instead of "permissive=0" in denied messagesWith root and SELinux disabled, we can now dump the full eMMC flash.
The eMMC shows up as /dev/block/mmcblk2 inside Android. We
use dd to read the raw block device and pipe it out over
ADB:
adb exec-out "dd if=/dev/block/mmcblk2 bs=4M" > mmcblk2.imgWe also need the boot partitions (where the bootloader lives):
adb exec-out "dd if=/dev/block/mmcblk2boot0 bs=4M" > mmcblk2boot0.img
adb exec-out "dd if=/dev/block/mmcblk2boot1 bs=4M" > mmcblk2boot1.img
adb exec-out "dd if=/dev/block/mmcblk2rpmb bs=4M" > mmcblk2rpmb.img
These four files are the complete contents of the eMMC flash.
mmcblk2.img contains all the Android partitions.
mmcblk2boot0.img is the most important , it contains the
SPL (Secondary Program Loader) and the FIT image with the bootloader
chain.
Images
1. mmcblk2boot0
2. mmcblk2boot1
3. mmcblk2rpmb
4. mmcblk2.img
Next: Part 3a: Bypass SDP programming mode