Challenge (reto_python_server)
Last updated
Last updated
Primero verificamos que en la opción de red, ambas máquinas estén en red nat
o nat network
en inglés.
Iniciamos la máquina víctima con la flecha del start y le damos a "Headless Start" lo que nos permitirá ejecutar la máquina sin GUI.
Luego aparecerá corriendo:
Corremos ip a
Vemos en este caso la ip 10.0.2.15
Escaneamos la red con nmap -sn 10.0.2.15/24
Vamos a tener un output como este:
Hay dos máquinas que son claramente de virtual box
Como vimos antes al hacer ip a
nuestra ip es 10.0.2.15
por lo tanto la máquina víctima del ejercicio es 10.0.2.4
Corremos ssh user1@10.0.2.4
y cuando le demos a enter nos pedirá es password. Que en este caso es St@rt1ng
Si lo hicimos correctamente estaremos dentro de la máquina.
Hacemos un ls
y luego un cd Documentos
para ver el ejercicio de este usuario.
Este nivel es facilito. Ejecutamos python3 nivel1.py
y ya nos da el password como output
Se asume que luego de ver Challenge (reto_comandos) ya investigamos las máquinas con ls
y nos sabemos mover y demas. Si no lo sabes hacer, volve a esa maquina.
Ahora hacemos su user2
ponemos el password, y vamos a su home con los comandos que vimos antes
Verificamos que somos el usuario correcto y estamos en el lugar correcto con pwd
y whoami
Si corremos el comando python3 nivel2.py
para ver que hay dentro. No nos aparece nada útil. Solo una carga y un fallo.
Qué podríamos hacer para avanzar?
Luego de leer el archivo de python deberiamos haber visto el password
Asumimos que sabemos leer los archivos .py
como vimos arriba.
Vez que pasa en el archivo?
Si analizamos este archivo de .py
como podemos sacar el password?
Hay que pasarle al programa una determinada cantidad y tipo de parametros para que nos de el password. Esto tiene dos condiciones.
if (len(args)%2 == 0)
Si el resultado de la división de los argumentos en 2 es de resto (Osea si la cantidad de argumentos es par)
and (args[4] == 'debug'
Y si el argumento de indice 4 es 'debug'
Entonces nos da el password del user5.
Recordemos que en programación se empieza a contar por el 0.
El argumento [4] es el quinto argumento
[0] [1] [2] [3] [4]
Y sepamos también que para python, el archivo en si es el argumento [0]
Si ejecutamos el python con python3 nivel5.py
nos dirá que no puede ayudarnos.
Si analizamos el código del python qué vemos?
Para ver que hay dentro del Response. Podemos descargarlo nosotros y guardarlo en un file con el siguiente comando:
wget URL
Y luego vemos las últimas lineas con tail
(es como cat
pero para ver las últimas lineas.) Y pasarselo a head
para ver la primera linea de ese output de tail
(Esto es opcional, también puedes abrir el archivo con cat
y leer la penúltima línea.
Este usuario está bastante complicado si no nos llevamos von python. Pero son unas pocas líneas que tendremos que escribir. O también las podemos escribir en bash.
Si la función verify_win()
devuelve True
nos da el password del user7
Verify win() lo que se fija es si el file .registered_users.db
tiene un millón de líneas.
Si somos el usario 1.000.000 nos da el password. Para ser el usuario un millon, tenemos que tener un archivo que tenga 999.999 lineas. Y con este programa, agregar el mail 1.000.000
Para ello podemos resolverlo escribiendo un script en python, o en cualquier otro lenguaje, que nos genere un archivo de 999.999 lineas.
Este podría ser un ejemplo en python:
mail = "shanick@muyu.es\n"
Se define una variable de tipo string que contiene un correo electrónico seguido de un salto de línea (), para que cada vez que se escriba en el archivo, quede en una nueva línea.
with open(".registered_users.db", "w") as file:
Se abre (o crea) un archivo llamado .registered_users.db
en modo escritura ("w"
).
Si el archivo ya existe, su contenido será sobrescrito.
El with
garantiza que el archivo se cierre correctamente al finalizar el bloque.
for _ in range(999999):
Se inicia un bucle que se ejecuta 999.999 veces.
La variable _
es una convención para indicar que el valor del índice no importa.
file.write(mail)
En cada iteración del bucle, se escribe el contenido de mail
en el archivo.
Como mail
termina en , cada entrada quedará en una línea separada.
Resultado final:
El archivo .registered_users.db
contendrá 999.999 líneas, todas con el texto shanick@muyu.es
.
Verificamos que nuestro archivo haya quedado bien
yes
en vez de con pythonHay una manera eficiente y mejor de hacerlo. Es usando yes
con el siguiente comando:
yes "shanick@muyu.es" | head -n 999999 > .registered_users.db
yes "shanick@muyu.es"
Este comando imprime infinitamente la cadena "shanick@muyu.es"
seguida de un salto de línea.
|
Es un pipe. Toma la salida del comando anterior (yes
) y la pasa como entrada al siguiente comando (head
).
head -n 999999
Este comando toma solo las primeras 999999 líneas de la entrada que recibe.
En este caso, las 999999 primeras líneas generadas por yes
.
>
Es un operador de redirección. Toma la salida final del head
y la escribe en un archivo.
.registered_users.db
Es el archivo de destino. Si no existe, se crea.
Si ya existe, se sobrescribe con el nuevo contenido.
Resultado:
Se crean exactamente 999.999 líneas en el archivo .registered_users.db
, cada una con shanick@muyu.es
.
bash
en vez de con python o yes
for i in {1..999998}; do
Inicia un bucle for
en Bash.
{1..999998}
usa la sintaxis de expansión de secuencia de números desde 1 hasta 999998.
i
es la variable que va tomando esos valores en cada iteración.
El do
abre el bloque de instrucciones que se ejecutan en cada vuelta del bucle.
echo "$i" >> .registered_users.db
En cada iteración, imprime el valor actual de i
(del 1 al 999998).
echo "$i"
genera una línea con ese número.
>>
agrega esa línea al final del archivo .registered_users.db
(sin sobrescribir lo anterior).
El archivo se va construyendo línea por línea.
done
Marca el final del bloque del bucle.
Cuando se llega a este punto, Bash vuelve al inicio del bucle y toma el siguiente número.
Resultado:
El archivo .registered_users.db
contendrá 999.998 líneas, cada una con un número del 1 al 999998.
Para esta máquina va a ser más fácil si tenemos dos consolas. Por lo que vamos a apretar cntrl + shift + R
para dividir la consola, y vamos a hacer login de nuevo pero esta vez en el usuario 7.
ssh user7@10.0.2.4
password: =0neM1llion
Nos debería quedar algo asi:
Si abrimos con less
u otro lector el archivo nivel7_srv.py
veremos el siguiente detalle:
Si nos conectamos con el otro file, podremos establecer una conexión entre un falso server y un "cliente"
Ejecutamos el server en una pestaña de la terminal con python3 nivel7_srv.py
y ejecutamos en la otra terminal el cliente con python3 nivel7_cli.py
Esto nos dará el password del usuario 8.
Si analizamos lo que tiene el script de python, esta vez nos encontramos con un juego.
En este juego, si lo ejecutamos, la consola nos ira pidiendo que ingresemos numeros para adivinar donde esta el "vaso indicado". Si bien parece random donde pone los vasos, no lo es. Está basado en un algorítmo que toma como semilla la hora actual del dispositivo.
decode()
Decodifica un mensaje en base64 que contiene una clave secreta.
Solo se ejecuta si el jugador gana el juego.
timeNow()
: devuelve la hora actual en formato "HH:MM:SS"
.
getNewPosition()
: calcula la posición de la bolita usando la hora actual y el número de ronda, generando un valor entre 1 y 3.
El jugador debe adivinar 5 veces seguidas.
Si falla, pierde inmediatamente.
Si acierta, se muestra una frase motivacional.
Si el jugador gana 5 veces seguidas, se decodifica y muestra la clave secreta.
Cada vez que lo ejecutes tomará tu hora actual como base para el agorítmo. Y luego entre funciones que se van pasando se ejecuta el siguiente algorítmo:
La función getNewPosition()
basicamente tome como variable base
el índice de la hora actual, lo divide en 3 y toma el resto.
Imaginando que nuestra hora es 22:42:36
En el round 0, osea el primer round, la ecuación quedaría asi:
base = timeexec.split(':')[round%3]
El round es 0, por lo que el índice equivale a 22. Si a 22 le hacemos módulo 3 nos queda 1.
Reempazamos
base = timeexec.split(":")[22%3]
osea que base = 1
Luego resolvemos la variable position
position = (int(base)+round)%3
Como base = 1, resolvemos:
position = (1+0)%3
Osea que position es 1
.
Y por último la línea del final hace return str(position + 1)
osea que el primer resultado es 2
Como no podemos modificar el archivo actual debido a las reglas, ni agregar ficheros. En nuestra máquina local, vamos a crear un script de python que resulve los vasitos por nosotros.
Hacemos un script ejecutando vim solve_time.py
Y escribimos lo siguiente:
Guardamos nuestro script con :wq
y ejecutamos. python3 "22:49:15"
< O la hora que corresponda.
Y esto nos dará la solución para cada ronda.
Hacemos login del user9 con el password N0tS0Rand0m!
Si ejecutamos python3 nivel9.py
entrará en una aplicación de consola falsa que nos da opciones y comandos.
Si apretamos 0
hay un output. Si apretamos 1
hay otro output. Y asi sucesivamente.
Al seleccionar la opcion 1
vemos que el output es Hex(Reverse(password))
Esto es una pista clave.
Si ponemos una letra en vez de un numero, nos quita del programa.
Vamos a ver como funciona por dentro el script de python
Corremos vim nivel9.py
Hay una función bastante clave que se llama get_privs()
y por lo que vemos en el interior, está abriendo un archivo .json
y está cargando el valor "privs"
de ese archivo.
Al final del script, también podemos ver que dependiendo el valor de privs. Ejeutará una cosa u otra.
Salimos de vim con :q!
y enter.
Si hacemos un ls
veremos un archivo .json
al lado del script de python. Vamos a ver que tiene dentro.
Hay una key que se llama "privs"
y su valor es "high"
. Excelente! Sabemos que si modificamos estos privilegios el programa de python se comportara diferente.
Usamos vim
o cualquier editor de texto para cambiar ese valor de high
por medium
y a ver que pasa.
Ahora si ejecutamos el programa y le damos a la opcion 0
nos dice lo siguiente:
User: user10 - Encoded pass: 6e6957267376697250796669646f4d
Aqui esta el password de nuestro user10
!
Pero claro. Esta en un formato raro...
Gracias a la pista del punto anterior
Hex(Reverse(password))
Pareciera que si le aplicamos una funcion que nos saque el valor desde un hexadecimal y luego lo revierta, tenemos el password!
Vamos a ello. Nos copiamos el valor del password 6e6957267376697250796669646f4d
Ejecutamos python con python3
Nos aparecerá el intérprete
Guardamos el password escribiendo password = "6e6957267376697250796669646f4d"
y le damos a enter.
Ahora decodeamos el hexa de este password con la siguiebnte funcion y guardamos el valos en decoded_password.
Le damos a enter. Ahora si ejecutamos un print, veremos el password!
Pero está al revés! Vamos a arreglarlo.
reversed_password = decoded_password[::-1]
Y ahora si. Hacemos un print(reversed_password)
y nos aparecerá el password!
También podemos crear un script en python que automatice los comandos que corrimos recién:
Creamos nuestro script con vim solve.py
y escribimos lo siguiente:
Y esto nos decodificará el password.
Cuando ves un b'...' al imprimir en Python, significa que estás trabajando con un objeto de tipo bytes y no con una cadena de texto (str). Para mostrarlo como texto legible, simplemente usá .decode(). Por ejemplo:
print(reversed_password.decode())
Con esto podemos hacer sudo su
e ingresar el password. Luego podemos ejecutar groups
y veremos que pertenecemos a la elite ;)
Y si le pasamos 'user' como comando. Nos dará un
Que la terminal te acompañe