Domanda:
È pericoloso compilare C arbitrario?
Sriotchilism O'Zaic
2016-10-06 07:01:41 UTC
view on stackexchange narkive permalink

Ho un piccolo server e vorrei controllare i tempi di compilazione sui programmi C forniti dagli utenti. I programmi non verrebbero mai eseguiti solo compilati.

Quali rischi ci sono nel consentire agli utenti di compilare C arbitrario utilizzando gcc 5.4.0?

Direi che questa non è l'idea migliore.Le vulnerabilità del compilatore non sono così comuni a causa del fatto che la maggior parte delle persone compila codice affidabile che non attiva tali vuln.Sono sicuro che ci sono ancora un bel po 'di tali vulnerabilità da sfruttare.Se devi assolutamente farlo, ti suggerisco di compilare il codice in VM usa e getta.
Esistono diversi servizi web che offrono esattamente questo.Per esempio.su Stack Overflow, ideone.com è popolare, così come godbolt.org.Il pericolo sembra gestibile.
@MSalters: C'è anche coliru.stacked-crooked.com, e penso che Stacked Crooked abbia descritto in modo approfondito come ha protetto il suo compilatore online.
Non c'erano intere voci IOCCC costruite attorno a questo?Certamente se compili C ++ arbitrario le persone possono sprecare * molto * della tua CPU da un piccolo programma.Penso che la voce vincente in una competizione "esplosiva di messaggi di errore" abbia generato 55 MB di errori da 1kB di input.
Non c'è tempo per scrivere questo in questo momento, ma controlla questo: https://www.ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf
È un rischio gestibile con l'attuale tecnologia Linux.Distribuisci l'origine in un contenitore Docker, esegui il compilatore containerizzato e se non termina o supera la quota di output, semplicemente fai saltare via il contenitore, registra l'errore e fai in modo che fail2ban rilevi gli utenti con problemi ripetuti.
Molte persone lo sconsigliano, ma ci sono un certo numero di siti online gratuiti che * compilano * codice arbitrario, come ideone, come dimostrato in un commento.Ti viene da chiederti come si proteggano.
@jpmc26 - "ti fa chiedere come si assicurano" Vedi il commento sopra di Matthieu M. su `coliru.stacked-crooked.com`.
Sei risposte:
CBHacking
2016-10-06 08:54:39 UTC
view on stackexchange narkive permalink

Un po 'strano, ma: è un rischio di negazione del servizio o potenziale divulgazione di informazioni.

Poiché il preprocessore di C includerà allegramente qualsiasi file specificato in una direttiva #include , qualcuno può #include "../../../../. ./../../../../../dev/zero " e il preprocessore proverà a leggere fino alla fine di / dev / zero (buona fortuna ).

Allo stesso modo, specialmente se permetti alle persone di vedere l'output dei loro tentativi di compilazione, qualcuno potrebbe provare a includere vari file che possono o meno essere presenti sul tuo sistema, e potrebbe imparare cose sulla tua macchina. In combinazione con un uso intelligente di #pragma poison , potrebbero persino imparare cose sul contenuto del file anche se non fornisci messaggi di errore completi.

Relativamente, i pragmi possono alterare molti comportamenti di preprocessore, compilatore o linker e sono specificati nei file sorgente. probabilmente non ce n'è uno che permetta a qualcuno di fare qualcosa come specificare il nome del file di output o qualcosa del genere, ma se c'è, potrebbe essere abusato per sovrascrivere i file sensibili o farsi eseguire (scrivendo in cron o simili). Potrebbe esserci qualcosa di altrettanto pericoloso. Dovresti davvero stare attento alla compilazione di codice non affidabile.

http://ideone.com/c2UhRl
@Ville-ValtteriTiittanen Aggiungi qualche spiegazione, non solo link.
@TorKlingberg La spiegazione è nella domanda.Ha appena fornito un'implementazione funzionante del secondo paragrafo ideea
In che misura questi attacchi vengono mitigati attraverso l'uso di un ambiente chroot configurato correttamente?Non è necessario avere `cron` o un significativo (altrove)` / etc / passwd`, in modo da ridurre considerevolmente la superficie di attacco.(È abbastanza facile in questi giorni creare un chroot minimo con `cdebootstrap` e` schroot` - è così che creo ambienti di compilazione per vecchie distribuzioni che devo supportare.)
Ho dimenticato di dire, usa anche `ulimit` per aiutare contro una certa quantità di DoS.
@CBHacking.+1.Puoi per favore spiegare come il veleno #pragma può essere usato per imparare cose sui contenuti dei file?
Il chroot di @TobySpeight: funziona bene contro questo tipo di attacco.Ad esempio, il tentativo di compilare il file @Ville's su [Coliru] (http://coliru.stacked-crooked.com/) restituisce semplicemente un errore di: `main.cpp: 1: 50: fatal error: ../../../../../../../../../../dev/zero: No such file or directory` (e simili per il file che collega nel commento alla risposta di Colin Cassidy).
AilifltywkCMT Yikes.
@PriyankGupta: In teoria, l'avvelenamento di determinati token che potrebbero essere in un file, e quindi includere il file, fallirà rapidamente se questi token sono presenti.Questo può fornire un attacco a canale laterale (temporizzazione) per rivelare alcune informazioni sul contenuto di un file anche se tu (l'attaccante) non ottieni l'output effettivo del compilatore.Il file dovrebbe comunque essere C valido, o almeno vicino ad esso, o il parser fallirebbe prima dell'applicazione del controllo veleno.Dovresti anche scegliere i nomi dei file alla cieca.Non un attacco facile, ma forse significativo in alcune circostanze.
@Ville-ValtteriTiittanen Stai cercando di dimostrare che questo * è * un problema o * non è * un problema?Non sembra aver causato alcun danno a ideone.
Molte utilità di Linux leggono i file con `open` /` fstat` / `mmap`, quindi leggere file con zero byte o" file "senza lunghezza non funzionerebbe.Non possono nemmeno leggere "file regolari" falsi "/ proc".Sono stato battuto da questo quando alcuni programmi hanno insistito per avere un "file normale" regolare `/ etc / fstab` e non un collegamento / montaggio di` / proc / mount`.
James
2016-10-06 19:10:05 UTC
view on stackexchange narkive permalink

