La serializzazione Java è un meccanismo per trasformare un oggetto in un flusso di byte. La deserializzazione Java è esattamente il contrario e ci consente di ricreare un oggetto da un flusso di byte. La serializzazione Java—e più specificamente la deserializzazione in Java-è anche conosciuta come ” il dono che continua a dare”. Questo si riferisce ai molti problemi di sicurezza e altri problemi che ha prodotto nel corso degli anni.,
Che cos’è la serializzazione in Java?
In Java, creiamo oggetti. Questi oggetti vivono in memoria e vengono rimossi dal garbage collector una volta che non vengono più utilizzati. Se vogliamo trasferire un oggetto, ad esempio, memorizzarlo su un disco o inviarlo su una rete, dobbiamo trasformarlo in un flusso di byte. Per fare ciò, la classe di quell’oggetto deve implementare l’interfaccia Serializable
. La serializzazione sta convertendo lo stato di un oggetto in un flusso di byte. Questo flusso di byte non contiene il codice effettivo.,
Che cos’è la deserializzazione in Java?
La deserializzazione è esattamente l’opposto della serializzazione. Con la deserializzazione, si dispone di un flusso di byte e si ricrea l’oggetto nello stesso stato di quando lo si serializza. Ciò significa che è necessario avere la definizione effettiva dell’oggetto per realizzare la ricreazione.
Come funziona la serializzazione Java?
La serializzazione Java utilizza reflection per raschiare tutti i dati dai campi dell’oggetto che devono essere serializzati. Questo include i campi privati e finali., Se un campo contiene un oggetto, tale oggetto viene serializzato in modo ricorsivo. Anche se potresti avere getter e setter, queste funzioni non vengono utilizzate quando si serializza un oggetto in Java.
Come funziona la deserializzazione Java?
Quando deserializza un flusso di byte su un oggetto, non utilizza il costruttore. Crea un oggetto vuoto e utilizza reflection per scrivere i dati nei campi. Proprio come con la serializzazione, sono inclusi anche i campi private e final.
Che cos’è una vulnerabilità Java deserialize?,
Una vulnerabilità di deserializzazione Java è una vulnerabilità di sicurezza che si verifica quando un utente malintenzionato tenta di inserire un oggetto serializzato modificato nel sistema che alla fine compromette il sistema oi suoi dati. Pensa all’esecuzione arbitraria di codice che può essere attivata quando si deserializza un oggetto serializzato. Per spiegare meglio Java deserializzare le vulnerabilità, abbiamo prima bisogno di esplorare come funziona la deserializzazione in Java.
Spiegare Java deserializzare vulnerabilità
Un oggetto serializzato in Java è un array di byte con informazioni dello stato., Contiene il nome dell’oggetto a cui si riferisce e i dati del campo. Se si guarda un oggetto serializzato memorizzato con un editor esadecimale, è possibile racchiudere e manipolare rapidamente le informazioni.
Sappiamo già che la deserializzazione Java non utilizza il costruttore per creare un oggetto, ma piuttosto utilizza la riflessione per caricare i campi. Ciò significa che qualsiasi controllo di convalida eseguito nel costruttore non viene mai chiamato quando si ricrea l’oggetto. Puoi pensare a controlli come data di inizio prima della data di fine quando descrivi un periodo., Quando si deserializza un oggetto Java, questo nuovo oggetto può avere uno stato non valido.
Diamo un’occhiata al seguente esempio di vulnerabilità Java deserialize in cui serializziamo un oggetto da una classe serializzabileValueObject
:
Quando si legge il fileValueObject.ser
contenente l’oggetto serializzato con un editor esadecimale l’output è questo.
Ora posso facilmente manipolare il valore della stringa. Di seguito lo cambio da Hi
aHallo
.,
Quando si deserializza il file binario regolato, scopriamo che l’oggettovalue
è cambiato. Vediamo anche che il timestamp non è cambiato, dimostrando che il costruttore non viene mai chiamato. Quindi, se un’applicazione accetta oggetti serializzati, è relativamente facile temperare con i valori. Alterando gli oggetti serializzati, possiamo creare oggetti non validi, compromettere l’integrità dei dati o anche peggio.,
Esecuzione arbitraria di codice, gadget e catene
La manomissione dei dati in un oggetto è già dannosa. Tuttavia, questo può anche portare all’esecuzione del codice se il set corretto di oggetti è deserializzato. Per spiegare questo devo prima spiegare gadget e catene.
Gadget
Un gadget—come usato da Lawrence& Frohoff nel loro discorso Marschalling Pickle a AppSecCali 2015—è una classe o una funzione che ha già codice eseguibile esistente presente nel processo vulnerabile. Questo codice eseguibile esistente può essere riutilizzato per scopi dannosi., Se osserviamo oggetti serializzabili Java, alcuni metodi magici, come il metodo privato readObject()
, vengono chiamati in modo riflessivo durante la deserializzazione.
Diamo un’occhiata al gadget semplificato di seguito:
Questa classe di gadget sovrascrive il metodoreadObject
predefinito. Di conseguenza, ogni volta che un oggetto di Gadget di classe viene deserializzato, viene eseguito il comando oggetto Runnable
. Quando una classe di comando assomiglia all’esempio seguente, è facile manipolare questo oggetto serializzato ed eseguire l’iniezione di codice.,
Inoltre, si noti che se un’applicazione accetta oggetti serializzati, l’oggetto viene deserializzato prima di essere lanciato al tipo desiderato. Ciò significa che anche se il casting fallisce, la deserializzazione è già completata e viene eseguito il metodo readObject()
.
Attacco di deserializzazione delle catene di gadget
Un tipico attacco di deserializzazione consiste in una catena di gadget abilmente creata. Un utente malintenzionato cerca un gadget utilizzabile per lanciare un attacco e incatena diverse esecuzioni che terminano con l’esecuzione di codice arbitrario, ad esempio.,
Nel nostro esempio:
Gadget -> readObject() -> command.run() -> Runtime.getRuntime().exec()
Per un esempio più reale, dai un’occhiata all’implementazione di java.util.HashMap
. Questa classe ha un’implementazione personalizzata del metodoreadObject()
che attiva la funzionehashcode()
di ogni chiave.
Librerie
È bene sapere che qualsiasi catena di gadget sia disponibile nella tua applicazione, non è correlata al tuo codice., Poiché importiamo molto codice da librerie e framework, il numero di classi importate dalle dipendenze (transitive) influenza la possibilità di determinate catene di gadget. Anche se la creazione di una tale catena di gadget dannoso è molto difficile e ad alta intensità di lavoro, vulnerabilità di deserializzazione Java sono un rischio per la sicurezza genuino e pericoloso.
Come prevenire una vulnerabilità di deserializzazione Java?
Il modo migliore per prevenire una vulnerabilità di deserializzazione Java è prevenire la serializzazione Java in generale. Se l’applicazione non accetta oggetti serializzati, non può danneggiarti.,
Tuttavia, se è necessario implementare l’interfaccia serializzabile a causa dell’ereditarietà, è possibile sovrascriverereadObject()
, come visto di seguito, per impedire l’effettiva deserializzazione.
Se l’applicazione si basa su oggetti serializzati, è possibile esaminare il ObjectInputStream
prima di deserializzare. Una libreria che può aiutarti in questo è la libreria Apache Commons IO. Questa libreria fornisce un ValidatedObjectInputStream
in cui è possibile consentire esplicitamente gli oggetti che si desidera deserializzare. Ora previeni che i tipi imprevisti siano deserializzati.,
Uno strumento come ysoserial è anche estremamente utile per trovare Java deserializzare le vulnerabilità nel codice. È uno strumento che genera payload per scoprire catene di gadget nelle comuni librerie Java che possono, nelle giuste condizioni, sfruttare le applicazioni Java che eseguono una deserializzazione non sicura degli oggetti.
Si noti che le vulnerabilità di deserializzazione Java non sono esclusive dell’implementazione di serializzazione personalizzata di Java. Sebbene questo articolo si concentri solo su questa parte, le stesse vulnerabilità esistono nei framework di serializzazione o marshalling che gestiscono questo per te., Se esiste un framework che crea magicamente POJO da XML, JSON, yaml o formati simili, probabilmente utilizza la riflessione nello stesso modo descritto sopra. Ciò significa che esistono gli stessi problemi.