ClickCease Les bogues derrière les vulnérabilités Partie 5

Table des matières

Rejoignez notre populaire bulletin d'information

Rejoignez 4 500+ professionnels de Linux et de l'Open Source !

2 fois par mois. Pas de spam.

Les bogues derrière les vulnérabilités Partie 5

Joao Correia

27 avril 2023 - Évangéliste technique

Bienvenue dans le dernier volet de notre série en cinq parties consacrée aux bogues de code responsables des vulnérabilités et des exploits dont nous essayons de nous prémunir. Dans cette partie, nous passerons en revue les cinq dernières entrées du Mitre CWE Top 25de la cinquième à la première place.

 

Vous pouvez trouver la partie 1 ici, la partie 2 ici, la partie 3 iciet la partie 4 ici.

 

5. Lecture hors limites

 

La lecture hors limites se produit lorsqu'un produit lit des données au-delà de la fin ou avant le début de la mémoire tampon prévue. Cela peut permettre à des attaquants de lire des informations sensibles à partir d'autres emplacements de la mémoire ou de provoquer un plantage. 

 

Par exemple, considérons l'extrait de code C suivant qui lit un tableau à l'aide d'une entrée contrôlée par l'utilisateur :

#include <stdio.h>




int get_element(int *array, int len, int index) {

    int result;




    if (index < len) {

        result = array[index];

    } else {

        printf("Invalid index: %d\n", index);

        result = -1;

    }




    return result;

}




int main() {

    int my_array[5] = {10, 20, 30, 40, 50};

    int index = -1; // Simulating user-controlled input

    int value = get_element(my_array, 5, index);

    printf("Value at index %d: %d\n", index, value);




    return 0;

}

 

Dans cet exemple, la fonction get_element vérifie que l'indice fourni est compris dans la limite maximale du tableau, mais ne vérifie pas la limite minimale. Cela permet aux valeurs négatives d'être acceptées comme des indices de tableau valides, ce qui entraîne une lecture hors limites. Pour atténuer ce problème, il convient d'ajouter une vérification de la borne minimale :

 

if (index >= 0 && index < len) {

    result = array[index];

}

 

4. Validation incorrecte des données

 

Une mauvaise validation des entrées se produit lorsqu'un produit reçoit des entrées ou des données mais ne les valide pas ou les valide de manière incorrecte, ce qui entraîne une modification du flux de contrôle, un contrôle arbitraire d'une ressource ou l'exécution d'un code arbitraire.

 

private void buildList(int untrustedListSize) {

    if (0 > untrustedListSize) {

        die("Negative value supplied for list size, die evil hacker!");

    }

    Widget[] list = new Widget[untrustedListSize];

    list[0] = new Widget();

}


Dans cet exemple, le code vérifie si la valeur de untrustedListSize est négative, mais il ne vérifie pas si elle est égale à zéro. Si une valeur nulle est fournie, le code construira un tableau de taille 0 et essaiera ensuite de stocker un nouveau widget dans le premier emplacement, ce qui provoquera une exception. Pour éviter ce problème, il convient d'utiliser des techniques complètes de validation des entrées, en tenant compte de toutes les propriétés potentiellement pertinentes de l'entrée, et de ne pas se fier exclusivement à la recherche d'entrées malveillantes ou mal formées. Dans ce cas, nous devrions plutôt vérifier si le paramètre untrustedListSize est supérieur à 0.

 

3. Neutralisation incorrecte des éléments spéciaux utilisés dans une commande SQL (la redoutable "injection SQL")

 

L'injection SQL se produit lorsqu'une application construit tout ou partie d'une commande SQL en utilisant des données influencées de l'extérieur à partir d'un composant en amont sans neutraliser ou en neutralisant incorrectement les éléments spéciaux qui pourraient modifier la commande SQL prévue. 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>




int main(int argc, char *argv[]) {

    char query[1024];

    char *user_input = argv[1];




    snprintf(query, sizeof(query), "SELECT * FROM users WHERE username='%s'", user_input);




    printf("Generated query: %s\n", query);




    // Execute the query...




    return 0;

}

 

Dans cet exemple, l'entrée utilisateur est directement concaténée à la requête SQL, ce qui permet à un pirate d'injecter du code SQL malveillant. Pour éviter les injections SQL, utilisez des requêtes paramétrées, des instructions préparées ou des procédures stockées pour séparer l'entrée de l'utilisateur des instructions SQL. Dans ce cas, nous devrions utiliser des instructions préparées :

 

#include <stdio.h>

#include <stdlib.h>

#include <mysql/mysql.h>




(...)




MYSQL_STMT *stmt = mysql_stmt_init(con);

    if (!stmt) {

        fprintf(stderr, "mysql_stmt_init() failed\n");

        exit(1);

    }




    const char *query = "SELECT * FROM users WHERE username=?";

    if (mysql_stmt_prepare(stmt, query, strlen(query)) != 0) {

        fprintf(stderr, "mysql_stmt_prepare() failed: %s\n", mysql_stmt_error(stmt));

        exit(1);

    }



En utilisant des instructions préparées, l'entrée de l'utilisateur est traitée comme des données et non comme une partie de la requête SQL, ce qui empêche efficacement l'injection SQL.

2. Neutralisation incorrecte des entrées lors de la génération des pages Web (ou "Cross-Site Scripting")

Les vulnérabilités de type cross-site scripting (XSS) se produisent lorsqu'une application ne neutralise pas ou neutralise incorrectement les données contrôlables par l'utilisateur avant qu'elles ne soient placées dans une sortie utilisée comme page web servie à d'autres utilisateurs. 

 

Considérons l'extrait de code PHP suivant :

 

Nom d'utilisateur = $_GET['username'] ;

echo "Bienvenue, " . $username . " !";

 

Dans cet exemple, l'entrée de l'utilisateur est directement intégrée dans la page web sans vérification appropriée, ce qui permet à un pirate d'injecter du code HTML ou JavaScript malveillant. Pour prévenir les attaques XSS, il convient de valider et d'assainir les données utilisateur, d'utiliser des techniques d'encodage de sortie sécurisées lors de l'affichage des données utilisateur dans les pages web et d'appliquer des politiques de sécurité du contenu afin de réduire l'impact d'une attaque XSS. Dans ce cas, nous devons valider les données de l'utilisateur avant de les afficher :

 

Nom d'utilisateur = htmlspecialchars($_GET['username'], ENT_QUOTES, 'UTF-8') ;

echo "Bienvenue, " . $username . " !";

 

1. Écriture hors limites

 

L'écriture hors limites se produit lorsqu'un produit écrit des données au-delà de la fin ou avant le début de la mémoire tampon prévue, ce qui peut entraîner une corruption des données, un plantage ou l'exécution de code. 

 

Par exemple, considérons l'extrait de code C suivant qui écrit dans un tableau :

#include <stdio.h>




void fill_array(int *array, int len) {

for (int i = 0; i <= len; i++) {

  array[i] = i * 10;

 }

}




int main() {

 int my_array[5];

 fill_array(my_array, 5);

 for (int i = 0; i < 5; i++) {

     printf("Element at index %d: %d\n", i, my_array[i]);

 }




return 0;

}


In this example, the function `fill_array` writes to the array `my_array` using the loop variable `i`. However, the loop condition is `i <= len`, which allows the loop to run one iteration beyond the intended bounds of the array, causing an out-of-bounds write.

 

To avoid this issue, ensure that you use proper boundary checks when writing to buffers. In this case, the loop condition should be `i < len`:

 

for (int i = 0; i < len; i++) {

    array[i] = i * 10;

}

 

Avec cette modification, le code écrit correctement dans le tableau à l'intérieur de ses limites, évitant ainsi une vulnérabilité d'écriture hors limites.

 

Conclusion

 

En conclusion, il est essentiel que les développeurs soient conscients des bogues de code courants qui peuvent entraîner des vulnérabilités dans leurs applications. En comprenant ces problèmes et en mettant en œuvre des pratiques de codage sécurisées, vous pouvez réduire de manière significative le risque d'exploitation par des attaquants.

 

Voici quelques principes généraux de codage sécurisé à garder à l'esprit :

 

  • Le moindre privilège

Veillez à ce que vos applications fonctionnent avec les privilèges minimaux nécessaires à l'accomplissement de leurs tâches. Cela limite l'impact potentiel d'une faille de sécurité en réduisant la capacité de l'attaquant à élever ses privilèges ou à obtenir un accès non autorisé à des données sensibles ou à des ressources du système.

 

  • Défauts sécurisés

Concevez vos applications avec des paramètres de sécurité activés par défaut. Les utilisateurs devraient avoir à désactiver explicitement les fonctions de sécurité plutôt que de les activer. Cela favorise une expérience utilisateur plus sûre et réduit la probabilité de configurations non sécurisées.

 

  • Défense approfondie

Mettez en œuvre plusieurs couches de sécurité dans vos applications, de sorte que si une couche est violée, les autres peuvent encore fournir une protection. Cela peut inclure l'utilisation combinée de la validation des entrées, du codage des sorties et des contrôles d'accès afin de fournir une défense complète contre les différentes attaques.

 

  • Échouer en toute sécurité

Concevez vos applications de manière à ce qu'elles échouent en toute sécurité en cas d'erreur ou d'entrée inattendue. Par exemple, si une application rencontre une erreur lors du traitement de l'entrée d'un utilisateur, elle ne doit pas révéler d'informations sensibles ou accorder un accès involontaire. Au contraire, elle doit traiter l'erreur avec élégance et fournir un message d'erreur utile à l'utilisateur.

 

  • Simplicité

La complexité est l'ennemie de la sécurité. Efforcez-vous de simplifier votre code et de minimiser l'utilisation de constructions complexes qui peuvent être difficiles à comprendre et à maintenir. Cela permet de repérer plus facilement les problèmes de sécurité potentiels et réduit la probabilité d'introduire de nouvelles vulnérabilités au cours du développement ou de la maintenance.

 

  • Mettre régulièrement à jour les dépendances

Maintenez les dépendances de votre application à jour, car les bibliothèques et les cadres obsolètes peuvent introduire des vulnérabilités en matière de sécurité. Vérifiez régulièrement la présence de mises à jour et de correctifs, et intégrez-les dans vos processus de développement et de déploiement.

 

En intégrant ces principes de codage sécurisé et en corrigeant les bogues de code courants mentionnés dans cette série, vous serez sur la bonne voie pour développer des applications plus sûres et protéger vos utilisateurs contre les menaces de sécurité potentielles.

Résumé
Les bogues derrière les vulnérabilités Partie 5
Nom de l'article
Les bogues derrière les vulnérabilités Partie 5
Description
Découvrez les cinq dernières entrées de la série Mitre CWE Top 25 code bugs, où nous nous penchons sur les vulnérabilités qui conduisent à des exploits.
Auteur
Nom de l'éditeur
TuxCare
Logo de l'éditeur

Vous cherchez à automatiser la correction des vulnérabilités sans redémarrage du noyau, temps d'arrêt du système ou fenêtres de maintenance programmées ?

Découvrez le Live Patching avec TuxCare

Devenez rédacteur invité de TuxCare

Commencer

Courrier

Rejoindre

4,500

Professionnels de Linux et de l'Open Source
!

S'abonner à
notre lettre d'information