Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
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
Tools/GitHubGitHub/lsposed/lspromise
Android SecurityPrivilege EscalationExploit FrameworksVulnerability AnalysisExploitationPost-ExploitationPayload Development
GitHublsposed/lspromise

LSPromise

Android complete exploit chain that enables privilege escalation from a local untrusted app to root/kernel, combined of CVE-2026-49881 and CVE-2026-43284

View Repository
51914h 15m agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

LSPromise

A complete exploit chain that enables privilege escalation from a local untrusted app to root/kernel. It does not involve memory corruptions or race conditions, so attackers don't need to perform complex heap spraying or bypass mitigations against memory corruption vulnerabilities such as KASLR, MTE or CFI, making this exploit chain a 100% success rate on vulnerable devices.

Tested on Pixel 10 running the initial Android 17 official release. Note that it does not work on Pixel 6a and this issue may also occur on other devices running 6.1.xxx-android14 kernel trees due to another bug in these kernels.

Usage: Install KernelSU app, open this app, click "Run userspace exploit" then "Run kernel exploit and load KernelSU". After a successful exploitation, KernelSU will be activated and you can use it to grant root access to other apps. Known issue: If you have already run the kernel exploit and want to run it again, you need to reboot the device.

Screen recording: click here

Writeup

The chain is made from two distinct vulnerabilities: one is a 0-day in the Telecom service, while the other is a kernel 1-day that was disclosed 3 months ago. But AOSP and Pixel devices (except those running beta QPR versions) remain vulnerable at the time of writing.

Getting into system_server

The first vulnerability of the chain is a simple logic bug introduced in Android 17. It originates from a crazy change, which adds the following code to InCallController.java:

root@kitploit:~
        PackageManager packageManager = mContext.getPackageManager();
        Context userContext = mContext.createContextAsUser(userHandle,
                0 /* flags */);
        PackageManager userPackageManager = userContext != null ?
                userContext.getPackageManager() : packageManager;

        List<ResolveInfo> entries;
        entries = userPackageManager.queryIntentServices(
                serviceIntent,
                PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS);
        for (ResolveInfo entry : entries) {
            ServiceInfo serviceInfo = entry.serviceInfo;

            if (serviceInfo != null) {
                boolean isMetaFlag = serviceInfo.metaData != null &&
                        serviceInfo.metaData.getBoolean(
                                "android.telecom.CLASS_EXISTENCE_CHECK", false);
                if (isMetaFlag && !serviceClassExists(serviceInfo, userHandle)) {
                    continue;
                }
            }
        }

The relevant serviceClassExists() method is defined as follows:

root@kitploit:~
    /**
     * Verifies that the class for a given ServiceInfo exists within its package.
     * This prevents a system crash if a service is declared in the manifest but its
     * class was not included in the compiled code.
     * @param serviceInfo The ServiceInfo of the service to check.
     * @param userHandle The user under which to check for the service.
     * @return {@code true} if the class exists, {@code false} otherwise.
     */
    private boolean serviceClassExists(ServiceInfo serviceInfo, UserHandle userHandle) {
        Log.i(this, "serviceClassExists check");
        try {
            Context packageContext = mContext.createPackageContextAsUser(
                    serviceInfo.packageName,
                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY, userHandle);
            ClassLoader classLoader = packageContext.getClassLoader();
            Class.forName(serviceInfo.name, false, classLoader);
            return true;
        } catch (NameNotFoundException | ClassNotFoundException e) {
            Log.w(this, "Skipping InCallService: class not found for " + serviceInfo.name);
            return false;
        } catch (Exception e) {
            Log.e(this, e, "Error checking for existence of " + serviceInfo.name);
            return false;
        }
    }

This is the most unbelievable vulnerability I've ever seen. The code uses Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY to load code from an arbitrary app; While there appear to be some measures intended to prevent arbitrary code execution, such as passing false to Class.forName() to prevent class initialization, the app can still declare a custom AppComponentFactory that is invoked when getClassLoader() is called.

