¿Existe un riesgo real de explotación en el código Java cuando se hace referencia a un puntero nulo?

9

Estoy jugando con un código Java generalmente bien escrito y analizado, pero mi herramienta de escaneo de códigos arroja algunas rarezas.

Sé que una falta de referencia de puntero nulo puede bloquear un programa, pero asumiendo que el código está escrito para capturar y administrar todas las excepciones, ¿alguien sabe de un ataque real que pueda usar este problema?

Fragmentos de código recibidos con gratitud :-)

    
pregunta Rory Alsop 04.03.2011 - 12:17
fuente

4 respuestas

13

Si intenta usar un puntero que es nulo, Java lanzará un NullPointerException . Ya que esta es una excepción RuntimeException, no tiene que atraparla, pero puede hacerlo. Así, por ejemplo,

String iAmNull = null;
iAmNull.trim();

lanzará una NullPointException y saldrá del programa. Si por el contrario lo atrapas

try {
    String iAmNull = null;<br>
    iAmNull.trim();<br>
} catch (NullPointerException e) {
    log.warn("Null pointer in method x")
}

continuará ejecutándose y simplemente registrará el error (si, por supuesto, ha configurado un registrador). Alternativamente, también es posible capturar Exception e .

Los ataques basados en punteros nulos en Java son teóricamente imposibles, ya que la Máquina Virtual de Java maneja todos los punteros, por lo que no debería ser un problema si tiene un NullPointer en su código.

    
respondido por el Andreas Arnold 04.03.2011 - 13:05
fuente
19

Teóricamente, cualquier tipo de desreferenciación de puntero nulo en Java desencadena un NullPointerException , que puede manejarse dentro de Java como cualquier otra excepción. Esto no significa que sea bueno : en la práctica, es bastante difícil recuperarse de tal excepción, excepto eliminando la parte defectuosa (es decir, dejar que el hilo de llamada muera o volver a un retén). toda la cláusula). Seguir un puntero nulo es similar a anular un búfer: sigue siendo un error; La diferencia entre Java y los lenguajes no protegidos (como C) es que Java es más gracioso sobre las consecuencias de ese error: en particular, la excepción propagará la pila de llamadas, liberando monitores (las palabras clave synchronized ) y ejecutando las cláusulas finally , y solo se verá afectado el subproceso defectuoso.

En la práctica, sin embargo, pueden surgir algunos problemas. Cómo la JVM atrapa las referencias erróneas de punteros nulos depende de la implementación de JVM; pero lo que suelen hacer las implementaciones es lo siguiente: simplemente siguen el puntero. Si el puntero es null , esto conduce a un acceso a la memoria en la primera página de la memoria, lo cual está prohibido por el sistema operativo. El sistema operativo detecta la aparición (a través de la MMU) e informa a la aplicación de una manera relativamente brutal (en sistemas similares a Unix, esta es una señal SIGSEGV ). La JVM recibe la información y la transforma en un NullPointerException .

La conversión de señal a excepción es algo complejo porque la JVM solo recibe la dirección del código de operación ofensiva, que se encuentra en algún lugar en el intérprete de bytecode o en el código binario producido por JIT. La JVM debe ubicar el método y la pila de hilos. Esto tiene algunas buenas interacciones con cómo el sistema operativo pone las cosas en la memoria en primer lugar. Tal código es bastante estable en la actualidad, en plataformas convencionales. Sin embargo, en una combinación menos común (el JDK de Sun portado a FreeBSD), a veces tuve desreferencias de puntero nulo para las cuales el JVM no pudo localizar la pila de llamantes (porque el código de JVM estaba sintonizado para Linux, no para FreeBSD, y aparentemente estaba haciendo una suposición sobre dónde debería estar la pila, suposición que no siempre se cumplió en FreeBSD). La consecuencia fue la finalización inmediata de JVM, de la manera más ingrata.

Otro posible error es que la desviación del puntero nulo se atrapa porque el acceso se encuentra en algún lugar de una página "prohibida"; A saber, la primera página del espacio de direcciones. Sin embargo, al acceder a un campo de instancia, la JVM generalmente accede directamente al elemento de datos correcto: si la referencia es, a nivel de código nativo, un puntero para direccionar x , y el campo está en desplazamiento n en la estructura del objeto, entonces el código leerá los bytes en la dirección x + n (esto realmente depende de cómo JVM representa los objetos internamente, pero una estructura tipo C es común). Si la clase tiene muchos campos, n puede ser más grande que el tamaño de una página, en cuyo caso el acceso de lectura no caerá en la primera página, sino en la segunda. Lo que sucede en esa situación depende del sistema operativo.

La situación del "campo en alto desplazamiento" no se presenta con las matrices, ya que los accesos a la matriz se controlan por longitud y la "longitud" es generalmente un tipo de campo que está cerca del encabezado del objeto. Además, hay un límite en el número de campos en una clase de Java (hay un límite absoluto a 65535 en el formato de archivo de clase, en realidad menor que eso porque cada campo debe tener un nombre y un tipo, que también están en la clase formato de archivo y llegará a otros límites antes de eso). Por lo tanto, el problema no surgirá en los sistemas "comunes", por ejemplo, Un Linux ejecutando Sun / Oracle VM. Esto es principalmente algo que los implementadores de máquinas virtuales deben tener en cuenta.

Por lo tanto, mi consejo es considerar NullPointerException como un error grave, como un desbordamiento de búfer (que es IndexOutOfBoundsException en Java). La seguridad de la máquina virtual le ayudará a depurar su código (los seguimientos de pila son realmente útiles) y, si no realizó la depuración suficiente antes de la implementación, es probable que guarde su aspecto. Pero un error es un error.

    
respondido por el Thomas Pornin 04.03.2011 - 14:49
fuente
6

CWE-476: Desreferencia de puntero nulo : indica que la ejecución del código es posible en circunstancias muy raras y Los ambientes son posibles. Sin embargo, esto no es específico de Java. He comprobado todos los sitios web de exploits que se me ocurren para ver si alguno tiene exploits para Java basados en una deferencia de puntero nulo y no he podido encontrar ninguno.

Pero mientras miraba alrededor, me encontré con esta página en el sitio de Cert - EXC15-J. No atrapar NullPointerException . Afirman que la captura de la NullPointerException es, en el mejor de los casos, subóptima y que en lugar de agregar controles para evitar la excepción es significativamente más lenta. Entonces, dependiendo de tu aplicación, eso puede ser algo que quieras considerar.

    
respondido por el Mark Davidson 04.03.2011 - 12:56
fuente
4

La desreferenciación de cualquier null en el código Java causará un NPE. A diferencia de C, no hay manera de agregar un desplazamiento para aterrizar en la memoria asignada. El NPE será atrapado por un retén o pasará al controlador de excepciones no capturado del subproceso.

Una causa de las vulnerabilidades reales en Java es aceptar null s donde no deberían estar. El código de omisión para variables nulas es, de hecho, más peligroso que seguir y NPEing. Por ejemplo, las referencias ClassLoader son capacidades, pero el cargador de clases más importante (el cargador de clases de arranque) generalmente se indica mediante null (algunas API de Java agregan comprobaciones de seguridad adicionales si una referencia del cargador de clases suministrada es null ). / p>     

respondido por el Tom Hawtin - tackline 04.03.2011 - 14:48
fuente

Lea otras preguntas en las etiquetas