Frage:
Ist es gefährlich, beliebiges C zu kompilieren?
Sriotchilism O'Zaic
2016-10-06 07:01:41 UTC
view on stackexchange narkive permalink

Ich habe einen kleinen Server und möchte die Kompilierungszeiten für C-Programme überprüfen, die von Benutzern bereitgestellt werden. Die Programme würden niemals nur kompiliert ausgeführt.

Welche Risiken bestehen, wenn Benutzer beliebiges C mit gcc 5.4.0 kompilieren können?

Ich würde sagen, das ist nicht die beste Idee.Compiler-Schwachstellen sind nicht so häufig, da die meisten Benutzer vertrauenswürdigen Code kompilieren, der solche Sicherheitslücken nicht auslöst.Ich bin mir sicher, dass noch einige solcher Sicherheitslücken auszunutzen sind.Wenn Sie dies unbedingt tun müssen, empfehle ich, den Code in Wegwerf-VMs zu kompilieren.
Es gibt mehrere Webdienste, die genau dies anbieten.Z.B.Bei Stack Overflow ist ideone.com ebenso beliebt wie godbolt.org.Die Gefahr scheint beherrschbar.
@MSalters: Es gibt auch coliru.stacked-crooked.com, und ich denke, Stacked Crooked hat beschrieben, wie er seinen Online-Compiler gründlich gesichert hat.
Gab es nicht ganze IOCCC-Einträge, die darauf aufgebaut waren?Wenn Sie beliebige C ++ - Dateien kompilieren, können Benutzer mit Sicherheit * viel * Ihrer CPU aus einem winzigen Programm verschwenden.Ich denke, der Siegerbeitrag in einem Wettbewerb "Explodierende Fehlermeldungen" hat 55 MB Fehler aus 1 KB Eingabe generiert.
Keine Zeit, dies jetzt aufzuschreiben, aber überprüfen Sie dies: https://www.ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf
Mit der aktuellen Linux-Technologie ist dies ein überschaubares Risiko.Stellen Sie die Quelle in einem Docker-Container bereit, führen Sie den containerisierten Compiler aus. Wenn der Ausgabekontingent nicht beendet oder überschritten wird, blasen Sie den Container einfach weg, protokollieren Sie den Fehler und lassen Sie fail2ban wiederholte Problembenutzer abholen.
Viele Leute raten davon ab, aber es gibt eine Reihe von kostenlosen Online-Sites, die beliebigen Code * kompilieren *, wie ideone, wie in einem Kommentar gezeigt.Man wundert sich, wie sie sich sichern.
@jpmc26 - "lässt Sie sich fragen, wie sie sich sichern" Siehe den obigen Kommentar von Matthieu M. zu `coliru.stacked-crooked.com`.
Sechs antworten:
#1
+95
CBHacking
2016-10-06 08:54:39 UTC
view on stackexchange narkive permalink

Etwas seltsam, aber: Es handelt sich um ein Denial-of-Service-Risiko oder eine potenzielle Offenlegung von Informationen.

Da der Präprozessor von C alle in einer #include -Anweisung angegebenen Dateien fröhlich enthält, kann jemand #include "../../../../. ./../../../../../dev/zero " und der Präprozessor versuchen, bis zum Ende von / dev / zero zu lesen (viel Glück ).

In ähnlicher Weise könnte jemand versuchen, verschiedene Dateien einzuschließen, die möglicherweise auf Ihrem System vorhanden sind oder nicht, und insbesondere Informationen über Ihren Computer erhalten, insbesondere wenn Sie die Ausgabe ihrer Kompilierungsversuche anzeigen lassen. In Kombination mit der cleveren Verwendung von #pragma gift können sie sogar etwas über den Dateiinhalt erfahren, selbst wenn Sie keine vollständigen Fehlermeldungen angeben.

In ähnlicher Weise können Pragmas das Verhalten von Präprozessoren, Compilern oder Linkern stark verändern und werden in Quelldateien angegeben. Es gibt wahrscheinlich keine, mit der jemand den Namen der Ausgabedatei oder ähnliches angeben kann. Wenn dies jedoch der Fall ist, kann er missbraucht werden, um vertrauliche Dateien zu überschreiben oder sich selbst ausführen zu lassen (indem er in cron schreibt) oder ähnliches). Es könnte etwas ähnlich Gefährliches geben. Sie sollten wirklich vorsichtig sein, wenn Sie nicht vertrauenswürdigen Code kompilieren.

