Strut2-001
Vulnerability description
When the framework parses the JSP page tag, it will obtain the Value value entered by the user. In obtaining the corresponding Value value, it recursively parses% {,}, resulting in secondary parsing, and finally triggers the expression injection vulnerability to execute arbitrary code
Impact version
2.0.1 ~ 2.0.8
Vulnerability analysis
The environment has been built for a long time... The last one I saw https://xz.aliyun.com/t/2672#toc-2, only success, do not know where the mistake is. Finally, it is found that it is also related to the version of tomcat
Suggestion: if the environment can be built, don't go too deep into why. Don't deviate from the main line -- analyze vulnerabilities
Data flow in struts 2: request - < filterStack - > action - < view - > Client
-
First, navigate directly to the doFilter method in the parametersintector
-
Parametersintector first establishes a value stack and stores values through setParameters (for backdoor use, check directly from the value stack)
-
After a series of interceptors, the data will successfully enter the actual business Action. The program will select the corresponding JSP view to display according to the Action processing results, and process the struts 2 tag in the view. As shown in the following figure, in this example, the Action will return error when the user fails to log in.
Then start processing the struts 2 tag in index and JSP
That is, the so-called label rendering, which replaces the label with the established target syntax through file parsing
/** TextParseUtil#translateVariables()analysis */ public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) { // deal with the "pure" expressions first! //expression = expression.trim(); Object result = expression; while (true) { int start = expression.indexOf(open + "{"); int length = expression.length(); int x = start + 2; int end; char c; int count = 1; while (start != -1 && x < length && count != 0) { c = expression.charAt(x++); if (c == '{') { count++; } else if (c == '}') { count--; } } end = x - 1; if ((start != -1) && (end != -1) && (count == 0)) { String var = expression.substring(start + 2, end); Object o = stack.findValue(var, asType); if (evaluator != null) { o = evaluator.evaluate(o); } String left = expression.substring(0, start); String right = expression.substring(end + 1); if (o != null) { if (TextUtils.stringSet(left)) { result = left + o; } else { result = o; } if (TextUtils.stringSet(right)) { result = result + right; } expression = left + o + right; } else { // the variable doesn't exist, so don't display anything result = left + right; expression = left + right; } } else { break; } } return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType); }
The general flow of the above function is to find% {param}, then extract the middle content, truncate the strings on the left and right sides of% {} and divide them into left and right, findValue param, and re splice left+value(param)+right. If not, directly splice the left and right sides. This is a normal tag processing logic (those who have learned the compilation principle should be familiar with it).
Vulnerability: if the parameter value passed in is% {1 + 1} and reaches 29L: findValue(var, asType), recursive parsing will be performed again (it feels similar to ssti) to trigger Expression Inject
Exploit vulnerability
payload:
%{(new java.lang.ProcessBuilder(new java.lang.String[]{"calc.exe"})).start()}
Replace calc.exe with another to execute any command
Vulnerability repair
The cause of the vulnerability is nothing more than recursive parsing of strings. So just don't let it parse recursively.
Finally, the official gives the above fix, that is, limit the default number of recursion, rather than prohibit recursion. Guess the official should be to avoid recursive parsing in some cases, leaving room for it.