Avventure in S3 Scraping — Parte 1

Nov 29 2022
Non crederesti agli strani file che le persone condividono nei bucket S3. Cose che probabilmente non dovrebbero.

Non crederesti agli strani file che le persone condividono nei bucket S3. Cose che probabilmente non dovrebbero. Cose che sicuramente non dovrebbero.

AWS, S3

Proprio questo mese ho visto file come:

  • Chiavi di licenza per il software di un'azienda.
  • Documento Excel di una conferenza relativa ai media contenente nomi, e-mail e numeri di telefono dei dipendenti dei media locali in 9 stati diversi.
  • Documento Powerpoint per una divisione latinoamericana di un'importante azienda tecnologica contrassegnata come "Proprietario e riservato" (il mio spagnolo è un po' arrugginito) che credo abbia elencato costi/commissioni/margini per i servizi proposti.
  • 45.000-50.000 documenti PDF contenenti le informazioni personali dei clienti (nomi completi, indirizzi e-mail, numeri di telefono e sedi) per un'azienda che ha cessato l'attività negli ultimi 2 anni. (Ho segnalato il bucket ad AWS Support e discuterò il problema in modo più dettagliato SE agiranno e proteggeranno i dati nel prossimo futuro.)
  • Scansione ad alta risoluzione della patente di guida, della tessera assicurativa e dell'immatricolazione del veicolo di qualcuno dal 2015 al 2016. (In un tentativo di decenza ho provato a contattare questa persona cercandola su LinkedIn e Google solo per scoprire che qualcuno con lo stesso nome, data di nascita e indirizzo è stato condannato nel 2021 per un reato abbastanza grave e ora sta scontando la pena, quindi Non perderò il sonno perché i suoi documenti vecchi di 7 anni sono là fuori su Internet).

Negli ultimi 10 anni ho pensato che le persone sarebbero state meglio attrezzate e avrebbero avuto strumenti migliori per bloccare i loro contenuti e condividere solo ciò che dovrebbe essere condiviso. Mi sbagliavo. Allora perché prendersi la briga di ripetere questa attività 10 anni dopo? Per divertimento e consapevolezza. Sono passati anche alcuni anni da quando ho scritto una quantità sostanziale di codice, quindi ho voluto rivisitare e affinare alcune abilità.

Come puoi visualizzare i file di un bucket?

Innanzitutto, volevo identificare i bucket S3 esistenti che potrebbero essere disponibili in una regione AWS specifica (us-east, us-west, ecc.). Se avessi un nome valido per un bucket, potrei provarlo in un browser web e vedere se ha elencato il contenuto del secchio. Ciò non significa che i file stessi possano essere visualizzati, ma almeno fammi vedere i percorsi dei file per future indagini su quei file.

Ad esempio, se il nome del bucket "MyObviouslyFakeBucket" fosse visibile pubblicamente e si trovasse nella regione AWS "US East 1", potresti potenzialmente vedere i contenuti nel tuo browser web visitando https://myobviouslyfakebucket.s3.us-east-1. amazonaws.com/

Ciò restituirebbe un elenco simile alla seguente immagine parzialmente oscurata.

File contenuti nel bucket S3 myovviouslyfakebucket.

Nel documento XML che viene visualizzato come risultato puoi vedere le voci di file sotto ogni tag "Contents". Per ogni nodo "Contenuto" è presente un
nodo "Chiave" che visualizza il percorso e il nome del file di ciascun file. Pertanto, per il file "file-testo-interessante.txt" potresti potenzialmente testare l'accesso al file aggiungendo il percorso alla fine dell'URL del bucket come segue:

https://myobviouslyfakebucket.s3.us-east-1.amazonaws.com/interesting-text-file.txt

Se fosse possibile visualizzare il file, si aprirebbe nel browser o attiverebbe un download automatico (a seconda del tipo di file e del browser). Se non avevi accesso, vedresti un risultato XML che mostra essenzialmente un messaggio "Accesso negato".

Nonostante i migliori sforzi di AWS, ci sono ancora persone che impostano i contenuti in modo che siano visibili pubblicamente quando non dovrebbero. Non lavoro con S3 da alcuni anni, quindi potrei perdermi qualcosa, ma sembra che ci siano MOLTEPLICI passaggi coinvolti prima che il tuo bucket possa essere facilmente enumerato e visualizzato in un browser web.

Quando si crea un nuovo bucket, l'opzione "Blocca tutti gli accessi pubblici" è selezionata per impostazione predefinita. Devi deselezionarlo e quindi selezionare la casella di controllo "Accetto" più in basso. Vedi sotto.

