Proiectul Google Zero a descoperit cum să ocolească Hypervisor-ul Knox de la Samsung (remediat în corecția din ianuarie)

În cea mai recentă postare pe blog Project Zero, echipa a descoperit o modalitate de a ocoli protecția în timp real a nucleului Samsung, numită Hypervisor Knox.

Echipa Google Project Zero a verificat o serie de exploit-uri care permit atacarea telefoanelor Samsung care rulează suita de securitate Samsung Knox, presupus-securizată. Blogul notează că toate vulnerabilitățile au fost transmise Samsung, care a lansat de fapt remedieri pentru ele într-o actualizare software din ianuarie.


fundal

Ca parte a suitei de software de securitate Samsung Knox introdusă de Samsung, există un program care se află între aplicațiile Android și nucleu numit Hypervisor. Acesta poate fi folosit ca un strat suplimentar pentru a securiza și mai mult dispozitivele Android. Hypervisor-ul Samsung Knox se numește „Protecție Kernel în timp real" sau RKP pe scurt, așa cum o voi face referire în restul acestui articol.

Kernel-ul se află sub RKP în stiva de software Android, iar aplicațiile care rulează pe dispozitiv se află în partea de sus. Ideea din spatele RKP este de a oferi un nivel suplimentar de securitate pentru dispozitiv, deoarece toate solicitările (memorie și alte resurse) făcute de aplicațiile către Kernel trebuie să treacă mai întâi prin Knox, care încearcă să detecteze dacă o aplicație face ceva nu ar trebui. RKP oferă, de asemenea, securitate prin obscuritate cu un strat suplimentar pentru a ascunde informațiile sensibile pe care o aplicație le-ar putea folosi pentru a compromite dispozitivul.

Postarea de blog este destul de aprofundată în modul în care funcționează memoria Android, RKP și sistemele de operare în general, așa că am condensat și simplificat pentru a oferi o privire de ansamblu rapidă a ceea ce a fost descoperit. Vă încurajez, totuși, să citiți întregul articol dacă aveți timp, deoarece este foarte lămuritor.


Exploata #1:

KASLR sau Kernel Address Space Layout Randomization este procesul de schimbare a locației codului kernel-ului în memorie cu o cantitate aleatoare la pornire. De fiecare dată când dispozitivul este pornit, nucleul este încărcat într-un spațiu de adrese diferit (zonă din memorie). Ideea este să fie mai greu de găsit unde se află codul kernel-ului pentru a-l ataca deoarece după fiecare pornire codul kernel-ului se „schimbă” cu o cantitate aleatorie în memorie. Acesta pare un pas grozav pentru a preveni potențialii atacatori, dar recent cercetare a arătat că puteți învinge acest lucru fără a necesita o eroare software sau o vulnerabilitate, deoarece KASLR este de fapt foarte greu de implementat într-un mod robust împotriva atacatorilor locali.

În cazul software-ului RKP, capacitatea de a ocoli KASLR este de fapt mai simplă decât cercetarea menționată mai sus. Memoria tuturor dispozitivelor Android este referită prin indicatori și pentru a proteja dispozitivele împotriva atacurilor, ori de câte ori dispozitivele Android imprimă sau scot (fie pentru ecran sau pentru a fi fișiere pentru jurnale sau depanare), referințele pointerilor sunt anonimizate, - ceea ce face imposibil să aflați unde indică de fapt pointerul atunci când citiți ieșire.

Gândiți-vă la indicatoarele de memorie ca la un indicator stradal care indică o locație și gândiți-vă că anonimizarea este neclară. La fel ca la televiziune, anonimizarea se face după filmare, Android aplică și această anonimizare la momentul ieșirii și numai dacă anonimizarea este configurată corect, iar autorul afirmă că fiecare dispozitiv pe care l-a întâlnit a avut anonimizarea pointerului configurată corect. Acest lucru ar putea suna ca și cum ar fi foarte greu de spart, dar tot ce trebuie să faceți este să găsiți un singur indicator (gândiți-vă la semnul stradal) care nu a fost anonimizat (încețoșat) de către dezvoltatorul kernelului (ai grijă, acesta nu este dezvoltatorul tău obișnuit de aplicații Android) când indicatorul este scris în jurnalele sau în altă locație, de ex. ecran sau a fişier.