http://ideone.com/c2UhRl
@Ville-ValtteriTiittanen Fügen Sie einige Erklärungen hinzu, nicht nur Links.
@TorKlingberg Die Erklärung ist in der Frage.Er hat gerade eine funktionierende Umsetzung der Idee des zweiten Absatzes geliefert
Wie gut werden diese Angriffe durch die Verwendung einer ordnungsgemäß konfigurierten Chroot-Umgebung abgewehrt?Es ist nicht erforderlich, "cron" oder ein aussagekräftiges (anderswo) "/ etc / passwd" zu haben, wodurch die Angriffsfläche erheblich reduziert wird.(Es ist heutzutage ziemlich einfach, mit "cdebootstrap" und "schroot" eine minimale Chroot zu erstellen - so erstelle ich Kompilierungsumgebungen für alte Distributionen, die ich unterstützen muss.)
Ich habe vergessen zu sagen, benutze auch "ulimit", um gegen eine gewisse Menge an DoS zu helfen.
@CBHacking.+1.Können Sie bitte erklären, wie #pragma gift verwendet werden kann, um etwas über Dateiinhalte zu lernen?
@TobySpeight: chroot funktioniert gut gegen diese Art von Angriff.Wenn Sie beispielsweise versuchen, eine @Ville's-Datei unter [Coliru] (http://coliru.stacked-crooked.com/) zu kompilieren, wird einfach der Fehler angezeigt: `main.cpp: 1: 50: schwerwiegender Fehler: ../../../../../../../../../../dev/zero: Keine solche Datei oder kein solches Verzeichnis` (und ähnlich für die Datei, die er im Kommentar mit Colin Cassidys Antwort verknüpft).
AilixjiccgCMT Huch.
@PriyankGupta: Theoretisch schlägt das Vergiften bestimmter Token, die sich möglicherweise in einer Datei befinden, und das anschließende Einschließen der Datei schnell fehl, wenn diese Token vorhanden sind.Dies kann einen Seitenkanalangriff (Timing-Angriff) bereitstellen, um einige Informationen über den Inhalt einer Datei anzuzeigen, selbst wenn Sie (der Angreifer) nicht die tatsächliche Ausgabe des Compilers erhalten.Die Datei muss noch C oder zumindest in der Nähe davon gültig sein, oder der Parser schlägt fehl, bevor die Giftprüfung angewendet wird.Sie würden auch Dateinamen blind auswählen.Kein einfacher Angriff, aber unter Umständen möglicherweise ein sinnvoller.
@Ville-ValtteriTiittanen Versuchen Sie zu demonstrieren, dass dies * ein * Problem ist oder * kein * Problem ist?Scheint Ideone keinen Schaden zuzufügen.
Viele Linux-Dienstprogramme lesen Dateien mit "open" / "fstat" / "mmap", sodass das Lesen von Null-Byte-Dateien oder "Dateien" ohne Länge nicht funktioniert.Sie können auch keine gefälschten "regulären Dateien" lesen.Das hat mich geschlagen, als einige Programme darauf bestanden, eine reguläre `/ etc / fstab`" reguläre Datei "und keinen Link / Mount von` / proc / mount` zu haben.
#2
+42
James
2016-10-06 19:10:05 UTC
view on stackexchange narkive permalink

Compiler-Bomben

C ist eine sehr mächtige Sprache, und einige der schrecklichen Dinge, die Sie damit tun können, würden Sie schockieren. Sie können beispielsweise ein 16-Byte-C-Programm erstellen, dessen Kompilierung 27 Minuten dauert . Nach Abschluss wird es auf 16 Gigabyte em kompiliert > ausführbare Datei. Und das mit nur 16 Bytes. Wenn Sie den Präprozessor und größere Quellcodedateien berücksichtigen, können Sie sicher viel größere Compilerbomben erstellen.

Dies bedeutet, dass jeder, der Zugriff auf Ihren Server hat, effektiv ein DoS a ausführen kann > Angriff auf Ihren Server. Um fair zu sein, ist dies deutlich weniger gefährlich, als wenn jemand eine Sicherheitsanfälligkeit im Compiler missbraucht oder vertrauliche Dateien einschließt, um Informationen über Ihren Server zu erhalten (wie die anderen Antwortenden, über die gesprochen wurde).

Aber es ist noch eine andere Mögliche Belästigung beim Kompilieren von beliebigem Code. Ich bin sicher, Sie könnten ein Zeitlimit für alle Builds festlegen und sicherstellen, dass die Binärdateien niemals gespeichert werden. Obwohl Sie es natürlich immer noch auf der Festplatte behalten müssen, während es erstellt wird . Wenn also jemand eine Compilerbombe hypothetisch größer als Ihre Festplatte gemacht hat, sind Sie in Schwierigkeiten (wenn Sie den Build zulassen beenden).

