
Auditor runtime delle funzioni libc che rileva race condition nell'accesso ai file e vulnerabilità di symlink agganciando le syscall del filesystem tramite LD_PRELOAD, registrando potenziali percorsi di escalation dei privilegi.
PathAuditor è uno strumento progettato per trovare vulnerabilità legate all'accesso ai file, controllando le funzioni libc.
L'idea è approssimativamente la seguente:
Utilizziamo LD_PRELOAD per intercettare tutte le chiamate di libreria relative al filesystem e registrare le violazioni riscontrate in syslog.
Questo non è un prodotto ufficialmente supportato da Google.
Vediamo un esempio del tipo di vulnerabilità che questo strumento può rilevare. CVE-2019-3461 era un bug in tmpreaper, uno strumento che attraversa /tmp ed elimina file vecchi. Di solito viene eseguito come cron job come root. Poiché non vuole eliminare file al di fuori di tmp, utilizzava il seguente codice per verificare se una directory è un punto di montaggio:
if (S_ISDIR (sb.st_mode)) {
char *dst;
if ((dst = malloc(strlen(ent->d_name) + 3)) == NULL)
message (LOG_FATAL, "malloc failed.\n");
strcpy(dst, ent->d_name);
strcat(dst, "/X");
rename(ent->d_name, dst);
if (errno == EXDEV) {
free(dst);
message (LOG_VERBOSE,
"File on different device skipped: `%s/%s'\n",
dirname, ent->d_name);
continue;
}
// [...]
In breve, questo codice chiama rename("/tmp/foo", "/tmp/foo/x") che restituirà EXDEV se "/tmp/foo" è un punto di montaggio.
PathAuditor segnalerebbe questa chiamata come potenziale vulnerabilità se "/tmp/foo" è di proprietà di un utente diverso da root.
Per capire il perché, dobbiamo pensare a cosa accade nel kernel quando viene eseguita la syscall rename (semplificato):
"/tmp/foo" per il primo argomento."/tmp/foo/x" per il secondo argomento.C'è una condizione di gara qui poiché "/tmp/foo" verrà risolto due volte. Se è controllato dall'utente, l'utente può sostituirlo con un file diverso in qualsiasi momento.
In particolare, vogliamo che "/tmp/foo" sia inizialmente una directory per superare il controllo if(S_ISDIR) nel codice di tmpreaper. Lo sostituiamo quindi con un file appena prima che il codice entri nella syscall. Quando il kernel risolve il primo argomento, vedrà un file con contenuto controllato dall'utente.
Ora lo sostituiamo di nuovo, questa volta con un collegamento simbolico a una directory arbitraria sullo stesso filesystem. Il kernel risolverà il percorso una seconda volta, seguirà il collegamento simbolico e sposterà il file controllato in una directory scelta.
La restrizione dello stesso filesystem è dovuta al fatto che rename non funziona tra filesystem diversi. Ma su alcune distribuzioni Linux /tmp è solo una cartella nella rootfs per impostazione predefinita e si potrebbe usare questo bug per spostare un file in /etc/cron, che verrà eseguito come root.
Per provarlo, devi compilare libpath_auditor.so con bazel e caricarlo in un binario utilizzando LD_PRELOAD. Qualsiasi violazione verrà registrata in syslog, quindi assicurati che sia in esecuzione.
bazel build //pathauditor/libc:libpath_auditor.so
LD_PRELOAD=/path/to/bazel-bin/pathauditor/libc/libpath_auditor.so cat /tmp/foo/bar
tail /var/log/syslog
È anche possibile eseguirlo su tutti i processi del sistema aggiungendolo a /etc/ld.so.preload. Tuttavia, attenzione: è consigliato solo su sistemi di test poiché può causare instabilità.
Per iniziare rapidamente, puoi provare il container docker fornito con questo progetto:
docker build -t pathauditor-example .
docker run -it pathauditor-example
# LD_PRELOAD=/pathauditor/bazel-bin/pathauditor/libc/libpath_auditor.so cat /tmp/foo/bar
# cat /var/log/syslog