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
CVE-2026-0073-Research — CVE-2026-0073 is an RCE with a CVSS severity score of 8.3, and here we will explain how it works. | Kitploit
Tools/GitHubGitHub/novaek/cve-2026-0073-research
Vulnerability AnalysisExploitationReverse EngineeringWeb SecurityBinary Analysis
GitHubnovaek/cve-2026-0073-research

CVE-2026-0073-Research

CVE-2026-0073 is an RCE with a CVSS severity score of 8.3, and here we will explain how it works.

View Repository
51104 months 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

CVE-2026-0073-Research

CVE-2026-0073 is an RCE with a CVSS severity score of 8.3, and here we will explain how it works.

First Part : Code analysis:

At first, the only thing that could possibly be interesting is learn more about the bug itself.

My first source is : https://www.tenable.com/cve/CVE-2026-0073

This source tells us that the auth.cpp file shows a function called adbd_tls_verify_cert which has a flow that allows an unauthenticated RCE.

The main objective now is to get the source code of auth.cpp.

As I couldn't find it in any official repo, I found this repository made by Project-Awaken at : https://github.com/Project-Awaken/android_packages_modules_adb/blob/12/daemon/auth.cpp

and there it is ! our misterious function :

root@kitploit:~
int adbd_tls_verify_cert(X509_STORE_CTX* ctx, std::string* auth_key) {
    if (!auth_required) {
        // Any key will do.
        LOG(INFO) << __func__ << ": auth not required";
        return 1;
    }

    bool authorized = false;
    X509* cert = X509_STORE_CTX_get0_cert(ctx);
    if (cert == nullptr) {
        LOG(INFO) << "got null x509 certificate";
        return 0;
    }
    bssl::UniquePtr<EVP_PKEY> evp_pkey(X509_get_pubkey(cert));
    if (evp_pkey == nullptr) {
        LOG(INFO) << "got null evp_pkey from x509 certificate";
        return 0;
    }

    IteratePublicKeys([&](std::string_view public_key) {
        // TODO: do we really have to support both ' ' and '\t'?
        std::vector<std::string> split = android::base::Split(std::string(public_key), " \t");
        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
        const std::string& pubkey = split[0];
        if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
            LOG(ERROR) << "Invalid base64 key " << pubkey;
            return true;
        }

        RSA* key = nullptr;
        if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
            LOG(ERROR) << "Failed to parse key " << pubkey;
            return true;
        }

        bool verified = false;
        bssl::UniquePtr<EVP_PKEY> known_evp(EVP_PKEY_new());
        EVP_PKEY_set1_RSA(known_evp.get(), key);
        if (EVP_PKEY_cmp(known_evp.get(), evp_pkey.get())) {
            LOG(INFO) << "Matched auth_key=" << public_key;
            verified = true;
        } else {
            LOG(INFO) << "auth_key doesn't match [" << public_key << "]";
        }
        RSA_free(key);
        if (verified) {
            *auth_key = public_key;
            authorized = true;
            return false;
        }

        return true;
    });

    return authorized ? 1 : 0;
}

But the interesting part of the function is the following one :

root@kitploit:~
bool verified = false;
bssl::UniquePtr<EVP_PKEY> known_evp(EVP_PKEY_new());
EVP_PKEY_set1_RSA(known_evp.get(), key);
if (EVP_PKEY_cmp(known_evp.get(), evp_pkey.get())) {
  LOG(INFO) << "Matched auth_key=" << public_key;
  verified = true;
} else {
  LOG(INFO) << "auth_key doesn't match [" << public_key << "]";
}

Why ? because verified is set as a boolean that allow or not the connection, and it is only changed with the "if" statement. the issue ? the EVP_PKEY_cmp(known_evp.get(), evp_pkey.get()) don't always returns 1 or 0, but also -1 and -2 because EVP_PKEY_cmp() return 1 if the keys match, 0 if they don't match, -1 if the key types are different and -2 if the operation is not supported.

So it validates the certificates of different keys or if the operation is not supported, even though the key is not a match.

In order to validate our session we will have to force one of these two options.

Second part : POC production and reverse of the ADB connection protocole

In order to try to exploit that flaw, we will need to engage a TLS session.

That works only if both the attacker and targeted device are able to use TLS, However the decision to use TLS is only decided by the targeted device.

If the targeted device allows TLS, you can engage into a TLS session.

It all happens here :

  • First : CNXN packets (connection packets)
  • Second : STLS packets (upgrade to TLS packets)
  • Third : TLS handshake (with EC key instead of RSA)

Let's try to get to work

Download Tool