Aventures dans S3 Scraping — Partie 1
Vous ne croiriez pas les fichiers étranges que les gens partagent dans les compartiments S3. Des choses qu'ils ne devraient probablement pas faire. Des choses qu'ils ne devraient certainement pas.

Juste ce mois-ci, j'ai vu des fichiers tels que:
- Clés de licence du logiciel d'une entreprise.
- Document Excel d'une conférence liée aux médias contenant les noms, les e-mails et les numéros de téléphone des employés des médias locaux dans 9 États différents.
- Document Powerpoint pour une division latino-américaine d'une grande entreprise de technologie portant la mention "Propriétaire et confidentiel" (mon espagnol est un peu rouillé) qui, je crois, répertorie les coûts/frais/marges pour les services proposés.
- 45 000 à 50 000 documents PDF contenant les informations personnelles des clients (noms complets, adresses e-mail, numéros de téléphone et emplacements) pour une entreprise qui a cessé ses activités au cours des deux dernières années. (J'ai signalé le compartiment à AWS Support et discuterai du problème plus en détail S'ils prennent des mesures et protègent les données dans un avenir proche.)
- Numérisation haute résolution du permis de conduire, de la carte d'assurance et de l'immatriculation du véhicule d'une personne de 2015 à 2016. (Dans une tentative de décence, j'ai essayé de contacter cette personne en la recherchant sur LinkedIn et Google uniquement pour trouver quelqu'un avec le même nom, date de naissance et adresse a été reconnu coupable en 2021 d'un crime assez grave et purge maintenant une peine, donc Je ne vais pas perdre le sommeil à cause de ses documents vieux de 7 ans qui sont sur Internet).
J'ai supposé au cours des 10 dernières années que les gens seraient mieux équipés et disposeraient de meilleurs outils pour verrouiller leur contenu et ne partager que ce qui devrait être partagé. J'ai eu tort. Alors pourquoi s'embêter 10 ans plus tard à renouveler cette activité ? Pour le plaisir et la sensibilisation. Cela fait également quelques années que je n'ai pas écrit une quantité substantielle de code, donc je voulais revoir et affiner certaines compétences.
Comment pouvez-vous afficher les fichiers d'un compartiment ?
Tout d'abord, je voulais identifier les compartiments S3 existants qui pourraient se trouver dans une région AWS spécifique (us-east, us-west, etc.). Si j'avais un nom valide pour un compartiment, je pourrais alors l'essayer dans un navigateur Web et voir s'il répertorie le contenu du seau. Cela ne signifie pas que les fichiers eux-mêmes peuvent être visualisés, mais permettez-moi au moins de voir les chemins d'accès aux fichiers pour une enquête future sur ces fichiers.
Par exemple, si le nom de compartiment « MyObviouslyFakeBucket » était visible publiquement et situé dans la région AWS « US East 1 », vous pourriez potentiellement voir le contenu dans votre navigateur Web en visitant https://myobviouslyfakebucket.s3.us-east-1. amazonaws.com/
Cela renverrait une liste similaire à l'image partiellement expurgée suivante.

Dans le document XML qui s'affiche en conséquence, vous pouvez voir les entrées de fichier sous chaque balise "Contenu". Pour chaque nœud "Contenu", il existe un
nœud "Clé" qui affiche le chemin d'accès et le nom de chaque fichier. Ainsi, pour le fichier "interesting-text-file.txt", vous pouvez éventuellement tester l'accès au fichier en ajoutant le chemin à la fin de l'URL du bucket, comme suit :
https://myobviouslyfakebucket.s3.us-east-1.amazonaws.com/interesting-text-file.txt
Si le fichier pouvait être visualisé, il s'ouvrirait dans le navigateur ou déclencherait un téléchargement automatique (selon le type de fichier et votre navigateur). Si vous n'aviez pas accès, vous verriez un résultat XML montrant essentiellement un message "Accès refusé".
Malgré les meilleurs efforts d'AWS, il y a encore des gens qui définissent le contenu pour qu'il soit visible publiquement alors qu'ils ne le devraient pas. Je n'ai pas travaillé avec S3 depuis quelques années, donc il me manque peut-être quelque chose, mais il semble y avoir PLUSIEURS étapes avant que votre compartiment puisse être facilement énuméré et visualisé dans un navigateur Web.
Lors de la création d'un nouveau bucket, l'option "Bloquer tous les accès publics" est cochée par défaut. Vous devez la décocher, puis cocher la case "J'accepte" plus bas. Voir ci-dessous.

