Crusher, Astra Linux / Sudo Null IT-News

Einführung

Hey Habr! Mein Name ist Dima, ich teste die Sicherheit des Betriebssystems Astra Linux in der Astra Unternehmensgruppe. Unser Team führt verschiedene Arten von Softwareüberprüfungen durch, wie zum Beispiel:

  • statische und dynamische Softwarecodeanalyse;

  • Suche nach Software-Schwachstellen;

  • Fuzz-Tests;

  • Tracking gekennzeichneter Daten;

  • Antivirus-Kontrolle;

  • Penetrationstests;

  • Funktionsprüfung.

In diesem Artikel werde ich über Fuzzing-Tests sprechen, das dabei hilft, Schwachstellen in Programmen zu erkennen, indem verschiedene Datensätze an deren Eingabeschnittstellen eingespeist werden, bei deren Verarbeitung sich die Software möglicherweise abnormal verhält oder fehlschlägt.

Der Artikel behandelt nur einen kleinen Teil der enormen Arbeit, die die Astra Group of Companies an Fuzzing-Tests geleistet hat. Sie erfahren, wie Sie es implementieren, Tools und die Fähigkeit, diese Art von Tests in Ihren Projekten anzuwenden.

Regulatorischer Teil

Bevor wir also in die Praxis übergehen, müssen wir uns mit dem theoretischen Teil unseres Themas befassen. In der Welt gibt es eine Reihe von Praktiken für die sogenannte „sichere Softwareentwicklung“. In unserem Land werden Praktiken auf der Grundlage von GOST R 56939-2016 in diesem Bereich immer beliebter.

Dieses Dokument beschreibt die Prozesse und Aktionen, die in verschiedenen Phasen des Softwarelebenszyklus durchgeführt werden müssen, damit die entwickelte Software zumindest vor der Weltgemeinschaft bereits bekannten Schwachstellen und logischen Fehlern im Programmcode, die zu verschiedenen Bedrohungen führen können, geschützt ist jenes Informationssystem, in dem das entwickelte Programm funktionieren wird. Eine der Maßnahmen zur Erstellung sicherer Software ist das Fuzzing-Testing. Sein Wesen besteht darin, Zufallsdaten an den Eingang des Programms zu liefern, um abnormales Verhalten zu identifizieren.

Um der ersten (höchsten) Vertrauensstufe zu entsprechen, die durch das Dokument „Informationssicherheitsanforderungen, die Vertrauensniveaus in technischen Informationsschutz-Tools und Informationstechnologie-Sicherheitstools festlegen“ (genehmigt durch die Verordnung Nr. 76 des FSTEC of Russia) geregelt wird ) führt unser Unternehmen ständig Tests in Übereinstimmung mit der Methodik zur Identifizierung von Schwachstellen und nicht deklarierten Funktionen in Software durch (entwickelt und genehmigt am 25. Dezember 2020).

Was genau werden wir entdecken? Jede Person, die sich ein wenig mit Testen auskennt, wird “Bugs” sagen, aber das ist nicht ganz richtig. Bugs können harmlos oder gefährlich sein. Daher ist es beim Fuzzing-Testen äußerst wichtig, gefährliche Fehler oder, offiziell gesprochen, Fehler zu identifizieren, die zur Implementierung von Bedrohungen für die Sicherheit von Informationen führen können, die in Informationssystemen verarbeitet werden. Diese Begriffe sind ausführlicher in GOST R 56546-2015 beschrieben (gut, Wikipedia hat niemand abgesagt).

Über das Instrument

Nach der Theorie geht es nun an die Praxis. Wir werden das Crusher-Tool verwenden. Es gibt andere beliebte Fuzz-Test-Tools. Zum Beispiel AFL, aber es gibt bereits viele Informationen darüber im Web. Crusher ist ein Fuzzing-Testtool, das vom Institut für Systemprogrammierung der Russischen Akademie der Wissenschaften entwickelt wurde. V. P. Ivannikova.

Zur Durchführung der Arbeiten benötigen wir:

  • Betriebssystem Astra Linux (russische Distribution);

  • Crusher Testing Tool (zum Zeitpunkt des Verfassens dieses Artikels entschied der Direktor des ISP RAS, kostenlose Lizenzen für seine Tools für einen Zeitraum von sechs Monaten bereitzustellen);

  • zu testendes Programm.

