RealFlex RealWin Server [SCADA] Reverse y Exploit

Miguel Méndez Z.
7 min readOct 17, 2018

--

CrackSLatinoS

Primero que todo esta vulnerabilidad ya tiene un par de años exactamente es del 2010 su CVE-2010–4142. Mi objetivo es volver a escribir el exploit ¿y esto porque?. Bueno la motivación de resolverlo es porque se publico como ejercicio en CrackSLatinoS buena comunidad.

Bueno antes de empezar de lleno con el análisis quiero aclarar algunas dudas que tenia sobre el binario y eso es lo que explicare en este post ya que necesitaba ciertas cosas para que el BoF se ejecutase y saber que función es la culpable. Ahora desarrollar el exploit es relativamente fácil no tenia ninguna complejidad, pero si habían algunas cosas que se daban por entendido que no se explicaban y eso es lo que necesitaba saber.

RealFlex 6.4 SCADA tiene un servidor que se ejecuta en un sistema operativo QNX Neutrino y utiliza un protocolo cifrado dinámicamente entre el servidor y los clientes para asegurar una comunicación segura, ademas de una interfaz grafica HMI (Human Machine Interface).

HMI

Voy a tratar que no sea tan extenso este post bueno empecemos ️👽.

Lo primero que veremos es que están corriendo unos servicios como el 910, 912, 917. Donde podemos crear un Socket y probar algunos Fuzzer conocidos o utilizar Python For Life en esos puertos abiertos . Para resumir la vulnerabilidad se encuentra en el servicio 912, entonces lo primero que hago es un script en python bien simple que me genere una conexión Socket y enviar una gran cantidad de bytes \x41 al servidor.

service
simple socket

Que es lo que ocurre aquí al enviar la data al servidor lo único que recibimos es un mensaje de error “FlexSim protocol header corruption detected” que nos quiere decir esto que la conexión se realizo pero no obtuvimos el crash y eso es por una simple razón lo que estamos enviando como paquete esta mal formado y eso nos lleva a reversiar para ver que es lo que pasa y que necesitamos 💡.

error de protocolo

Empiezo a ver por donde llega la conexión así que probé con WSARecv de WS2_32.DLL y vemos que obtenemos el largo del Buffer y la data que envié de solo A’s.

wsarecv

Luego la siguiente rutina por flecha Roja de WSARecv donde utiliza un MOV EDX, [ESI] como base para aplicar un desplazamiento de 18h y hacer una llamada a esa función.

desplazamiento 18h = 24

Entonces al llegar a sub_413630 encuentro lo que necesitaba, primero compara que el largo 21F0h sea mayor a 0xC dec(12) que eso ya seria el largo del header, cumpliendo eso llegamos a unos valores que se comparan 6A541264h si no se cumple la primera condición valida la siguiente 6A541266h de lo contrario entra a la función donde imprime el mensaje de header corrupto.

El flujo es así, EAX+18h es el puntero al Buffer con A’s y lo mueve a ESI para que compare los primero bytes con el string hardcode 6A541264h. Entonces ya se que debe contener los primeros bytes de mi data enviada.

ESI apunta al inicio del buffer, al sumar ESI+8 nos posicionamos en unos de los bytes que ingresamos, el cual esos byte serán sumados y comparados con EAX+1Ch que es el tamaño del Buffer 21F0h.

Entonces debo calcular el desplazamiento de los bytes y poner unos que sean menor a 21F0h así que pondré \x00*4 que ayudaran para el desplazamiento luego \x1D*2 estos son utilizados para que al sumar con 0xC no sea mayor a 21F0h y \x00*2 para que se fusione con 1D quedando de la siguiente manera 0x00001D1D.

Por el momento la estructura nuestro del header va de la siguiente manera:

Header : \x64\x12\x54\x6A\x00\x00\x00\x00\x1D\x1D\x00\x00

Ya pudimos pasar los filtros y nos queda poco al parecer 😃 . Ahora lo que vemos es que al registro EAX quedara con la dirección del inicio de nuestra data que son las A’s, en realidad nuestra data enviada parte desde el header pero con el desplazamiento de 0Ch saltamos el header quedando en las A’s.

Aquí lo dejo mas claro si no se entendió ESI es nuestro header y EAX es el inicio de las A’s.

En esta rutina lo que hace es enviar al stack la dirección de las A’s y un byte obtenido del header pero cual sera?. Bueno fácil si sabemos que ESI es el inicio de nuestra data enviada que se compone de header+A’s, entonces seria de la siguiente manera header+4

Header : \x64\x12\x54\x6A\x00\x00\x00\x00\x1D\x1D\x00\x00

Tomamos el valor del primer byte \x00 y lo enviamos a la función calculada EDX+28h.

Ahora la ultima parte del header para que quede funcional es saber que valor debe ir en ese byte y porque. Bueno explicare para que se utiliza ese byte.

Pondré un ejemplo imaginemos que el byte que debemos cambiar lo dejamos con el valor de 15h esto se mueve a ESI el valor es comparado y debe ser menor que 62h si este es menor seguimos por el camino correcto.

Después de pasar la condición la siguiente instrucción a ejecutar es movzx eax, ds:byte_415108[edi] lo que realizara es tomar un byte de un array, pero eso sera según el valor que hemos introducido como probamos con 15h que en decimal seria 21 caeríamos en el 12 del array y ese sera multiplicado por 4 y ejecutaría el salto.

Si utilizamos un numero el cual tome un valor incorrecto del array seremos redireccionados a esta función donde imprimirá un mensaje de “Unknown scanner protocol message recieved: FUNCTION=1”.

message

Ahora yo utilice los valores \x02 y \x20 que serian validos para ocasionar el overflow. Tener en cuenta que cada uno de estos byte redireccionan por distintos flujos pero llegan al mismo resultado.

Ahí tenemos los 2 flujos que llevan al crash, para ir por el flujo de la derecha utilizamos el valor \x20 y el \x02 el de la izquierda.

Ahora vamos a utilizar la opción de la derecha. Ahí podemos observar que el byte \x20 tomo el valor de 0Ch del array que corresponde a 12 en decimal.

El calculo que realiza para seguir por el flujo que necesitamos es el siguiente:

  • Ingresamos \x20 este toma el valor 0Ch del array
  • Después multiplicamos hex(0xc*4) = 0x30
  • Ahora calculamos la dirección al puntero hex(0x004150BC+0x30) = 0x4150ec y si nos fijamos es la dirección de loc_41487F.

Seguimos por ese flujo y llegamos a estas instrucciones donde obtenemos el mensaje a mostrar y lo imprime “Scanner (ID=%p) connection detected.”. Ademas de enviar los parámetros a la función que nombre como Bummmm.

mensaje impreso

Ya dentro de 0x00414958 -> Bummmm vemos 2 rutinas pintadas en verde la de arriba llegamos con el byte \x20 y la de abajo se la pueden imaginar :) con la \x02 en las 2 tenemos un lindo y famoso sprintf().

Ya en el final podemos ver los parámetros que se pasan a la función vulnerable quedando de la siguiente manera.

Parametros:

  • Data = A’s
  • Str = C:\Program Files\DATAC\Real.Win\DemoRW-1.06\\realflex\data\crt\fwd\tel\%s.%d
  • Buffer[9]

sprintf(Buffer, Str, Data)

y al pasar por la función de sprintf() vemos que ya tenemos el control de SEH Bummm ahora solo queda escribir el exploit que no es complicado.

Header Validos:

  • \x64\x12\x54\x6A\x20\x00\x00\x00\x1D\x1D\x00\x00
  • \x64\x12\x54\x6A\x02\x00\x00\x00\x1D\x1D\x00\x00

Video de ejecución del exploit:

Link: https://www.youtube.com/watch?v=DhhIv93p--M

Code Exploit:

https://ricardo.crver.net/WEB/OTROS/EXPLOIT/Realflex-realwin-server-scada-reverse-y-exploit_By_s1kr10s.pdf

By3…

--

--