| Kriptópolis alojado en |
| Zilos-Veloxia Network |
| Tu mejor defensa: |
| Bufet Almeida |
Desbordamiento de enteros en Java
Las vulnerabilidades por Integer Overflow (desbordamiento de enteros) son muy conocidas en lenguajes como C o C++, pero no tanto en Java.
Recientemente he estado experimentando con la posibilidad de realizar overflow de diferentes tipos de datos en Java (short, byte, int, etc.).
Me resulta curioso ver que algunos de ellos no están controlados por la máquina virtual. Por ejemplo, si mediante la clase Integer se desborda un entero, se lanza una excepción. Pero si se desborda un short o un byte, no ocurre nada...
Pego un ejemplo:
public class ShortOverflow
{
public static void main(String args[])
{
if(args.length<1)
return;
short num = Integer.valueOf(args[0]).shortValue();
System.out.println("num: "+num);
if(num>100)
System.out.println("num > 100");
else
System.out.println("num < 100");
}
}
$ javac ShortOverflow.java
$ java ShortOverflow 100
num: 100
num < 100
$ java ShortOverflow 101
num: 101
num > 100
$java ShortOverflow 100000
num: -31072
num > 100
Me pregunto si actualmente los cazadores de bugs mirarán estas cosas. En cualquier caso, si alguien tiene más información sobre el tema agradecería sus comentarios.
Más información en h4ck1t.



No lo veo claro
La clase Integer devuelve una excepción precisamente por ser una clase y estar programada para capturar la excepción.
Los tipos primitivos como short simplemente "dan la vuelta" cuando intentas añadir más datos de los que caben. No veo exactamente donde está el fallo.
Tampoco soy un experto en Java y no tengo claro que tratamiento se da a los tipos primitivos, si he dicho alguna barbaridad por favor corregidme.
Saludos
shortValue may involve rounding or truncation
El ejemplo concreto que has puesto no se trata exactamente de un Overflow incontrolado, sino de un truncamiento documentado:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Number.html#shortValue()
En cualquien caso, parece que sucede lo mismo si se desborda mediante una operación aritmética:
http://mindprod.com/jgloss/overflow.html
parse y valueOf
Hola.
Si en vez de hacer
short num = Integer.valueOf(args[0]).shortValue();
Haces
short num = Short.valueOf(args[0]).shortValue();
O bien
short num = Short.parseShort(args[0]);
Sí que se lanza una excepción. La lanza valueOf() o parseXXX(). El método Integer.shortValue() simplemente trunca el valor inicial. Como apuntan por ahí este truncamiento está documentado. La excepción no se lanza por un overflow, la excepción la lanza el método valueOf() (que llama internamente a parseXXX()) al parsear la cadena a convertir en entero. Por lo tanto es una verificación al parsear, no es un overflow.
saludos
Gracias Krampo
Gracias Krampo por los enlaces. Buscaba algo como lo que se comenta en el segundo.
Este comportamiento esta documentado en Java, pero también es ampliamente conocido en C y C++ (y seguramente en otros lenguajes). Aunque esto no evita que se puedan producir ciertas vulnerabilidades.
Me pregunto si esto se podría explotar de alguna manera en el caso de Java. En C/C++ es relativamente fácil explotarlo, pues puede combinarse con otros métodos como el buffer overflow. Pero en el caso de Java, me queda la duda.
Saludos.
No tengo claro que sea explotable
En C un desbordamiento de, por ejemplo un índice en un array,
te proporciona distracciones muy interesantes... hasta que descubres
que el índice es negativo :-( en cambio en java, la excepción
ArrayIndexOutOfBounds está asegurada
Donde sí se obtienen resultados curiosos es cuando intentas manejar
int, short o byte como unsigned... olvidando que por definición en
Java son siempre signed. He tenido que escribir una clase
UnsignedByte para poder manejar unsigned bytes de forma transparente,
en lugar de estar todo el día con byte&0x000000FF y con salidas por
pantalla de números negativos cuando busco rangos 0-255...
Es toda una aventura.
Lo curioso del caso es que internamente, la JVM utiliza 4 bytes
para manejar tanto int, como short, como byte, y trunca
convenientemente cuando pasa los datos al programa. Pudiera
parecer un error, pero si operáis los bytes como enteros con
signo de 32 bits, y se trunca al final, el resultado es correcto.
De hecho la propia especificación, recomienda usar (int) en lugar
de (byte) cuando se realizan operaciones cuyo resultado debe ser
un unsigned byte
En resumen, veo difícil pillar a la JVM por fallos debido al
desbordamiento de enteros. Tal vez, se le podría intentar buscar
las cosquillas trabajando en 64 bits, o mediante las conversiones
floatToIntValue() y su inversa intToFloatValue(), y jugando con
los pseudo números "NaN", pero no tengo tiempo ni ganas de hacer
pruebas...
No es explotable
Es un comportamiento esperado que no permite sobreescribir memoria, un código vulnerable tendría que ser del estilo:
public boolean login(int password) {
if (password > 0)
return false;
return true;
}
Vamos, que hay que hacerlo a propósito.
Eso no es una vulnerabilidad
Esto no es un error ni nada por el estilo, como desarrollador se debe tener claro esto, que cuando utilizas tipos primitivos short, al asignarle un valor superior a su capacidad, este simplemente toma su capacidad limite, perdiendo asi informacion, es por esto que a la hora de diseñar sistemas, se debe tener esto en cuenta.
Bueno
Yo creo que lo que decide si es una vulnerabilidad es encontrar una forma de explotarlo.
Si nadie la encuentra, entonces definitivamente no lo es.
Opinar