Crusher ermöglicht es Ihnen, Fuzzing auszuführen, ohne das Programm aus dem Quellcode zu erstellen. In diesem Fall wird es jedoch schwierig für uns, den Ort und die Ursache des „Absturzes“ des Programms zu finden, daher werden wir Fuzzing-Tests mit erneutem Zusammenbau des Programms in Betracht ziehen. Dazu benötigen wir in Zukunft den Quellcode des Programms.

Starten Sie den Test

Die Anweisungen für Crusher enthalten Anweisungen zum Starten des Fuzzing. Es ist nichts Außergewöhnliches. Lediglich beim ersten Start gibt es aufgrund der Besonderheiten der Astra-Linux-Sicherheitseinstellungen leichte Schwierigkeiten. Standardmäßig ist die Ptrace-Trace-Blockierung im Betriebssystem aktiviert. Eines der integrierten Informationssicherheitstools funktioniert. Um es zu deaktivieren, gehen Sie zum Terminal und geben Sie “astra-ptrace-lock disable” ein. Überprüfen Sie dann, ob alles gut gelaufen ist, mit dem Befehl “systemctl is-enabled astra-ptrace-lock”. Die Meldung „disabled“ sollte erscheinen, wir werfen das Ausführungsbit („sudo chmod + x“) auf die Crusher-Startup-Datei, starten neu und sind bereit für den Teil des Betriebssystems.

Um den Crusher zu starten, reicht es aus, ein Verzeichnis mit Eingabedaten (und das Vorhandensein der Eingabedaten selbst darin) und ein Verzeichnis mit Ausgabedaten zu haben – sein Inhalt wird automatisch erstellt, wenn der Test beginnt, es gibt Ordner mit Mutationsdaten , Ausnahmen und Abstürze. Beginnen wir also mit der Vorbereitung der Ausgangsdaten. Wir werden nicht sehr tief gehen, in unserem Fall reicht es aus, das erforderliche Programm im Terminal aufzurufen und seine Funktionalität anzufordern. Nehmen wir als Beispiel das Programm signtool, verwenden Sie das „-h“-Flag, um die vorhandene Funktionalität des Programms zu sehen und Rückschlüsse auf das Format der Eingabedaten des Programms zu ziehen.

Wir nehmen alle Flaggen auf und erstellen Dateien (eine separate Datei für jede Flagge), auf deren Grundlage Generationstransformationen stattfinden. Wenn Sie Ihr eigenes Programm testen müssen, hängt alles davon ab, was und wie es als Eingabe erhalten und verarbeiten soll.

Wozu dienen die Anfangsdaten, wenn der Fuzzer absolut zufällige Daten erzeugt? Sie ermöglichen es Ihnen, die maximale Anzahl von Funktionen zu nutzen, was zu einer Erhöhung der Codeabdeckung führt. Einfach gesagt, es gibt Ihnen die Möglichkeit, in alle geheimen Ecken des Programms zu blicken. Für eine maximale Codeabdeckung müssen Sie: die zu testende Software konfigurieren (wie von den Entwicklern beabsichtigt), alle möglichen Anfangsdaten vorbereiten und dem Fuzzer viel Zeit geben, um die Daten zu mutieren. Sie können auch einzelne Softwarefunktionen testen, indem Sie sie aus dem Programm entfernen.

Die Zeit für Fuzzing-Tests kann von einer Minute (in einigen Softwares können Abstürze sofort auftreten) bis unendlich variieren. Ein Beispiel ist Google, das dem kontinuierlichen Fuzzing des Chrome-Browsers Ressourcen gewidmet hat. Nach dem Vorbereiten der Anfangsdaten ist es der Einfachheit halber erforderlich, ein Testverzeichnis zu erstellen, in dem die Anfangsdaten abgelegt werden.

Wir starten den Test mit dem Befehl:

path/to/crusher/bin_x86-64/fuzz_manager -i -o -T Argv –start –/usr/bin/programm __DATA__

  • –start – Anzahl der Kerne für den Fuzzer-Manager;

  • -i — Pfad zum Verzeichnis mit Eingabedaten;

  • -o – Pfad zum Verzeichnis mit Ausgabedaten

  • -T Argv – Art der bereitgestellten Daten

  • __DATA__ – Eingabedaten werden hier ersetzt

Wir sehen, dass der Prozess gut läuft.

Gehen wir zur besseren Übersichtlichkeit zu einem neuen Terminalfenster und starten eine grafische Informationsanzeige. Dazu verwenden wir den Befehl:

crusher/bin_x86-64/ui –outdir

