Milioni di binari dopo. Come Linux si è consolidato

Milioni di binari dopo. Come Linux si è consolidatoTL;DR. In questo articolo esploreremo gli schemi di protezione (hardening schemes) che funzionano di default in cinque popolari distribuzioni Linux. Per ciascuna abbiamo preso la configurazione del kernel predefinita, caricato tutti i pacchetti e analizzato gli schemi di protezione nei file binari incorporati. Vengono considerati i seguenti sistemi: OpenSUSE 12.4, Debian 9, CentOS, RHEL 6.10 e 7, oltre a Ubuntu 14.04, 12.04 e 18.04 LTS.

I risultati confermano che anche gli schemi di base, come le canarini dello stack e il codice indipendente dalla posizione, non sono ancora adottati da tutti. La situazione è ancora peggiore per i compilatori quando si tratta di proteggere contro vulnerabilità come lo stack clash, che ha attirato l'attenzione a gennaio dopo la pubblicazione di informazioni sulle vulnerabilità in systemd.. Ma non è tutto così disperato. In una parte significativa dei binari sono implementati metodi di protezione di base, e il loro numero cresce ad ogni versione.

La verifica ha mostrato che il numero maggiore di metodi di protezione è implementato in Ubuntu 18.04 a livello di sistema operativo e applicazioni, seguito da Debian 9. D'altra parte, anche in OpenSUSE 12.4, CentOS 7 e RHEL 7 sono implementati schemi di protezione di base, mentre la protezione contro lo stack clash è applicata in modo più ampio con un set di pacchetti predefiniti molto più denso.

Introduzione

Garantire un'alta qualità del software è difficile. Nonostante l'enorme quantità di strumenti avanzati per l'analisi statica del codice e l'analisi dinamica durante l'esecuzione, così come i notevoli progressi nello sviluppo di compilatori e linguaggi di programmazione, il software moderno continua a soffrire di vulnerabilità che vengono costantemente sfruttate dai malintenzionati. La situazione è ancora peggiore negli ecosistemi che includono codice obsoleto. In questi casi non solo affrontiamo il problema eterno della ricerca di potenziali errori sfruttabili, ma siamo anche limitati da rigide linee guida di retrocompatibilità, che spesso richiedono di mantenere codice limitato, e ancor peggio vulnerabile o buggato.

Qui entrano in gioco i metodi di protezione o di indurimento dei programmi (hardening). Alcuni tipi di errori non possiamo prevenirli, ma possiamo rendere la vita dei malintenzionati più difficile e risolvere parzialmente il problema, prevenendo o ostacolando. sfruttamento queste vulnerabilità. Tale protezione è utilizzata in tutti i moderni sistemi operativi, ma i metodi possono variare notevolmente in complessità, efficacia e prestazioni: dai 'canarini nello stack' (stack canaries) e ASLR fino a protezioni complete CFI e ROP. In questo articolo esamineremo quali metodi di protezione vengono applicati nelle distribuzioni Linux più popolari con configurazioni predefinite e studieremo le proprietà dei pacchetti binari distribuiti attraverso i sistemi di gestione dei pacchetti di ciascuna distribuzione.

CVE e sicurezza

Tutti noi abbiamo visto articoli con titoli come 'Le applicazioni più vulnerabili dell'anno' o 'I sistemi operativi più vulnerabili'. Di solito, in essi viene fornita statistica sul numero totale di registrazioni di vulnerabilità tipo CVE (Common Vulnerability and Exposures), ottenuta da National Vulnerability Database (NVD) di NIST e altre fonti. Successivamente, queste applicazioni o sistemi operativi vengono classificati in base al numero di CVE. Sfortunatamente, sebbene le CVE siano molto utili per monitorare i problemi e informare fornitori e utenti, esse dicono poco sulla reale sicurezza del software.

Per esempio, consideriamo il numero totale di CVE nell'ultimo quadriennio per il kernel Linux e per cinque delle distribuzioni server più popolari, ovvero Ubuntu, Debian, Red Hat Enterprise Linux e OpenSUSE.

Milioni di binari dopo. Come Linux si è consolidato
Fig. 1

