
Apple MacOS Screen Sharing произвольное чтение/запись файлов -> RCE
Впервые за долгое время у нас есть RCE на MacOS.
Изначально обнаружена @osxreverser, а затем расширена bynar.io. См. https://blog.calif.io/p/no-country-for-old-passwords для дополнительной информации.
В основном это основано на работе @panchocosil (ну, Claude...), который опубликовал PoC только для чтения. Репозиторий от @HORKimhab выглядит довольно сомнительным, особенно потому, что get-svn.sh похож на попытку последующей атаки на цепочку поставок.
В любом случае, мне удалось заставить работать запись, а из этого — получить RCE.
usage: exploit.py [-h] [-w LOCAL] [-m MODE] [-p PORT] [-u USER] [-r RETRIES] [-t TIMEOUT] [-o FILE] ip [path]
-o, чтобы сохранить прочитанный файл в локальный файл. Полезно для бинарников-w — записать локальный файл в [path].Отчасти возможно. В MacOS чтение каталога (а не файла) выгружает сырое содержимое каталога (все файлы в нём). Так что невозможность получить список файлов — не проблема.
Итак, сначала немного разведки. python3 exploit.py <ip_addr> /Library/Preferences/com.apple.loginwindow.plist даёт имя пользователя вошедших в систему пользователей. Затем можно прочитать /User/<username>/.ssh/ и надеяться, что SSH тоже включён (обычно если включён VNC, то SSH тоже).
Поскольку чтение выполняется от root и игнорирует TCC (насколько я понимаю), можно просто выгрузить историю браузера и (возможно?) куки. Обычно этого достаточно.
В любом случае можно записать в /Library/LaunchDaemons/ и дождаться перезагрузки. После этого у вас будет персистентность. Но, разумеется, мы нетерпеливы, поэтому есть способы и получше.
Часто можно найти уже существующие записи, которые можно перезаписать. Например, /Library/PrivilegedHelperTools/com.microsoft.autoupdate.helper, us.zoom.ZoomDaemon и com.microsoft.teams.TeamsUpdaterDaemon довольно часто уже установлены.
<!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>
Судя по этому, бинарник /Library/Application Support/Microsoft/EdgeUpdater/Current/EdgeUpdater.app/Contents/MacOS/EdgeUpdater запускается через заданный интервал.
Затем мы можем заменить этот бинарник, и даже без необходимости возиться с launchctl получаем RCE!
Забавно.