Il compiler di Ken Thompson ha ancora una minaccia?

154

Ken Thompson Hack (1984)

Ken Thompson ha delineato un metodo per corrompere un binario del compilatore (e altro software compilato, come uno script di accesso su un sistema * nix) nel 1984. Ero curioso di sapere se la compilazione moderna ha risolto questo difetto di sicurezza o meno. p>

Breve descrizione:

Riscrivi il codice del compilatore per contenere 2 difetti:

  • Quando compila il proprio binario, il compilatore deve compilare questi difetti
  • Quando si compila un altro codice preselezionato (funzione di login), deve compilare qualche backdoor arbitrario

Quindi, il compilatore funziona normalmente - quando compila uno script di accesso o simile, può creare una backdoor di sicurezza, e quando compila nuove versioni di se stesso in futuro, mantiene i difetti precedenti - e i difetti esisterà solo nel compilatore binario quindi sono estremamente difficili da rilevare.

Domande:

Non ho trovato nessuna risposta a questi sul web:

  • In che modo si riferisce alla compilazione just-in-time?
  • Sono funzioni come il programma che gestisce gli accessi su un sistema * nix compilati quando lo sono eseguire?
  • È ancora una minaccia valida o ci sono stati sviluppi in la sicurezza della compilazione dal 1984 che impedisce a questo di essere un problema significativo?
  • Questo riguarda tutte le lingue?

Perché voglio sapere?

Mi sono imbattuto in questo mentre facevo alcuni compiti, e mi è sembrato interessante, ma mi manca lo sfondo per comprendere in modo concreto se si tratta di un problema corrente o di un problema risolto.

Materiale di riferimento

posta svick 25.01.2013 - 20:45
fonte

10 risposte

109

Questo hack deve essere compreso nel contesto. È stato pubblicato in un momento e in una cultura in cui Unix in esecuzione su tutti i tipi di hardware diverso era il sistema dominante.

Ciò che rendeva l'attacco così spaventoso era che il compilatore C era the parte centrale del software per questi sistemi. Quasi tutto nel sistema ha attraversato il compilatore quando è stato installato per la prima volta (le distribuzioni binarie erano rare a causa dell'hardware eterogeneo). Tutti hanno compilato roba tutto il tempo. Le persone ispezionavano regolarmente il codice sorgente (spesso dovevano fare delle regolazioni per farlo compilare del tutto), quindi avere il compilatore iniettare backdoor sembrava essere una specie di scenario di "crimine perfetto" in cui non si poteva essere scoperti.

Oggigiorno, l'hardware è molto più compatibile e quindi i compilatori hanno un ruolo molto più piccolo nell'operatività quotidiana di un sistema. Un compilatore compromesso non è più lo scenario più spaventoso: i rootkit e un BIOS compromesso sono ancora più difficili da rilevare e da eliminare.

    
risposta data 25.01.2013 - 22:51
fonte
69

Lo scopo di quel discorso non era quello di evidenziare una vulnerabilità che deve essere affrontata, o anche di proporre una vulnerabilità teorica di cui dobbiamo essere consapevoli.

Lo scopo era che, quando si tratta di sicurezza, ci piacerebbe non avere fiducia in nessuno, ma sfortunatamente è impossibile. Devi sempre fidarsi di qualcuno (da qui il titolo: "Reflections On Trusting Trust")

Anche se sei il tipo paranoico che crittografa il suo hard disk desktop e si rifiuta di eseguire qualsiasi software che non ti è stato compilato, devi comunque aver fiducia nel tuo sistema operativo. E anche se si compila autonomamente il sistema operativo, è comunque necessario fidarsi del compilatore che si è utilizzato. E anche se compili il tuo compilatore, devi ancora avere fiducia nel compilatore che ! E questo non menziona nemmeno i produttori di hardware!

Semplicemente non puoi farcela fidando di nessuno . Questo è il punto che stava cercando di trasmettere.

    
risposta data 26.01.2013 - 00:17
fonte
53