Cosa ci dice questo grafico? Un numero maggiore di CVE significa che una distribuzione è più vulnerabile di un'altra? La risposta è no. Ad esempio, in questo articolo vedrete che Debian implementa meccanismi di protezione più severi rispetto, ad esempio, a OpenSUSE o RedHat Linux, eppure ha un numero maggiore di CVE. Tuttavia, ciò non implica necessariamente una sicurezza compromessa: anche la presenza di CVE non indica se una vulnerabilità è sfruttabile. I punteggi di gravità forniscono un'idea di quanto sia probabile sfruttare una vulnerabilità, ma alla fine l'effettiva sfruttabilità dipende in larga misura dalla protezione presente nei sistemi interessati, nonché dalle risorse e dalle capacità degli aggressori. Inoltre, l'assenza di report CVE non dice nulla su altre vulnerabilità non registrate o sconosciute vulnerabilità. La differenza nel CVE può essere spiegata non dalla qualità del software, ma da altri fattori, inclusi le risorse dedicate ai test o la dimensione della base utenti. Nel nostro esempio, un numero maggiore di CVE in Debian potrebbe semplicemente indicare che Debian fornisce più pacchetti software.

Naturalmente, il sistema CVE fornisce informazioni utili che consentono di creare le protezioni adeguate. Più comprendiamo le cause dei malfunzionamenti del programma, più semplice risulta identificare i possibili modi di sfruttamento e sviluppare i meccanismi appropriati. di rilevamento e risposta.Nella Fig. 2 sono mostrate le categorie delle vulnerabilità per tutte le distribuzioni negli ultimi quattro anni (fonte). È immediatamente evidente che la maggior parte delle CVE rientrano nelle seguenti categorie: attacchi di negazione del servizio (DoS), esecuzione di codice, overflow, corruzione di memoria, fuga (exfiltrazione) di informazioni ed escalation dei privilegi. Anche se molte CVE sono contabilizzate più volte in diverse categorie, in generale, gli stessi problemi persistono di anno in anno. Nella parte successiva dell'articolo, valuteremo l'uso di diversi schemi di protezione per prevenire lo sfruttamento delle vulnerabilità indicate.

Milioni di binari dopo. Come Linux si è consolidato
Fig. 2

Problemi

In questo articolo intendiamo rispondere alle seguenti domande:

  • Qual è la sicurezza delle diverse distribuzioni Linux? Quali meccanismi di protezione esistono nel kernel e nelle applicazioni dello spazio utente?
  • Come è cambiata nel tempo l'adozione dei meccanismi di protezione per le diverse distribuzioni?
  • Quali sono le dipendenze medie dei pacchetti e delle librerie per ciascuna distribuzione?
  • Quali protezioni sono implementate per ciascun binario?

Scelta delle distribuzioni

Si scopre che è difficile trovare statistiche accurate sulle installazioni delle distribuzioni, poiché nella maggior parte dei casi il numero di download non indica il numero di installazioni reali. Tuttavia, le opzioni Unix costituiscono la maggior parte dei sistemi server (69,2% sui server web, secondo statistiche W3techs e altre fonti), e la loro quota è in costante crescita. Pertanto, per la nostra ricerca ci siamo concentrati su distribuzioni disponibili 'out of the box' sulla piattaforma Google Cloud. In particolare, abbiamo scelto i seguenti sistemi operativi:

Distribuzione/versione
Il kernel
Build

OpenSUSE 12.4
4.12.14-95.3-default
#1 SMP Wed Dec 5 06:00:48 UTC 2018 (63a8d29)

Debian 9 (stretch)
4.9.0-8-amd64
#1 SMP Debian 4.9.130-2 (2018-10-27)

CentOS 6.10
2.6.32-754.10.1.el6.x86_64
#1 SMP Tue Jan 15 17:07:28 UTC 2019

CentOS 7
3.10.0-957.5.1.el7.x86_64
#1 SMP Fri Feb 1 14:54:57 UTC 2019

Red Hat Enterprise Linux Server 6.10 (Santiago)
2.6.32-754.9.1.el6.x86_64
#1 SMP Wed Nov 21 15:08:21 EST 2018