Compiler bombs

C è un linguaggio molto potente e alcune delle cose terribili che puoi farci potrebbero scioccarti. Ad esempio, puoi creare un programma C a 16 byte che impiega 27 minuti per essere compilato e, quando finalmente finisce, viene compilato in un 16 Gigabyte file eseguibile. E questo utilizza solo 16 byte. Quando prendi in considerazione il preprocessore e file di codice sorgente più grandi, sono sicuro che potresti creare bombe del compilatore molto più grandi.

Ciò significa che chiunque abbia accesso al tuo server potrebbe effettivamente eseguire un DoS attacco al tuo server. Per essere onesti, questo è significativamente meno pericoloso che avere qualcuno che abusa di una vulnerabilità nel compilatore o includere file sensibili per ottenere informazioni sul tuo server (come hanno parlato gli altri risponditori).

Ma è ancora un altro possibile fastidio che incontrerai durante la compilazione di codice arbitrario. Sono sicuro che potresti impostare un limite di tempo su tutte le build e assicurarti di non memorizzare mai i file binari. Anche se, ovviamente, devi ancora tenerlo su disco mentre viene creato , quindi se qualcuno ipoteticamente creasse una bomba del compilatore più grande del tuo disco rigido, saresti nei guai (se lasci che la build finitura).

Stranamente, il motivo per cui lo chiedo è perché volevo fare una sfida PPCG per creare una bomba del compilatore, e volevo creare un server di punteggio.
Bryan Field
2016-10-06 08:01:24 UTC
view on stackexchange narkive permalink

@ AndréBorie è corretto. I compilatori e la configurazione corrispondente non saranno ben controllati per i problemi di sicurezza, quindi in generale non dovresti compilare codice non affidabile.

Il rischio è che venga sfruttato un overflow del buffer o qualche tipo di vulnerabilità di esecuzione della libreria, e il l'aggressore ottiene l'accesso all'account utente (si spera non root !) che ha eseguito il compilatore. Anche un hack non di root è serio nella maggior parte dei casi. Questo potrebbe essere elaborato in una domanda separata.

La creazione di una VM è una buona soluzione, per contenere eventuali potenziali exploit in modo che non possano danneggiare il resto dell'applicazione.

È la cosa migliore per avere un modello di VM Linux che puoi avviare secondo necessità con un ambiente di compilazione pulito.

Idealmente dovresti buttarlo via dopo ogni utilizzo, ma questo potrebbe non essere strettamente necessario. Se si isola abbastanza bene la VM e si disinfettano adeguatamente i dati di risposta dalla VM, cosa che si dovrebbe fare comunque; allora il peggio che un hack potrebbe fare è DoS o creare tempi di compilazione falsi. Questi non sono problemi seri da soli; almeno non così grave come l'accesso al resto della tua applicazione.

Tuttavia, il ripristino della VM dopo ogni utilizzo (cioè invece che quotidianamente) fornisce un ambiente più stabile in generale e può migliorare la sicurezza in certi edge casi.

Alcuni sistemi operativi forniscono contenitori come alternativa alle VM. Questo può essere un approccio più snello, ma si applicano gli stessi principi.