Même avec mon bucket configuré pour ne pas "bloquer tous les accès publics" lorsque j'ai ajouté deux exemples de fichiers texte, je ne pouvais toujours pas répertorier le contenu du bucket dans mon navigateur Web jusqu'à ce que j'ajoute une stratégie de bucket JSON accordant explicitement l'accès public.
{
"Version": "2012-10-17",
"Id": "Policy1669653712601",
"Statement": [
{
"Sid": "Stmt1669653708988",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::myobviouslyfakebucket"
}
]
}
Approche générale
Alors, comment répertorier le contenu d'un bucket sans deviner au hasard ? Mes deux principales options pour y parvenir au-delà d'un seul nom de compartiment de ma propre invention consistaient à utiliser un fichier de dictionnaire associé au SDK AWS ou à de simples HTTP GET.
J'ai choisi d'écrire du code Java en utilisant de simples HTTP GET pour une première version. Cela a évité d'avoir à apprendre le kit AWS Java SDK v2 mis à jour. La dernière fois que j'ai utilisé le SDK AWS Java, c'était dans une v1 et il y avait suffisamment de changements pour que je ne veuille pas qu'une courbe d'apprentissage retarde ma progression. J'ai également pu éviter d'avoir à configurer des informations d'identification AWS pour utiliser le SDK et toute erreur ou bizarrerie spécifique au SDK qui survenait pendant les tests. Rester simple.
J'ai commencé avec un fichier de dictionnaire existant que j'avais d'un projet personnel précédent. Il s'agissait d'un fichier texte plat avec un mot par ligne. À un moment donné, je l'ai divisé en 8 ou 10 fichiers distincts, chaque fichier contenant les entrées pour 1 à 3 lettres en fonction du nombre d'entrées. Cela m'a permis de traiter plus facilement un plus petit nombre d'entrées à la fois. Vous pouvez rechercher en ligne un fichier de dictionnaire car il en existe de nombreux.
J'ai esquissé les étapes à programmer sur 2 post-it. Ils étaient les suivants :
- Analysez le fichier du dictionnaire pour récupérer chaque entrée de mot.
- Pour chaque mot de la liste, créez l'URL à vérifier en utilisant le mot comme nom de compartiment et la région AWS (codée en dur pour l'instant sur "US East 1").
- Essayez de vous connecter à l'URL pour effectuer une opération GET.
- Récupérez le code de réponse envoyé par le serveur.
- Si le code de réponse indique un succès (le compartiment existe), ajoutez le mot à une structure de données.
- Enregistrez les mots réussis dans la structure de données dans un fichier texte plat pour une enquête ultérieure.
Analyser le fichier de dictionnaire
private void populateList(List<String> words, String dictionaryFile) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File(dictionaryFile)));
String line;
while ((line = br.readLine()) != null) {
words.add(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (Exception e) { }
}
}
Construire l'URL
String currentRegion = "us-east-1";
int wordSize = words.size();
for (int i = 0; i < wordSize; i++) {
String bucketName = words.get(i);
String sUrl = "https://" + bucketName + ".s3." + currentRegion + ".amazonaws.com";
URL url = new URL(sUrl);
// do something with the URL
}
Effectuer une opération GET
String sUrl = "https://" + bucketName + ".s3." + currentRegion + ".amazonaws.com/";
URL url = new URL(sUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
Récupérer le code de réponse et le stocker
int respCode = connection.getResponseCode();
if (respCode == 200) {
code200s.add(bucketName + "," + currentRegion);
}
Stocker les noms de bucket valides
private void writeCode200s(List<String> validBuckets, String parentDirectory) {
if(validBuckets == null || validBuckets.isEmpty()) {
return;
}
BufferedWriter bw = null;
try {
File parentDirectory = new File(parentDirectory);
if (!parentDirectory.exists()) {
parentDirectory.mkdirs();
}
FileWriter writer = new FileWriter(new File(parentDirectory, "valid_buckets_" + System.currentTimeMillis()+ ".txt"));
bw = new BufferedWriter(writer);
for (int i = 0; i < validBuckets.size(); i++) {
String bucketName = validBuckets.get(i);
bw.write(bucketName);
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (Exception e) { }
}
}
C'est ça. Simple et direct. Ce n'est peut-être pas la solution la plus élégante, mais cela a fonctionné et a été une base pour me permettre de l'étendre et de l'améliorer. J'ai identifié des milliers de compartiments S3 valides simplement en grattant plusieurs lettres de l'alphabet. Dès mes premières tentatives, j'ai trouvé des catalogues de fichiers MP3, des millions d'images, d'innombrables fichiers journaux, etc.
Depuis, j'ai supprimé mon compartiment de test "myobviouslyfakebucket", alors n'hésitez pas à revendiquer le nom si vous le souhaitez. Dans les prochaines parties de cette série d'articles, je soulignerai des étapes supplémentaires pour améliorer cette solution, telles que :
- Gestion et stockage des codes de réponse pour les compartiments autres que 200 (OK) et ce qu'ils signifient et ce que vous pouvez faire avec ces informations.
- Utilisez la liste des noms de compartiment valides pour voir si vous pouvez énumérer la liste des fichiers dans ce compartiment.
- Analyse de la liste des fichiers de compartiment pour capturer le chemin et le nom des fichiers individuels.
- Filtrez les fichiers par extension de fichier pour ignorer les bruits indésirables.
- Pagination des résultats de fichiers pour les buckets S3 avec plus de 1 000 fichiers.
- Vérification des listes de fichiers pour voir si des fichiers individuels peuvent être téléchargés.