Red Hat Enterprise Linux Server 7.6 (Maipo)
3.10.0-957.1.3.el7.x86_64
#1 SMP Thu Nov 15 17:36:42 UTC 2018

Ubuntu 14.04 (Trusty Tahr)
4.4.0–140-generic

#166~14.04.1-Ubuntu SMP Sat Nov 17 01:52:43 UTC 20…

Ubuntu 16.04 (Xenial Xerus)
4.15.0–1026-gcp
#27~16.04.1-Ubuntu SMP Fri Dec 7 09:59:47 UTC 2018

Ubuntu 18.04 (Bionic Beaver)
4.15.0–1026-gcp
#27-Ubuntu SMP Thu Dec 6 18:27:01 UTC 2018

Tabella 1

Analisi

Esamineremo la configurazione del kernel predefinita e le proprietà dei pacchetti disponibili tramite il gestore di pacchetti di ciascuna distribuzione out-of-the-box. In questo modo, consideriamo solo i pacchetti dagli specchi predefiniti di ciascuna distribuzione, ignorando i pacchetti dai repository instabili (ad esempio, gli specchi 'testing' in Debian) e i pacchetti di terze parti (ad esempio, i pacchetti Nvidia dagli specchi standard). Inoltre, non consideriamo le compilazioni del kernel personalizzate o le configurazioni con una maggiore protezione.

Analisi della configurazione del kernel

Abbiamo applicato uno script di analisi basato su un verificatore kconfig open source. Consideriamo i parametri di protezione predefiniti nelle distribuzioni nominate e li confrontiamo con l'elenco di Kernel Self-Protection Project (KSPP). Per ciascun parametro di configurazione, la tabella 2 descrive la configurazione desiderata: un segno di spunta indica le distribuzioni che soddisfano le raccomandazioni KSSP (il chiarimento dei termini è disponibile qui; in articoli futuri parleremo di come sono nati molti di questi metodi di protezione e di come compromettere il sistema in loro assenza).

Milioni di binari dopo. Come Linux si è consolidato

Milioni di binari dopo. Come Linux si è consolidato

In generale, i nuovi kernel hanno impostazioni più rigorose di serie. Ad esempio, CentOS 6.10 e RHEL 6.10 sul kernel 2.6.32 non hanno la maggior parte delle funzionalità critiche implementate nei nuovi kernel, come SMAP, autorizzazioni RWX rigorose, randomizzazione degli indirizzi o protezione copy2usr. È importante notare che molte delle opzioni di configurazione nella tabella sono assenti nelle versioni più vecchie del kernel e non sono applicabili nella realtà — in tabella ciò è comunque indicato come mancanza di protezione adeguata. Allo stesso modo, se un parametro di configurazione è assente in questa versione e per motivi di sicurezza questo parametro deve essere disabilitato, questa è considerata una configurazione ragionevole.

Un altro aspetto da considerare nell'interpretazione dei risultati è che alcune configurazioni del kernel che aumentano la superficie di attacco possono essere utilizzate anche per la sicurezza. Esempi di ciò includono uprobes e kprobes, moduli del kernel e BPF/eBPF. La nostra raccomandazione è di utilizzare i meccanismi sopra citati per garantire una protezione reale, dato che non sono di immediata utilizzazione e la loro sfruttamento implica che i soggetti malevoli siano già radicati nel sistema. Ma se queste opzioni sono abilitate, l'amministratore di sistema deve monitorare attivamente gli abusi.

Analizzando ulteriormente le registrazioni della tabella 2, notiamo che i kernel moderni offrono diverse opzioni per proteggere da vulnerabilità come la perdita di informazioni e l'overflow dello stack/heap. Tuttavia, notiamo che anche le distribuzioni più recenti e popolari non hanno ancora implementato protezioni più complesse (ad esempio, con patch grsecurity) o protezioni moderne contro attacchi di riutilizzo del codice (ad esempio, una combinazione di randomizzazione con schemi di tipo R^X per il codice). Ciò che è ancora più preoccupante è che anche questi strumenti di protezione più avanzati non difendono da un'ampia gamma di attacchi. È quindi fondamentale per gli amministratori di sistema integrare configurazioni ragionevoli con soluzioni che offrono rilevamento e prevenzione degli exploit in tempo reale.

