Ejecución remota de código (RCE), explicada: qué es y cómo prevenirla
La ejecución remota de código (RCE) es una clase de fallas/vulnerabilidades de seguridad de software. Las vulnerabilidades de RCE permitirán a un actor malicioso ejecutar cualquier código de su elección en una máquina remota a través de LAN, WAN o Internet. RCE pertenece a la clase más amplia de vulnerabilidades de ejecución de código arbitrario (ACE). Sin embargo, con la omnipresencia de Internet, el impacto de las vulnerabilidades de RCE crece rápidamente. Por lo tanto, los RCE son ahora probablemente el tipo más importante de vulnerabilidad ACE.
Como ese es el caso, queríamos echar un vistazo más detallado a los diversos tipos de vulnerabilidades de RCE y las posibles contramedidas.
Clasificación de RCE por origen
La mayoría, si no todas, de las vulnerabilidades de RCE conocidas tienen un pequeño número de causas subyacentes.
Ejecución dinámica de código
La ejecución dinámica de código tiende a ser el vector de ataque más común que conduce a RCE. La mayoría de los lenguajes de programación tienen alguna forma de generar código con código y ejecutarlo en el acto. Este es un concepto muy poderoso que ayuda a resolver muchos problemas complejos. Sin embargo, un tercero malicioso puede abusar fácilmente de él para obtener capacidades de RCE.
A menudo, el código generado en tiempo de ejecución se basa en alguna entrada del usuario. La mayoría de las veces, el código incluye esa entrada de alguna forma. Un actor malicioso, al darse cuenta de que la generación dinámica de código hará uso de una entrada determinada, podría proporcionar código válido como entrada para atacar su aplicación. Si no se revisan las entradas del usuario, ese código se ejecutará en la máquina de destino.
En términos generales, la ejecución de código dinámico causa dos clases principales de vulnerabilidades de RCE: directas e indirectas.
Direct
En el caso de la ejecución de código dinámico directo, el actor malicioso es consciente de que su entrada se utilizará en la generación de código.
Indirecto
Un caso indirecto, de nuevo, se reduce a la generación de código dinámico que incluye entradas de usuario. Sin embargo, la entrada del usuario pasa a través de una o más capas. Algunas de las capas podrían incluso transformar esa entrada antes de que termine con la generación de código dinámico. Además, la generación de código dinámico puede ser un efecto secundario y no el uso principal de la entrada. Como tal, no es realmente evidente para el usuario que proporciona la entrada que la entrada se utilizará como un bloque de construcción en un fragmento de código que se ejecutará en una máquina remota.
Deserialización
La deserialización es un muy buen ejemplo de este escenario. Aparentemente, no debería producirse ninguna generación dinámica de código en la deserialización. Ese es en realidad el caso cuando el objeto serializado contiene solo campos de datos de tipos primitivos u otros objetos de ese tipo. Sin embargo, las cosas se complican cuando los métodos/funciones de un objeto se serializan. La deserialización generalmente incluirá algún tipo de generación de código dinámico.
Podría pensar que los lenguajes dinámicos son el único lugar donde la serialización de funciones tiene sentido. El problema será entonces de alcance limitado. Pero también es un escenario útil en lenguajes estáticos. Es un poco más difícil de lograr en un lenguaje estático, pero de lejos no es imposible.
Con bastante frecuencia, la implementación consiste en objetos/funciones proxy generados por deserialización. Generar objetos / funciones en tiempo de ejecución es un caso de generación de código dinámico. Por lo tanto, si los datos que se deserializan se originan en una solicitud realizada por una máquina remota, un actor malicioso podría modificarlos. Se pueden inyectar fragmentos de código serializados cuidadosamente diseñados que engañan a la generación de código dinámico para ejecutarlos cuando se invocan como parte de la deserialización.
Seguridad de la memoria
Otra causa de vulnerabilidades de RCE tiene que ver con la seguridad de la memoria. La seguridad de la memoria significa evitar que el código acceda a partes de la memoria que no inicializó ni obtuvo como entrada. Intuitivamente, es de esperar que la falta de seguridad de la memoria dé lugar a un acceso no autorizado a los datos. Sin embargo, el sistema operativo y el hardware subyacente usan memoria para almacenar código ejecutable real. Los metadatos sobre la ejecución de código también se almacenan en la memoria. Obtener acceso a este tipo de memoria podría resultar en ACE y posiblemente RCE. Entonces, ¿cuáles son las principales razones detrás de los problemas de seguridad de la memoria?
Defectos de diseño de software
Los defectos de diseño de software son un tipo de vulnerabilidad de seguridad de memoria en la que hay un error de diseño en algún componente subyacente. La mayoría de las veces, sería un compilador, intérprete o máquina virtual, o potencialmente el núcleo o las bibliotecas del sistema operativo. Hay una serie de defectos diferentes que pertenecen a esta clase. Vamos a echar un vistazo más detallado a lo que posiblemente sea el más común.
Desbordamiento de búfer o exceso de búfer
Desbordamiento de búfer (también conocido como exceso de búfer) es una técnica bastante simple y conocida para violar la seguridad de la memoria. Explota un defecto de diseño o un error para escribir en las celdas de memoria que siguen el final real de un búfer de memoria. El búfer en sí se devuelve de una llamada legítima a la API pública. Sin embargo, el búfer solo sirve como punto de origen para calcular las direcciones de memoria física de los valores de campo/miembro privados de algún contador de objetos o programas. Su posición relativa al búfer es bien conocida o podría adivinarse. Investigar el código si está disponible o depurar la ejecución del programa en tiempo de ejecución podría ayudar a un actor malicioso a obtener posiciones relativas.
Por lo tanto, un desbordamiento de búfer permite modificar la memoria que debería ser inaccesible por diseño. Ese búfer puede residir en el espacio de direcciones de otra máquina y modificarse llamando a una API remota. Eso permitirá el acceso a la memoria de la máquina remota. Es evidente que hay varias formas de utilizar este tipo de acceso en la instrumentación de un RCE. La suposición general es que si existe una vulnerabilidad de desbordamiento de búfer, entonces es posible un RCE. Por lo tanto, los propietarios de código deben corregir los desbordamientos de búfer LO antes posible, mucho antes de que surja el ataque real de RCE.
Alcance
La mayoría de las veces, el desbordamiento de búfer se dirige al código de C/C++, ya que estos lenguajes no tienen comprobaciones de tamaño de búfer integradas. Muchos otros frameworks y tecnologías populares terminan utilizando bibliotecas de C / C++ en el fondo de la superficie, lo que las hace vulnerables automáticamente a este tipo de ataque.Nodo
.js es un buen ejemplo de esto ya que, además de estar basado en C/C++, el tiempo de ejecución de JavaScript también permite complementos nativos de C/C++. Debido a esto, un atacante puede crear cuidadosamente las solicitudes a un nodo.servidor js para causar desbordamiento de búfer y, por lo tanto, modificar la memoria del sistema en la máquina afectada, causando la ejecución de código arbitrario.
Defectos de diseño de hardware
Curiosamente, las violaciones de seguridad de la memoria también pueden ocurrir debido a defectos de diseño de seguridad de hardware. Aunque son menos comunes y más difíciles de encontrar, estas vulnerabilidades generalmente tienen un impacto extremadamente alto.
Desviar ataques RCE
Si bien el resultado de cada ataque RCE es el mismo en términos de código de ejecución de un atacante, los vectores de ataque son de naturaleza muy diferente. Bloquear todos ellos requiere un esfuerzo significativo. Además, el esfuerzo crece junto con la pila de tecnología. Todos los vectores de ataque descritos en este post son independientes de la tecnología. Sin embargo, todas las implementaciones son específicas de la tecnología, al igual que los mecanismos de defensa.
Por lo tanto, un enfoque tradicional para ahorrar tiempo es monitorear el tráfico de red en busca de contenido sospechoso en lugar de monitorear cada extremo con su tecnología específica. Normalmente, un firewall de aplicaciones web (WAF) realiza este trabajo. Si bien esto ahorra tiempo, también tiene un precio: el WAF es un cuello de botella del rendimiento de la red y carece de toda la información de fondo disponible en el punto final real o en los niveles de aplicación y usuario. Por lo tanto, el análisis de tráfico WAF nunca podría ser perfecto. La heurística es inevitable sin datos completos, por lo que no surgirán todas las amenazas o surgirán falsos positivos, o muy a menudo ambos.
Moverse dentro de la aplicación: El enfoque de Sqreen
Sqreen aborda estas deficiencias de WAF sin aumentar el costo de desarrollo para el usuario final al mover la visibilidad dentro de la aplicación, brindando una protección más completa con una ESCOFINA específica de la tecnología y WAF en la aplicación. ESCOF y WAF de Sqreen se ejecutan dentro de la aplicación web, la API o el tráfico de red receptor de microservicios real. Sin embargo, no requiere ninguna modificación de código. Utiliza puntos de instrumentación específicos para cada tecnología (por ejemplo, API JVM para Java, API v8 para Nodo).js, etc.) para modificar el código antes de la ejecución en tiempo de ejecución. Por lo tanto, es capaz de monitorear y modificar los eventos del sistema y la red mientras tiene el contexto completo de todo lo que sucede dentro de la aplicación.
Por lo tanto, Sqreen puede detectar que la aplicación está utilizando componentes con problemas de seguridad de memoria conocidos. También puede detectar las entradas de usuario reales que llegan a los eventos de ejecución de código dinámico. Naturalmente, este es un enfoque superior para detectar y prevenir RCE en comparación con un WAF tradicional que solo tiene acceso al tráfico de red.
Envolviendo
Claramente, RCE es un vector de ataque muy potente. Pero, por suerte, también es posible defenderse de los ataques de RCE. La información anterior realmente puede ayudar en la construcción de su estrategia de defensa. Si está interesado en otros vectores de ataque y detalles, consulte nuestras publicaciones anteriores sobre inyección SQL, XXE y LFI.
Leave a Reply