Impostazioni sulla privacy per il nuovo bucket S3.

Anche con il mio bucket configurato per non "bloccare tutto l'accesso pubblico" quando ho aggiunto due file di testo di esempio, non sono ancora riuscito a elencare i contenuti del bucket nel mio browser Web fino a quando non ho aggiunto una policy del bucket JSON che concede esplicitamente l'accesso pubblico.

{
    "Version": "2012-10-17",
    "Id": "Policy1669653712601",
    "Statement": [
        {
            "Sid": "Stmt1669653708988",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::myobviouslyfakebucket"
        }
    ]
}

Approccio globale

Quindi, come si elencano i contenuti del bucket senza indovinare a caso? Le mie due opzioni principali per raggiungere questo obiettivo oltre a un singolo nome di bucket di mia invenzione erano utilizzare un file di dizionario abbinato all'SDK AWS o a semplici HTTP GET.

Ho scelto di scrivere codice Java utilizzando semplici HTTP GET per una prima versione. Ciò ha evitato la necessità di apprendere l'SDK AWS Java aggiornato v2. L'ultima volta che ho utilizzato AWS Java SDK era in una v1 e ne è cambiato abbastanza da non volere che una curva di apprendimento ritardasse i miei progressi. Potrei anche evitare la necessità di impostare le credenziali AWS per utilizzare l'SDK e qualsiasi errore o stranezza specifici dell'SDK emersi durante i test. Mantienilo semplice.

Ho iniziato con un file di dizionario esistente che avevo da un precedente progetto personale. Questo era un file di testo piatto con una parola per riga. Ad un certo punto l'ho suddiviso in 8 o 10 file separati con ogni file contenente le voci per 1-3 lettere a seconda del numero di voci. Ciò mi ha permesso di elaborare più facilmente un numero inferiore di voci alla volta. Puoi cercare online un file di dizionario poiché ce ne sono molti disponibili.

Ho abbozzato i passaggi che dovevo programmare su 2 post-it. Erano i seguenti:

  • Analizza il file del dizionario per recuperare ogni voce di parola.
  • Per ogni parola nell'elenco, costruisci l'URL da controllare utilizzando la parola come nome del bucket e la regione AWS (hardcoded per ora su "US East 1").
  • Prova a connetterti all'URL per eseguire un'operazione GET.
  • Recupera il codice di risposta inviato dal server.
  • Se il codice di risposta ha indicato il successo (il bucket esiste), aggiungi la parola a una struttura di dati.
  • Salva le parole di successo nella struttura dei dati in un file di testo semplice per un'analisi successiva.

Analizza il file del dizionario

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) { }
   }
}

Costruisci 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
}

Eseguire un'operazione GET

String sUrl = "https://" + bucketName + ".s3." + currentRegion + ".amazonaws.com/";
URL url = new URL(sUrl);

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();

Recupera il codice di risposta e memorizzalo

int respCode = connection.getResponseCode();

if (respCode == 200) {
   code200s.add(bucketName + "," + currentRegion);
}

Memorizza i nomi dei bucket validi

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) { }
   }
}

Questo è tutto. Semplice e lineare. Potrebbe non essere la soluzione più elegante, ma ha funzionato ed è stata una base per permettermi di espanderla e migliorarla. Ho identificato migliaia di bucket S3 validi solo raschiando diverse lettere dell'alfabeto. Fin dai miei primi tentativi ho trovato cataloghi di file MP3, milioni di immagini, innumerevoli file di registro e altro ancora.

Da allora ho eliminato il mio bucket di prova "myobviouslyfakebucket", quindi sentiti libero di rivendicare il nome se lo desideri. Nelle prossime parti di questa serie di articoli evidenzierò ulteriori passaggi per migliorare questa soluzione come:

  • Gestione e archiviazione dei codici di risposta per i bucket oltre a 200 (OK) e cosa significano e cosa puoi fare con tali informazioni.
  • Utilizzo dell'elenco di nomi di bucket validi per verificare se è possibile enumerare l'elenco di file in tale bucket.
  • Analisi dell'elenco dei file bucket per acquisire il percorso e il nome dei singoli file.
  • Filtra i file in base all'estensione del file per ignorare il rumore indesiderato.
  • Impaginazione dei risultati dei file per i bucket S3 con più di 1000 file.
  • Controllo degli elenchi di file per vedere se i singoli file possono essere scaricati.