Analisi delle applicazioni

Non sorprende che le diverse distribuzioni presentino caratteristiche differenti nei pacchetti, opzioni di compilazione, dipendenze delle librerie, ecc. Le differenze esistono anche per distribuzioni affini e pacchetti con poche dipendenze (ad esempio, coreutils in Ubuntu o Debian). Per valutare le differenze, abbiamo scaricato tutti i pacchetti disponibili, estratto il loro contenuto e analizzato i file binari e le dipendenze. Per ogni pacchetto abbiamo tracciato altri pacchetti dai quali dipende e per ogni binario abbiamo tracciato le sue dipendenze. In questa sezione presenteremo brevemente le conclusioni.

Distribuzioni

In totale, abbiamo caricato 361.556 pacchetti per tutte le distribuzioni, estraendo solo pacchetti dai mirror predefiniti. Abbiamo ignorato i pacchetti privi di file eseguibili ELF, come il codice sorgente, i font, ecc. Dopo il filtraggio, sono rimasti 129.569 pacchetti, contenenti in totale 584.457 file binari. La distribuzione dei pacchetti e dei file tra le distribuzioni è mostrata nella fig. 3.

Milioni di binari dopo. Come Linux si è consolidato
Fig. 3

Si può notare che più moderna è la distribuzione, maggiore è il numero di pacchetti e file binari, il che è logico. Tuttavia, i pacchetti di Ubuntu e Debian includono molti più file binari (sia eseguibili che moduli dinamici e librerie) rispetto a CentOS, SUSE e RHEL, il che potrebbe influenzare la superficie di attacco di Ubuntu e Debian (è importante notare che i numeri riflettono tutti i binari di tutte le versioni del pacchetto, ovvero alcuni file vengono analizzati più volte). Questo è particolarmente significativo se si considerano le dipendenze tra i pacchetti. Pertanto, una vulnerabilità in un binario di un pacchetto può influire su molte parti dell'ecosistema, proprio come una libreria vulnerabile può influenzare tutti i file binari che la importano. Come punto di riferimento, esaminiamo la distribuzione del numero di dipendenze per pacchetto nei vari sistemi operativi:

Milioni di binari dopo. Come Linux si è consolidato
Figura 4

Quasi in tutte le distribuzioni, il 60% dei pacchetti ha almeno 10 dipendenze. Inoltre, alcuni pacchetti hanno un numero di dipendenze significativamente maggiore (oltre 100). Lo stesso vale per le dipendenze inverse dei pacchetti: come previsto, diversi pacchetti sono utilizzati da molti altri pacchetti nella distribuzione, quindi le vulnerabilità in questi pochi selezionati comportano un alto rischio. Ad esempio, nella seguente tabella sono elencati 20 pacchetti con il massimo numero di dipendenze inverse in SLES, CentOS 7, Debian 9 e Ubuntu 18.04 (in ogni cella è indicato il pacchetto e il numero di dipendenze inverse).

Milioni di binari dopo. Come Linux si è consolidato
Tabella 3

Fatto interessante. Sebbene tutti i sistemi operativi analizzati siano costruiti per l'architettura x86_64, e la maggior parte dei pacchetti abbia l'architettura definita come x86_64 e x86, i pacchetti spesso contengono file binari per altre architetture, come mostrato nella fig. 5.

Milioni di binari dopo. Come Linux si è consolidato
Fig. 5

Nel prossimo capitolo approfondiremo le caratteristiche dei binari analizzati.

Statistiche sulla protezione dei file binari

Come minimo, è necessario studiare un insieme di opzioni di protezione di base per i file binari esistenti. Alcuni distributivi Linux vengono forniti con script che eseguono tali verifiche. Ad esempio, in Debian/Ubuntu esiste uno script di questo tipo. Ecco un esempio del suo funzionamento:

$ hardening-check $(which docker)
/usr/bin/docker:
 Eseguibile indipendente dalla posizione: sì
 Stack protetto: sì
 Funzioni di fonte fortificate: no, trovate solo funzioni non protette!
 Ridenominazioni di sola lettura: sì
 Legame immediato: sì

