Esiste un rischio reale di sfruttamento nel codice java in cui un puntatore nullo è dereferenziato

9

Sto giocando con un codice java generalmente ben scritto e analizzato, ma ci sono alcune stranezze generate dal mio strumento di scansione del codice.

So che una deviazione del puntatore nullo può mandare in crash un programma, ma supponendo che il codice sia scritto per intercettare e gestire tutte le eccezioni, qualcuno sa di un attacco reale che potrebbe utilizzare questo problema?

Frammenti di codice ricevuti con piacere: -)

    
posta Rory Alsop 04.03.2011 - 12:17
fonte

4 risposte

13

Se si tenta di utilizzare un puntatore null, Java genererà un NullPointerException . Poiché si tratta di un RuntimeException, non è necessario prenderlo, ma è possibile. Quindi per esempio

String iAmNull = null;
iAmNull.trim();

genererà una NullPointException e uscirà dal programma. Se comunque lo prendi

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

continuerà a funzionare e registrerà semplicemente l'errore (se è stato impostato un logger, ovviamente). In alternativa, è anche possibile prendere Exception e .

Gli attacchi basati su puntatori nulli in Java sono teoricamente impossibili, dal momento che Java Virtual Machine gestisce tutti i puntatori, quindi non dovrebbe essere un problema se hai un NullPointer nel tuo codice.

    
risposta data 04.03.2011 - 13:05
fonte
19

Teoricamente, qualsiasi tipo di dereferenziazione di puntatori nulli in Java attiva un NullPointerException , che può essere gestito all'interno di Java come qualsiasi altra eccezione. Questo non significa che sia buono : in pratica, è piuttosto difficile recuperare da tale eccezione, tranne rimuovendo la parte difettosa (cioè lasciando che il thread chiamante muoia o tornando a un catch- tutta la clausola). Seguire un puntatore nullo è come sovrascrivere un buffer: è ancora un bug; la differenza tra Java e i linguaggi non protetti (come C) è che Java è più aggraziato dalle conseguenze di tale errore: in particolare, l'eccezione si propagherà di nuovo allo stack delle chiamate, rilasciando i monitor (le parole chiave synchronized ) e eseguendo le clausole finally e sarà interessato solo il thread difettoso.

In pratica, tuttavia, potrebbero sorgere alcuni problemi. In che modo JVM intercetta i dereferences del puntatore nullo fino all'implementazione JVM; ma di solito le implementazioni sono le seguenti: seguono semplicemente il puntatore. Se il puntatore è null , questo porta a un accesso alla memoria nella prima pagina della memoria, che è vietata dal sistema operativo. Il sistema operativo cattura l'evento (tramite la MMU) e informa l'applicazione in modo relativamente brutale (su sistemi di tipo Unix, questo è un segnale SIGSEGV ). La JVM riceve le informazioni e le trasforma in NullPointerException .

La conversione da segnale a eccezione è una cosa complessa perché la JVM riceve solo l'indirizzo opcode offendente, che è da qualche parte nell'interprete bytecode o nel codice binario prodotto da JIT. La JVM deve individuare il metodo e lo stack di thread. Questo ha alcune belle interazioni con il modo in cui il sistema operativo mette le cose in memoria in primo luogo. Tale codice è abbastanza stabile oggigiorno, su piattaforme mainstream. Tuttavia, su una combinazione meno comune (il JDK di Sun è stato convertito in FreeBSD), a volte avevo riferimenti ai puntatori nulli per i quali JVM non era in grado di localizzare lo stack chiamante (perché il codice JVM era sintonizzato per Linux, non per FreeBSD, e apparentemente stava facendo un'ipotesi su dove dovrebbe essere lo stack, ipotesi che non è sempre stata soddisfatta su FreeBSD). La conseguenza è stata la cessazione immediata della JVM, in un modo molto spiacevole.

Un altro possibile trucchetto è che il dereferenziamento del puntatore nullo viene catturato perché l'accesso cade da qualche parte in una pagina "vietata"; vale a dire, la prima pagina dello spazio degli indirizzi. Tuttavia, quando si accede a un campo di istanza, la JVM di solito accede direttamente all'elemento di dati corretto: se il riferimento è, a livello di codice nativo, un puntatore all'indirizzo x e il campo è all'offset n nella struttura dell'oggetto, il codice leggerà i byte all'indirizzo x + n (questo dipende in realtà da come la JVM rappresenta gli oggetti internamente, ma una struttura simile a C è comune). Se la classe ha molti campi, allora n potrebbe essere maggiore della dimensione di una pagina, nel qual caso l'accesso in lettura non cadrà sulla prima pagina, ma il secondo. Ciò che accade in quella situazione dipende dal sistema operativo.

La situazione di "campo ad alto scostamento" non si presenta con gli array, perché gli accessi agli array sono controllati per lunghezza e la "lunghezza" è solitamente un tipo di campo vicino all'intestazione dell'oggetto. Inoltre, esiste un limite al numero di campi in una classe Java (esiste un limite assoluto a 65535 nel formato del file di classe, in realtà inferiore a quello perché ogni campo deve avere un nome e un tipo, che sono anche nella classe formato di file e colpirà altri limiti prima di quello). Quindi il problema non si presenterà su sistemi "comuni", ad es. un Linux che esegue Sun / Oracle VM. Questo è principalmente qualcosa di cui gli implementatori di VM devono essere consapevoli.

Quindi il mio consiglio è di considerare NullPointerException come un bug grave, proprio come un buffer overflow (che è IndexOutOfBoundsException in Java). La sicurezza della VM ti aiuterà a eseguire il debug del tuo codice (le tracce dello stack sono davvero utili) e, se non esegui il debug abbastanza prima della distribuzione, probabilmente la tua skin verrà salvata. Ma un bug è un bug.

    
risposta data 04.03.2011 - 14:49
fonte
6

CWE-476: Dereferimento puntatore NULL - afferma che l'esecuzione del codice è possibile in circostanze molto rare e gli ambienti sono possibili. Tuttavia questo non è specifico di Java. Ho controllato tutti i siti Web di exploit che posso immaginare per vedere se qualcuno ha degli exploit per Java basati su una deferenza puntatore nullo e non sono stati in grado di trovarli.

Ma guardandomi intorno mi sono imbattuto in questa pagina sul sito Cert - EXC15-J. Non prendere NullPointerException . Esse affermano che la cattura di NullPointerException è al massimo ottimale e che invece di aggiungere controlli per evitare l'eccezione è molto più lento. Quindi, a seconda dell'applicazione che potrebbe essere qualcosa che vuoi prendere in considerazione.

    
risposta data 04.03.2011 - 12:56
fonte
4

Dereferenziare qualsiasi null nel codice Java causerà un NPE. A differenza di C, non è possibile aggiungere un offset alla terra nella memoria mappata. L'NPE verrà catturato da un catch o passato al gestore delle eccezioni non catturato del thread.

Una causa delle attuali vulnerabilità in Java è l'accettazione di null s dove non dovrebbero essere. Saltare il codice per le variabili nulle è in effetti più pericoloso rispetto al proseguimento e all'NPE. Ad esempio, i riferimenti a ClassLoader sono funzionalità, ma il caricatore di classi più importante (il caricatore di classe di avvio) viene in genere indicato da null (alcune API Java aggiungono ulteriori controlli di sicurezza se un riferimento di programma di caricamento classe fornito è null ). / p>     

risposta data 04.03.2011 - 14:48
fonte

Leggi altre domande sui tag