
Post del blog che esplora il macOS App Sandbox, gli entitlements tramite codesign e le tecniche di evasione della sandbox usando launchd, LaunchAgents e attributi di quarantena.
Continuando con la mia serie di articoli sulla transizione a macOS, vorrei parlare un po' della sandbox delle App di macOS.
È vivamente consigliato leggere prima l'articolo Struttura delle app macOS - darò per scontato che il lettore conosca la differenza tra App, processi (task), sappia qualcosa su launchd e la sua relazione con l'avvio delle App.
La prima volta che ho imparato a conoscere la sandbox di macOS, ho ingenuamente provato a creare una macro di Word.
Questo è (ancora) un vettore d'ingresso molto comune nell'ecosistema Windows, quindi volevo vedere se potevo semplicemente avviare processi e seminare il caos.
Beh, le cose non sono così facili su macOS - sono riuscito a eseguire processi, per esempio, ma sembrava che non potessero fare granché.
Il tentativo di creare file mi restituiva sempre un criptico errore Operation not permitted - cosa succede?
Ho iniziato a leggere un po' su macOS e Word e mi sono imbattuto in questo eccellente articolo di Adam Chester (lavora in MDSec). Consiglio vivamente di leggere l'articolo, ma riassumerò qui i risultati:
MacOS aveva un'utility funzionante chiamata sandbox-exec che eseguiva comandi in una sandbox. Sebbene deprecata, poteva mettere in luce parecchie cose. Nella sua pagina di manuale si vede che accetta un profile, quindi possiamo concludere che le regole della sandbox sono mantenute in profili. Questi profili possono avere varie forme - file, nomi predefiniti o persino stringhe letterali.
Le pagine di manuale affermano anche che gli sviluppatori dovrebbero usare la funzionalità App Sandbox. Leggendo di più ho capito che le regole della sandbox sono incorporate nel binario, nel nostro caso, situato in /Application/Microsoft Word.app/Contents/MacOS/Microsoft Word (se questo ti sembra estraneo, dai un'occhiata al mio articolo sulla struttura delle app macOS).
Anche se puoi estrarle facilmente a mano, è meglio usare uno strumento: codesign:
```jbo@McJbo ~ % codesign -dv --entitlements - /Applications/Microsoft\ Word.app/Contents/MacOS/Microsoft\ Word
Executable=/Applications/Microsoft Word.app/Contents/MacOS/Microsoft Word
Identifier=com.microsoft.Word
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=351454 flags=0x10000(runtime) hashes=10972+7 location=embedded
Signature size=8980
Timestamp=Apr 10, 2023 at 8:09:50 AM
Info.plist entries=52
TeamIdentifier=UBF8T346G9
Runtime Version=13.1.0
Sealed Resources version=2 rules=13 files=28766
Internal requirements count=1 size=180
[Dict]
[Key] com.apple.application-identifier
[Value]
[String] UBF8T346G9.com.microsoft.Word
[Key] com.apple.developer.aps-environment
[Value]
[String] production
[Key] com.apple.developer.team-identifier
[Value]
[String] UBF8T346G9
[Key] com.apple.security.app-sandbox
[Value]
[Bool] true
...
[Key] com.apple.security.temporary-exception.files.absolute-path.read-only
[Value]
[Array]
[String] /Library/Preferences/com.microsoft.office.licensingV2.plist
[String] /Library/Application Support/Microsoft/
...
[Key] com.apple.security.temporary-exception.sbpl
[Value]
[Array]
[String] (allow file-read* file-write* (require-all (vnode-type REGULAR-FILE) (regex #"(^|/)~\$[^/]+$")) )
[String] (deny file-write* (subpath (string-append (param "_HOME") "/Library/Application Scripts")) (subpath (string-append (param "_HOME") "/Library/LaunchAgents")) )
[Key] com.apple.security.temporary-exception.shared-preference.read-only
[Value]
[Array]
[String] com.ThomsonResearchSoft.EndNote
...
C'è molto da analizzare, quindi prendiamo alcune note di alto livello:
-dv, che sta per display e verbose. Poi, --entitlements presenta gli entitlements associati all'App o al binario (sì, codesign può funzionare su entrambi). Approfondiremo gli entitlements in un altro articolo, ma per ora diciamo che riflettono le capacità dell'App, e uno di essi afferma che l'App è in sandbox (com.apple.security.app-sandbox ha un valore booleano True).plist (di nuovo, nel mio [articolo sulla struttura delle app macOS]) potrebbero sospettare che il dizionario chiave-valore sia una rappresentazione di una property list, e avrebbero ragione.com.apple.security.temporary-exception.files.absolute-path.read-only menziona un array di percorsi assoluti da cui l'App può leggere.com.apple.security.temporary-exception.sbpl è qui - serve a creare quei famigerati file temporanei a cui Word è così affezionato.Nell'articolo di MDSec del 2018 che ho menzionato prima, la parte deny file-write* sotto com.apple.security.temporary-exception.sbpl non esisteva, il che permetteva alle macro di creare file con contenuti arbitrari come /Library/LaunchAgents/~$evil.plist. Perché questo permette di evadere dalla sandbox?
LaunchAgents e LaunchDaemons sono un noto meccanismo (legittimo) di persistenza in macOS. Li ho già menzionati prima, ma puoi pensarli come Servizi (se vieni dal mondo Windows) - i LaunchDaemons si avviano all'avvio del sistema operativo (e quindi vivono al di fuori della sessione dell'utente), mentre i LaunchAgents si avviano quando un utente accede.
È interessante notare che entrambi sono descritti in semplici file plist. Ecco un esempio per il mio aggiornatore OneDrive:
jbo@McJbo ~ % plutil -p /Library/LaunchAgents/com.microsoft.OneDriveStandaloneUpdater.plist
{
"Label" => "com.microsoft.OneDriveStandaloneUpdater"
"Program" => "/Applications/OneDrive.app/Contents/StandaloneUpdater.app/Contents/MacOS/OneDriveStandaloneUpdater"
"ProgramArguments" => [
]
"RunAtLoad" => 1
"StartInterval" => 86400
}
Questi LaunchAgents e LaunchDaemons vengono avviati da launchd (ricordi quel processo?) e quindi sfuggono alla sandbox, poiché launchd non sapeva se la plist fosse stata creata da un processo in sandbox o meno (e anche se lo sapesse - come farebbe a sapere quali regole di sandbox applicare?).
Questo concetto di usare launchd per evadere dalla sandbox di macOS è stato ampiamente utilizzato, e infatti l'ho usato in passato.
Risparmiandoti un paio di clic - ecco l'idea:
launchd avvia le app macOS. Queste app possono essere avviate facendo doppio clic su di esse, o con altri mezzi - ad esempio, facendo clic su un file zip si userà Archive Utility poiché è associato ai file zip.launchd è con il comando open.open è ricco - puoi usare alcune delle sue funzionalità interessanti come selezionare l'app, selezionare il nome del file da aprire o persino fornire argomenti completi da riga di comando.Python integrata (che non esiste più sui nuovi dispositivi macOS standard) per avviare Python con un argomento stdin che di fatto reindirizza l'input standard da un file che ho creato (quel file era ~$evil.py a causa dei vincoli di Word).launchd ha eseguito un'istanza dell'app Python non in sandbox che ha iniziato a leggere da contenente comandi Python arbitrari, riuscendo di fatto a evadere dalla sandbox.Idee simili sono state presentate in altre divulgazioni (un bell'esempio è qui) ma l'idea resta la stessa. Sono abbastanza sicuro che ce ne siano molte altre in bella vista!
Una menzione d'onore va a un ottimo articolo di Wojciech Regula - questa volta incentrato sull'app Terminal e sulla manipolazione delle variabili d'ambiente. Dovresti dargli un'occhiata!
Il problema trovato da MDSec era specifico di Office - ed è stato corretto con regole più severe.
Quelli che abusano di LaunchServices (che è il nome del framework per l'avvio delle app con launchd) sono più generici - e quindi Apple ha dovuto correggerli.
Una delle cose che ho notato è che i file creati da Word ora vengono creati con l'attributo esteso com.apple.quarantine, sì, lo stesso che ho menzionato nel mio articolo introduttivo su Gatekeeper.
A quanto pare, quell'attributo di quarantena è una sorta di indurimento contro alcuni attacchi - ad esempio, l'app Terminal rifiutava di eseguire script di shell creati con quell'attributo. Questo è il motivo, tra l'altro, per cui ho dovuto usare l'opzione --stdin per Python.
Come sottolineato da Gergely Kalman - Apple ha aggiunto ulteriori controlli al binario open per indurire questo tipo di exploit. Sembra che --stdin, --args e altre opzioni da riga di comando vengano ignorate se il processo chiamante è in sandbox. Tuttavia, open chiama semplicemente LaunchServices (in launchd) con una IPC, e convenientemente ci sono API per questo, ad esempio LSOpenURLsWithRole.
Non ho indagato se anche LaunchServices stesso sia stato indurito - se non lo è, credo che evasioni simili dalla sandbox potrebbero essere facilmente realizzate.
Abbiamo brevemente discusso un'altra tecnologia di macOS - la sandbox. Abbiamo visto quanto sia potente e configurabile, e come possa essere violata.
Abbiamo anche collegato alcune cose - come le app interagiscono con le regole della sandbox, come l'avvio delle app da parte di launchd rompa più dei semplici alberi dei processi e come i file plist possano essere usati per il bene o per il male - questa volta con la persistenza (LaunchAgents e LaunchDaemons).
Per fortuna, abbiamo anche collegato l'attributo esteso com.apple.quarantine dell'articolo introduttivo su Gatekeeper e spiegato come potrebbe essere usato come ulteriore indurimento contro le evasioni dalla sandbox. Non male!
Nei prossimi articoli, esploreremo altri meccanismi di sicurezza in macOS e potremmo parlare di strategie per violarli.
Restate sintonizzati!
Jonathan Bar Or (https://jonathanbaror.com)
~$whatever.docx~$evil.py