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.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-43499-pmg110-root — Android LPE exploit for CVE-2026-43499 targeting OPPO PMG110 (kernel 6.6). Uses futex PI UAF to gain root and install a su daemon via LD_PRELOAD. | Kitploit
Tools/GitHubGitHub/soralis0912/cve-2026-43499-pmg110-root
Android SecurityPrivilege EscalationVulnerability AnalysisExploitationPost-ExploitationPenetration TestingMobile SecurityRed TeamingPayload Development

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
Binary Exploitation
GitHubsoralis0912/cve-2026-43499-pmg110-root

CVE-2026-43499-pmg110-root

Android LPE exploit for CVE-2026-43499 targeting OPPO PMG110 (kernel 6.6). Uses futex PI UAF to gain root and install a su daemon via LD_PRELOAD.

View Repository
2302 months agoNot yet reviewed

pmg110-root

CVE-2026-43499 (futex PI rt_mutex_waiter use-after-free) local privilege escalation, ported to the OPPO PMG110 / K15 Pro+ — MediaTek MT6991, ColorOS 16.

One file pushed, run over LD_PRELOAD:

adb push out/preload-pmg110-16.0.9.400.so /data/local/tmp/preload.so
adb shell chmod 644 /data/local/tmp/preload.so
adb shell LD_PRELOAD=/data/local/tmp/preload.so /system/bin/true

On success a persistent su is left behind:

adb shell /data/local/tmp/su -c id      # uid=0(root)

Verified on device (2026-07-27): uid=0 in about 35 seconds from a bare run with no environment overrides, and su answering afterwards from an ordinary unprivileged adb shell:

$ adb shell "/data/local/tmp/su -c 'echo 0 > /proc/sys/kernel/kptr_restrict'"
$ adb shell "/data/local/tmp/su -c 'grep -w init_task /proc/kallsyms'"
ffffffe89033e780 D init_task

The exploit and the su install are both verified on this device. What that rooted shell then read back also confirms P0_KERNEL_PHYS_LOAD, the symbol offsets and KS_MTE_TAGGED=0 independently of the exploit — see targets/pmg110-16.0.9.400/NOTES.md.

DeviceOPPO PMG110 / K15 Pro+ / OP61E5L1
SoCMediaTek MT6991 (Dimensity 9500s)
Kernel6.6.118-android15-8-g93e223c276e7-abogki500782043-4k (GKI, 4K pages)
BuildColorOS 16 / PMG110_16.0.9.400(CN01) — same kernel bytes as 16.0.8.300
BugCVE-2026-43499, unfixed in this image (shown by disassembly, not by version)

What it does, and what it does not

It runs Write 1 (SELinux permissive) and Write 2 (cred → init_cred), gets a child process to uid=0, and from there installs the embedded su daemon.

  • still one file pushed. su is not a second artifact: su_daemon.c is built as a standalone aarch64 PIE and .incbin'd into the library's .rodata, so it rides inside preload.so and is written back out at run time. warhol-root's route, unchanged.
  • no root script, no ksud, no KernelSU
  • the calling process stays unprivileged — it gets root by asking the daemon, which is the same thing you will do from the shell afterwards
  • SELinux is left permissive, as warhol-root leaves it: the daemon has to serve unprivileged clients over its socket. Reboot to restore enforcing.

su is installed in three places, because one of them is the one you will actually reach:

PathWhy
/apex/com.android.virt/bin/suon a tmpfs mounted over that directory; on PATH for a root shell
/data/local/tmp/sureachable from a plain adb shell with no PATH games
/apex/com.android.virt/bin/su in adbd's mount namespaceinstalled via setns, so a new adb shell sees it

The daemon listens on /data/local/tmp/temp_su.sock and logs to /data/local/tmp/su_daemon.log. Root is not persistent across reboot — re-run the LD_PRELOAD line after each boot.

For KernelSU installation, use the /data/local/tmp/a/e route in ghostlock-oneplus instead.

Relationship to warhol-root

Everything except the exploit core is warhol-root's, taken rather than reinvented:

  • the layout — per-device headers under targets/<device>/, staged into source/src/ at build time, so switching DEVICE can never leave the previous device's headers behind
  • the build — source/Makefile's toolchain selection (NDK if there is one, host clang against the NDK sysroot if there is not) and the two-stage embed rule that produces build/embed/su_daemon_aarch64_pie before linking the .so
  • the su route — su_daemon.c and su_blob.S are byte-identical to warhol-root's, and su_install.c is its preload.c installer

The exploit core is not warhol-root's. warhol-root is popsicle, which is pinned to GKI 6.12 / android16 and whose generate_target.py refuses any other banner. PMG110 is 6.6 / android15, so the core here is the ghostlock 6.6 tree — itself a descendant of the same code (kernelsnitch/utils.h and timeutils.h are byte-identical between the two repos), further developed.

FileRelationship
util.c slide.c fops.c pipe.c root.c miniadb.c common.h offset.h kernelsnitch/*ghostlock's, byte-identical
su_daemon.c su_blob.Swarhol-root's, byte-identical (su_blob.S adds two .hidden lines — see Build)
su_install.cwarhol-root's preload.c installer, moved to its own file because this tree's preload.c already has a different job
main.cghostlock's, plus the su call in the rooted child and the result reporting
preload.conly here — the constructor and the dual-sink log
offsets.hstruct definition only; the entry is staged from targets/<device>/device_offsets.h

Every line of the exploit proper — Write 1, Write 2, KernelSnitch, the pselect route — is the same code in both trees.

Where the su install is called from

This is the one structural difference, and it is forced by the two trees getting root in different shapes.

warhol-root roots the exploit process itself and so calls install_embedded_su() straight from run_direct_root(). Here Write 2 swaps the cred pointer of a forked child and the parent stays the unprivileged caller, so the child in child_main() is the only context that can do the install — that is where it runs.

Both trees carry the same weak install_embedded_su() stub in util.c that returns ENOSYS; providing the strong definition is what turns the route on. That is worth knowing because a build that somehow drops su_install.c still links and still runs — it just reports su=0/38 and installs nothing.

Build

make                      # = make preload -> out/preload-<DEVICE>.so
make DEVICE=<name>        # use targets/<name>/
make devices              # list available DEVICE values
make info                 # show the selected target and the resolved toolchain

The toolchain is found on its own: ANDROID_NDK_HOME / ANDROID_NDK_ROOT first, then the usual NDK install locations for Linux and macOS, and failing all of those, host clang targeting the NDK sysroot. Set ANDROID_NDK_HOME only to override the search. make info prints what it picked.

The build is two stages, which is the part worth knowing:

  1. su_daemon.c → build/embed/su_daemon_aarch64_pie, a standalone aarch64 PIE
  2. su_blob.S .incbins that binary into .rodata, and the whole thing links into the one preload.so

So make clean and a rebuild are the only way to change the embedded su — editing su_daemon.c alone is enough, the dependency is declared, but the blob is a build artifact and is not tracked.

targets/<device>/{target.h,device_offsets.h} are re-staged into source/src/ on every build, so a stale header from another device cannot be picked up silently.

out/*.so is not tracked (same convention as warhol-root) — clone and make.

The .so is built -fvisibility=hidden and exports zero symbols. An LD_PRELOAD library wins symbol lookup for the entire process, so anything it exported could shadow a same-named symbol in the host binary or in libc. That flag governs C codegen only, so su_blob.S marks its two symbols .hidden by hand — without those lines the blob bounds would be the only thing the library still exported.

Environment variables

Download Tool