On the other hand, the bug exists in InCallController.java, which is a part of the com.android.server.telecom package rather than com.android.phone. It is worth noting that the package declares android:sharedUserId="android.uid.system" and android:process="system" in AndroidManifest.xml, so it runs in the system_server process, one of the most privileged userspace processes in Android. Therefore, we now have the ability to execute arbitrary Java code inside system_server.

It's a surprise that even a Google engineer can make such a big mistake in the AI era. We found and reported it to the Android Security Team on July 23, 2026. They told us it was a duplicate. Google has switched the monthly security bulletin to quarterly release, which may explain why the vulnerability was not fixed 3 months after the release of Android 17.

The vulnerability was assigned CVE-2026-49881 and fixed in September 2026 by Remove serviceClassExists logic to address security vulnerability.

Getting into network stack

The first bug allows us to escalate privileges to system, but is still far away from root. A complete root requires at least UID 0 and not being restricted by SELinux.

Now it's time to introduce the kernel 1-day: the DirtyFrag vulnerabilities. The underlying principles will not be elaborated here; please refer to the original reporter's writeup. There are 2 variants: CVE-2026-43500 requires RxRPC which is disabled for Android Generic Kernels; CVE-2026-43284 requires xfrm-ESP and is exploitable on Android. However, SELinux forbids untrusted apps from using that feature:

root@kitploit:~
# Privileged netlink socket interfaces.
neverallow { appdomain -network_stack }
    domain:{
        netlink_tcpdiag_socket
        netlink_nflog_socket
        netlink_xfrm_socket
        netlink_audit_socket
        netlink_dnrt_socket
    } *;

The only allowed domains are system_server, network_stack and netd. In order to exploit DirtyFrag, attackers must first compromise one of the allowlisted privileged processes.

Combine two bugs together. While the userspace bug allows us to execute Java code inside system_server, SELinux also forbids system_server from either loading native libraries from /data or mapping anonymous executable memory. This makes it impossible to use native code, increasing the difficulty of exploitation. It would therefore be preferable to execute code inside com.android.networkstack, which can load native code from our APK and has sufficient privileges to exploit DirtyFrag.

Luckily, system_server is the process where ActivityManager runs. ActivityManager stores IApplicationThread handles of every app process into a Java map and since we run as the same process of ActivityManager we can retrieve them using Java reflection. With this, we can send arbitrary commands to com.android.networkstack to force it to load our code. For more information on this trick, please refer to my previous exploit for CVE-2026-0091.

Getting into kernel

DirtyFrag allows to overwrite read-only files. This is a powerful primitive in Linux world, because we can overwrite the su binary which has the SUID bit. However, we don't have su in Android world. We refer to polygraphene's exploit for DirtyPipe to turn DirtyFrag into kernel code execution on Android:

  1. We patch libc.so, libc++.so and /vendor/lib64/libstagefright_aidl_bufferpool2.so through DirtyFrag. libstagefright_aidl_bufferpool2.so is labeled as vendor_file domain so it can't be accessed from network stack process. The solution is to patch /apex/com.android.runtime/bin/crash_dump64 first, execute it, and once we transition to the crash_dump domain we can open libstagefright_aidl_bufferpool2.so.
  2. Create and destroy an orphan process to trigger code execution in init process. Because libc++.so is patched, our code gets executed as UID 0 with the init domain. We then execute /vendor/bin/modprobe to transition to vendor_modprobe domain.
Download Tool
  • When modprobe is executed, because libc.so is also patched, our code is executed under vendor_modprobe domain. We can now load kernel modules but only for files that have specified labels. We load libstagefright_aidl_bufferpool2.so which has vendor_file label.
  • Since we patched libstagefright_aidl_bufferpool2.so, the real content of that file has been replaced by our own kernel module. The kernel module gets loaded, and now we can do anything, including adjusting SELinux policy or setting SELinux to permissive.
  • We set SELinux to permissive. We now have UID 0 with SELinux disabled; we launch KernelSU for you.