PC
Última actualización
¿Te fue útil?
Última actualización
¿Te fue útil?
PC
es una máquina Linux de dificultad fácil que cuenta con un punto final gRPC
que es vulnerable a la inyección SQL. Después de enumerar y volcar el contenido de la base de datos, las credenciales de texto sin formato conducen al acceso SSH
a la máquina. Al enumerar los puertos que se ejecutan localmente, se revela una versión obsoleta del servicio pyLoad
, que es susceptible a la ejecución remota de código (RCE) previa a la autenticación a través de CVE-2023-0297
. Como el servicio lo ejecuta root
, explotar esta vulnerabilidad conduce a privilegios completamente elevados.
Realizaremos un reconocimiento con nmap para ver los puertos que están expuestos en la máquina PC. Este resultado lo almacenaremos en un archivo llamado allPorts
.
Lanzaremos scripts de reconocimiento sobre los puertos encontrados y lo exportaremos en formato oN y oX para posteriormente trabajar con ellos. En el resultado, comprobamos que se encuentra el servicio SSH
en el puerto 22
expuesto y un servicio llamado grpc
en el puerto 50051
.
Transformaremos el archivo generado targetedXML
para transformar el XML en un archivo HTML para posteriormente montar un servidor web y visualizarlo.
De los puertos expuestos que se encuentran en la máquina, solamente disponemos del puerto 50051
que corresponde al servicio de gRPC
para tratar de buscar alguna vulnerabilidad, poder encontrar información que nos permite acceder al equipo, etc.
Realizando una búsqueda por Internet, nos encontramos con el siguiente blog en el cual nos mostraban diferentes técnicas y ejemplos de cómo enumerar el servicio de gRPC
en el ámbito del pentest
.
Al intentar realizar la enumeración, se nos mostraba un mensaje de error indicando que el servidor no respondió con el protocolo TLS
, ya que gRPC
normalmente funciona con TLS
de manera predeterminada.
Realizamos una comprobación del panel de ayuda de la herramienta y comprobamos que tenemos la opción -plaintext
para indicar a grpcurl
que no utilice TLS
.
A través de la directiva list
, hemos podido enumerar los servicios del servidor. En este caso, nos encontramos con un servicio llamado SimpleApp
y otro denominado ServerReflection
.
El servicio ServerReflection
permite realizar consultas al servidor para obtener información sobre los servicios disponibles, como los métodos y tipos de mensajes que maneja, sin necesidad de tener acceso previo a los archivos .proto
. Esto facilita la introspección dinámica del servidor y nos da visibilidad sobre su estructura, lo cual puede ser clave para interactuar con él de manera efectiva.
Al ejecutar el comando grpcurl
para listar los métodos disponibles en el servicio SimpleApp, encontramos las siguientes funciones disponibles:
SimpleApp.LoginUser
SimpleApp.RegisterUser
SimpleApp.getInfo
Estos métodos nos permiten interactuar con el servicio y realizar diversas acciones, como iniciar sesión, registrar usuarios o recuperar información.
Al ejecutar el comando grpcurl
para describir el servicio SimpleApp
, obtuvimos la siguiente estructura del servicio:
SimpleApp
es un servicio que ofrece tres métodos RPC:
LoginUser: Recibe un mensaje de tipo .LoginUserRequest
y devuelve un mensaje de tipo .LoginUserResponse
.
RegisterUser: Recibe un mensaje de tipo .RegisterUserRequest
y devuelve un mensaje de tipo .RegisterUserResponse
.
getInfo: Recibe un mensaje de tipo .getInfoRequest
y devuelve un mensaje de tipo .getInfoResponse
.
Estos métodos permiten interactuar con el servicio SimpleApp y realizar las operaciones correspondientes de acuerdo a los tipos de mensajes definidos.
Al ejecutar el comando grpcurl
para describir los mensajes asociados a los métodos del servicio SimpleApp
, obtuvimos la siguiente estructura de mensajes:
LoginUserRequest: Es un mensaje que contiene dos campos:
username
: tipo string
password
: tipo string
LoginUserResponse: Es un mensaje que contiene un campo:
message
: tipo string
RegisterUserRequest: Es un mensaje que contiene dos campos:
username
: tipo string
password
: tipo string
RegisterUserResponse: Es un mensaje que contiene un campo:
message
: tipo string
getInfoRequest: Es un mensaje que contiene un campo:
id
: tipo string
getInfoResponse: Es un mensaje que contiene un campo:
message
: tipo string
Estos mensajes están estructurados para ser enviados y recibidos durante la ejecución de las funciones del servicio SimpleApp
, facilitando la comunicación entre el cliente y el servidor.
Al realizar la solicitud con grpcurl
para registrar un nuevo usuario, hemos obtenido la siguiente respuesta.
Esto indica que se ha creado correctamente la cuenta para el usuario gzzcoo1
con la contraseña Gzzcoo123
.
Al realizar la solicitud con grpcurl para iniciar sesión con el usuario gzzcoo1 y la contraseña Gzzcoo123, obtuvimos la siguiente respuesta:
message: "Your id is 435."
Además, en los encabezados de la respuesta, se nos entregó un token de autenticación válido:
token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZ3p6Y29vMSIsImV4cCI6MTc0MDAzMTMyNX0.P0skEoAiBqW6BiH6E4m1nOutqPax4bGItF0mg0BPcjo'
Este token está asociado al usuario gzzcoo1 con el id 435 y puede usarse para realizar solicitudes autenticadas en futuras interacciones con el servicio SimpleApp.
La respuesta que recibimos indica que la solicitud para obtener información a través del método getInfo
fue rechazada debido a un error de autorización.
Esto significa que necesitamos incluir el token de autenticación en la cabecera de la solicitud para que el servidor nos permita acceder a la información. Podemos hacerlo añadiendo el token que recibimos anteriormente al encabezado token
.
Al incluir el token correctamente en la solicitud, hemos recibido la siguiente respuesta, la cual no nos ofrece ningún tipo de información interesante.
Por otro lado, también podemos hacer uso de la herramienta de gRPC UI
para realizar los mismos comandos anteriores pero a través de una interfaz web.
Utilizaremos el servicio SimpleApp
con el método RegisterUser
y trataremos de registrar un usuario nuevo. Para enviar la solicitud le deberemos de dar a la opción de Invoke
.
En la respuesta por parte del servidor se nos muestra el mensaje indicando que la cuenta ha sido registrada correctamente, el mismo mensaje que se nos mostraba con grpcurl
.
Utilizaremos el método de LoginUser
para iniciar sesión con el usuario recién creado, le daremos a Invoke
nuevamente.
En la respuesta por parte del servidor, se nos muestra la respuesta en la cual nos proporcionan nuestro ID
y en el apartado de Response Trailers
se nos proporciona el Token
correspondiente a nuestro usuario.
Por último, utilizaremos el método de getInfo
para probar la funcionalidad de este método. Especificaremos nuestro ID
y le añadiremos un nuevo valor Token
en el apartado de Request Metadata
.
En la respuesta por parte del servidor, se nos muestra el mensaje de Will update soon
, tal y como nos aparecía en la herramienta de grpcurl
.
Después de revisar los endpoints, vimos que no hay nada explotable a simple vista. Pero como el servicio maneja autenticación con usuarios, contraseñas e identificadores, es probable que haya una base de datos detrás. Esto nos abre la puerta a probar una posible inyección SQL (SQLi) si algún parámetro es vulnerable.
Para comprobarlo, empezamos a jugar con el parámetro id en getInfo
. Un truco básico para detectar SQLi es usar OR 1=1
, que si funciona, suele devolver un resultado válido sin importar el ID.
El mensaje de respuesta sugiere que la consulta se ejecutó sin error, lo que indica que podría haber SQLi en este punto.
Después de investigar los diferentes payloads para detectar la infraestructura de la base de datos, comprobamos que se trata de SQLite
.
A través de PayloadsAllTheThings
realizaremos las inyecciones SQL típicas para lograr extraer los datos de las bases de datos presentes.
El primer paso a realizar, será lograr determinar el total de columnas que dispone le base de datos, para así lograr inyectar el payload. En este caso, se confirma que la base de datos solamente dispone de una columna con una versión de SQLite 3.31.1
.
A través de la siguiente inyección SQL, comprobamos las tablas presentes en la base de datos. En el resultado obtenido, verificamos la existencia de las tablas accounts
y messages
.
Enumeraremos las columnas presentes en la tabla accounts
, en la cual se nos muestran las columnas username
y password
.
Comprobaremos los datos de las columnas presentes en la tabla accounts
. En el resultado obtenido, comprobamos que nos aparecen las credenciales del usuario admin
y del usuario sau
.
Probaremos de conectarnos al equipo mediante SSH
, una vez comprobado el acceso verificaremos la flag user.txt.
En el equipo, después de una enumeración inicial básica comprobamos algunos puertos internos desconocidos, en el cual al realizar un cURL
sobre ellos se nos mostraba una redirección a lo que parece ser a un panel de login
.
Después de identificar los puertos 8000
y 9666
corriendo en localhost
, establecemos un port forwarding
con SSH para exponerlos en nuestra máquina.
A través de una búsqueda por Internet, comprobaremos las credenciales que se utilizan por defecto en pyLoad
.
Al tratar de iniciar sesión las credenciales pyload/pyload
se nos mostraba un mensaje de error indicando que las credenciales proporcionadas no eran válidas.
Volvemos al equipo víctima y verificaremos quién es el usuario que está ejecutando el pyLoad
, en este caso se verifica que es el usuario root
. Por otro lado, también logramos comprobar la versión exacta del servicio de pyLoad
.
Realizaremos una búsqueda con searchsploit
para verificar si existe alguna vulnerabilidad conocida para pyLoad
. En el resultado que hemos obtenido, comprobamos que existe una vulnerabilidad de Pre-auth RCE
para la versión exacta que está levantado en el sistema víctima, con lo cual podríamos intentar explotar dicha vulnerabilidad reportada como CVE-2023-0297
.
Inyección de código en el repositorio de GitHub pyload/pyload anterior a 0.5.0b3.dev31.
Realizando una búsqueda por Internet, nos encontramos con el siguiente repositorio de GitHub en el cual nos proporcionan un exploit para aprovecharnos de la vulnerabilidad.
Nos pondremos en escucha con nc
para recibir la Reverse Shell.
Comprobaremos que hemos recibido la conexión al equipo victima y nos encontramos como root
debido que el usuario que levantaba el servicio de pyLoad
era él, por lo tanto, los comandos inyectados se ejecutarán como dicho usuario.
Finalmente logramos obtener la flag root.txt.
Analizaremos el exploit para verificar cómo funciona por detrás. Para ello, a través de la variable de entorno HTTP_PROXY
indicaremos la dirección IP de nuestro localhost
por el puerto 8080
que es donde tenemos configurado BurpSuite
.
Una vez indicado el proxy, ejecutaremos el exploit para que por ejemplo ejecute el comando whoami
.
En la solicitud que se intercepta a través de BurpSuite
, se verifica que para aprovecharnos de la vulnerabilidad se realiza una solicitud por el método POST
al endpoint /flash/addcrypted2
.
Posteriormente, se importa a realizar la importación de la librería os
y se realiza la ejecución del payload, posteriormente se declaran funciones y variables necesarias para la explotación de la vulnerabilidad.
En este ejemplo, verificamos el funcionamiento de la vulnerabilidad a través de la solicitud por POST
que tramitamos a través de BurpSuite
.
A través de la herramienta de , la utilizaremos para extraer los puertos del archivo que nos generó el primer escaneo a través de Nmap
. Esta herramienta nos copiará en la clipboard los puertos encontrados.
Accederemos a y verificaremos el resultado en un formato más cómodo para su análisis.
Para lograr interactuar con el servicio, decidimos utilizar la herramienta de . En la propia documentación de la herramienta se nos mostraban diferentes ejemplos también del uso.
Esto nos permite acceder a los servicios en y desde nuestro navegador, como si estuvieran corriendo en nuestra máquina local. Ahora podemos interactuar con ellos y buscar posibles vulnerabilidades.
Accederemos a y comprobaremos que se trata de una página de inicio de sesión de pyLoad
.
Realizaremos la ejecución del exploit sobre la URL vulnerable donde está el pyLoad
, en este caso, utilizaremos debido que hemos aplicado Port-Forwarding
e indicaremos nuestra dirección y puerto de atacante donde recibiremos la Reverse Shell.