Przygody w S3 Scraping — część 1

Nov 29 2022
Nie uwierzyłbyś, jakie dziwne pliki udostępniają ludzie w zasobnikach S3. Rzeczy, których prawdopodobnie nie powinni.

Nie uwierzyłbyś, jakie dziwne pliki udostępniają ludzie w zasobnikach S3. Rzeczy, których prawdopodobnie nie powinni. Rzeczy, których zdecydowanie nie powinni.

AWS, S3

Tylko w tym miesiącu widziałem takie pliki jak:

  • Klucze licencyjne do oprogramowania firmowego.
  • Dokument programu Excel z konferencji poświęconej mediom, zawierający nazwiska, adresy e-mail i numery telefonów pracowników lokalnych mediów w 9 różnych stanach.
  • Dokument Powerpoint dotyczący latynoamerykańskiego oddziału dużej firmy technologicznej oznaczonej jako „Zastrzeżony i poufny” (mój hiszpański jest trochę zardzewiały), w którym, jak sądzę, wymieniono koszty/opłaty/marże za proponowane usługi.
  • 45 000–50 000 dokumentów PDF zawierających dane osobowe klientów (imię i nazwisko, adresy e-mail, numery telefonów i lokalizacje) dla firmy, która zakończyła działalność w ciągu ostatnich 2 lat. (Zgłosiłem wiadro do pomocy technicznej AWS i omówię problem bardziej szczegółowo, JEŚLI podejmą działania i będą chronić dane w najbliższej przyszłości).
  • Skan w wysokiej rozdzielczości czyjegoś prawa jazdy, karty ubezpieczeniowej i rejestracji pojazdu z lat 2015–2016. (W próbie przyzwoitości próbowałem skontaktować się z tą osobą, wyszukując ją na LinkedIn i Google tylko po to, aby znaleźć osobę o tym samym nazwisku, dacie urodzenia i adresie, która została skazana w 2021 r. za dość poważne przestępstwo i teraz odsiaduje wyrok, a więc Nie zasnę, gdy jego 7-letnie dokumenty są w Internecie).

Przez ostatnie 10 lat zakładałem, że ludzie będą lepiej wyposażeni i będą mieli lepsze narzędzia do blokowania swoich treści i udostępniania tylko tego, co powinno być udostępniane. Myliłem się. Po co więc zawracać sobie głowę powtórzeniem tej czynności po 10 latach? Dla zabawy i świadomości. Minęło również kilka lat, odkąd napisałem jakąkolwiek znaczną ilość kodu, więc chciałem ponownie odwiedzić i udoskonalić niektóre umiejętności.

Jak przeglądać pliki wiadra?

Najpierw chciałem zidentyfikować istniejące zasobniki S3, które mogą znajdować się w określonym regionie AWS (na wschód od nas, na zachód od usa itp.). Gdybym miał prawidłową nazwę zasobnika, mógłbym go wypróbować w przeglądarce internetowej i sprawdź, czy wymieniono zawartość wiadra. Nie oznacza to, że można przeglądać same pliki, ale przynajmniej pozwól mi zobaczyć ścieżki plików do przyszłego zbadania tych plików.

Na przykład, jeśli nazwa zasobnika „MyObviouslyFakeBucket” była publicznie widoczna i znajdowała się w regionie AWS „US East 1”, zawartość można potencjalnie zobaczyć w przeglądarce internetowej, odwiedzając stronę https://myobviouslyfakebucket.s3.us-east-1. amazonaws.com/

Spowoduje to zwrócenie listy podobnej do następującego częściowo zredagowanego obrazu.

Pliki zawarte w zasobniku myobviouslyfakebucket S3.

W dokumencie XML, który jest wyświetlany jako wynik, możesz zobaczyć wpisy plików pod każdym znacznikiem „Zawartość”. Dla każdego węzła „Zawartość” istnieje węzeł
„Klucz”, który wyświetla ścieżkę do pliku i nazwę każdego pliku. Dlatego w przypadku pliku „interesujący-tekst-plik.txt” można potencjalnie przetestować dostęp do pliku, dodając ścieżkę na końcu adresu URL zasobnika, na przykład:

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

Gdyby plik można było wyświetlić, otworzyłby się w przeglądarce lub uruchomił automatyczne pobieranie (w zależności od typu pliku i przeglądarki). Jeśli nie masz dostępu, zobaczysz wynik XML zasadniczo przedstawiający komunikat „Odmowa dostępu”.

Pomimo najlepszych starań AWS wciąż są ludzie, którzy ustawiają treści jako publicznie widoczne, kiedy nie powinni. Nie pracowałem z S3 od kilku lat, więc mogę coś przegapić, ale wydaje się, że jest WIELE kroków, zanim twoje wiadro będzie można łatwo wyliczyć i wyświetlić w przeglądarce internetowej.