No

L'attacco, come originariamente descritto, non è mai stato una minaccia. Mentre un compilatore teoricamente potrebbe fare ciò, in realtà il ritiro dell'attacco richiederebbe la programmazione del compilatore in

  • Riconoscere quando il codice sorgente che si sta compilando è di un compilatore e
  • Scopri come modificare il codice sorgente arbitrario per inserire l'hack in esso.

Ciò significa capire come funziona il compilatore dal suo codice sorgente, in modo che possa modificarlo senza interruzioni.

Ad esempio, immagina che il formato di collegamento memorizzi le lunghezze dei dati o l'offset del codice macchina compilato da qualche parte nel file eseguibile. Il compilatore dovrebbe capire da solo quali di questi devono essere aggiornati, e dove, quando si inserisce il carico utile di exploit. Le versioni successive del compilatore (versione innocua) possono cambiare arbitrariamente questo formato, quindi il codice exploit dovrebbe effettivamente comprendere questi concetti.

Questa è una programmazione auto-diretta di alto livello, un problema di intelligenza artificiale difficile (l'ultima volta che ho controllato, lo stato dell'arte stava generando codice che è praticamente determinato dai suoi tipi). Guarda: pochi umani possono persino farlo; dovresti imparare il linguaggio di programmazione e capire prima il codice base.

Anche se il problema di intelligenza artificiale è risolto, le persone si accorgerebbero se compilando i loro piccoli risultati del compilatore in un file binario con un'enorme libreria di IA collegata in esso.

Attacco analogo: trust di avvio

Tuttavia, una generalizzazione dell'attacco è pertinente. Il problema di base è che la tua catena di fiducia deve iniziare da qualche parte, e in molti domini la sua origine potrebbe sovvertire l'intera catena in un modo difficile da rilevare.

Un esempio che potrebbe essere facilmente rimosso nella vita reale

Il tuo sistema operativo, ad esempio Ubuntu Linux, garantisce la sicurezza (integrità) degli aggiornamenti controllando i pacchetti di aggiornamento scaricati contro la chiave di firma del repository (utilizzando la crittografia a chiave pubblica). Ma questo garantisce solo autenticità degli aggiornamenti se puoi provare che la chiave di firma è di proprietà di una fonte legittima.

Dove hai preso la chiave per la firma? Quando hai scaricato per la prima volta la distribuzione del sistema operativo.

Devi credere che la fonte della tua catena di fiducia, questa chiave di firma, non sia malvagia.

Chiunque sia in grado di MITM la connessione Internet tra te e il server di download di Ubuntu, questo potrebbe sii il tuo ISP, un governo che controlla l'accesso a Internet (ad esempio la Cina) o il provider di hosting di Ubuntu potrebbe aver dirottato questo processo:

  • Rileva che stai scaricando l'immagine del CD di Ubuntu. Questo è semplice: verifica che la richiesta sia indirizzata a uno dei mirror di Ubuntu (elencati) e richieda il nome file dell'immagine ISO.
  • Fornisci la richiesta dal proprio server, fornendo un'immagine del CD contenente la chiave pubblica e la posizione del repository dell'utente malintenzionato invece di Ubuntu.

Da quel momento in poi, riceverai i tuoi aggiornamenti in modo sicuro dal server dell'attaccante. Gli aggiornamenti vengono eseguiti come root, quindi l'autore dell'attacco ha il controllo completo.

Puoi prevenire l'attacco assicurandoti che l'originale sia autentico. Ma ciò richiede che tu convalidi l'immagine del CD scaricato usando un hash ( poche persone lo fanno effettivamente ) - e l'hash deve essere scaricato in modo sicuro, ad es. su HTTPS. E se l'utente malintenzionato può aggiungere un certificato sul computer (comune in un ambiente aziendale) o controlla un'autorità di certificazione (ad esempio, Cina), anche HTTPS non fornisce alcuna protezione.

    
risposta data 26.01.2013 - 00:03
fonte
25

Per prima cosa, la mia scrittura preferita di questo hack si chiama Strange Loops .

Questo particolare hack potrebbe certamente (*) essere fatto oggi in uno dei principali progetti OS open source, in particolare Linux, * BSD e simili. Mi aspetterei che funzionasse in modo quasi identico. Ad esempio, si scarica una copia di FreeBSD che ha un compilatore sfruttato per modificare openssh. Da quel momento in poi, ogni volta che aggiorni openssh o il compilatore per sorgente, continuerai il problema. Supponendo che l'attaccante abbia sfruttato il sistema utilizzato per impacchettare FreeBSD in primo luogo (probabilmente, dal momento che l'immagine stessa è corrotta, o l'attaccante è in effetti il packager), quindi ogni volta che il sistema ricostruisce i binari di FreeBSD, reinpreterà il problema. Ci sono molti modi in cui questo attacco può fallire, ma non sono fondamentalmente diversi da come l'attacco di Ken avrebbe potuto fallire (**). Il mondo non è davvero cambiato così tanto.

Naturalmente, attacchi simili potrebbero essere altrettanto facilmente (o più facilmente) iniettati dai loro proprietari in sistemi come Java, iOS SDK, Windows o qualsiasi altro sistema. Alcuni tipi di falle nella sicurezza possono persino essere ingegnerizzati nell'hardware (in particolare indebolendo la generazione di numeri casuali).

(*) Ma con "certamente" intendo "in principio". Dovresti aspettarti che questo tipo di buco esista in un particolare sistema? No. Lo considererei piuttosto improbabile per varie ragioni pratiche. Col passare del tempo, man mano che il codice cambia e cambia, la probabilità che questo tipo di hack possa causare strani bug aumenta. E questo aumenta la probabilità che venga scoperto. Minori backdoor ingegnosi richiederebbero cospirazioni da mantenere. Naturalmente sappiamo per certo che le backdoor "intercettazione legale" sono state installate in vari sistemi di telecomunicazioni e di rete, quindi in molti casi questo tipo di hack elaborato non è necessario. L'hack è installato apertamente.

Quindi sempre difesa in profondità.

(**) Presumendo che l'attacco di Ken sia mai esistito. Ha appena discusso di come potrebbe essere fatto. Non ha detto che lo ha fatto per quanto ne so.

    
risposta data 25.01.2013 - 22:22
fonte
15

Ha effetto su tutte le lingue?

Questo attacco riguarda principalmente le lingue che si auto-ospitano. Quelle sono le lingue in cui il compilatore è scritto nella lingua stessa. C, Squeak Smalltalk e l'interprete PyPy Python ne sarebbero influenzati. Perl, JavaScript e l'interprete Python CPython non lo farebbero.

In che modo si tratta della compilazione just-in-time?

Non molto. È la natura self-hosting del compilatore che consente di nascondere l'hack. Non conosco compilatori JIT self-hosting. (Forse LLVM?)

Sono funzioni come il programma che gestisce gli accessi su un sistema * nix compilati quando vengono eseguiti?

Non di solito. Ma la domanda non è quando è compilata, ma da quale compilatore . Se il programma di accesso è compilato da un compilatore corrotto, sarà contaminato. Se è compilato da un compilatore pulito, sarà pulito.

È ancora una minaccia valida o ci sono stati sviluppi nella sicurezza della compilazione dal 1984 che impediscono che ciò sia un problema significativo?

Questa è ancora una minaccia teorica, ma non è molto probabile.