Deci, dacă puteți găsi un pointer care nu a fost anonimizat, atunci puteți calcula schimbarea aleatorie a adresei kernelului ca diferență între cele două. Interesant, autorul nu a putut găsi un pointer exploatabil în nucleu, dar l-a găsit în RPK unde dezvoltatorii au uitat să anonimizeze un pointer în ieșirea de depanare (înregistrare), care a apărut prin intermediul unui greșeală de scriere. Pentru a anonimiza pointerii în Android, trebuie să utilizați un cod special și se pare că dezvoltatorii RPK au folosit din greșeală un minuscul „k” în loc de o „K” majuscule. Prin urmare, a fost relativ simplu să descoperi cantitatea de schimbare aleatorie a codului nucleului și să-l ataci.


Exploata #2:

Următorul exploit este puțin mai complex: Samsung Knox vă protejează dispozitivul aplicând un set de reguli în memoria dispozitivului pentru a opri codul rău intenționat. Regulile sunt următoarele:

  1. Toate paginile (codul din memorie), cu excepția codului nucleului, sunt marcate ca „Executare cu privilegiu niciodată” (adică codul de aici nu poate rula niciodată)
  2. Paginile de date kernel (date folosite de program în memorie) nu sunt niciodată marcate ca executabile (deci codul de aici nu poate rula niciodată)
  3. Paginile de coduri kernel (codul din memorie) nu sunt niciodată marcate ca fiind inscriptibile (deci niciun cod rău intenționat nu le poate schimba)
  4. Toate paginile nucleului sunt marcate ca fiind doar pentru citire în tabelul de traducere din etapa 2 (tabelul care se află între aplicație și nucleu pentru a împiedica aplicațiile să cunoască locațiile reale de memorie)
  5. Toate intrările de traducere din memorie sunt marcate ca doar pentru citire pentru aplicații.

Ne vom concentra asupra regulii 3, deoarece aici autorul a găsit o problemă cu implementarea regulilor de mai sus. De fapt, RPK marchează memoria pentru nucleu ca fiind doar pentru citire, totuși, ca o ignorare a KASL-ului, a fost descoperită o gaură, ceea ce a condus la scrierea codului în secțiunea presupusă „numai citire”.. Pentru a ofusca locația nucleului în momentul pornirii, memoria este alocată nucleului, dar această cantitate de memorie este mult mai mare decât segmentul de text al nucleului. Prin alocarea unei cantități mai mari de memorie, este mult mai dificil să găsiți codul kernel-ului real care ar putea fi oriunde și, după cum am văzut mai sus, este mutat aleatoriu la fiecare pornire a dispozitivului.

_text și _etext marchează intervalul protejat

Autorul a putut confirma că memoria folosită de nucleu a fost într-adevăr marcată ca „numai citire”, totuși restul acelei cantități mari de memorie folosită pentru a ascunde nucleul a fost nu marcat ca „numai citire”. Acest lucru se datorează faptului că RKP protejează doar regiunea care conține textul nucleului după aplicarea slide-ului KASLR.


Exploata #3

În a treia exploatare, autorul a putut accesa o altă zonă de memorie care ar trebui să fie limitată și la numai citire. RKP protejează memoria și utilizează a Registrul de configurare a hypervisorului (HCR) pentru a controla operațiunile cheie ale nucleului. Scopul HCR este de a permite operațiunilor valide și reale ale nucleului să acceseze registrele și să blocheze atacurile rău intenționate. Face acest lucru verificând apelurile efectuate către registrele care guvernează caracteristicile de virtualizare. HCR este configurat pentru a bloca operațiuni specifice care ar fi gestionate în mod normal, permițând RKP să aleagă dacă să permită sau să respingă o solicitare.

În această exploatare a fost controlul HCR care nu acoperă două registre asta s-a dovedit a fi foarte important. Autorul a săpat adânc în manualul de referință ARM și a descoperit că primul registru i-a permis practic să dezactiveze RKP pentru aplicații. "Registrul de control al sistemului pentru EL1 (SCTLR_EL1) oferă control de nivel superior asupra sistemului, inclusiv asupra sistemului de memorie.” Într-o lume perfectă, aplicația ar folosi memoria care a fost mapată prin RKP, astfel încât RKP să poată controla ceea ce poate accesa aplicația. Cu toate acestea, dezactivarea acestui registru a permis RKP să fie dezactivat prin readucerea efectivă a dispozitivului la modul în care funcționa înainte de instalarea RKP - ceea ce înseamnă că dispozitivul este mapat la memoria fizică fără securitatea suplimentară oferită de RKP. Aceasta a însemnat, la rândul său, că autorul putea citi și scrie în memoria care a fost inițial și corect blocată de software-ul RKP.