Lo script controlla cinque funzioni di protezione:

  • Eseguibile indipendente dalla posizione (PIE): indica se è possibile spostare in memoria la sezione di codice del programma per ottenere la randomizzazione, se l'ASLR è abilitato nel kernel.
  • Stack protetto: sono attivate le canarie dello stack per proteggersi dagli attacchi di collisione dello stack.
  • Fortify Source: le funzioni non sicure (ad esempio, strcpy) vengono sostituite con i loro equivalenti più sicuri, e le chiamate verificate in fase di esecuzione vengono sostituite con le loro versioni non verificate (ad esempio, memcpy invece di __memcpy_chk).
  • Ridenominazioni di sola lettura (RELRO): le voci della tabella delle ridenominazioni sono contrassegnate come "sola lettura", se sono state attivate prima dell'inizio dell'esecuzione.
  • Legame immediato: consente all'editor di collegamenti di risolvere tutte le ridenominazioni prima dell'inizio dell'esecuzione del programma (equivalente a un RELRO completo).

Bastano i meccanismi sopra elencati? Purtroppo no. Sono noti metodi per eludere tutte le protezioni sopra menzionate, ma più rigida è la protezione, maggiore è la soglia per l'attaccante. Ad esempio, i metodi per eludere RELRO sono più difficili da applicare se sono attivi PIE e legame immediato. Allo stesso modo, un ASLR completo richiede un lavoro supplementare per creare un exploit funzionante. Tuttavia, gli aggressori sofisticati sono già pronti ad affrontare tali protezioni: la loro assenza accelera essenzialmente l'hacking. È quindi estremamente importante che queste misure siano considerate necessarie. almeno.

