GNU/Linux >> Tutoriels Linux >  >> Linux

Identifier les propriétés de sécurité sous Linux à l'aide de checksec

La compilation du code source produit un binaire. Lors de la compilation, vous pouvez fournir des indicateurs au compilateur pour activer ou désactiver certaines propriétés sur le binaire. Certaines de ces propriétés sont pertinentes pour la sécurité.

Checksec est un petit outil astucieux (et un script shell) qui, entre autres fonctions, identifie les propriétés de sécurité qui ont été intégrées dans un binaire lors de sa compilation. Un compilateur peut activer certaines de ces propriétés par défaut, et vous devrez peut-être fournir des indicateurs spécifiques pour en activer d'autres.

Cet article explique comment utiliser checksec pour identifier les propriétés de sécurité sur un binaire, notamment :

  1. Les commandes sous-jacentes que checksec utilise pour trouver des informations sur les propriétés de sécurité
  2. Comment activer les propriétés de sécurité à l'aide de GNU Compiler Collection (GCC) lors de la compilation d'un exemple de binaire

Installer checksec

Pour installer checksec sur Fedora et d'autres systèmes basés sur RPM, utilisez :

$ sudo dnf install checksec 

Pour les distributions basées sur Debian, utilisez l'équivalent apt commande.

Le script shell

Checksec est un script shell à fichier unique, bien qu'assez volumineux. Un avantage est que vous pouvez lire rapidement le script et comprendre toutes les commandes système en cours d'exécution pour trouver des informations sur les binaires ou les exécutables :

$ file /usr/bin/checksec
/usr/bin/checksec :script shell Bourne-Again, exécutable en texte ASCII, avec de très longues lignes

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

Prenez checksec pour un lecteur avec un binaire que vous exécutez probablement quotidiennement :l'omniprésent ls commande. Le format de la commande est checksec --file= suivi du chemin absolu du ls binaire :

 $ checksec --file =/ usr / bin / ls 
Stack Relro Stack NX Pie RPATH Symboles FORTIFY FORDIFIABLE FORTIFIABLE FORTIFIABLE FORTIFIABLE
TRANSFORME COMPLET NX activé Non RPATH Aucun Symbole Non Symboles Oui 5       17              /usr/bin/ls

Lorsque vous l'exécutez dans un terminal, vous voyez un code couleur indiquant ce qui est bon et ce qui ne l'est probablement pas. Je dis "probablement" parce que même si quelque chose est en rouge, cela ne signifie pas nécessairement que les choses sont horribles - cela peut simplement signifier que les fournisseurs de distribution ont fait des compromis lors de la compilation des binaires.

La première ligne fournit diverses propriétés de sécurité qui sont généralement disponibles pour les binaires, comme RELRO , STACK CANARY , NX , et ainsi de suite (j'explique en détail ci-dessous). La deuxième ligne montre le statut de ces propriétés pour le binaire donné (ls , dans ce cas). Par exemple, NX enabled signifie qu'une propriété est activée pour ce binaire.

Un exemple binaire

Pour ce tutoriel, j'utiliserai le programme "hello world" suivant comme exemple binaire.

#include 

int main()
{
        printf("Hello World\n");
        return 0;
}
 

Notez que je n'ai pas fourni gcc avec tous les drapeaux supplémentaires lors de la compilation :

$ gcc hello.c -o hello
 
$ file hello
hello :ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamiquement lié, interpréteur / lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pour GNU/Linux 3.2.0, non supprimé

$ ./hello
Hello World

Exécutez le binaire via checksec. Certaines propriétés sont différentes de celles avec ls commande ci-dessus (sur votre écran, celles-ci peuvent être affichées en rouge) :

 $ CheckSec --File =. / Hello 
Relro Stack Canary Nx Pie RPATH Symboles RunPath FORTIFY FORTIFIABLE FORTIFIABLE FORTIFIABLE
NO PARTIE FONCTIONNAIRE NX activé Non Pie Pas de RPATH No RunPath 85) Symboles No 0 0./bonjour

Modifier le format de sortie