Istantanee del file system (ad esempio ZFS) + un contenitore (quindi nessun tempo di avvio del kernel) e probabilmente potresti ripulire tra le richieste entro 5 secondi.E se vuoi più contenitori potresti persino usare i cloni di CoW.
Suona bene.Presumo che tu intenda un effettivo ripristino (che non richiede l'avvio del kernel), in modo che i daemon dannosi vengano distrutti.
La maggior parte delle soluzioni di containerizzazione implementa alcune operazioni di "arresto" che uccideranno tutti i processi avviati nel container.Credo che LXD (`stop --force`) lo faccia mettendoli tutti in un cgroup.Ma poiché la creazione di un clone di CoW da un'istantanea in ZFS è economica, potresti persino creare un contenitore completamente nuovo prima che il vecchio finisca di terminare.La maggior parte del tempo verrebbe probabilmente speso per avviare init all'interno del container.
Assicurati di eseguire le VM su un server separato per non provocare attacchi a tempo e altri attacchi di canale laterale sul tuo server web!
Matt G
2016-10-07 19:13:49 UTC
view on stackexchange narkive permalink

Sì, è pericoloso: ma come si dice è possibile. Sono l'autore e il manutentore dei compilatori online su https://gcc.godbolt.org/ e ho trovato abbastanza fattibile renderlo sicuro usando una combinazione di:

  • L'intero sito viene eseguito su un'istanza VM con pochi permessi per fare qualsiasi cosa. La rete è fortemente limitata con solo la porta 80 visibile e ssh abilitato solo dagli IP autorizzati (il mio).
  • Ogni istanza di compilazione viene eseguita all'interno di un contenitore Docker usa e getta con ancora meno autorizzazioni
  • Il compilatore viene eseguito da uno script che imposta tutti i limiti del processo (memoria, tempo della CPU, ecc.) A limiti bassi per prevenire bombe di codice.
  • Il compilatore viene eseguito con un LD_PRELOAD wrapper ( fonte qui) che impedisce al compilatore di aprire file non inclusi in una whitelist esplicita. Questo gli impedisce di leggere / etc / passwd o altre cose simili (non che questo aiuterebbe più di tanto).
  • Di solito analizzo le opzioni della riga di comando e non eseguo il compilatore se c'è qualcosa di particolarmente sospetto. Questa non è una vera protezione; solo un modo per dare un messaggio di errore "seriamente, non provare questo" invece di LD_PRELOAD che rileva un cattivo comportamento.

L'intera fonte è su GitHub, così come la fonte delle immagini del contenitore docker e dei compilatori e simili.

Ho scritto un post sul blog che spiega come viene eseguito anche l'intero setup.

La tecnica `LD_PRELOAD` è quasi inutile.È assolutamente banale aggirare una volta ottenuta l'esecuzione del codice tramite una vulnerabilità del compilatore.Potrebbe aiutare per problemi confusi con i deputati, ma non molto altro ... Inoltre, anche se funzionasse, hai perso molte funzioni che possono essere utilizzate per aprire i file.
Colin Cassidy
2016-10-06 13:20:24 UTC
view on stackexchange narkive permalink

Non si vorrebbe eseguire il compilatore come root, anche se l'ho visto accadere per ragioni di "facilità e comodità". Sarebbe fin troppo facile per un utente malintenzionato includere qualcosa del tipo:

  #include "../../../../etc/passwd"#include" ../. ./../../etc/shadow"

e recuperare il contenuto di questi file come parte del messaggio di errore del compilatore.

Anche i compilatori sono programmi come ogni altra cosa, e avranno i loro bug che potrebbero essere vulnerabili, sarebbe tutto troppo facile per qualcuno semplicemente confondere i programmi C e causare problemi.

La maggior parte della sicurezza delle applicazioni si concentrerà prima di tutto sulla convalida dell'input, sfortunatamente la definizione di un input "sicuro e valido" per un compilatore C è probabilmente all'altezza del problema in termini di difficoltà :)

http://ideone.com/ZzPHMw http://ideone.com/xc4s5a
il mio punto esattamente, ce ne sono altri là fuori che sono suscettibili a quello etc / shadow
Ma i messaggi di errore verranno inviati al * tuo * terminale e potresti comunque _cat / etc / passwd_.
sì, voglio che i messaggi di errore mi tornino, sto cercando di ottenere gli hash delle password.Per quanto riguarda cat / etc / passwd, dipende dalla configurazione, forse il codice C viene inviato a un server separato, nel qual caso ora ho gli hash per il sistema remoto che posso iniziare a crackare offline.
cym13
2016-10-07 04:13:46 UTC
view on stackexchange narkive permalink

Se consenti a un utente di fornire un archivio contenente il codice puoi avere problemi, non esattamente con il compilatore ma con il linker che usa;)

ld segue i collegamenti simbolici se puntano a un file che non esiste. Ciò significa che se compili test.c sull'output a.out ma hai già un collegamento simbolico chiamato a.out nella tua directory che punta a un file non esistente, l'eseguibile compilato verrà scritto nella posizione che punta al file (con la limitazione dei diritti dell'utente).

In pratica un attaccante potrebbe, ad esempio, includere una stringa contenente una chiave ssh pubblica nel suo codice e fornire un collegamento simbolico denominato a.out a ~ / .ssh / authorized_keys . Se quel file non esiste già, questo permette all'attaccante di piantare la sua chiave ssh nella macchina di destinazione permettendogli l'accesso esterno senza dover decifrare alcuna password.



Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...