Aventuras en S3 Scraping — Parte 1
No creerías los archivos extraños que la gente comparte en los cubos S3. Cosas que probablemente no deberían. Cosas que definitivamente no deberían.

Solo este mes he visto archivos como:
- Claves de licencia para el software de una empresa.
- Documento de Excel de una conferencia relacionada con los medios que contiene nombres, correos electrónicos y números de teléfono de empleados de medios locales en 9 estados diferentes.
- Documento de Powerpoint para una división latinoamericana de una importante empresa de tecnología marcada como "Propietario y confidencial" (mi español está un poco oxidado) que creo que enumera los costos/tarifas/márgenes de los servicios propuestos.
- 45 000–50 000 documentos PDF que contienen PII de clientes (nombres completos, direcciones de correo electrónico, números de teléfono y ubicaciones) para una empresa que cerró en los últimos 2 años. (Informé el depósito a AWS Support y discutiré el problema con más detalles SI toman medidas y protegen los datos en un futuro cercano).
- Escaneo de alta resolución de la licencia de conducir, la tarjeta del seguro y el registro del vehículo de una persona entre 2015 y 2016. (En un intento de decencia, traté de contactar a esta persona buscándolo en LinkedIn y Google solo para encontrar a alguien con el mismo nombre, fecha de nacimiento y dirección que fue condenado en 2021 por un delito bastante grave y ahora está cumpliendo condena, por lo tanto No perderé el sueño porque sus documentos de hace 7 años estén en Internet).
Supuse que durante los últimos 10 años las personas estarían mejor equipadas y tendrían mejores herramientas para bloquear su contenido y compartir solo lo que se debe compartir. Estaba equivocado. Entonces, ¿por qué molestarse 10 años después en repetir esta actividad? Para la diversión y la conciencia. También han pasado algunos años desde que escribí una cantidad sustancial de código, así que quería volver a visitar y mejorar algunas habilidades.
¿Cómo puede ver los archivos de un cubo?
Primero, quería identificar los depósitos S3 existentes que pueden estar disponibles en una región específica de AWS (us-east, us-west, etc.). Si tuviera un nombre válido para un depósito, podría probarlo en un navegador web y ver si enumeró el contenido del balde. Eso no significa que los archivos en sí se puedan ver, pero al menos déjame ver las rutas de los archivos para futuras investigaciones de esos archivos.
Por ejemplo, si el nombre del depósito "MyObviouslyFakeBucket" fuera públicamente visible y estuviera ubicado en la región "US East 1" de AWS, podría ver el contenido en su navegador web visitando https://myobviouslyfakebucket.s3.us-east-1. amazonaws.com/
Esto devolvería una lista similar a la siguiente imagen parcialmente redactada.

En el documento XML que se muestra como resultado, puede ver las entradas del archivo debajo de cada etiqueta de "Contenido". Para cada nodo de "Contenido" hay un
nodo de "Clave" que muestra la ruta del archivo y el nombre de cada archivo. Por lo tanto, para el archivo "interesante-texto-archivo.txt" podría probar el acceso al archivo agregando la ruta al final de la URL del depósito, como la siguiente:
https://myobviouslyfakebucket.s3.us-east-1.amazonaws.com/interesting-text-file.txt
Si el archivo se pudiera ver, se abriría en el navegador o activaría una descarga automática (según el tipo de archivo y su navegador). Si no tuviera acceso, vería un resultado XML que muestra esencialmente un mensaje de "Acceso denegado".
A pesar de los mejores esfuerzos de AWS, todavía hay personas que configuran el contenido para que sea visible públicamente cuando no deberían hacerlo. No he trabajado con S3 en algunos años, por lo que es posible que me esté perdiendo algo, pero parece que hay MÚLTIPLES pasos involucrados antes de que su depósito se pueda enumerar y ver fácilmente en un navegador web.
Al crear un nuevo depósito, la opción "Bloquear todo el acceso público" está marcada de forma predeterminada. Debe desmarcarlo y luego seleccionar la casilla de verificación "Reconozco" más abajo. Vea abajo.

