
Programma di test per CVE-2014-0094 in struts1
Riassumo l'impatto di CVE-2014-0094 su Struts1. Salvo diversa indicazione, ogni versione è stata verificata con java 1.7.0_02, Struts 1.3.10, apache-tomcat-6.0.39 e FreeBSD 8.2.
In ogni caso, non garantisco il contenuto dei sorgenti, dei testi, ecc. Inoltre, non sono responsabile di qualsiasi evento possa verificarsi. In particolare, non sono in alcun modo responsabile dell'uso improprio di questo contenuto. (Anche se, a dirla tutta, non c'è nulla di particolarmente nuovo.)
Questa volta ho presentato esempi concreti di soluzioni facendo riferimento a vari siti web. Salvo i fatti già noti, ho indicato nei sorgenti gli URL di riferimento. Ringrazio coloro che hanno reso pubbliche queste informazioni.
Ho cercato di evitare il più possibile termini tecnici, usando un linguaggio semplice, anche se potrebbe esserci qualche imprecisione.
La vulnerabilità in Struts1 di cui parliamo ha vari nomi, come CVE-2014-0094, S2-020, non sono sicuro se ce ne siano altri, ma per ora la chiamerò CVE-2014-0094.
Inutile ribadirlo, CVE-2014-0094 comporta un problema molto serio.
http://www.nta.go.jp/sonota/sonota/osirase/service.htm
Secondo l'avviso di sospensione del servizio (importante) del 25 aprile 2014 per «e-Tax Software (versione WEB)», «Angolo di compilazione della dichiarazione dei redditi», «NISA (ISA giapponese)», il servizio web dell'Agenzia delle Entrate giapponese utilizzava Struts1 e ha sospeso il servizio il giorno stesso in cui è stata scoperta la vulnerabilità.
Si ritiene che la sospensione sia stata effettuata con urgenza per limitare al minimo i danni.
Avendo fatto un test di prova qui, è bastato accedere a un URL per constatare l'interruzione del servizio e la fuoriuscita di file arbitrari.
Poiché è sufficiente accedere a un URL, basta inviare a una mailing list, da un indirizzo email anonimo, un'email contenente l'URL: è difficile identificare il colpevole e si può facilmente fermare il servizio.
Un problema che può essere attaccato così facilmente, eh.
Questa è la cosa più importante. Se un ente terzo ha annunciato che probabilmente c'è un impatto, il modo corretto è fermare subito il sistema e prevenire l'espansione dei danni. Anche se un'indagine successiva rivelasse che non c'è alcun impatto, le informazioni divulgate non possono essere recuperate. Naturalmente serve un giudizio politico. Per le aziende, vengono messi alla prova etica, sensibilità quotidiana ai problemi, gestione del rischio, ecc.
Questo problema deriva dal fatto che è possibile riscrivere parte dei valori di configurazione del sistema. È necessario indagare quali valori di configurazione possono essere riscritti. In base a tali valori si determina quali attacchi sono possibili.
Questi valori di configurazione variano a seconda del contenitore Servlet. In Tomcat 6 l'esecuzione di codice arbitrario è probabilmente impossibile, ma in Tomcat 8 è possibile eseguire codice arbitrario. Inoltre, a seconda dell'ambiente utilizzato, come Jetty, WebSphere Application Server, ecc., è necessario verificare quali valori di configurazione esistono.
Nel caso di Tomcat 6, si ritiene che siano possibili 23 modifiche di configurazione di questo tipo; se si modifica class.classLoader.resources.dirContext.docBase il normale funzionamento del sistema diventa impossibile e, invece di mostrare una JSP, specificando un file sul server diventa possibile ottenere (far fuoriuscire) file arbitrari.
Nel caso di Tomcat 8 è possibile eseguire codice arbitrario, perché i valori configurabili sono aumentati rispetto a Tomcat 6. Se tali valori di configurazione non esistono nel contenitore Servlet utilizzato, per ora si ritiene che i problemi siano limitati.
Questa modifica dei valori di configurazione può essere effettuata non solo inserendo la stringa nell'URL, ma anche come campo nascosto di una normale richiesta, e pare sia possibile anche includendo il valore nei cookie.
Dai log di accesso non è possibile capire se è stato usato un campo nascosto.
Spesso i riavvii vengono eseguiti a tarda notte la domenica; se poco prima vengono effettuate la riscrittura di docBase e l'acquisizione di file, e poi il sistema viene riavviato, per un amministratore di sistema è difficile notare l'anomalia. Se in quella fascia oraria si verificano molti status 404, 500, ecc., è probabile che sia stato esfiltrato qualche file.
Il supporto per Struts1 è terminato (tralasciando la questione "cosa significa supporto per l'open source?"), quindi non sono disponibili patch di sicurezza. È necessario risolvere il problema con le proprie forze.
L'origine del problema è BeanUtil; è necessario implementare un meccanismo che ignori le stringhe inappropriate che vi giungono. BeanUtil è uno strumento che modifica i valori di configurazione degli oggetti (una descrizione piuttosto imprecisa).
Gli esempi di implementazione sono
com.haselab.struts.filter
web.xml
Spiegando brevemente, in web.xml si richiama un programma che all'avvio del sistema modifica il comportamento di BeanUtil. Viene richiamato SafeResolverListener.java, e d'ora in poi BeanUtil userà SafeResolver.java. In SafeResolver.java, se la stringa da analizzare è (senza distinzione tra maiuscole e minuscole) 'classLoader', viene restituito "". In altre parole, si impedisce l'impostazione di valori arbitrari per classLoader. Per questo comportamento https://gist.github.com/nakamura-to/11347570 è stato preso come riferimento. (Essendo un programma breve, è stato usato così com'è.)
Se l'applicazione dovesse aver bisogno di modificare un'impostazione chiamata classLoader, questo metodo non lo consentirebbe, quindi non è una soluzione in quel caso. Ma in generale, primo, è improbabile che un'impostazione venga chiamata classLoader, quindi per ora non ci sono problemi. Se siete preoccupati, potete verificare su tutti i sorgenti dell'applicazione: grep -r -i classLoader * e assicurarvi che non esista nulla di simile.
Ho verificato la riscrittura di docBase. Dopo il deploy con mvn, guardate la directory struts nel browser. A ogni pressione del pulsante vengono eseguiti la riscrittura di docBase e la visualizzazione del file /etc/passwd.