Una cosa che potresti fare per mitigarla è usare più compilatori. Ad esempio, un compilatore LLVM che è compilato da GCC stesso non passerà lungo una back door. Allo stesso modo, un GCC compilato da LLVM non passerà lungo una porta secondaria. Quindi, se sei preoccupato per questo tipo di attacco, allora potresti compilare il tuo compilatore con un'altra generazione di compilatori. Ciò significa che il malvagio hacker (al tuo fornitore del sistema operativo?) Dovrà contaminare entrambi i compilatori per riconoscersi a vicenda; Un problema molto più difficile.

    
risposta data 25.01.2013 - 22:47
fonte
12

C'è una possibilità teorica che ciò accada. Esiste, tuttavia, un modo per verificare se un compilatore specifico (con codice sorgente disponibile) è stato compromesso, tramite Diverse di David A. Wheeler doppio compilazione .

In pratica, usa sia il compilatore sospetto che un altro compilatore sviluppato in modo indipendente per compilare l'origine del compilatore sospetto. Questo ti dà SC sc e SC T . Ora, compilare la fonte sospetta usando entrambi questi binari. Se i binari risultanti sono identici (ad eccezione di una varietà di cose che possono legittimamente variare, come i timestamp assortiti), il compilatore sospetto non stava effettivamente abusando della fiducia.

    
risposta data 26.01.2013 - 13:39
fonte
3

Come attacco specifico, è più una minaccia che sia mai stata, il che non rappresenta affatto una minaccia.

How does this relate to just-in-time compilation?

Non sei sicuro di cosa intendi con questo. Un JITter è immune a questo? No. È più vulnerabile? Non proprio. Come sviluppatore, la tua app è più vulnerabile semplicemente perché non puoi verificare che non sia stata eseguita. Nota che la tua app non ancora sviluppata è praticamente immune a questa e a tutte le varianti pratiche, devi solo preoccuparti di un compilatore più recente del tuo codice.

Are functions like the program handling logins on a *nix system compiled when they are run?

Questo non è molto pertinente.

Is this still a valid threat, or have there been developments in the security of compilation since 1984 that prevent this from being a significant issue?

Non esiste una vera sicurezza di compilazione e non può esserlo. Questo è stato davvero il punto del suo discorso, che ad un certo punto ti devi fidare di qualcuno.

Does this affect all languages?

Sì. Fondamentalmente, a un certo momento o in un altro, le tue istruzioni devono essere trasformate in qualcosa che il computer riproduce e che la traduzione può essere eseguita in modo errato.

    
risposta data 26.01.2013 - 04:37
fonte
-2

David Wheeler ha un buon articolo: link

Io sono più preoccupato per gli attacchi hardware. Penso che abbiamo bisogno di una toolchain di progettazione totalmente VLSI con il codice sorgente FLOSS, che possiamo modificare e compilare noi stessi, che ci consente di costruire un microprocessore che non ha backdoor inserite dagli strumenti. Gli strumenti dovrebbero anche farci capire lo scopo di ogni transistor sul chip. Quindi potremmo aprire un campione dei chip finiti e controllarli con un microscopio, assicurandoti che avessero lo stesso circuito che gli strumenti hanno detto che dovevano avere.

    
risposta data 27.01.2013 - 17:31
fonte
-3

I sistemi in cui gli utenti finali hanno accesso al codice sorgente sono quelli per i quali si dovrebbe nascondere questo tipo di attacco. Quelli sarebbero sistemi open source nel mondo di oggi. Il problema è che sebbene ci sia una dipendenza da un singolo compilatore per tutti i sistemi Linux, l'attacco dovrebbe entrare nei server di compilazione per tutte le principali distribuzioni Linux. Dal momento che questi non scaricano i binari del compilatore direttamente per ogni versione del compilatore, la sorgente per l'attacco avrebbe dovuto essere sui loro server di compilazione in almeno una versione precedente del compilatore. O quella o la primissima versione del compilatore che hanno scaricato come binario avrebbe dovuto essere compromessa.

    
risposta data 27.01.2013 - 16:16
fonte
-4

