Protege tu #Magento: Explotación del bug CVE-2016-4010 que permite Ejecución Remota de Código
Magento es una de las principales plataformas de comercio electrónico en Internet y con una amplia comunidad - incluso han desarrollado un plugin de Latch para Magento -. Es posible encontrar multitud de tiendas online que hacen uso de este software de código abierto y en el equipo de Faast lo tenemos muy presente para la evaluación de sus vulnerabilidades en los procesos de pentesting persistente que ejecutamos sobre nuestros clientes. En mayo de este año, Netanel Rubin descubrió una vulnerabilidad de alta criticidad (CVE 2016-4010), que permite a un atacante no autenticado inyectar y ejecutar código en el servidor.
Esta vulnerabilidad está presente en las versiones de Magento comprendidas entre la 2.0.0 y la 2.0.5 y, por supuesto, tenemos un plugin en nuestro sistema para detectar versiones afectadas por ella. Aprovechando que tenemos el entorno de test del plugin que montamos, hemos hecho este artículo para explicar el fallo y su explotación, que es un caso típico de PHP Object Injection tal y como se explica en el libro de Hacking Web Technologies.
En que consiste el CVE-2016-4010
Para entender la vulnerabilidad es necesario conocer cómo se comunican cliente y servidor. Cuando el cliente envía un objeto al servidor (nuestros productos, nuestros datos bancarios, etcétera), antes de insertarlo en la base de datos, serializa aquellos campos que estén especificados en el diccionario _serializableFields y que además sean arrays u objetos.
Una vez el servidor recibe los datos, se aplica la lógica inversa para deserializarlos. Como se ve en la línea 27 de la figura 1 el servidor no va a deserializar arrays ni objetos, lo que a priori pone las cosas difíciles si queremos inyectar un objeto en el servidor.
Sin embargo, si introducimos un string adecuado en uno de los campos catalogados como _serializableFields, esa cadena sí será deserializada posteriormente, por lo que el servidor es vulnerable.
Basta con determinar qué campo es el adecuado. En este caso, la vulnerabilidad está en la información de pago, concretamente en el campo additional_information del diccionario additional_data, que permite al usuario añadir información adicional sobre el método de pago seleccionado. Esa información no se controla en servidor, sino que es deserializada directamente. Ahí es donde inyectaremos nuestro payload.
Para que la inyección funcione es necesario utilizar como payload un objeto de PHP serializado que tenga ‘métodos mágicos’ (como _wakeup(), _sleep(), etcétera más info en el artículo de PHP Object Injection). Estos métodos tienen la particularidad de que se ejecutan automáticamente cuando el objeto es serializado o deserializado, y por tanto son muy útiles ya que en este escenario no es posible llamar explícitamente a ningún método del objeto.
Así pues, usando un objeto de estas características, es posible modificar el comportamiento de los métodos mágicos ya que tenemos control total de las propiedades del objeto. Podríamos, por ejemplo, modificar las propiedades que usa el método _destruct() para así llamar indirectamente a otro método del propio Magento. Las posibilidades son infinitas, tan solo es necesario utilizar objetos que cumplan esta condición. Un buen ejemplo (el utilizado por el descubridor de la vulnerabilidad) es una instancia de la clase Credis_Client, un cliente de Redis para PHP.
¿Cómo se explota?
Magento incluye una API REST que permite la integración de terceros. A través de esta API es posible realizar todo tipo de transacciones. El endpoint set-payment-information es el punto vulnerable en este caso.
Cuando un cliente anónimo (esto es, no autenticado contra el servidor de la tienda) va a realizar el checkout de una compra, automáticamente se le asigna un ID alfanumérico de 32 caracteres, el guest cart ID. Es posible obtener este ID a partir de la petición POST que se realiza internamente contra la API cuando se pulsa el botón checkout, ya que va en plano en la propia URL.
A partir de ese momento, todas las transacciones entre cliente y servidor relacionadas con esa compra están asociadas a ese ID. Así, modificando adecuadamente la petición a set-payment-information es posible conseguir la inyección de código.
Para comprobar que el ataque ha funcionado, basta con crear el fichero en un directorio del servidor que sea accesible públicamente, y navegar hasta él. Por supuesto, todo el proceso puede ser automatizado, haciendo uso de otras funciones de la API para emular el proceso de compra:
Más artículos sobre Seguridad en Magento
Faast Engineer en ElevenPaths
Figura 1: Protege tu Magento: Explotación del bug CVE-2016-4010 que permite RCE |
Esta vulnerabilidad está presente en las versiones de Magento comprendidas entre la 2.0.0 y la 2.0.5 y, por supuesto, tenemos un plugin en nuestro sistema para detectar versiones afectadas por ella. Aprovechando que tenemos el entorno de test del plugin que montamos, hemos hecho este artículo para explicar el fallo y su explotación, que es un caso típico de PHP Object Injection tal y como se explica en el libro de Hacking Web Technologies.
En que consiste el CVE-2016-4010
Para entender la vulnerabilidad es necesario conocer cómo se comunican cliente y servidor. Cuando el cliente envía un objeto al servidor (nuestros productos, nuestros datos bancarios, etcétera), antes de insertarlo en la base de datos, serializa aquellos campos que estén especificados en el diccionario _serializableFields y que además sean arrays u objetos.
Una vez el servidor recibe los datos, se aplica la lógica inversa para deserializarlos. Como se ve en la línea 27 de la figura 1 el servidor no va a deserializar arrays ni objetos, lo que a priori pone las cosas difíciles si queremos inyectar un objeto en el servidor.
Figura 2: Métodos serializeFields y unserializeFields de Magento |
Sin embargo, si introducimos un string adecuado en uno de los campos catalogados como _serializableFields, esa cadena sí será deserializada posteriormente, por lo que el servidor es vulnerable.
Basta con determinar qué campo es el adecuado. En este caso, la vulnerabilidad está en la información de pago, concretamente en el campo additional_information del diccionario additional_data, que permite al usuario añadir información adicional sobre el método de pago seleccionado. Esa información no se controla en servidor, sino que es deserializada directamente. Ahí es donde inyectaremos nuestro payload.
Para que la inyección funcione es necesario utilizar como payload un objeto de PHP serializado que tenga ‘métodos mágicos’ (como _wakeup(), _sleep(), etcétera más info en el artículo de PHP Object Injection). Estos métodos tienen la particularidad de que se ejecutan automáticamente cuando el objeto es serializado o deserializado, y por tanto son muy útiles ya que en este escenario no es posible llamar explícitamente a ningún método del objeto.
Figura 4: Exploit para CVE-2016-4010 publicado en Exploit-DB |
Así pues, usando un objeto de estas características, es posible modificar el comportamiento de los métodos mágicos ya que tenemos control total de las propiedades del objeto. Podríamos, por ejemplo, modificar las propiedades que usa el método _destruct() para así llamar indirectamente a otro método del propio Magento. Las posibilidades son infinitas, tan solo es necesario utilizar objetos que cumplan esta condición. Un buen ejemplo (el utilizado por el descubridor de la vulnerabilidad) es una instancia de la clase Credis_Client, un cliente de Redis para PHP.
¿Cómo se explota?
Magento incluye una API REST que permite la integración de terceros. A través de esta API es posible realizar todo tipo de transacciones. El endpoint set-payment-information es el punto vulnerable en este caso.
Cuando un cliente anónimo (esto es, no autenticado contra el servidor de la tienda) va a realizar el checkout de una compra, automáticamente se le asigna un ID alfanumérico de 32 caracteres, el guest cart ID. Es posible obtener este ID a partir de la petición POST que se realiza internamente contra la API cuando se pulsa el botón checkout, ya que va en plano en la propia URL.
Figura 4: Petición POST a la API REST de Magento, con el Guest Cart ID en plano |
A partir de ese momento, todas las transacciones entre cliente y servidor relacionadas con esa compra están asociadas a ese ID. Así, modificando adecuadamente la petición a set-payment-information es posible conseguir la inyección de código.
Figura 5: Body de la petición a set-payment-information, con el payload en"additional_information". En rojo, el nombre del fichero a crear en el servidor y su contenido. |
Para comprobar que el ataque ha funcionado, basta con crear el fichero en un directorio del servidor que sea accesible públicamente, y navegar hasta él. Por supuesto, todo el proceso puede ser automatizado, haciendo uso de otras funciones de la API para emular el proceso de compra:
• /rest/V1/guest-carts permitiría obtener un guest cart IDTras esos tres pasos previos, la vulnerabilidad ya estaría en condiciones de ser explotada. En el siguiente vídeo tienes el proceso completo para ver cómo se puede explotar esta vulnerabilidad en un servidor con Magento afectado por este CVE-2016-4010.
• /rest/V1/{guest-cart-id}/items permite añadir objetos al carro, pero es necesario conocer su SKU o número de referencia
• /rest/V1/{guest-cart-id}/shipping-information permite añadir la información de envío
Figura 6: Explotación del CVE-2016-4010
- Configurar y utilizar Latch en Magento CommunityAutor: Cristobal Bordiú
- Magento Repair Tool: Un XSPA a quitar de tu e-commerce
- Magento Check: Un info leak a eliminar de tu servidor
Faast Engineer en ElevenPaths
No hay comentarios:
Publicar un comentario