Lustigerweise frage ich, weil ich eine PPCG-Herausforderung durchführen wollte, um eine Compilerbombe zu erstellen, und einen Scoring-Server einrichten wollte.
#3
+29
Bryan Field
2016-10-06 08:01:24 UTC
view on stackexchange narkive permalink

@ AndréBorie ist korrekt. Compiler und die entsprechende Konfiguration werden nicht gut auf Sicherheitsprobleme überprüft. Daher sollten Sie im Allgemeinen keinen nicht vertrauenswürdigen Code kompilieren.

Das Risiko besteht darin, dass ein Pufferüberlauf oder eine Sicherheitsanfälligkeit bezüglich der Bibliotheksausführung ausgenutzt wird Der Angreifer erhält Zugriff auf das Benutzerkonto (hoffentlich nicht root !), auf dem der Compiler ausgeführt wurde. Selbst ein Nicht- root -Hack ist in den meisten Fällen schwerwiegend. Dies könnte in einer separaten Frage erläutert werden.

Das Erstellen einer VM ist eine gute Lösung, um potenzielle Exploits einzudämmen, damit sie den Rest Ihrer Anwendung nicht schädigen können.

Es ist am besten Um eine Linux-Vorlagen-VM zu haben, können Sie diese nach Bedarf mit einer sauberen Slate-Compiler-Umgebung starten.

Idealerweise würden Sie sie nach jedem Gebrauch wegwerfen, dies ist jedoch möglicherweise nicht unbedingt erforderlich. Wenn Sie die VM gut genug isolieren und die Antwortdaten von der VM ordnungsgemäß bereinigen, sollten Sie dies trotzdem tun. Dann ist das Schlimmste, was ein Hack tun kann, DoS oder das Erstellen falscher Kompilierungszeiten. Dies sind keine ernsthaften Probleme für sich; Zumindest nicht annähernd so ernst wie der Zugriff auf den Rest Ihrer Anwendung.

Das Zurücksetzen der VM nach jeder Verwendung (dh statt täglich) sorgt jedoch insgesamt für eine stabilere Umgebung und kann die Sicherheit in bestimmten Bereichen verbessern Fälle.

Einige Betriebssysteme bieten Container als Alternative zu VMs an. Dies mag ein schlankerer Ansatz sein, es gelten jedoch dieselben Grundsätze.

Dateisystem-Snapshots (z. B. ZFS) + ein Container (also keine Kernel-Startzeiten) und Sie könnten wahrscheinlich innerhalb von 5 Sekunden zwischen Anforderungen bereinigen.Und wenn Sie mehrere Container möchten, können Sie sogar CoW-Klone verwenden.
Das klingt gut.Ich gehe davon aus, dass Sie einen tatsächlichen Reset meinen (kein Kernel-Start erforderlich), damit böswillige Daemons zerstört werden.
Die meisten Containerisierungslösungen implementieren eine Stoppoperation, die alle im Container gestarteten Prozesse abbricht.Ich glaube, LXD (`stop --force`) tut dies, indem es sie alle in eine cgroup einordnet.Da das Erstellen eines CoW-Klons aus einem Snapshot in ZFS jedoch billig ist, können Sie sogar einen ganz neuen Container erstellen, bevor der alte beendet wird.Die meiste Zeit würde wahrscheinlich damit verbracht werden, init im Container zu starten.
Stellen Sie sicher, dass die VMs auf einem separaten Server ausgeführt werden, um keine Timing-Angriffe und andere Seitenkanalangriffe auf Ihren Webserver zu provozieren!
#4
+14
Matt G
2016-10-07 19:13:49 UTC
view on stackexchange narkive permalink

Ja, es ist gefährlich, aber wie die Leute gesagt haben, ist es möglich. Ich bin der Autor und Betreuer der Online-Compiler unter https://gcc.godbolt.org/, und ich fand es ziemlich praktikabel, sie mit einer Kombination aus: p sicher zu machen >

  • Die gesamte Site wird auf einer VM-Instanz mit geringen Berechtigungen ausgeführt. Das Netzwerk ist stark eingeschränkt, da nur Port 80 sichtbar ist und ssh nur über IPs auf der Whitelist (meine eigenen) aktiviert ist.
  • Jede Kompilierungsinstanz wird in einem wegwerfbaren Docker-Container mit noch weniger Berechtigungen
  • ausgeführt Der Compiler wird von einem Skript ausgeführt, das alle Prozessgrenzen (Speicher, CPU-Zeit usw.) auf niedrige Grenzen setzt, um Codebomben zu verhindern.
  • Der Compiler wird mit einem LD_PRELOAD ausgeführt Wrapper ( Quelle hier), der verhindert, dass der Compiler Dateien öffnet, die nicht auf einer expliziten Whitelist stehen. Dies verhindert, dass es / etc / passwd oder andere solche Dinge liest (nicht, dass das allzu viel helfen würde).
  • Als Nizza analysiere ich die Befehlszeilenoptionen und führe den Compiler nicht aus, wenn Es gibt etwas besonders Verdächtiges. Dies ist kein wirklicher Schutz. Nur eine Möglichkeit, eine Fehlermeldung "Ernsthaft, versuchen Sie es nicht" zu geben, anstatt dass LD_PRELOAD ein schlechtes Verhalten erkennt.

