Entrada

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.

Bandit: nivel 17 → 18

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 la c significa change: esa línea se ha modificado. Si fuera una línea añadida verías una a (add) y si fuera borrada, una d (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 en diff 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ónQué hace
-f passwords.oldUsa cada línea de passwords.old como un patrón de búsqueda
-FTrata los patrones como texto literal, no como expresiones regulares
-xSolo cuenta como coincidencia si la línea entera es igual
-vInvierte 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 el sort y le pasa su salida a comm como si fuera un fichero.
  • -13 oculta 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 .bashrc de 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 / conceptoPara qué sirve
diff viejo nuevoMostrar las diferencias entre dos ficheros
< / > en diffLínea del primer fichero / línea del segundo
c, a, dLínea cambiada, añadida o borrada
diff -uFormato unificado (el de Git y los parches)
diff -y --suppress-common-linesVer solo los cambios, lado a lado
grep -vxFf A BLí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
Esta entrada está licenciada bajo CC BY 4.0 por el autor.