Predictable DockerLabs (Hard)
Instalación
Cuando obtenemos el .zip nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.
unzip predictable.zipNos lo descomprimira y despues montamos la maquina de la siguiente forma.
bash auto_deploy.sh predictable.tarInfo:
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
___ ____ ____ _ _ ____ ____ _ ____ ___ ____
| \ | | | |_/ |___ |__/ | |__| |__] [__
|__/ |__| |___ | \_ |___ | \ |___ | | |__] ___]
Estamos desplegando la máquina vulnerable, espere un momento.
Máquina desplegada, su dirección IP es --> 172.17.0.2
Presiona Ctrl+C cuando termines con la máquina para eliminarlaPor lo que cuando terminemos de hackearla, le damos a Ctrl+C y nos eliminara la maquina para que no se queden archivos basura.
Escaneo de puertos
Info:
Vemos que hay un puerto interesante que es el 1111 y si entramos en el, veremos una pagina web con una lista de numeros, pero en la barra que esta en la parte superior en el centro vemos que nos indica que tendremos que meter una "semilla" para que nos diga algo secreto, pero tiene que coincidir con la siguiente semilla que intuimos que podria ser la numero 100 de la lista de la pagina, por lo que vamos a calcular todo esto y nos montaremos un script para que todo esto sea mas rapido.
Para poder calcular los parámetros de un generador congruencial lineal (LCG), necesitas tres valores consecutivos generados por el LCG: s0, s1 y s2. Usando estos valores y el módulo nnn, el script puede calcular el multiplicador aaa y el incremento ccc que el generador está utilizando. Estos valores se eligen porque son tres puntos consecutivos generados por la misma función de LCG, lo que permite calcular los parámetros.
En la siguiente pagina encontramos mas informacion:
URL = Info LCG
calculatorLCG.py
Esos números provienen de la secuencia generada por el generador congruencial lineal (LCG) que se utiliza en un proceso de prueba o ataque. Para encontrar el multiplicador, el incremento y el módulo del LCG, es necesario conocer al menos tres valores consecutivos de la secuencia generada. Si tienes valores reales de la secuencia generada (como s0, s1, s2), puedes aplicarlos en el script para obtener los parámetros de configuración del generador.
El valor de --n, que en este caso es 9223372036854775783, corresponde al módulo utilizado en el generador congruencial lineal (LCG). Este valor es esencial para calcular la secuencia generada por el LCG y es típico usar un valor muy grande, cercano a 2632^{63}263, en sistemas modernos para garantizar un rango amplio de números generados. Este valor también es una elección estándar cuando no se especifica otro módulo en particular, por lo tanto, puede ser un valor predeterminado en ciertos contextos.
Como resultado nos daria lo siguiente:
Info:
Una vez teniendo calculados los valores que necesitamos para descubrir la "semilla" haremos el siguiente script:
Escalate user mash
calculatorSeed.py
Lo utilizamos de la siguiente forma:
Ejemplo:
Info:
Y esto lo metemos en la barra esa de busqueda:

