Struts(S-16/17)远程命令执行漏洞分析
之前winwin已经发过这个漏洞的分析文章,分析的很到位,不过有几个点有些问题,所以我在这里把自己的分析内容发出来,供各位参考。
这个漏洞的数据污染点和触发点,和其他的Struts不一样,所以本篇分析将从Struts执行流程中剖析此漏洞。在Struts2.3以后,官方将原有的起始过滤器换为:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.class
所以我们此次跟踪的第一个断点便下在这个类的doFilter方法中,代码如下:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
[color=Red]ActionMapping mapping = prepare.findActionMapping(request, response, true);[/color]
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
if (mapping == null || forceLookup) {
try {
[color=Red]mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());[/color]
if (mapping != null) {
request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
}
} catch (Exception ex) {
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
}
}
return mapping;
}
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
ActionMapping mapping = new ActionMapping();
String uri = getUri(request);
int indexOfSemicolon = uri.indexOf(";");
uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
uri = dropExtension(uri, mapping);
if (uri == null) {
return null;
}
parseNameAndNamespace(uri, mapping, configManager);
[color=Red] handleSpecialParameters(request, mapping);[/color]
return parseActionName(mapping);
}
public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) {
// handle special parameter prefixes.
Set<String> uniqueParameters = new HashSet<String>();
Map parameterMap = request.getParameterMap();
for (Object o : parameterMap.keySet()) {
String key = (String) o;
// Strip off the image button location info, if found
if (key.endsWith(".x") || key.endsWith(".y")) {
key = key.substring(0, key.length() - 2);
}
// Ensure a parameter doesn't get processed twice
if (!uniqueParameters.contains(key)) {
ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key);
if (parameterAction != null) {
[color=Red] parameterAction.execute(key, mapping);[/color]
uniqueParameters.add(key);
break;
}
}
}
public void execute(String key, ActionMapping mapping) {
ServletRedirectResult redirect = new ServletRedirectResult();
container.inject(redirect);
redirect.setLocation(key.substring(REDIRECT_PREFIX
.length()));
mapping.setResult(redirect);
}
问题的关键点就在这个result属性中,Struts在处理action后,返回的内容都是依赖result属性中的内容。平常这个属性都是通过配置文件来设置的,但是在这里,用户可以通过redirect来控制这个属性的内容。而且,用来解析返回内容的conditionalParse方法使用了translateVariables方法处理参数,这个方法会将其参数作为Ognl表达式执行,从而导致此漏洞的触发。conditionalParse方法代码如下:
protected String conditionalParse(String param, ActionInvocation invocation) {
if (parse && param != null && invocation != null) {
return TextParseUtil.translateVariables(param, invocation.getStack(),
new TextParseUtil.ParsedValueEvaluator() {
public Object evaluate(String parsedValue) {
if (encode) {
if (parsedValue != null) {
try {
// use UTF-8 as this is the recommended encoding by W3C to
// avoid incompatibilities.
return URLEncoder.encode(parsedValue, "UTF-8");
}
catch(UnsupportedEncodingException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("error while trying to encode ["+parsedValue+"]", e);
}
}
}
}
return parsedValue;
}
});
} else {
return param;
}
}
评论11次
呵呵 俺正需要此类文章。。。。。敢问楼主 90sec哪位大牛分析得不错。。。
我也承认我也色盲了
我也色盲了的呢
新洞~~~~~~~~~~~????????
顶一个。。。
悲剧的struts
祝你早日挖到新的漏洞
顶一个
这真不能赖我
我也色盲了
莫非我色盲了?