Checksec autorise différents formats de sortie, que vous pouvez spécifier avec --output . Je vais choisir le format JSON et diriger la sortie vers le jq utilitaire pour de jolies impressions.

Pour suivre, assurez-vous d'avoir jq installé car ce didacticiel utilise ce format de sortie pour rechercher rapidement des propriétés spécifiques à partir de la sortie et signaler yes ou no sur chaque :

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

Parcourir les propriétés de sécurité

En savoir plus sur la sécurité

  • Le guide de codage défensif
  • Webinaire :Automatiser la sécurité et la conformité du système avec un système d'exploitation standard
  • 10 couches de sécurité des conteneurs Linux
  • Livre de coloriage SELinux
  • Plus d'articles sur la sécurité

Le binaire ci-dessus inclut plusieurs propriétés de sécurité. Je vais comparer ce binaire avec le ls binaire ci-dessus pour examiner ce qui est activé et expliquer comment checksec a trouvé cette information.

1. Symboles

Je vais d'abord commencer par le plus facile. Lors de la compilation, certains symboles sont inclus dans le binaire, principalement pour le débogage. Ces symboles sont nécessaires lorsque vous développez un logiciel et nécessitent plusieurs cycles pour déboguer et réparer les choses.

Ces symboles sont généralement supprimés (supprimés) du binaire final avant qu'il ne soit publié pour une utilisation générale. Cela n'affecte en rien l'exécution du binaire; il fonctionnera comme il le ferait avec les symboles. La suppression est souvent effectuée pour économiser de l'espace, car le binaire est un peu plus léger une fois que les symboles ont été supprimés. Dans les logiciels à source fermée ou propriétaires, les symboles sont souvent supprimés, car le fait d'avoir ces symboles dans un binaire permet de déduire assez facilement le fonctionnement interne du logiciel.

Selon checksec, les symboles sont présents dans ce binaire, mais ils n'étaient pas dans le ls binaire. Vous pouvez également trouver ces informations en exécutant le file commande sur le programme—vous voyez not stripped dans la sortie vers la fin :

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

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

$ file hello
hello:ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamiquement lié , interpréteur /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pour GNU/Linux 3.2.0, non supprimé

Comment checksec a-t-il trouvé cette information ? Eh bien, il fournit un --debug pratique option pour montrer quelles fonctions ont été exécutées. Par conséquent, l'exécution de la commande suivante devrait vous montrer quelles fonctions s'exécutent dans le script shell :

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

Dans ce didacticiel, je recherche les commandes sous-jacentes utilisées pour trouver ces informations. Comme il s'agit d'un script shell, vous pouvez toujours utiliser les fonctionnalités de Bash. Cette commande affichera toutes les commandes exécutées à partir du script shell :

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

Si vous faites défiler la sortie, vous devriez voir un echo_message suivi de la catégorie de la propriété de sécurité. Voici ce que checksec indique si le binaire contient des symboles :

+ readelf -W --symbols ./hello
+ grep -q '\.symtab'
+ echo_message '\033[31m96) Symboles\t\033[m  ' Symboles, ' symboles ="oui"' '"symboles":"oui",'

Pour simplifier cela, checksec utilise le readelf utilitaire pour lire le binaire et fournit un --symbols spécial drapeau qui répertorie tous les symboles dans le binaire. Ensuite, il recherche une valeur spéciale, .symtab , qui fournit un nombre d'entrées (symboles) qu'il trouve. Vous pouvez essayer les commandes suivantes sur le binaire de test que vous avez compilé ci-dessus :

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

Comment supprimer les symboles

Vous pouvez supprimer les symboles après la compilation ou pendant la compilation.

  • Post-compilation : Après compilation, vous pouvez utiliser le strip utilitaire sur le binaire pour supprimer les symboles. Confirmez que cela a fonctionné en utilisant le file commande, qui affiche maintenant la sortie comme stripped :
    $ gcc bonjour.c -o bonjour
    $
    $ fichier bonjour
    bonjour :exécutable LSB ELF 64 bits, x86-64, version 1 (SYSV) , lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, pour GNU/Linux 3.2.0, non supprimé
    $
    $ strip hello
    $
    $ fichier bonjour
    bonjour :exécutable LSB 64 bits ELF, x86-64, version 1 (SYSV), lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so .2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, pour GNU/Linux 3.2.0, supprimé
    $

Comment supprimer les symboles lors de la compilation

Au lieu de supprimer manuellement les symboles après la compilation, vous pouvez demander au compilateur de le faire pour vous en fournissant le -s argument :

$ gcc -s hello.c -o hello
$
$ file hello
hello :ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamiquement lié , interpréteur /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, pour GNU/Linux 3.2.0, supprimé
$

Après avoir réexécuté checksec, vous pouvez voir que symbols sont affichés comme no :

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

2. Canari

Les canaris sont des valeurs connues qui sont placées entre un tampon et des données de contrôle sur la pile pour surveiller les débordements de tampon. Lorsqu'une application s'exécute, deux types de mémoire lui sont affectés. L'un d'eux est une pile , qui est simplement une structure de données avec deux opérations :push , qui place les données sur la pile, et pop , qui supprime les données de la pile dans l'ordre inverse. Une entrée malveillante pourrait déborder ou corrompre la pile avec une entrée spécialement conçue et provoquer le plantage du programme :

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

Comment checksec trouve-t-il si le binaire est activé avec un canari ? En utilisant la méthode ci-dessus, vous pouvez l'affiner en exécutant la commande suivante dans le script shell :

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

Activer canari

Pour se protéger contre ces cas, le compilateur fournit le -stack-protector-all flag, qui ajoute du code supplémentaire au binaire pour vérifier ces débordements de tampon :

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

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

Checksec montre que la propriété est maintenant activée. Vous pouvez également le vérifier avec :

$ readelf -W -s ./bonjour | Grep -e '__stack_chk_fail | __intel_security_cookie' 
2:0000000000000000 0 Func global par défaut und __stack_chk_fail@glibc_2.4 (3)
83:0000000000000000 0 Func global par défaut und __stack_chk_fail @@ glibc_2.4
$

3. TARTE

PIE signifie exécutable indépendant de la position. Comme son nom l'indique, c'est du code qui est placé quelque part en mémoire pour exécution quelle que soit son adresse absolue :

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

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

Souvent, PIE n'est activé que pour les bibliothèques et non pour les programmes de ligne de commande autonomes. Dans la sortie ci-dessous, hello est affiché comme LSB executable , tandis que la libc bibliothèque standard (.so ) le fichier est marqué LSB shared object :

$ fichier bonjour
bonjour :exécutable LSB 64 bits ELF, x86-64, version 1 (SYSV), lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so.2, BuildID[ sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pour GNU/Linux 3.2.0, non supprimé

$ fichier /lib64/libc-2.32.so
/lib64/libc-2.32.so :ELF 64 bits Objet partagé LSB, x86-64, version 1 (GNU/Linux), lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, pour GNU/Linux 3.2.0, non dépouillé

Checksec essaie de trouver ces informations avec :

$ readelf -W -h ./bonjour | grep EXEC
  Tapez :                             EXEC (fichier exécutable)

Si vous essayez la même commande sur une bibliothèque partagée au lieu de EXEC , vous verrez un DYN :

$ readelf -W -h /lib64/libc-2.32.so | grep DYN
  Tapez :                             DYN (fichier objet partagé)

Activer PIE

Pour activer PIE sur un programme de test, envoyez les arguments suivants au compilateur :

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

Vous pouvez vérifier que PIE est activé en utilisant checksec :

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

Il devrait apparaître comme un exécutable PIE avec le type changé de EXEC à DYN :

$ fichier bonjour
bonjour :ELF 64 bits LSB pie exécutable, x86-64, version 1 (SYSV), lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so.2, BuildID [sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, pour GNU/Linux 3.2.0, non supprimé

$ readelf -W -h ./hello | grep DYN
  Tapez :                             DYN (fichier objet partagé)

4. NX

NX signifie "non exécutable". Il est souvent activé au niveau du processeur, de sorte qu'un système d'exploitation avec NX activé peut marquer certaines zones de la mémoire comme non exécutables. Souvent, les exploits de débordement de tampon placent du code sur la pile, puis tentent de l'exécuter. Cependant, rendre cette zone inscriptible non exécutable peut empêcher de telles attaques. Cette propriété est activée par défaut lors de la compilation régulière à l'aide de gcc :

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

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

Checksec détermine ces informations avec la commande ci-dessous. RW vers la fin signifie que la pile est lisible et inscriptible ; puisqu'il n'y a pas de E , il n'est pas exécutable :

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

Désactiver NX à des fins de démonstration

Ce n'est pas recommandé, mais vous pouvez désactiver NX lors de la compilation d'un programme en utilisant -z execstack argument :

$ gcc -z execstack hello.c -o hello

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

A la compilation, la pile devient exécutable (RWE ), ce qui permet à un code malveillant de s'exécuter :

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

5. RELRO

RELRO signifie Relocation Read-Only. Un binaire ELF (Executable Linkable Format) utilise une table de décalage globale (GOT) pour résoudre les fonctions de manière dynamique. Lorsqu'elle est activée, cette propriété de sécurité rend le GOT dans le binaire en lecture seule, ce qui empêche certaines formes d'attaques de relocalisation :

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

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

Checksec trouve ces informations en utilisant la commande ci-dessous. Ici, l'une des propriétés RELRO est activée ; par conséquent, le binaire affiche "partial" lors de la vérification via checksec :

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

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

Activer le RELRO complet

Pour activer le RELRO complet, utilisez les arguments de ligne de commande suivants lors de la compilation avec gcc :

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

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

Maintenant, la deuxième propriété est également activée, rendant le programme complet RELRO :

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

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

6. Fortifier

Fortify est une autre propriété de sécurité, mais elle sort du cadre de cet article. Je vais apprendre comment checksec vérifie fortifier dans les binaires et comment il est activé avec gcc comme un exercice à aborder.

$ 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"

Autres fonctionnalités de checksec

Le sujet de la sécurité est sans fin, et bien qu'il ne soit pas possible de tout couvrir ici, je veux mentionner quelques fonctionnalités supplémentaires du checksec commande avec laquelle il est agréable de travailler.

Exécuter sur plusieurs binaires

Vous n'avez pas à fournir chaque binaire à checksec individuellement. Au lieu de cela, vous pouvez fournir un chemin de répertoire où résident plusieurs fichiers binaires, et checksec les vérifiera tous pour vous en une seule fois :

$ checksec --dir=/usr/bin 

Processus

En plus des binaires, checksec fonctionne également sur les programmes pendant l'exécution. La commande suivante recherche les propriétés de sécurité de tous les programmes en cours d'exécution sur votre système. Vous pouvez utiliser --proc-all si vous voulez qu'il vérifie tous les processus en cours d'exécution, ou vous pouvez sélectionner un processus spécifique en utilisant son nom :

$ checksec --proc-all

$ checksec --proc=bash

Propriétés du noyau

En plus des applications utilisateur de checksec décrites dans cet article, vous pouvez également l'utiliser pour vérifier les propriétés du noyau intégrées à votre système :

$ checksec --kernel 

Essayez-le

Checksec est un bon moyen de comprendre quelles propriétés de l'espace utilisateur et du noyau sont activées. Passez en revue chaque propriété de sécurité en détail et essayez de comprendre les raisons de l'activation de chaque fonctionnalité et les types d'attaques qu'elle empêche.


Linux
  1. Déboguer Linux avec ProcDump

  2. 13 tutoriels de sécurité Linux

  3. Exemples d'utilisation de la commande dmsetup sous Linux

  4. Exemple d'utilisation de getnstimeofday dans le noyau Linux

  5. Déplacer un dossier sous Linux à l'aide de la commande mv

Installer MongoDB à l'aide de Vagrant sous Linux

15 choses à savoir avant d'utiliser Kali Linux

Utilisation du transfert de port SSH comme outil de sécurité sous Linux

Utilisation de la commande Watch sous Linux

Utilisation de cut sur Linux Terminal

Sécurité Linux contre Windows