Se uno ha il codice sorgente per un compilatore / sistema di compilazione il cui output non dovrebbe dipendere da qualcosa di diverso dal contenuto dei file sorgente forniti, e se uno ha diversi altri compilatori e sa che non tutti contengono lo stesso hack del compilatore , ci si può assicurare che si ottiene un eseguibile che non dipende da nient'altro che dal codice sorgente.

Supponiamo che uno abbia un codice sorgente per un pacchetto compilatore / linker (per esempio Groucho Suite) scritto in modo tale che il suo output non dipenda da alcun comportamento non specificato, né da altro che dal contenuto dei file sorgente di input, e uno compila / collega quel codice su una varietà di pacchetti compilatori / linker prodotti indipendentemente (ad esempio la Suite Harpo, la suite Chico e la Suite Zeppo), producendo un diverso insieme di exeuctables per ognuno (chiamali G-Harpo, G- Chico e G-Zeppo). Non sarebbe inaspettato che questi eseguibili contengano sequenze di istruzioni diverse, ma dovrebbero essere funzionalmente identiche. Dimostrando che sono funzionalmente identici in tutti i casi, tuttavia, sarebbe probabilmente un problema irrisolvibile.

Fortunatamente, tale dimostrazione non sarà necessaria se si utilizzano solo gli eseguibili risultanti per un solo scopo: compilare nuovamente la suite Groucho. Se si compilano i compilatori della suite Groucho usando G-Harpo (che produce GG-Harpo), G-Chico (GG-Chico) e G-Zeppo (GG-Zeppo), quindi tutti e tre i file risultanti, GG-Harpo, GG-Chico e GG-Zeppo, dovrebbe essere identico a byte per byte. Se i file corrispondono, ciò implicherebbe che qualsiasi "virus del compilatore" esistente in uno di essi deve esistere identicamente in tutti loro (poiché tutti e tre i file sono identici byte per byte, non è possibile che i loro comportamenti possano differire in alcun modo modo).

A seconda dell'età e della discendenza degli altri compilatori, potrebbe essere possibile garantire che tale virus non possa esistere in modo plausibile in essi. Ad esempio, se si utilizza un Macintosh antico per alimentare un compilatore che è stato scritto da zero nel 2007 attraverso una versione di MPW scritta negli anni '80, i compilatori degli anni '80 non sapevano dove inserire un virus nel compilatore 2007. Oggi è possibile che un compilatore esegua un'analisi di codice sufficientemente elaborata per capirlo, ma il livello di calcolo richiesto per tale analisi supererebbe di molto il livello di calcolo richiesto per compilare semplicemente il codice e non sarebbe potuto passare inosservato in un mercato in cui la velocità di compilazione era un punto di forza.

Direi che se si sta lavorando con strumenti di compilazione in cui i byte in un file eseguibile da produrre non dovrebbero dipendere in alcun modo da qualcosa di diverso dal contenuto dei file sorgente inviati, è possibile ottenere un'immunità ragionevolmente buona da un virus in stile Thompson. Sfortunatamente, per qualche ragione, il non determinismo nella compilazione sembra essere considerato normale in alcuni ambienti. Riconosco che su un sistema multi-CPU può essere possibile che un compilatore funzioni più velocemente se è permesso che alcuni aspetti della generazione del codice cambino a seconda di quale dei due thread finisce per primo un pezzo di lavoro.

D'altra parte, non sono sicuro di vedere alcun motivo per cui compilatori / linker non dovrebbero fornire una modalità di "output canonico" in cui l'output dipende solo dai file sorgente e da una "data di compilazione" che può essere sovrascritta dall'utente. Anche se la compilazione di un codice in tale modalità richiedesse il doppio della normale compilazione, suggerirei che ci sarebbe un notevole valore nel ricreare qualsiasi "release build", byte per byte, interamente da materiali di origine, anche se ciò significava che le build di rilascio richiederebbero più tempo di "build normali".

    
risposta data 26.01.2013 - 21:00
fonte

Leggi altre domande sui tag