Al doilea registru care a fost ratat a avut un efect mai subtil, dar în cele din urmă la fel de devastator pentru securitate. The Registrul de control al traducerii pentru EL1 Registrul (TCR_EL1) se referă direct la cantitatea de memorie cu care lucrează o aplicație numită pagină. RKP este codificat la o dimensiune a paginii de 4 kb, deoarece nucleele AARCH64 Linux (cum ar fi Android) folosesc o dimensiune de traducere de 4KB. Registrul în cauză (TCR_EL1) setează chipset-urile ARM la dimensiunea memoriei care urmează să fie returnată. Se pare că acest registru nu este protejat de HCR și, prin urmare, un atacator îl poate schimba așa cum autorul a schimbat-o la o dimensiune de pagină de 64 kb.

Aceasta înseamnă că atunci când cererea este îndeplinită de RKP, cantitatea reală de memorie accesibilă este acum de 64 kb în loc de 4 kb. Motivul este că chipsetul ARM încă controlează dimensiunea paginii și a fost setat la 64 kb de către exploit. Deoarece RKP protejează memoria de a fi scrisă, ca parte a regulilor enumerate în exploit #2, memoria este încă protejată. Dar aici este problema - deoarece RKP este codificat la 4 kb, nu se schimbă la o dimensiune a paginii de 64 kb atunci când registrul a fost actualizat, deci doar primii 4 kb de memorie sunt protejați permițând atacatorului să facă orice vrea cu restul de 60kb.


Exploata #4

Ultima exploatare pe care o arată autorul este referirea la memorie unde se află software-ul RKP, astfel încât atacatorul ar putea ataca software-ul RKP în sine. Un truc pentru a opri acest tip de atac pe care îl folosesc și nucleele Linux este de a dezamapa programul din spațiul de adrese din memoria virtuală, astfel încât nicio aplicație să nu îl poată ataca, deoarece nu poate face referire la el.

Amintiți-vă că memoria se referă la indicatori și tabele care mapează memoria fizică cu memoria virtuală. Conform apărării obișnuite în acest tip de atac, RKP se dezactivează astfel încât să nu poată fi atacat. Cu toate acestea, acolo unde nucleul nu oferă astfel de abilități, RKP permite ca o bucată de memorie să fie mapată și marcată ca Citire/Scriere. Singura verificare este că nu este nucleul de bază în sine, deoarece RKP nu efectuează verificări pentru a vedea dacă adresele care sunt solicitate să fie mapate sunt zona în care RKP însuși se află în memorie. Practic, RKP își permite să fie re-cartografiat înapoi în spațiul de adrese pe care aplicațiile îl pot accesa și ca o parte afectează memoria este marcată automat ca Citire/Scriere astfel încât un atacator poate acum să folosească memoria cum dorește.


Concluzie

Una dintre cele mai mari probleme cu cele patru exploit-uri enumerate mai sus este că autorul menționează cât de dificil ar fi acestea de realizat din cauza lipsei de funcții din nucleul Android de bază. În mod ironic, Hypervisorul RKP securizat a oferit toate instrumentele necesare pentru a efectua atacurile. Se dovedește că, uneori, software-ul bine intenționat cauzează mai multe probleme decât rezolvă și suntem norocoși că avem oameni ca Gal Beniamini dispus să-și murdărească mâinile și să testeze că documentația se potrivește cu software-ul de fapt face.

În timp ce aceste exploituri par înfricoșătoare și fac ca Knox să sune foarte vulnerabil, aș dori să-i asigur pe toți că aceste probleme au fost toate remediat în actualizarea din ianuarie de la Samsung. Mai mult, aceste exploit-uri necesită o înțelegere foarte profundă a procesoarelor ARM și a programării, astfel încât bariera de intrare în utilizarea acestor exploit-uri este astronomic de mare.


Sursa: Project Zero