Nach nur 8 Minuten fanden wir einen Fehler (im Bild oben „uniqe_crashes“ zu sehen). Es ist zwar ein wenig Zeit vergangen, aber wir haben genug für ein Beispiel, also lasst uns den Test abschließen. Kommen wir zum Fehler selbst. Wenn wir nur das Flag “-b” angeben, kommt es zu einem Anwendungsabsturz.

Fehlerbehandlung

Wir haben also herausgefunden, bei welchen Daten sich das Programm abnormal verhält. Als nächstes fahren wir mit der Analyse dieses Fehlers fort. Dazu verwenden wir vscode und die Quelltexte unserer Software (das signtool-Tool ist im nss-Paket enthalten).

Um den Fehler schnell zu finden, beginnen wir mit dem Bau des Pakets und gehen in das Quellverzeichnis. Wir sehen die Datei „build.sh“, führen sie aus, um das Paket zu konfigurieren (Befehl zum Ausführen von „./build.sh“).

Der nächste Befehl ist “make”, um das Paket zu erstellen. Aber nicht alles ist so klar. Während des Builds ist ein Fehler aufgetreten:

Um dies zu beheben, müssen Sie gcc-multilib installieren (Dieses Paket befindet sich im offiziellen Astra Linux-Repository, führen Sie einfach den Befehl aus: „sudo apt-get install gcc-multilib“). Wir führen „make clean“ aus, dann „make“, aber wir bekommen wieder einen Fehler:

Der Build findet die Datei “nspr.h” nicht, obwohl sie im System installiert ist. Es ist in Ordnung, schreiben wir den Pfad manuell und geben an, dass wir ein 64-Bit-System haben. “make clean” und dann “make USE_64=1 C_INCLUDE_PATH=/usr/include/nspr/ CPLUS_INCLUDE_PATH=/usr/include/nspr/”. Diesmal Erfolg.

Um mit dem Code in vscode zu arbeiten, installieren Sie die C/C++-Erweiterung (wie im Bild unten) und installieren Sie gdb auf dem System selbst (sudo apt install gdb).

Für unsere Aufgabe ist dies die optimale und bequemste Option.

Sie können auch in der Konsole gdb arbeiten, aber das ist nicht sehr komfortabel, und in vscode ist alles viel übersichtlicher. Öffnen Sie das Projekt im Terminal, in unserem Fall ist es nss, ohne den Quellcode zu verlassen, geben Sie den Befehl „code .“ ein. Gehen Sie dann zum Debug-Fenster und fügen Sie die folgende Konfiguration hinzu: “(gdb) Run”.

Es wird eine JSON-Datei geben, in die wir den Pfad zum Programm in das Feld “Programm” und die Argumente in das Feld “Argumente” schreiben. Wir drücken Start und sehen uns die Ausgabe an.

Eine detaillierte Beschreibung des Fehlers würde den Rahmen des Artikels sprengen, aber ich gehe kurz darauf ein. Lassen Sie uns zuerst unser Projekt ausführen (grünes Dreieck). Nach dem Start sehen wir ein solches Bild.

Der Fehler tritt beim Versuch auf, Speicher freizugeben (Funktion “PR_free ()”), machen wir dem ein Ende und sehen, was in der Variable “base” steckt.

Die erste Annahme, dass base leer ist, wird sofort verworfen, da wir in die „if (base)“-Bedingung eintreten (dies ist im Bild zu sehen). Lassen Sie uns dann herausfinden, wie diese Variable festgelegt wird. Zuerst sehen wir “char *base = DEFAULT_BASE_NAME;”, wir schauen weiter. Wir finden “#define DEFAULT_BASE_NAME “zigbert””, und hier ist der angebliche Fehler. Der Speicher für die String-Variable „base“ wird nicht auf dem Heap allokiert – dementsprechend wird die Verwendung der „PR_free()“-Funktion, die eine Wrapper-Funktion für „free()“ ist, nicht empfohlen, da Aborted auftritt. Dieser Fehler stellt keine ernsthafte Bedrohung dar, muss aber behoben werden, also habe ich diesen Fehler den Entwicklern dieser Software gemeldet (ich habe einen Fehlerbericht in Mozilla erstellt). Basierend auf den Ergebnissen der Überprüfungen werden solche Fehlerberichte regelmäßig gesendet und recht schnell behoben, wie z. B. ein zuvor identifizierter Fehler und bereits in Tassen behoben: https://github.com/OpenPrinting/cups/issues/457.

Also haben wir uns ein kleines Beispiel zum Finden von Codefehlern angesehen, uns ein wenig mit Fuzz-Tests und dem Crusher-Tool vertraut gemacht. Vielen Dank für Ihre Aufmerksamkeit!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *