Atacurile de deserializare - manipularea neautorizată a datelor serializate pentru a executa cod malițios - pot provoca daune grave organizațiilor. Dezvoltatorii și echipele de securitate trebuie să identifice proactiv vulnerabilitățile cheie care dezvăluie cum, când și unde a avut loc atacul.
Un exemplu recent al acestei amenințări este CVE-2023-34040, un vector de atac de deserializare în Spring pentru Apache Kafka care poate duce la RCE (executarea codului de la distanță). De fapt, prevalența vulnerabilităților de deserializare este evidențiată de lista OWASP Top 10, care include "Deserializarea datelor nesigure" ca unul dintre primele 10 cele mai critice riscuri de securitate ale aplicațiilor web.
Instrumente precum OPSWAT MetaDefender Core™ cu motorul său SBOMSoftware Bill of Materials) sunt esențiale în detectarea și prevenirea atacurilor de deserializare. Acestea permit dezvoltatorilor să își scaneze și să își analizeze eficient codul, asigurându-se că nu sunt trecute cu vederea vulnerabilități.
În acest blog, bursierii noștri absolvenți vor discuta detaliile CVE-2023-34040 și exploatarea sa, precum și modul de securizare a componentelor open-source împotriva amenințărilor similare.
Despre CVE-2023-34040
CVE-2023-34040 dezvăluie un vector de atac de deserializare în Spring pentru Apache Kafka, care poate fi exploatat atunci când este aplicată o configurație neobișnuită. Această vulnerabilitate permite unui atacator să construiască un obiect serializat malițios într-unul dintre anteturile înregistrării excepției de deserializare, ceea ce poate duce la RCE. Vulnerabilitatea afectează versiunile Spring for Apache Kafka 2.8.1 până la 2.9.10 și 3.0.0 până la 3.0.9.
Mai exact, o aplicație/consumator este vulnerabil în următoarele configurații și condiții specifice:
- Clasa ErrorHandlingDeserializer nu este configurată pentru cheia și/sau valoarea înregistrării.
- Proprietățile checkDeserExWhenKeyNull și/sau checkDeserExWhenValueNull ale consumatorului sunt setate la true.
- Sursele neîncrezătoare sunt autorizate să publice pe un subiect Kafka.
Apache Kafka
Apache Kafka, dezvoltată de Apache Software Foundation, este o platformă distribuită de streaming de evenimente concepută pentru a capta, procesa, răspunde și direcționa fluxuri de date în timp real din diverse surse, inclusiv baze de date, senzori și dispozitive mobile .
De exemplu, acesta poate transmite notificări către servicii care reacționează la activitățile clienților, cum ar fi finalizarea unui proces de cumpărare a unui produs sau efectuarea unei plăți.
În Apache Kafka, un eveniment - denumit și înregistrare sau mesaj - servește drept unitate de date care reprezintă un eveniment în aplicație ori de câte ori datele sunt citite sau scrise. Fiecare eveniment include o cheie, o valoare, un timestamp și antete opționale de metadate.
Cheie-binară (poate fi nulă) | Valoare-binară (poate fi nulă) | ||||
Tip de compresie [none, gzip, snappy, lz4, zstd] | |||||
Antet (opțional)
| |||||
Partiție + decalaj | |||||
Timestamp (setat de sistem sau de utilizator) |
Evenimentele sunt stocate durabil și organizate în subiecte. Aplicațiile client care trimit (scriu) evenimente în subiectele Kafka sunt denumite producători, în timp ce cele care se abonează la evenimente (le citesc și le procesează) sunt cunoscute sub numele de consumatori.
Spring pentru Apache Kafka
Pentru a conecta Apache Kafka cu ecosistemul Spring, dezvoltatorii pot utiliza Spring for Apache Kafka, care simplifică integrarea în aplicațiile Java.
Spring pentru Apache Kafka oferă instrumente și API-uri robuste care simplifică procesul de trimitere și primire a evenimentelor cu Kafka, permițând dezvoltatorilor să îndeplinească aceste sarcini fără codare extinsă și complexă.
Serializare și deserializare
Serializarea este un mecanism de conversie a stării unui obiect într-un șir sau într-un flux de octeți. În schimb, deserializarea este procesul invers, în care datele serializate sunt convertite înapoi în obiectul sau structura de date inițială. Serializarea permite transformarea datelor complexe astfel încât acestea să poată fi salvate într-un fișier, trimise printr-o rețea sau stocate într-o bază de date. Serializarea și deserializarea sunt esențiale pentru schimbul de date în sistemele distribuite și promovează comunicarea între diferitele componente ale unei aplicații software. În Java, writeObject() este utilizat pentru serializare, iar readObject() este utilizat pentru deserializare.
Deoarece deserializarea permite conversia unui flux de octeți sau a unui șir de caractere într-un obiect, manipularea necorespunzătoare sau lipsa validării corespunzătoare a datelor de intrare poate duce la o vulnerabilitate de securitate semnificativă, care poate duce la un atac RCE.
Analiza vulnerabilității
În conformitate cu descrierea CVE, bursierii OPSWAT au configurat checkDeserExWhenKeyNull și checkDeserExWhenValueNull la true pentru a declanșa vulnerabilitatea de securitate. Prin trimiterea unei înregistrări cu o cheie/valoare goală și efectuarea unei analize detaliate prin depanarea consumatorului pe măsură ce acesta primea o înregistrare Kafka de la producător, bursierii noștri absolvenți au descoperit următorul flux de lucru în timpul procesării înregistrării:
Etapa 1: Primirea înregistrărilor (mesajelor)
La primirea înregistrărilor, consumatorul invocă metoda invokeIfHaveRecords(), care apoi apelează metoda invokeListener() pentru a declanșa un ascultător de înregistrări înregistrat (o clasă adnotată cu adnotarea @KafkaListener ) pentru prelucrarea efectivă a înregistrărilor.
Metoda invokeListener() invocă apoi metoda invokeOnMessage().
Etapa 2: Verificarea înregistrărilor
În cadrul metodei invokeOnMessage(), mai multe condiții sunt evaluate în raport cu valoarea înregistrării și cu proprietățile de configurare, care determină ulterior următorul pas care urmează să fie executat.
Dacă o înregistrare are o cheie sau o valoare nulă și proprietățile checkDeserExWhenKeyNull și/sau checkDeserExWhenValueNull sunt setate explicit la true, metoda checkDeser() va fi apelată pentru a examina înregistrarea.
Pasul 3: Verificarea excepției din antet
În checkDesr(), consumatorul invocă continuu getExceptionFromHeader() pentru a extrage orice excepție din metadatele înregistrării, dacă există, și stochează rezultatul într-o variabilă numită excepție.
Pasul 4: Extragerea excepției din antet
Metoda getExceptionFromHeader() este concepută pentru a extrage și a returna o excepție din antetul unei înregistrări Kafka. Metoda extrage mai întâi antetul înregistrării și apoi obține valoarea antetului, care este stocată într-un array de octeți.
Ulterior, acesta transmite matricea de octeți a valorii antetului către metoda byteArrayToDeserializationException() pentru a fi tratată ulterior.
Pasul 5: Deserializarea datelor
În byteArrayToDeserializationException(), funcția resolveClass() este suprascrisă pentru a restricționa deserializarea numai la clasele permise. Această abordare împiedică deserializarea oricărei clase care nu este permisă în mod explicit. Valoarea byte array a antetului poate fi deserializată în byteArrayToDeserializationException() numai dacă îndeplinește condiția stabilită în resolveClass(), care permite deserializarea exclusiv pentru clasa DeserializationException.
Cu toate acestea, clasa DeserializationException extinde clasa Exception standard și include un constructor cu patru parametri. Ultimul parametru, cause, reprezintă excepția inițială care a declanșat DeserializationException, cum ar fi o IOException sau o ClassNotFoundException.
Clasa Throwable servește drept superclasă pentru toate obiectele care pot fi aruncate ca excepții sau erori în Java. În limbajul de programare Java, clasele de gestionare a excepțiilor precum Throwable, Exception și Error pot fi deserializate în siguranță. Atunci când o excepție este deserializată, Java permite încărcarea și instanțierea clasei părinte Throwable cu verificări mai puțin stricte decât cele aplicate claselor obișnuite.
Pe baza fluxului de lucru și a analizei cuprinzătoare, dacă datele serializate corespund unei clase malițioase care moștenește din clasa părinte Throwable, aceasta poate ocoli verificările condițiilor. Acest lucru permite deserializarea unui obiect rău intenționat, care poate executa cod dăunător și poate duce la un atac RCE.
Exploatare
După cum se indică în analiză, exploatarea acestei vulnerabilități necesită generarea de date malițioase trimise consumatorului prin intermediul înregistrării antetului Kafka. Inițial, atacatorul trebuie să creeze o clasă malițioasă care extinde clasa Throwable și apoi să utilizeze un lanț de gadgeturi pentru a obține executarea codului de la distanță. Gadgeturile sunt fragmente de cod exploatabile în cadrul aplicației, iar prin înlănțuirea lor, atacatorul poate ajunge la un "gadget de scurgere" care declanșează acțiuni dăunătoare.
Următoarea este o clasă malițioasă care poate fi utilizată pentru a exploata această vulnerabilitate în Spring pentru Apache Kafka:
În continuare, se creează o instanță a clasei malițioase și se transmite ca argument pentru parametrul cause din constructorul clasei DeserializationException. Instanța DeserializationException este apoi serializată într-un flux de octeți, care este utilizat ulterior ca valoare în antetul înregistrării Kafka malițioase.
Dacă atacatorul reușește să păcălească victima să folosească producătorul său rău intenționat, poate controla înregistrările Kafka trimise consumatorului, creând o oportunitate de a compromite sistemul.
Atunci când consumatorul vulnerabil primește o înregistrare Kafka de la producătorul rău intenționat care conține chei și valori nule, împreună cu o instanță serializată rău intenționată în antetul înregistrării, consumatorul procesează înregistrarea, inclusiv procesul de deserializare. Acest lucru duce în cele din urmă la executarea codului de la distanță, permițând atacatorului să compromită sistemul.
Mitigarea CVE-2023-34040 cu SBOM în MetaDefender Core
Pentru a reduce în mod eficient riscurile asociate cu CVE-2023-34040, organizațiile au nevoie de o soluție cuprinzătoare care să ofere vizibilitate și control asupra componentelor open-source.
SBOM, o tehnologie fundamentală din cadrul MetaDefender Core, oferă un răspuns puternic. Acționând ca un inventar cuprinzător al tuturor componentelor software, bibliotecilor și dependențelor utilizate, SBOM permite organizațiilor să urmărească, să securizeze și să actualizeze componentele lor open-source într-un mod proactiv și eficient.
Cu SBOM, echipele de securitate pot:
- Localizați rapid componentele vulnerabile: Identificați imediat componentele open-source afectate de atacurile de deserializare. Acest lucru asigură o acțiune rapidă de remediere sau înlocuire a bibliotecilor vulnerabile.
- Asigurați patch-uri și actualizări proactive: Monitorizați continuu componentele open-source prin intermediul SBOM pentru a rămâne în fața vulnerabilităților de deserializare. SBOM poate detecta componente învechite sau nesigure, permițând actualizări în timp util și reducând expunerea la atacuri.
- Mențineți conformitatea și raportarea: SBOM ajută organizațiile să îndeplinească cerințele de conformitate, deoarece cadrele de reglementare impun din ce în ce mai mult transparența în lanțurile de aprovizionare cu software.
Gânduri de încheiere
Vulnerabilitățile de deserializare reprezintă o amenințare semnificativă la adresa securității care poate fi utilizată pentru a exploata o gamă largă de aplicații. Aceste vulnerabilități apar atunci când o aplicație deserializează date malițioase, permițând atacatorilor să execute cod arbitrar sau să acceseze informații sensibile. Vulnerabilitatea CVE-2023-34040 din Spring pentru Apache Kafka reamintește cu claritate pericolele atacurilor de deserializare.
Pentru a preveni atacurile de deserializare, este esențial să implementați instrumente avansate precum OPSWAT MetaDefender Core și tehnologia sa SBOM. Organizațiile pot obține o vizibilitate profundă asupra lanțului lor de aprovizionare cu software, pot asigura remedierea la timp a vulnerabilităților și se pot proteja împotriva peisajului amenințărilor în continuă evoluție. Securizarea proactivă a componentelor open-source nu este doar o bună practică - este o necesitate pentru protejarea sistemelor moderne împotriva exploatării potențiale.