Podczas tworzenia nowego zasobnika opcja „Blokuj dostęp publiczny” jest domyślnie zaznaczona. Musisz odznaczyć to pole wyboru, a następnie zaznaczyć pole wyboru „Potwierdzam” poniżej. Zobacz poniżej.

Ustawienia prywatności dla nowego segmentu S3.

Nawet z moim zasobnikiem skonfigurowanym tak, aby nie „blokował całego dostępu publicznego”, kiedy dodałem dwa przykładowe pliki tekstowe, nadal nie mogłem wyświetlić zawartości zasobnika w mojej przeglądarce internetowej, dopóki nie dodam zasad zasobnika JSON jawnie przyznających dostęp publiczny.

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

Ogólne podejście

Jak więc wymienić zawartość wiadra bez zgadywania losowo? Moje dwie główne opcje osiągnięcia tego poza pojedynczą nazwą zasobnika według mojego własnego wynalazku polegały na użyciu pliku słownika sparowanego z zestawem SDK AWS lub prostym HTTP GET.

Zdecydowałem się napisać kod Java przy użyciu prostych HTTP GET dla pierwszej wersji. Dzięki temu uniknięto konieczności uczenia się zaktualizowanego AWS Java SDK v2. Ostatnim razem, gdy korzystałem z AWS Java SDK, było to w wersji 1 i wystarczająco dużo się zmieniło, że nie chciałem, aby krzywa uczenia się opóźniała moje postępy. Mógłbym również uniknąć konieczności konfigurowania poświadczeń AWS w celu korzystania z SDK i wszelkich błędów lub dziwactw specyficznych dla SDK, które pojawiły się podczas testowania. Nie komplikuj.

Zacząłem od istniejącego pliku słownika, który miałem z poprzedniego osobistego projektu. Był to płaski plik tekstowy z jednym słowem w wierszu. W pewnym momencie podzieliłem go na 8 lub 10 oddzielnych plików, z których każdy zawierał wpisy dla 1–3 liter w zależności od liczby wpisów. Pozwoliło mi to łatwiej przetwarzać mniejszą liczbę wpisów na raz. Możesz wyszukać online plik słownika, ponieważ jest ich wiele.

Na 2 karteczkach samoprzylepnych naszkicowałem kroki, które potrzebowałem do zaprogramowania. Były one następujące:

  • Przeanalizuj plik słownika, aby pobrać każdy wpis słowa.
  • Dla każdego słowa na liście utwórz adres URL do sprawdzenia, używając słowa jako nazwy zasobnika i regionu AWS (na razie zakodowany na stałe jako „US East 1”).
  • Spróbuj połączyć się z adresem URL, aby wykonać operację GET.
  • Pobierz kod odpowiedzi wysłany z serwera.
  • Jeśli kod odpowiedzi wskazywał na powodzenie (wiadro istnieje), dodaj słowo do struktury danych.
  • Zapisz udane słowa w strukturze danych w prostym pliku tekstowym do późniejszego zbadania.

Przeanalizuj plik słownika

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

Skonstruuj adres 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
}

Wykonaj operację GET

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

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

Pobierz kod odpowiedzi i zapisz go

int respCode = connection.getResponseCode();

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

Przechowuj prawidłowe nazwy zasobników

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

Otóż ​​to. Proste i bezpośrednie. Może nie jest to najbardziej eleganckie rozwiązanie, ale zadziałało i było bazą, dzięki której mogłem je rozbudować i udoskonalić. Zidentyfikowałem tysiące ważnych wiader S3 po prostu zeskrobując kilka liter alfabetu. Już po kilku pierwszych próbach znalazłem katalogi plików MP3, miliony obrazów, niezliczone pliki dziennika i nie tylko.

Od tego czasu usunąłem mój segment testowy „myobviouslyfakebucket”, więc jeśli chcesz, możesz ubiegać się o tę nazwę. W kilku następnych częściach tej serii artykułów zwrócę uwagę na dodatkowe kroki w celu ulepszenia tego rozwiązania, takie jak:

  • Obsługa i przechowywanie kodów odpowiedzi dla zasobników oprócz 200 (OK) oraz ich znaczenie i możliwości wykorzystania tych informacji.
  • Korzystając z listy prawidłowych nazw wiader, aby sprawdzić, czy możesz wyliczyć listę plików w tym wiadrze.
  • Analizowanie listy plików segmentów w celu przechwycenia ścieżki i nazwy poszczególnych plików.
  • Filtruj pliki według rozszerzenia, aby zignorować niechciany szum.
  • Stronicowanie wyników plików dla zasobników S3 zawierających ponad 1000 plików.
  • Sprawdzanie list plików w celu sprawdzenia, czy można pobrać poszczególne pliki.