Incluso con mi depósito configurado para no "bloquear todo el acceso público" cuando agregué dos archivos de texto de muestra, aún no podía enumerar el contenido del depósito en mi navegador web hasta que agregué una política de depósito JSON que otorgaba explícitamente acceso público.
{
"Version": "2012-10-17",
"Id": "Policy1669653712601",
"Statement": [
{
"Sid": "Stmt1669653708988",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::myobviouslyfakebucket"
}
]
}
Enfoque global
Entonces, ¿cómo se enumeran los contenidos del cubo sin adivinar al azar? Mis dos opciones principales para lograr esto más allá de un solo nombre de depósito de mi propia invención eran usar un archivo de diccionario emparejado con el SDK de AWS o HTTP GET simple.
Elegí escribir código Java utilizando HTTP GET simples para una primera versión. Esto evitó la necesidad de aprender la versión actualizada de AWS Java SDK v2. La última vez que usé AWS Java SDK fue en una v1 y cambió lo suficiente como para que no quisiera que una curva de aprendizaje retrasara mi progreso. También podría evitar la necesidad de configurar las credenciales de AWS para usar el SDK y cualquier error o rareza específico del SDK que surja durante la prueba. Mantenlo simple.
Empecé con un archivo de diccionario existente que tenía de un proyecto personal anterior. Este era un archivo de texto plano con una palabra por línea. En un momento, lo dividí en 8 o 10 archivos separados y cada archivo contenía las entradas de 1 a 3 letras, según la cantidad de entradas. Esto me permitió procesar un número menor de entradas a la vez más fácilmente. Puede buscar en línea un archivo de diccionario, ya que hay muchos disponibles.
Esbocé los pasos que necesitaba para programar en 2 notas adhesivas. Eran los siguientes:
- Analice el archivo del diccionario para recuperar cada entrada de palabra.
- Para cada palabra en la lista, construya la URL para verificar usando la palabra como nombre de depósito y la región de AWS (codificada por ahora como "US East 1").
- Intente conectarse a la URL para realizar una operación GET.
- Recuperar el código de respuesta enviado desde el servidor.
- Si el código de respuesta indicó éxito (el depósito existe), agregue la palabra a una estructura de datos.
- Guarde las palabras exitosas en la estructura de datos en un archivo de texto sin formato para una investigación posterior.
Analizar el archivo del diccionario
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) { }
}
}
Construya la 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
}
Realizar una operación GET
String sUrl = "https://" + bucketName + ".s3." + currentRegion + ".amazonaws.com/";
URL url = new URL(sUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
Recupere el código de respuesta y guárdelo
int respCode = connection.getResponseCode();
if (respCode == 200) {
code200s.add(bucketName + "," + currentRegion);
}
Almacenar los nombres de depósito válidos
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) { }
}
}
Eso es todo. Simple y directo. Puede que no sea la solución más elegante, pero funcionó y fue una base para permitirme expandirlo y mejorarlo. Identifiqué miles de cubos de S3 válidos simplemente raspando varias letras del alfabeto. Desde mis primeros intentos, encontré catálogos de archivos MP3, millones de imágenes, innumerables archivos de registro y más.
Desde entonces, eliminé mi cubo de prueba "myobviouslyfakebucket", así que no dude en reclamar el nombre si lo desea. En las próximas partes de esta serie de artículos, destacaré pasos adicionales para mejorar esta solución, como:
- Manejo y almacenamiento de códigos de respuesta para cubos además de 200 (OK) y lo que significan y lo que puede hacer con esa información.
- Usando la lista de nombres de depósito válidos para ver si puede enumerar la lista de archivos en ese depósito.
- Analizar la lista de archivos del depósito para capturar la ruta y el nombre de los archivos individuales.
- Filtre los archivos por extensión de archivo para ignorar el ruido no deseado.
- Paginación de resultados de archivos para depósitos S3 con más de 1000 archivos.
- Comprobación de listas de archivos para ver si se pueden descargar archivos individuales.