Des activités réseau suspectes ont été identifiées, concernant une personne qui s'est déjà fait remarquer. Que se passe-t-il ?
Deux personnes viennent donc d'être identifiées : il s'agit d'un responsable de la production et d'un prestataire externe.
Les administrateurs réseaux nous indiquent avoir identifié des activités inhabituelles concernant le premier quelques jours avant la fuite, et viennent de faire le rapprochement. Investiguez pour savoir de quoi il en retourne.
Nous avons à notre disposition un fichier log d'un serveur Nginx, nous devons faire un script qui détecte des requêtes identiques réalisées dans un intervalle de temps réduit par la même IP.
Voici un exemple très simple de script qui peut réaliser cette tâche :
endpoint = ""
count = 0
prev = ""
# Affiche les endpoints qui apparaissent 5 fois ou plus à la suite
with open("nginx_access.log") as file:
for line in file:
# Vérifier si c'est une requête GET ou POST
if "GET" in line:
endpoint = line.split("GET")[1].split("HTTP")[0].strip()
elif "POST" in line:
endpoint = line.split("POST")[1].split("HTTP")[0].strip()
else:
# Si ni GET ni POST, passer à la ligne suivante
continue
if endpoint == prev:
count += 1
if count == 5:
print(f"Endpoint répété 5 fois: {endpoint}")
else:
count = 1
prev = endpoint
On obtient en sortie :

En utilisant grep pour filtrer les logs sur ces deux points d'entrée, on constate que les accès à /login (à gauche), semblent tout à fait légitimes, tandis que les accès à /recipe/20/version/1 de l'API (à droite) sont bien plus suspects : ils sont très rapprochés et réguliers dans le temps, et finissent toujours par renvoyer une erreur 401.

Nous pouvons donc en déduire que les activités suspectes que l'on cherche à identifier sont les nombreux appels à ce point d'entrée.
Pour la deuxième moitié de l'exercice, nous nous retrouvons avec le code correspondant au front de l'application concernée, qui est l'interface de visualisation des recettes, dont la base de données a été extraite à l'étape précédente.
Comme l'indique la note de l'équipe de développement dans le fichier README.md qu'ils ont ajouté, cette application vient d'être décommissionnée, c'est pourquoi on ne peut l'inspecter que de cette façon. On y apprend aussi que l'authentification des utilisateurs se fait par OIDC, une information qui pourrait nous servir plus tard.
L'archive contenant des centaines de lignes de JavaScript et HTML peu propres et "anciennes" (testé et fonctionnel avec Firefox 12 sur Windows 2000 !), n'utilisant pas les fonctionnalités les plus récentes (API fetch, ES6...), il est peu lisible. Il vaut donc mieux s'orienter directement vers ce qui nous intéresse.
Pour cela, on part de ce qu'on a découvert lors de la première moitié de l'exercice : de nombreux appels à /recipe/20/version/1 de l'API. On commence donc par chercher où se fait cet appel dans le code JavaScript(1). Cela nous amène à la fonction requestPrecise(2).
On remarque que celle-ci prépare simplement la requête, pour l'envoyer à authenticate qui réalise effectivement l'appel API, avant d'appeler la fonction de retour preciseResponse(3). Dans cette dernière fonction, une faute de frappe discrète est présente : elle peut se voir directement, ou apparaître plus clairement en activant un correcteur orthographique dans son éditeur, à la ligne 209(4).

Mais en quoi cette simple erreur peut-elle poser problème ? Puisque cette ligne se situe dans une condition indiquant que le jeton a expiré, nous allons nous placer dans cette situation.
Imaginons que le jeton soit expiré lors de l'appel API réalisé dans authenticate qui appelle notre fonction preciseResponse en retour. La fonction est donc appelée avec le code d'erreur 401 et le message Token Expired.
On voudrait alors retirer le jeton d'accès du stockage local, et rejouer la requête. De cette façon, la fonction authenticate ne disposant plus de jeton d'accès pour contacter l'API, en demandera au préalable un nouveau à partir de celui de rafraîchissement.
Cependant, à cause de cette faute de frappe, le jeton d'accès n'est pas retiré du stockage local, ainsi l'appel à authenticate rejoue exactement la même requête, qui va à nouveau appeler la fonction de retour, et ainsi de suite. Nous arrivons dans des appels de fonctions de retour à l'infini, dont l'une réalise un appel API, d'où les très nombreux appels effectués sur la même URL.
En résumé :
/api/recipe/:id/version/:id. Une telle erreur sur un appel précis de l'API peut facilement passer inaperçu lors des tests fonctionnelsL'activité suspecte provient donc bien d'un problème dans l'application, et non d'une action humaine. La personne est donc innocentée, il s'agissait d'une fausse piste.