it-swarm-es.com

¿Existe un riesgo real de explotación en el código Java donde un puntero nulo está desreferenciado

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

Sé que una desreferencia de puntero nulo puede bloquear un programa, pero suponiendo 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 :-)

9
Rory Alsop

Si intenta usar un puntero que es nulo, Java arrojará un NullPointerException . Como se trata de una RuntimeException, no tiene que atraparlo, pero puede . Así por ejemplo

String iAmNull = null;
iAmNull.trim();

lanzará una NullPointException y saldrá del programa. Sin embargo, si 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 ha configurado un registrador, por supuesto). Alternativamente, también es posible atrapar Exception e.

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

13
Andreas Arnold

Teóricamente, cualquier tipo de desreferenciación de puntero nulo en Java activa un NullPointerException, que puede manejarse dentro de Java como cualquier otra excepción. Esto no significa que esto sea bueno: en la práctica, es bastante difícil recuperarse de tal excepción, excepto quitando la parte defectuosa (es decir, dejando que el hilo de llamada muera o volviendo a una captura- cláusula completa). Seguir un puntero nulo es similar a desbordar un búfer: sigue siendo un error; la diferencia aquí entre Java y lenguajes no protegidos (como C) es que Java es más elegante sobre las consecuencias de ese error: en particular, la excepción propagará la pila de llamadas, liberará monitores (las palabras clave synchronized) y ejecutará el finally cláusulas, y solo el hilo defectuoso se verá afectado.

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

La conversión de la señal a la excepción es algo complejo porque la JVM solo recibe la dirección de código de operación ofensiva, que está en algún lugar del intérprete de código de bytes o en el código binario producido por JIT. La JVM debe ubicar el método y la pila de subprocesos. 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 hoy en día, en las plataformas principales. Sin embargo, en una combinación menos común (JDK de Sun portado a FreeBSD), a veces tenía desreferencia de puntero nulo para el cual JVM no pudo localizar la pila de llamantes (porque el código 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 terminación inmediata de JVM, de la manera más desagradable.

Otro posible problema es que la desreferencia de puntero nulo se detecta porque el acceso cae 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 a la dirección x, y el campo está en desplazamiento n en la estructura del objeto, entonces el código leerá bytes en la dirección x + n (esto realmente depende de cómo la JVM representa los objetos internamente, pero una estructura tipo C es común). Si la clase tiene muchos campos, entonces n puede ser mayor que el tamaño de una página, en cuyo caso el acceso de lectura no estará en la primera página, sino en la segunda. Lo que sucede en esa situación depende del sistema operativo.

La situación de "campo en alto desplazamiento" no surge con las matrices, porque los accesos a las matrices se verifican por longitud y la "longitud" suele ser 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 Java clase (hay un límite absoluto a 65535 en el formato de archivo de clase, en realidad más bajo que eso porque cada campo debe tener un nombre y un tipo, que también está en el formato de archivo de clase y alcanzará otros límites antes de eso). Por lo tanto, el problema no surgirá en sistemas "comunes", por ejemplo, un Linux que ejecuta Sun/Oracle VM. Esto es principalmente algo que VM deben tener en cuenta.

Entonces, mi consejo es considerar NullPointerException como un error grave, al igual que un desbordamiento de búfer (que es IndexOutOfBoundsException en Java). La seguridad VM) lo ayudará a depurar su código (los seguimientos de pila son realmente útiles) y, si no depuró lo suficiente antes de la implementación, probablemente salvará su máscara. Pero un error es un error.

20
Thomas Pornin

CWE-476: NULL Pointer Dereference - establece que la ejecución del código es posible en circunstancias muy raras y que es posible hacerlo en entornos. Sin embargo, esto no es específico de Java. Revisé todos los sitios web de exploits en los que puedo pensar para ver si alguno tiene exploits para Java basado en una deferencia de puntero nulo y no he podido encontrar ninguno.

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

6
Mark Davidson

Desreferenciar cualquier null en Java causará un NPE. A diferencia de C, no hay forma de agregar un desplazamiento para aterrizar en la memoria asignada. El NPE será capturado por un atrapar o pasar al controlador de excepciones no capturado del hilo.

Una causa de vulnerabilidades reales en Java está aceptando nulls donde no deberían estar. Omitir código para variables nulas es, de hecho, más peligroso que continuar y NPEing. Por ejemplo, ClassLoader las referencias son capacidades, pero el cargador de clases más importante (el cargador de clases de arranque) generalmente se indica mediante null (algunas Java APIs agregan comprobaciones de seguridad adicionales si una referencia de cargador de clases suministrada es null).

4