Y veremos que nos muestra unas credenciales, las cuales nos conectaremos por ssh.
SSH
Metemos como contraseña LCG_1s_E4Sy_t0_bR34k y veremos que estamos dentro con dicho usuario.
Escalate Privileges
Una vez que entramos vemos que estamos dentro de python encerrados en un pyjail, y tendremos que escapar de ahi para obtener una shell de bash:
Vamos a ver que podemos hacer:
Info:
Si intentamos poner cosas como __import__ u os nos pondra que lo tenemos bloqueado, por lo que tendremos que Bypassear este bloqueo de la siguiente forma.
Explicación para salir del pyjail
pyjailCuando trabajamos en un entorno controlado, como un CTF (Capture the Flag), algunas palabras clave de Python están bloqueadas para evitar la ejecución de comandos no deseados. Uno de estos bloqueos comunes es la palabra clave import, que se usa para cargar módulos.
¿Por qué dividir import y usar getattr()?
import y usar getattr()?1. Restricción de palabras clave: El sistema puede bloquear el uso directo de palabras clave como import para evitar que se carguen módulos como os, que pueden permitir ejecutar comandos del sistema.
2. Solución: dividir y concatenar palabras:
Para evitar el bloqueo, podemos dividir la palabra clave
importen dos partes:'__im'y'port__', y luego unirlas con el operador+.Usamos este enfoque con el módulo
ospara ejecutar comandos del sistema (comoos.system()).
3. Uso de getattr() para acceder a funciones internas:
globals()devuelve un diccionario de todas las variables globales del entorno, que incluye funciones comoprinto__import__.getattr()permite acceder a una función de un objeto a través de su nombre. En este caso,getattr(globals()['__builtins__'], '__im'+'port__')accede a la función__import__, que es la encargada de cargar módulos en Python.Después de eso, podemos usar
('o' + 's')para formar el nombre del módulo que queremos cargar, en este caso,os.
¿Qué pasa con getattr() y por qué es importante?
getattr() y por qué es importante?getattr()es una función que obtiene atributos de un objeto. En este caso, se utiliza para obtener la función__import__que se usa para cargar módulos. El uso degetattr()es clave porque nos permite acceder a funciones, incluso aquellas que están protegidas o son menos obvias (como__import__).
Ejemplo completo:
El comando completo getattr(globals()['__builtins__'], '__im'+'port__')('o'+'s') realiza lo siguiente:
globals(): Trae todas las variables globales disponibles en el entorno de ejecución, incluidas las funciones y objetos internos de Python.['__builtins__']: Especifica que vamos a buscar dentro de los "builtins", que son funciones que Python siempre tiene disponibles (comoprint,input, etc.).'__im' + 'port__': Concatenamos las partes de la palabra claveimport, usando el signo+para eludir el bloqueo del sistema.('o' + 's'): De forma similar, dividimos la palabraosy la unimos con el operador+para cargar el móduloos.Resultado: Esto permite acceder y cargar el módulo
ossin que el sistema detecte el uso directo de la palabra bloqueadaimport.
Conclusión:
Este es un enfoque ingenioso para evadir restricciones y continuar ejecutando código con módulos esenciales en entornos donde ciertas palabras clave están bloqueadas. A través de este truco, podemos obtener acceso a módulos importantes como os y ejecutar comandos del sistema de manera efectiva.
Practica de la explicación
Esto hace lo siguiente:
getattr(globals()['__builtins__'], '__im'+'port__')('o'+'s'): Aquí usamosgetattrpara acceder al método__import__y cargar el móduloosen Python. Fragmentamos la palabraimporten__imyport__y unimosoyspara obtener el móduloos.getattr(..., 'sys'+'tem'): Después, usamosgetattrde nuevo para acceder a la funciónsystemdentro del móduloos, fragmentandosystemensysytem.('bash'): Finalmente, ejecutamosos.system('bash')que invoca el comandobashen la terminal, lo que te da acceso a la shell.
Este es un truco comúnmente utilizado para evadir restricciones en entornos controlados donde las palabras clave como import o funciones como system están bloqueadas.
Info:
Y con esto habremos obtenido una shell en bash habiendo escapado del pyjail.
Si hacemos sudo -l veremos lo siguiente:
Vemos que podemos ejecutar el binario /opt/shell como el usuario root, por lo que haremos lo siguiente:
Info:
Vemos que nos da una pista sobre como utilizar esto.
Info:
Ingeniería Inversa
Vemos que efectivamente esta instalado y si buscamos informacion sobre el binario, veremos que es una herramienta para realizar ingenieria inversa, por lo que la utilizaremos para hacer ingenieria inversa al archivo shell.
Una vez dentro del binario para examinarlo, veremos las funciones que tiene:
Info:
Vamos a ver la funcion main en modo ensamblador:
Info:
Para obtener una shell en el código desensamblado que estoy mostrando, podemos centrarnos en el flujo de ejecución del programa en la función main. El análisis muestra que si el programa recibe el argumento correcto (en este caso, si el valor de argv es "r"), el código ejecuta la función system("/bin/bash").
El paso crítico es este fragmento:
Este bloque de código prepara el comando /bin/bash para ejecutarlo mediante la llamada a system(), que es una función estándar para ejecutar comandos en la línea de comandos del sistema operativo. Si puedes controlar el argumento que pasa al programa (por ejemplo, mediante un "input"), puedes hacer que ejecute /bin/bash y obtener acceso a una shell.
Pero si nosotros le pasamos directamente la r, vemos que no funciona:
Info:
En esta parte de aqui vemos que tambien nos esta mostrando que esta ralizando una validacion con el argumento 0:
Y vemos que esta en el 0x30, por lo que tendremos que cambiar el valor de esta cabecera para saltarnos la verificacion y que cuando le pasemos 0 automaticamente nos ejecute la shell.
Si analizamos el encabezado del ELF vemos que lo que queremos cambiar para omitir esa validacion esta en el byte 6 por lo que tendremos que cambiar el valor de 0x30 del byte 6 por cualquier otro numero que no sea el 0x01, en mi caso le pondre un 0x00.
Con esto ya habremos modificado dicho byte y lo podremos comprobar con el siguiente comando:
Info:
Vemos que efectivamente se modifico de buena forma, por lo que ya solo faltaria introducir la informacion correcta, que en este caso seria 0 para que ejecute la shell.
Nos saldremos con q y ejecutamos lo siguiente:
Info:
Y con esto ya seremos root, por lo que habremos terminado la maquina.
Last updated