Bandit: nivel 17 → 18
Cómo resolver el nivel 17 → 18 de OverTheWire Bandit encontrando la única línea que cambia entre dos ficheros con diff, grep y comm.
Después de dos niveles de red, volvemos a los ficheros. Este nivel va de una tarea muy habitual: comparar dos versiones de un fichero y encontrar qué ha cambiado. Es lo mismo que hace Git cuando te enseña un commit, y la herramienta clásica para ello en Linux es diff.
Las contraseñas de los niveles aparecen como [REDACTED]. Siguiendo las normas de OverTheWire, no publico credenciales: la gracia es que llegues a ellas tú.
Conexión
En el nivel anterior no conseguimos una contraseña sino una clave privada SSH, así que entro con ella:
1
2
$ ssh -i bandit17.key bandit17@bandit.labs.overthewire.org -p 2220
bandit17@bandit:~$ export TERM=xterm
El enunciado
El enunciado del nivel dice que en el home hay dos ficheros, passwords.old y passwords.new, y que la contraseña del siguiente nivel está en passwords.new: es la única línea que ha cambiado entre los dos.
1
2
bandit17@bandit:~$ ls
passwords.new passwords.old
Cada fichero tiene un montón de líneas que parecen contraseñas. Compararlas a ojo sería una locura, así que dejamos que lo haga el ordenador.
La solución: diff
1
2
3
4
5
bandit17@bandit:~$ diff passwords.old passwords.new
<n>c<n>
< [REDACTED]
---
> [REDACTED]
Y ahí está la contraseña. Pero hay que saber leer la salida de diff, porque aparecen dos líneas tapadas y solo una es la buena:
<n>c<n>: es la cabecera del cambio. El número es la línea afectada (en cada fichero) y lacsignifica change: esa línea se ha modificado. Si fuera una línea añadida verías unaa(add) y si fuera borrada, unad(delete).<: líneas que vienen del primer fichero que le pasamos (passwords.old).---: separador entre la versión vieja y la nueva.>: líneas que vienen del segundo fichero (passwords.new).
Como la contraseña está en passwords.new, la buena es la línea que empieza por >.
El orden de los argumentos importa. Si haces
diff passwords.new passwords.old, los símbolos se invierten y la contraseña sería la línea con<. Un truco para no liarte: piensa endiff viejo nuevo, igual que Git te enseña el cambio “de antes a después”.
Otras formas de hacerlo
1. diff con otros formatos de salida
diff puede mostrar el cambio de formas más legibles:
1
bandit17@bandit:~$ diff -u passwords.old passwords.new
El formato unificado (-u) es el que verás en Git y en los parches: la línea vieja aparece con - y la nueva con +, con unas pocas líneas de contexto alrededor.
1
bandit17@bandit:~$ diff -y --suppress-common-lines passwords.old passwords.new
Con -y pone los dos ficheros lado a lado, y --suppress-common-lines esconde las líneas iguales. Lo que queda es la línea vieja a la izquierda, la nueva a la derecha y un | en medio marcando el cambio.
2. grep usando un fichero como lista de patrones
Otra forma de pensarlo: quiero las líneas de passwords.new que no están en passwords.old. Eso lo hace grep:
1
2
bandit17@bandit:~$ grep -vxFf passwords.old passwords.new
[REDACTED]
Cada opción tiene su motivo:
| Opción | Qué hace |
|---|---|
-f passwords.old | Usa cada línea de passwords.old como un patrón de búsqueda |
-F | Trata los patrones como texto literal, no como expresiones regulares |
-x | Solo cuenta como coincidencia si la línea entera es igual |
-v | Invierte el resultado: muestra las líneas que no coinciden |
Juntas: “muéstrame las líneas de passwords.new que no son exactamente iguales a ninguna línea de passwords.old”. Y sale directamente la contraseña, sin símbolos que interpretar.
3. comm con ficheros ordenados
comm compara dos ficheros ordenados y saca tres columnas: líneas solo del primero, solo del segundo y comunes a los dos. Como nuestros ficheros no están ordenados, los ordeno sobre la marcha con sort, como en el nivel de sort | uniq:
1
2
bandit17@bandit:~$ comm -13 <(sort passwords.old) <(sort passwords.new)
[REDACTED]
<(sort fichero)es una sustitución de procesos: bash ejecuta elsorty le pasa su salida acommcomo si fuera un fichero.-13oculta la columna 1 (solo en el viejo) y la 3 (comunes), así que solo queda la columna 2: lo que está solo en el nuevo.
Pasar al nivel siguiente
1
2
bandit17@bandit:~$ exit
$ sshpass -p '[REDACTED]' ssh bandit18@bandit.labs.overthewire.org -p 2220
Ojo con el siguiente nivel: su enunciado ya avisa de que alguien ha modificado el
.bashrcde bandit18 para echarte nada más entrar por SSH. Así que no te extrañes si la conexión se cierra al instante: ese es el reto del nivel 18 → 19.
Resumen
| Comando / concepto | Para qué sirve |
|---|---|
diff viejo nuevo | Mostrar las diferencias entre dos ficheros |
< / > en diff | Línea del primer fichero / línea del segundo |
c, a, d | Línea cambiada, añadida o borrada |
diff -u | Formato unificado (el de Git y los parches) |
diff -y --suppress-common-lines | Ver solo los cambios, lado a lado |
grep -vxFf A B | Líneas de B que no aparecen enteras en A |
comm -13 <(sort A) <(sort B) | Líneas que solo están en B |
<(comando) | Sustitución de procesos: usar la salida de un comando como fichero |