Die gesamte Quelle befindet sich auf GitHub, ebenso wie die Quelle für die Docker-Container-Images und Compiler und dergleichen.

Ich habe einen Blog-Beitrag geschrieben, in dem erklärt wird, wie die Das gesamte Setup wird ebenfalls ausgeführt.

Die "LD_PRELOAD" -Technik ist nahezu nutzlos.Es ist absolut trivial zu umgehen, sobald Sie die Codeausführung über eine Compiler-Sicherheitsanfälligkeit erreicht haben.Es könnte bei verwirrten Problemen mit Stellvertretern helfen, aber sonst nicht viel ... Auch wenn es funktioniert hat, haben Sie eine ganze Reihe von Funktionen verpasst, die stattdessen zum Öffnen von Dateien verwendet werden können.
#5
+12
Colin Cassidy
2016-10-06 13:20:24 UTC
view on stackexchange narkive permalink

Sie möchten den Compiler nicht als Root ausführen, obwohl ich dies aus Gründen der "Einfachheit und Bequemlichkeit" gesehen habe. Für einen Angreifer wäre es allzu einfach, Folgendes einzuschließen:

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

und den Inhalt dieser Dateien als Teil der Compiler-Fehlermeldung zurückerhalten.

Auch Compiler sind Programme Wie alles andere und mit Fehlern, die anfällig sein könnten, wäre es für jemanden zu einfach, nur C-Programme zu fuzzeln und Probleme zu verursachen.

Die meisten Anwendungssicherheiten konzentrieren sich in erster Linie auf die Eingabevalidierung. Leider ist die Definition der 'sicheren und gültigen' Eingabe für einen C-Compiler wahrscheinlich mit dem Problem des Anhaltens in Bezug auf die Schwierigkeit verbunden :)

http://ideone.com/ZzPHMw http://ideone.com/xc4s5a
Mein Punkt genau, es gibt andere da draußen, die für die etc / shadow anfällig sind
Aber die Fehlermeldungen werden an * Ihr * Terminal gesendet, und Sie könnten trotzdem nur _cat / etc / passwd_.
Ja, ich möchte, dass die Fehlermeldungen zu mir zurückkehren. Ich möchte die Passwort-Hashes erhalten.Was cat / etc / passwd betrifft, das vom Setup abhängt, wird der C-Code möglicherweise an einen separaten Server gesendet. In diesem Fall habe ich jetzt die Hashes für das Remote-System, mit denen ich offline knacken kann.
#6
+3
cym13
2016-10-07 04:13:46 UTC
view on stackexchange narkive permalink

Wenn Sie einem Benutzer erlauben, ein Archiv mit dem Code bereitzustellen, können Probleme auftreten, nicht genau mit dem Compiler, sondern mit dem verwendeten Linker;)

ld folgt symbolischen Links wenn sie auf eine Datei verweisen, die nicht vorhanden ist. Dies bedeutet, dass, wenn Sie test.c in die Ausgabe a.out kompilieren, aber bereits einen symbolischen Link mit dem Namen a.out in Ihrem Verzeichnis haben, der auf eine nicht vorhandene Datei verweist, die kompilierte ausführbare Datei an der Stelle geschrieben wird, die auf die verweist Datei (mit Einschränkung der Benutzerrechte).

In der Praxis könnte ein Angreifer beispielsweise eine Zeichenfolge mit einem öffentlichen SSH-Schlüssel in seinen Code aufnehmen und einen symbolischen Link mit dem Namen a.out bis ~ / .ssh / autorisierte_Tasten . Wenn diese Datei noch nicht vorhanden ist, kann der Angreifer seinen SSH-Schlüssel in den Zielcomputer einfügen, sodass er von außen darauf zugreifen kann, ohne ein Kennwort knacken zu müssen.



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...