Parcours en profondeur des APIs de recherche

Table des matières :

Introduction

De plus en plus d’applications web se découpent en deux parties. Un frontend affichant les données à l’utilisateur, et un backend sous forme d’une API envoyant ces données. Aujourd’hui nous allons nous pencher sur ces APIs de backend et voir comment extraire le contenu d’une base de données optimalement.

Lors d’un pentest ou d’une redteam il est très intéressant de connaître la liste des utilisateurs d’une application (pour obtenir des accès avec des mots de passe faibles par exemple). Cette liste peut aussi être un sous ensemble ou la totalité des comptes du domaine Windows de l’entreprise. Pendant le test, vous pouvez avoir trouvé une application avec une fonctionnalité permettant de chercher un utilisateur dans l’annuaire.

C’est un point d’entrée prometteur pour constituer une liste d’utilisateurs, mais l’API limite la réponse aux 100 premiers résultats. Alors comment faire ?

Application de test

J’ai préparé une application web de test pour que vous puissiez l’exploiter avec cet article (télécharger les sources).

Lancement de l’application

Pour lancer l’application, il faut installer les paquets python nécessaires avec pip :

python3 -m pip install -r requirements.txt

Une fois que les paquets sont installés, vous pouvez lancer l’application avec la commande suivante :

python3 app.py

L’application web est ensuite accessible à http://127.0.0.1:5000/.

Cette application permet de chercher un utilisateur dans l’annuaire de l’entreprise. Elle ne renvoie que les 100 premiers résultats.

Génération d’un jeu de données aléatoire

Si vous le souhaitez, vous pouvez utiliser le script create_db.py pour générer un jeu de données aléatoires (nom, prénom, pseudo, age) pour remplir la base de données de l’API.

$ ./create_db.py -h
usage: create_db.py [-h] [-f FILE] [-n NUMBER] [-v]

Description message

optional arguments:
  -h, --help            show this help message and exit
  -f FILE, --file FILE  arg1 help message
  -n NUMBER, --number NUMBER
                        Number of entries to generate
  -v, --verbose         Verbose mode

Extraction des données de l’API rapidement

Dans l’application de test, les requêtes sont faites à l’url /api/search/<query>. Cette URL renvoie le résultat sous forme de JSON contenant champ message et une liste results contenant les résultats de la recherche:

{
  "message": "2 results.",
  "results": [
    {
      "id": 1616,
      "age": 23,
      "firstname": "Abigail",
      "lastname": "Sanchez",
      "username": "abigail.sanchez"
    },
    {
      "id": 1990,
      "age": 45,
      "firstname": "Abdul",
      "lastname": "Hays",
      "username": "abdul.hays"
    }
  ]
}

La manière la plus rapide d’extraire toutes les données de l’API est de réaliser un parcours de graphe en profondeur.

Parcours en profondeur

Nous allons parcourir l’API à l’aide d’un parcours de graphe en profondeur pour extraire toute la base de données. Lorsque nous envoyons une requête à l’API nous pouvons avoir deux types de réponses:

  • Plus de 100 résultats: La réponse est tronquée aux 100 premiers résultats.
  • Moins de 100 résultats: Nous avons toutes les données de la réponse de la requête.

Nous sommes donc sûr que nous avons toutes les données de réponse de la requête si le nombre de résultats est inférieur à la limite fixée par l’API (dans l’application d’exemple cette limite est à 100 résultats).

Voici donc notre arbre de décision :

  • Effectuer la requête à l’API:
    • Si Nombre de résultats >= 100: Affiner la requête.
    • Sinon Nombre de résultats < 100: Stocker le résultat et passer à la prochaine requête.

Voici une animation montrant le parcours du graphe de l’API et le nombre de résultats des requêtes:

Il suffit maintenant d’écrire un script permettant de réaliser ce parcours de graphe.

Résultat final

Une fois le script terminé, nous pouvons extraire les 20000 users en 4min 45secondes sans connaissance préalable des noms d’utilisateur.

Références