Advertisements

Identifizieren Sie Sicherheitseigenschaften unter Linux mit checksec

Das Kompilieren des Quellcodes erzeugt eine Binärdatei. Während der Kompilierung können Sie dem Compiler Flags bereitstellen, um bestimmte Eigenschaften der Binärdatei zu aktivieren oder zu deaktivieren. Einige dieser Eigenschaften sind sicherheitsrelevant.

Checksec ist ein raffiniertes kleines Tool (und Shell-Skript), das neben anderen Funktionen die Sicherheitseigenschaften identifiziert, die bei der Kompilierung in eine Binärdatei eingebaut wurden. Ein Compiler aktiviert möglicherweise einige dieser Eigenschaften standardmäßig, und Sie müssen möglicherweise bestimmte Flags bereitstellen, um andere zu aktivieren.

In diesem Artikel wird erläutert, wie Sie mithilfe von Checksec die Sicherheitseigenschaften einer Binärdatei identifizieren, einschließlich:

  1. Die zugrunde liegenden Befehle, die checksec verwendet, um Informationen zu den Sicherheitseigenschaften zu finden
  2. So aktivieren Sie Sicherheitseigenschaften mithilfe der GNU Compiler Collection (GCC) beim Kompilieren einer Beispiel-Binärdatei

Checksec installieren

Um checksec auf Fedora und anderen RPM-basierten Systemen zu installieren, verwenden Sie:

$ sudo dnf install checksec

Verwenden Sie für Debian-basierte Distributionen das Äquivalent apt Befehl.

Das Shell-Skript

Checksec ist ein Ein-Datei-Shell-Skript, wenn auch ein ziemlich großes. Ein Vorteil ist, dass Sie das Skript schnell durchlesen und alle ausgeführten Systembefehle verstehen können, um Informationen zu Binärdateien oder ausführbaren Dateien zu finden:

$ file /usr/bin/checksec
/usr/bin/checksec: Bourne-Again shell script, ASCII text executable, with very long lines

$ wc -l /usr/bin/checksec
2111 /usr/bin/checksec

Nehmen Sie checksec für ein Laufwerk mit einer Binärdatei, die Sie wahrscheinlich täglich ausführen: die allgegenwärtige ls Befehl. Das Format des Befehls ist checksec --file= gefolgt vom absoluten Pfad des ls binär:

$ checksec --file=/usr/bin/ls
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols        Yes   5       17              /usr/bin/ls

Wenn Sie dies in einem Terminal ausführen, sehen Sie eine Farbcodierung, die anzeigt, was gut ist und was wahrscheinlich nicht. Ich sage “wahrscheinlich”, denn selbst wenn etwas rot ist, bedeutet dies nicht unbedingt, dass die Dinge schrecklich sind – es könnte nur bedeuten, dass die Distributionsanbieter beim Kompilieren der Binärdateien einige Kompromisse eingegangen sind.

Die erste Zeile bietet verschiedene Sicherheitseigenschaften, die normalerweise für Binärdateien verfügbar sind, wie z RELRO, STACK CANARY, NX, und so weiter (das erkläre ich weiter unten). Die zweite Zeile zeigt den Status dieser Eigenschaften für die angegebene Binärdatei (ls, in diesem Fall). Zum Beispiel, NX enabled bedeutet, dass eine Eigenschaft für diese Binärdatei aktiviert ist.

Eine Beispiel-Binärdatei

Für dieses Tutorial verwende ich das folgende “hello world”-Programm als Beispiel-Binärdatei.

#include <stdio.h>

int main()
{
        printf("Hello Worldn");
        return 0;
}
 

Beachten Sie, dass ich nicht bereitgestellt habe gcc mit eventuellen zusätzlichen Flags während der Kompilierung:

$ gcc hello.c -o hello
 
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ ./hello
Hello World

Führen Sie die Binärdatei durch checksec aus. Einige der Eigenschaften sind anders als bei den ls Befehl oben (auf Ihrem Bildschirm können diese in Rot angezeigt werden):

$ checksec --file=./hello
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   85) Symbols       No    0       0./hello
$

Ausgabeformat ändern

Checksec erlaubt verschiedene Ausgabeformate, die Sie mit angeben können --output. Ich wähle das JSON-Format und leite die Ausgabe an die jq Dienstprogramm für hübsches Drucken.

Um mitzumachen, stellen Sie sicher, dass Sie jq installiert, weil dieses Tutorial dieses Ausgabeformat verwendet, um schnell nach bestimmten Eigenschaften aus der Ausgabe und dem Bericht zu suchen yes oder no auf jeder:

$ checksec --file=./hello --output=json | jq
{
  "./hello": {
    "relro": "partial",
    "canary": "no",
    "nx": "yes",
    "pie": "no",
    "rpath": "no",
    "runpath": "no",
    "symbols": "yes",
    "fortify_source": "no",
    "fortified": "0",
    "fortify-able": "0"
  }
}

Durch die Sicherheitseigenschaften gehen

Mehr zum Thema Sicherheit

Die obige Binärdatei enthält mehrere Sicherheitseigenschaften. Ich vergleiche diese Binärdatei mit der ls binär oben, um zu untersuchen, was aktiviert ist, und zu erklären, wie checksec diese Informationen gefunden hat.

1. Symbole

Ich fange zuerst mit dem einfachen an. Während der Kompilierung werden bestimmte Symbole in die Binärdatei aufgenommen, hauptsächlich zum Debuggen. Diese Symbole werden bei der Entwicklung von Software benötigt und erfordern mehrere Zyklen zum Debuggen und Beheben von Problemen.

Diese Symbole werden normalerweise aus der endgültigen Binärdatei entfernt (entfernt), bevor sie für den allgemeinen Gebrauch freigegeben wird. Dies hat keinerlei Einfluss auf die Ausführung der Binärdatei; es läuft genauso wie mit den Symbolen. Das Strippen wird oft durchgeführt, um Platz zu sparen, da die Binärdatei nach dem Strippen der Symbole etwas heller ist. In Closed-Source- oder proprietärer Software werden Symbole oft entfernt, da diese Symbole in einer Binärdatei es etwas einfacher machen, auf das Innenleben der Software zu schließen.

Laut checksec sind in dieser Binärdatei Symbole vorhanden, die jedoch nicht in der ls binär. Sie können diese Informationen auch finden, indem Sie die file Befehl im Programm – Siehst du not stripped in der Ausgabe gegen Ende:

$ checksec --file=/bin/ls --output=json | jq | grep symbols
    "symbols": "no",

$ checksec --file=./hello --output=json | jq | grep symbols
    "symbols": "yes",

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

Wie hat checksec diese Informationen gefunden? Nun, es bietet ein praktisches --debug Option, um anzuzeigen, welche Funktionen ausgeführt wurden. Daher sollte Ihnen die Ausführung des folgenden Befehls zeigen, welche Funktionen innerhalb des Shell-Skripts ausgeführt wurden:

$ checksec --debug --file=./hello

In diesem Tutorial suche ich nach den zugrunde liegenden Befehlen, die zum Auffinden dieser Informationen verwendet werden. Da es sich um ein Shell-Skript handelt, können Sie jederzeit die Bash-Funktionen nutzen. Dieser Befehl gibt jeden Befehl aus, der innerhalb des Shell-Skripts ausgeführt wurde:

$ bash -x /usr/bin/checksec --file=./hello

Wenn Sie durch die Ausgabe scrollen, sollten Sie ein . sehen echo_message gefolgt von der Kategorie der Sicherheitseigenschaft. Folgendes meldet checksec darüber, ob die Binärdatei Symbole enthält:

+ wiederelfen -W --symbole ./Hallo
+ grep -Q ' .symtab'
+ echo_message '33[31m96) Symbolst33[m  ' Symbols, ' symbols="yes"' '"symbols":"yes",'

To simplify this, checksec utilizes the readelf utility to read the binary and provides a special --symbols flag that lists all symbols within the binary. Then it greps for a special value, .symtab, that provides a count of entries (symbols) it finds. You can try out the following commands on the test binary you compiled above:

$ readelf -W --symbols ./hello
$ readelf -W --symbols ./hello | grep -i symtab

How to strip symbols

You can strip symbols after compilation or during compilation.

  • Post compilation: After compilation, you can use the strip utility on the binary to remove the symbols. Confirm it worked using the file command, which now shows the output as stripped:
    $ gcc hello.c -o hello
    $
    $ file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, zum GNU/Linux 3.2.0, nicht abgespeckt
    $
    $ Streifen Hallo
    $
    $ Datei Hallo
    Hallo: ELF 64-bit LSB ausführbar, x86-64, Ausführung 1 (SYSV), dynamisch verknüpft, Interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, zum GNU/Linux 3.2.0, abgespeckt
    $

So entfernen Sie Symbole während der Kompilierung

Anstatt Symbole nach der Kompilierung manuell zu entfernen, können Sie den Compiler bitten, dies für Sie zu tun, indem Sie die -s Streit:

$ gcc -s hello.c -o hello
$
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, for GNU/Linux 3.2.0, stripped
$

Nachdem Sie checksec erneut ausgeführt haben, können Sie das sehen symbols werden angezeigt als no:

$ checksec --file=./hello --output=json | jq | grep symbols
    "symbols": "no",
$

2. Kanarienvogel

Kanarienvögel sind bekannte Werte, die zwischen einem Puffer und Kontrolldaten auf dem Stapel Pufferüberläufe zu überwachen. Wenn eine Anwendung ausgeführt wird, werden ihr zwei Arten von Speicher zugewiesen. Einer von ihnen ist ein Stapel, die einfach eine Datenstruktur mit zwei Operationen ist: push, die Daten auf den Stack legt, und pop, die Daten in umgekehrter Reihenfolge vom Stack entfernt. Böswillige Eingaben können den Stack mit speziell gestalteten Eingaben überlaufen oder beschädigen und zum Absturz des Programms führen:

$ checksec --file=/bin/ls --output=json | jq | grep canary
    "canary": "yes",
$
$ checksec --file=./hello --output=json | jq | grep canary
    "canary": "no",
$

Wie findet checksec heraus, ob die Binärdatei mit einem Canary aktiviert ist? Mit der obigen Methode können Sie es eingrenzen, indem Sie den folgenden Befehl innerhalb des Shell-Skripts ausführen:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'

Kanarienvogel aktivieren

Um sich vor diesen Fällen zu schützen, bietet der Compiler die -stack-protector-all Flag, das der Binärdatei zusätzlichen Code hinzufügt, um auf solche Pufferüberläufe zu prüfen:

$ gcc -fstack-protector-all hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep canary
    "canary": "yes",

Checksec zeigt an, dass die Eigenschaft jetzt aktiviert ist. Sie können dies auch überprüfen mit:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (3)
    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4
$

3. TORTE

PIE steht für positionsunabhängige ausführbare Datei. Wie der Name schon sagt, handelt es sich um Code, der unabhängig von seiner absoluten Adresse zur Ausführung irgendwo im Speicher abgelegt wird:

$ checksec --file=/bin/ls --output=json | jq | grep pie
    "pie": "yes",

$ checksec --file=./hello --output=json | jq | grep pie
    "pie": "no",

PIE ist oft nur für Bibliotheken und nicht für eigenständige Befehlszeilenprogramme aktiviert. In der Ausgabe unten, hello wird angezeigt als LSB executable, während die libc Standardbibliothek (.so) Datei ist markiert LSB shared object:

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ file /lib64/libc-2.32.so
/lib64/libc-2.32.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, for GNU/Linux 3.2.0, not stripped

Checksec versucht diese Informationen zu finden mit:

$ readelf -W -h ./hello | grep EXEC
  Type:                              EXEC (Executable file)

Wenn Sie denselben Befehl in einer gemeinsam genutzten Bibliothek versuchen, anstatt EXEC, du wirst sehen DYN:

$ readelf -W -h /lib64/libc-2.32.so | grep DYN
  Type:                              DYN (Shared object file)

PIE aktivieren

Um PIE in einem Testprogramm zu aktivieren, senden Sie die folgenden Argumente an den Compiler:

$ gcc -pie -fpie hello.c -o hello

Sie können überprüfen, ob PIE mit checksec aktiviert ist:

$ checksec --file=./hello --output=json | jq | grep pie
    "pie": "yes",
$

Es sollte als ausführbare PIE-Datei mit dem Typ angezeigt werden, der von geändert wurde EXEC zu DYN:

$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, for GNU/Linux 3.2.0, not stripped

$ readelf -W -h ./hello | grep DYN
  Type:                              DYN (Shared object file)

4. NX

NX steht für „nicht ausführbar“. Es wird oft auf CPU-Ebene aktiviert, sodass ein Betriebssystem mit aktiviertem NX bestimmte Speicherbereiche als nicht ausführbar markieren kann. Häufig legen Buffer-Overflow-Exploits Code auf den Stack und versuchen dann, ihn auszuführen. Wenn Sie diesen beschreibbaren Bereich jedoch nicht ausführbar machen, können solche Angriffe verhindert werden. Diese Eigenschaft ist während der regulären Kompilierung standardmäßig aktiviert mit gcc:

$ checksec --file=/bin/ls --output=json | jq | grep nx
    "nx": "yes",

$ checksec --file=./hello --output=json | jq | grep nx
    "nx": "yes",

Checksec ermittelt diese Informationen mit dem folgenden Befehl. RW gegen Ende bedeutet, dass der Stapel lesbar und beschreibbar ist; da es keine gibt E, es ist nicht ausführbar:

$ readelf -W -l ./hello | grep GNU_STACK
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

Deaktivieren Sie NX für Demozwecke

Es wird nicht empfohlen, aber Sie können es deaktivieren NX beim Kompilieren eines Programms mit dem -z execstack Streit:

$ gcc -z execstack hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep nx
    "nx": "no",

Beim Kompilieren wird der Stack ausführbar (RWE), wodurch bösartiger Code ausgeführt werden kann:

$ readelf -W -l ./hello | grep GNU_STACK
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

5. RELRO

RELRO steht für Relocation Read-Only. Eine Binärdatei im Executable Linkable Format (ELF) verwendet eine Global Offset Table (GOT), um Funktionen dynamisch aufzulösen. Wenn diese Sicherheitseigenschaft aktiviert ist, macht diese Sicherheitseigenschaft das GOT innerhalb der Binärdatei schreibgeschützt, was irgendeine Form von Relocation-Angriffen verhindert:

$ checksec --file=/bin/ls --output=json | jq | grep relro
    "relro": "full",

$ checksec --file=./hello --output=json | jq | grep relro
    "relro": "partial",

Checksec findet diese Informationen mithilfe des folgenden Befehls. Hier ist eine der RELRO-Eigenschaften aktiviert; daher zeigt die Binärdatei “partiell” an, wenn sie über checksec verifiziert wird:

$ readelf -W -l ./hello | grep GNU_RELRO
  GNU_RELRO      0x002e10 0x0000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW

Vollständiges RELRO aktivieren

Um vollständiges RELRO zu aktivieren, verwenden Sie die folgenden Befehlszeilenargumente beim Kompilieren mit gcc:

$ gcc -Wl,-z,relro,-z,now hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep relro
    "relro": "full",

Jetzt ist auch die zweite Eigenschaft aktiviert, wodurch das Programm vollständig RELRO wird:

$ readelf -W -l ./hello | grep GNU_RELRO
  GNU_RELRO      0x002dd0 0x0000000000403dd0 0x0000000000403dd0 0x000230 0x000230 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW
 0x0000000000000018 (BIND_NOW)          

6. Stärken

Fortify ist eine weitere Sicherheitseigenschaft, die jedoch in diesem Artikel nicht behandelt wird. Ich werde lernen, wie Checksec Fortify in Binärdateien überprüft und wie es mit aktiviert wird gcc als Übung für Sie anzugehen.

$ checksec --file=/bin/ls --output=json | jq  | grep -i forti
    "fortify_source": "yes",
    "fortified": "5",
    "fortify-able": "17"

$ checksec --file=./hello --output=json | jq  | grep -i forti
    "fortify_source": "no",
    "fortified": "0",
    "fortify-able": "0"

Andere Checksec-Funktionen

Das Thema Sicherheit ist endlos, und obwohl es hier nicht möglich ist, alles abzudecken, möchte ich noch ein paar weitere Funktionen des checksec Befehle, mit denen die Arbeit zu einem Vergnügen wird.

Gegen mehrere Binärdateien ausführen

Sie müssen nicht jede Binärdatei einzeln für checksec bereitstellen. Stattdessen können Sie einen Verzeichnispfad angeben, in dem sich mehrere Binärdateien befinden, und checksec überprüft alle auf einmal für Sie:

$ checksec --dir=/usr/bin

Prozesse

Neben Binärdateien arbeitet checksec auch an Programmen während der Ausführung. Der folgende Befehl findet die Sicherheitseigenschaften aller laufenden Programme auf Ihrem System. Sie können verwenden --proc-all Wenn Sie möchten, dass alle laufenden Prozesse überprüft werden, oder Sie können einen bestimmten Prozess mithilfe seines Namens auswählen:

$ checksec --proc-all

$ checksec --proc=bash

Kernel-Eigenschaften

Zusätzlich zu den in diesem Artikel beschriebenen Userland-Anwendungen von checksec können Sie damit auch die in Ihr System integrierten Kernel-Eigenschaften überprüfen:

$ checksec --kernel

Versuche es

Checksec ist eine gute Möglichkeit zu verstehen, welche Userland- und Kernel-Eigenschaften aktiviert sind. Gehen Sie jede Sicherheitseigenschaft im Detail durch und versuchen Sie, die Gründe für die Aktivierung der einzelnen Funktionen und die Arten von Angriffen zu verstehen, die sie verhindern.

Identifizieren Sie Sicherheitseigenschaften unter Linux mit checksec

Leave a Reply

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

Scroll to top