Volevamo studiare quante applicazioni binarie nei distributivi esaminati sono protette da queste e altre tre metodologie:

  • Il bit non eseguibile (NX) impedisce l'esecuzione in qualsiasi zona che non dovrebbe essere eseguibile, ad esempio nell'heap dello stack, ecc.
  • RPATH/RUNPATH indica il percorso di esecuzione utilizzato dal caricatore dinamico per trovare le librerie appropriate. Il primo è obbligatorio per qualsiasi sistema moderno: la sua assenza consente agli aggressori di scrivere arbitrariamente il payload nella memoria ed eseguirlo così com'è. Per il secondo, configurazioni errate del percorso di esecuzione aiutano a introdurre codice inaffidabile, che può portare a una serie di problemi (ad esempio, elevazione di privilegi, e inoltre altri problemi).
  • La protezione contro le collisioni dello stack offre protezione contro attacchi che costringono lo stack a sovrapporsi ad altre aree di memoria (ad esempio, all'heap). Considerando gli exploit recenti che abusano vulnerabilità di collisione dell'heap in systemd, abbiamo ritenuto opportuno includere questo meccanismo nel nostro set di dati.

Quindi, senza ulteriori indugi, passiamo ai numeri. Le tabelle 4 e 5 contengono un riepilogo dell'analisi dei file eseguibili e delle librerie di diverse distribuzioni, rispettivamente.

  • Come si può notare, la protezione NX è implementata ovunque, con poche eccezioni. In particolare, si può notare un utilizzo leggermente più basso nelle distribuzioni Ubuntu e Debian rispetto a CentOS, RHEL e OpenSUSE.
  • Le canarini dello stack mancano in molti luoghi, specialmente nelle distribuzioni con kernel obsoleti. Alcuni progressi si osservano nelle ultime distribuzioni di CentOS, RHEL, Debian e Ubuntu.
  • Ad eccezione di Debian e Ubuntu 18.04, nella maggior parte delle distribuzioni c'è un cattivo supporto per PIE.
  • La protezione delle collisioni dello stack è debolmente implementata in OpenSUSE, CentOS 7 e RHEL 7 e praticamente assente nelle altre.
  • Tutte le distribuzioni con kernel moderni hanno un certo supporto per RELRO, con Ubuntu 18.04 in testa e Debian al secondo posto.

Come già accennato, le metriche in questa tabella sono medie su tutte le versioni del file binario. Se si considerano solo le ultime versioni dei file, le cifre saranno diverse (ad esempio, vedi i progressi di Debian con l'implementazione di PIE). Inoltre, la maggior parte delle distribuzioni di solito calcola le statistiche controllando la protezione solo di alcune funzioni nel codice binario, mentre nella nostra analisi è indicato il vero percentuale delle funzioni rinforzate. Pertanto, se in un binario sono protette 5 su 50 funzioni, daremo un punteggio di 0,1, che corrisponde al 10% delle funzioni rinforzate.

Milioni di binari dopo. Come Linux si è consolidato
Tabella 4. Caratteristiche di protezione per i file eseguibili mostrati nella figura 3 (implementazione delle funzioni corrispondenti in percentuale rispetto al numero totale di file eseguibili)

Milioni di binari dopo. Come Linux si è consolidato
Tabella 5. Caratteristiche di sicurezza per le librerie mostrate nella fig. 3 (implementazione delle funzioni corrispondenti in percentuale rispetto al numero totale di librerie)

C'è progresso? Certamente c'è: è evidente dalle statistiche relative a singoli distribuzioni (ad esempio, Debian), così come dalle tabelle sopra fornite. Come esempio, nella fig. 6 è mostrata l'implementazione dei meccanismi di protezione in tre distribuzioni consecutive di Ubuntu LTS 5 (abbiamo omesso le statistiche sulla protezione contro gli overflow del buffer). Notiamo che da una versione all'altra un numero crescente di file supporta le 'canarini dello stack' e sempre più file binari vengono forniti con protezione RELRO completa.

Milioni di binari dopo. Come Linux si è consolidato
Fig. 6

Sfortunatamente, diversi file eseguibili in diverse distribuzioni non possiedono ancora alcuna delle protezioni sopra menzionate. Ad esempio, osservando Ubuntu 18.04, possiamo notare il binario ngetty (sostituzione di getty), così come le shell mksh e lksh, l'interprete picolisp, i pacchetti nvidia-cuda-toolkit (un pacchetto popolare per applicazioni accelerate da GPU, come i framework di machine learning) e klibc-utils. Analogamente, il binario mandos-client (uno strumento amministrativo che consente di riavviare automaticamente le macchine con file system crittografati), così come il rsh-redone-client (una rielaborazione di rsh e rlogin) vengono forniti senza protezione NX, nonostante abbiano diritti SUID :(. Inoltre, in diversi binari suid non è presente la protezione di base, come le canarini dello stack (ad esempio, il file binario Xorg.wrap dal pacchetto Xorg).

Riepilogo e osservazioni finali

In questo articolo abbiamo evidenziato diverse proprietà di sicurezza delle moderne distribuzioni Linux. L'analisi ha dimostrato che nell'ultima distribuzione di Ubuntu LTS (18.04) è implementata in media la più forte protezione a livello di OS e applicazioni tra le distribuzioni con kernel relativamente recenti, come Ubuntu 14.04, 12.04 e Debian 9. Tuttavia, le distribuzioni considerate, CentOS, RHEL e OpenSUSE nel nostro dataset, offrono per default un pacchetto più ricco, e nelle ultime versioni (CentOS e RHEL) hanno una percentuale più alta di implementazione della protezione contro il collision stacking, rispetto ai concorrenti basati su Debian (Debian e Ubuntu). Confrontando le versioni di CentOS e RedHat, notiamo significativi miglioramenti nell'implementazione delle stack canaries e RELRO da versioni 6 a 7, ma in media CentOS ha implementato più funzionalità rispetto a RHEL. In generale, tutte le distribuzioni dovrebbero prestare particolare attenzione alla protezione PIE, che, ad eccezione di Debian 9 e Ubuntu 18.04, è implementata in meno del 10% dei file binari nel nostro dataset.

Infine, è importante notare: anche se abbiamo condotto la ricerca manualmente, esistono molti strumenti di sicurezza (ad esempio, Lynis, Tiger, Hubble), che eseguono analisi e aiutano a evitare configurazioni non sicure. Sfortunatamente, anche una forte protezione in configurazioni ragionevoli non garantisce l'assenza di exploit. Ecco perché siamo fermamente convinti che sia fondamentale garantire monitoraggio affidabile e prevenzione degli attacchi in tempo reale, concentrandosi sui modelli di sfruttamento e prevenendoli.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster