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.

Comentarios

Selecciona arriba tu forma preferida de visualizar
los comentarios y pulsa el botón para guardar tus
preferencias. Éstas sólo se recordarán para tus
próximas visitas si eres usuario registrado.

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()

Returns the value of the specified number as a short. This may involve rounding or truncation.

En cualquien caso, parece que sucede lo mismo si se desborda mediante una operación aritmética:

http://mindprod.com/jgloss/overflow.html

Why does Java ignore overflow? Most computer hardware has no ability to automatically generate an interrupt on overflow. And some hardware has no ability to detect it. Java would have to explicitly test for it on every add, subtract and multiply, greatly slowing down production. Further ex-C programmers are very used to this cavalier ignoring of overflow, and commonly write code presuming that high order bits will be quietly dropped.

The Pentium has hardware overflow detect but no hardware interrupt. So if Java were to support overflow detect, inside the JVM implementation would need to add a JO *jump on overflow" instruction after every add and subtract, and special code to look at the high order bits of the 32x32->64 bit multiply. 64/32->32 bit division might need special handling.

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

Los comentarios publicados en este sitio expresan sólo la opinión de su autor, quien será el único responsable de los mismos. La publicación de cualquier comentario no supone en absoluto la conformidad del responsable de este sitio con su contenido.

Como norma general, en este sitio no se publican comentarios que incluyan datos personales, ni direcciones de correo, ni ninguna otra forma de establecer contactos privados o comerciales, así como comentarios que no aportan nada, fuera de tema o que no se ajustan a la netiqueta, la ortografía o la educación.

Para poder enviar tus comentarios has de permitir las cookies del sitio.

  • Etiquetas HTML permitidas: <a> <em> <strong> <ul> <ol> <li> <p> <u> <br><strike> <blockquote> <div>

Más información sobre las opciones de formato...

CAPTCHA
Esta prueba busca evitar la entrada de mensajes basura automatizados. Muchas gracias por tu colaboración.
2 + 9 =
Resuelve esta sencilla operación e introduce el resultado.