preface

This paper mainly describes some puzzles encountered in the process of reproduction and analysis of CVE-2021-26084. Secondly, a relatively complete vulnerability chain is analyzed. Due to the author’s first analysis of the Confluence vulnerabilities, unavoidable deficiencies, please comment on the section.

Confluence is a team collaboration software for knowledge sharing (WIKI) and team collaboration. Confluence refers to working environments as Spaces, such as creating a space for each project, setting user permissions, adding wikis, ideas, events, and more via Pages.

This vulnerability has multiple trigger points, but the trigger point that does not require authorization is at pages/ createpage-entervaries.vm, around which this article will analyze.

2021 Network security/penetration testing/security learning /100 SRC technical documents (full set of videos, big factory surface, boutique manuals, essential kits, routes

Environment set up

This vulnerability analysis uses the Docker environment Confluence 7.12.4 version.

Ognl expression injection analysis

Cve-2021-26084-update. sh Indicates that this patch only replaces 5 template files at the end of the vm with strings and does not change code logic. Details are as follows:

  1. Modify the confluence was/users/user – dark – the features. The vm

    value='$! action.featureKey' => value=featureKeyCopy the code

    This file has been changed in version 7.12.4

  2. Modify the confluence was/login. The vm

    value='$! action.token' => value=tokenCopy the code

    This file has been changed in version 7.12.4

  3. Modify the confluence was/pages/createpage – entervariables. Vm

    value='$! querystring' => value=querystring value='$linkCreation' => value=linkCreationCopy the code
  4. Modify the confluence was/template/custom/content – editor. The vm

    Multiple input tags were replaced with values, mainly by removing $from value

    "Hidden" "name='linkCreation'" "value='$isLinkCreation'" => "Hidden" "name='linkCreation'" "value=isLinkCreation"
    
    Copy the code
  5. Modify templates/editor-preload-container.vm in the JAR file

    value='$! {action.syncRev}' => value=syncRevCopy the code

Combined with the above 5 changes, 1 and 2 do not exist in 7.12.4, 3 and 4 trigger input tags are the same, but 4 and 5 require authorization. Therefore, trigger point no. 3 is analyzed here. The input label of trigger point No. 3 is as follows:

<form name="filltemplateform" method="POST" action="doenterpagevariables.action"> #form_xsrfToken() #tag ("Hidden" "name='queryString'" "value='$! queryString'") #tag ("Hidden" "name='templateId'" "value='$pageTemplate.id'") #tag ("Hidden" "name='linkCreation'" "value='$linkCreation'") #tag ("Hidden" "name='title'" "value=title") #tag ("Hidden" "name='parentPageId'" "value=parentPageId") #tag ("Hidden" "name='fromPageId'" "value=fromPageId") #tag ("Hidden" "name='spaceKey'" "value=spaceKey")Copy the code

Combined with github analysis [^3], the point of vulnerability is queryString, linkCreation. Looking at the six tags, I had the following question:

  • Why does queryString fire but title doesn’t, which is the role of the $symbol?
  • Pagetemplate. id also has the $symbol, why is it not the vulnerability trigger point?
  • How do I get around the single quote limit?

With these three questions in mind, I began to analyze this vulnerability in depth. Ognl.getValue is the source of the vulnerability, so I can break the ogNl. getValue code. After decomcompiling web-INF /lib, I found the following 3 places:

com/opensymphony/xwork/util/OgnlUtil.java#copy()

com/opensymphony/webwork/views/jsp/ui/OgnlTool.java#findValue()

com/opensymphony/xwork/util/OgnlValueStack.java

For this a few points on a breakpoint, I start debugging Confluence was, after tests found trigger breakpoints in the code in the com/opensymphony/xwork/util/OgnlValueStack. Java

In order to clarify the input process, need to start from the upstream analysis, as shown in figure 7, can be found here on the left to enter the WebWork doenterpagevariablesaction for processing.

Follow the handler to the Velocity template processing class, as shown in Figure 8. The template specified by finalLocation is loaded via getTemplate, and the result is written to Writer by processing the context.

Go to the processing logic of the Template class and process it by converting the syntax tree generated by the Template into a SimpleNode node. From the variables area on the right side of Figure 9, you can see that the template generated a total of eight subtrees, with the input tag in the seventh subtree.

As shown in the figure, the label is eventually processed through the AbstractTagDirective class. As shown in Figure 12, the processTag function calls evaluateParams through the doEndTag function to get the value of the relevant variable from OgnlValueStack, such as Name =queryString.

The evaluateParams function has two concerns. The first is to compute the name through nameAttr. That is, change ‘queryString’ to name=queryString

Focus on the second, namely, the calculation of value= XXX.

Enter findValue function, can be seen in figure 15 before the real expression to compute Ognl, can call a static method SafeExpressionUtil. IsSafeExpression safety checks the results of the compiled. There are four aspects:

  1. The first hashset restricts the constructor key: new, static method call: @ symbol
  2. The second and third hashsets restrict access to classloaders, such as xxx.class or xxx.getClass().
  3. The fourth Hashset restricts the presence of specific variables in the compiled results

“[“class”].forname [^4]

Figure 15 Blacklist check

Findvalue evaluates the expression through OgnlValueStack#findValue. As shown in Figure 16, OgnlUtil correctly recognizes \u0027 as’, turns the expression into a full Ognl expression, and finally calls ogNl.getValue to evaluate the expression.

Question answer

1. Processing logic of single quotes

Answer first: Tags are evaluated and evaluated from OgnlValueStack based on nameattr and valueAttr. These two attributes are set by applyAttributes. ApplyAttributes with Ognl in the context of the initial context to get the parameters to submit a value, after ConfluenceHtmlEntityEncodingPolicyHTML entity encoding class to handle. So ‘is encoded by entities, but since Ognl expressions normally handle unicode-encoded single quotes \u0027, they can be replaced with Unicode encoders.

In the second section, we analyze the full trigger flow, but note that the payload uses unicode encoding: ‘=>\u0027. So why not? See the processTag section above, as shown in Figure 17. The parameters required by processTag are passed in through Object.

Change the input to: queryString=aaa’%2b#{2*1}%2b\u0027bbb Follow up with the applyAttributes function, which creates a MAP object for subsequent property Settings with createPropertyMap, which calls the putProperty function, whose main logic is in the Node. value function.

After jumping to ASTReference’s processing logic, the execute method first values the value from the context (which is actually OgnlValueStack’s findValue). This function is not do analysis first, continue to come to EventHandlerUtil referenceInsert (enclosing RSVC, context, enclosing literal (), value), the function will use HTML entities in dealing with single quotation marks

2. The $sign function

In 1, it said:

The applyAttributes function creates a MAP object with createPropertyMap for subsequent property Settings. CreatePropertyMap calls putProperty, whose main logic is in node.value.

In order to know the difference between the $sign and the $sign, you need to know the logic of the value of Node. value. Interpolate This function evaluates whether it should be evaluated by Ognl based on the node tree attribute: interpolate, as shown in Figure 21. It evaluates the value of a queryString whose tag is: interpolate #tag (“Hidden” “name=’queryString'” “value=’$! QueryString ‘”), with the $symbol, interpolate property true, will be evaluated by Ognl.

What about title?

Title is treated as a string because $is not set. Value =title = OgnlValueStack = expr=”title”

Pagetemplate. id also has the $symbol, why is it not the vulnerability trigger point?

To clarify why $pagetemplate. id was not triggered, change the input to: templatePage= AAA \u0027%2b#{2*1}%2b\u0027bbb, truncated when rootString is pageTemplate, as shown in Figure 23. The OgnlValueStack value is null. The pageTemplate value has been set to NULL. When the value is null, nullString is used instead

Now that the value of pageTemplate in OgnlValueStack has been set, you need to break the setValue function in OgnlValueStack

After many jump, come as shown in figure 26, through OgnlRuntime. HasSetProperty function to judge whether the setting attributes.

Determines whether the method that sets the property exists

After following the function, it gets the PageVariablesAction class through the getClass method. Then check whether it has a setxxx method, such as: queryString=>setqueryString(). See Figure 27. Neither the PageVariablesAction class nor its inherited parent class has a setpageTemplate method, so pageTemplate can only be null.