一、使用Dongtai-IAST检测S2-008漏洞
1. 启动在线靶场
登陆在线靶场:http://labs.iast.huoxian.cn:8081,启动S2-008环境,等待环境启动之后,点击访问靶场按钮即可前往靶场环境。该环境来源于vulhub和vulapps

2. 登陆**洞态IAST**
网站:http://iast.huoxian.cn:8000/,查看漏洞检测结果

3. 进入搜索功能,分析完整的污点调用图
3.1 Source点
首先,在org.apache.struts2.dispatcher.mapper.DefaultActionMapper#handleSpecialParameters()
方法中,调用Servlet
接口的getParameterMap
方法获取外部参数,形成初始污点

3.2 Propagator方法
污点经过一系列的处理,最终在com.opensymphony.xwork2.util.OgnlUtil#compile
方法中,调用ognl.Ognl#parseExpression
方法将污点数据传播为Ognl表达式对象

3.3 Sink方法
最后,在ognl.Ognl#getValue
方法中,使用Ognl表达式对象的getValue
方法获取Ognl表达式的值

二、S2-009 devmod漏洞手工分析
首先,使用struts.xml开启devmod
<struts>
<!-- <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
<constant name="struts.devMode" value="true" />
...
通过官方的描述是在DebuggingInterceptor这个类里。

private final static String XML_MODE = "xml";
private final static String CONSOLE_MODE = "console";
private final static String COMMAND_MODE = "command";
private final static String BROWSER_MODE = "browser";
private final static String SESSION_KEY = "org.apache.struts2.interceptor.debugging.VALUE_STACK";
private final static String DEBUG_PARAM = "debug";
private final static String OBJECT_PARAM = "object";
private final static String EXPRESSION_PARAM = "expression";
private final static String DECORATE_PARAM = "decorate";
先是定义了一大堆常量。然后获取参数。
boolean actionOnly = false;
boolean cont = true;
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
boolean devMode = devModeOverride != null ? devModeOverride.booleanValue() : this.devMode;
if (devMode) {
final ActionContext ctx = ActionContext.getContext();
String type = getParameter(DEBUG_PARAM);
ctx.getParameters().remove(DEBUG_PARAM);
....
因为type是command所以进到这个判断语句
else if (COMMAND_MODE.equals(type)) {
ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
if (stack == null) {
//allows it to be embedded on another page
stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
ctx.getSession().put(SESSION_KEY, stack);
}
String cmd = getParameter(EXPRESSION_PARAM);
ServletActionContext.getRequest().setAttribute("decorator", "none");
HttpServletResponse res = ServletActionContext.getResponse();
res.setContentType("text/plain");
try {
PrintWriter writer =
ServletActionContext.getResponse().getWriter();
writer.print(stack.findValue(cmd));
writer.close();
} catch (IOException ex) {
ex.printStackTrace();
}
可以看到使用cmd
String类型变量来存放expression
参数的值。然后stack.findValue(cmd)
。
然后findValue(String expr)
调findValue(String expr, boolean throwExceptionOnFailure)
public Object findValue(String expr) {
return findValue(expr, false);
}
public Object findValue(String expr, boolean throwExceptionOnFailure) {
try {
setupExceptionOnFailure(throwExceptionOnFailure);
return tryFindValueWhenExpressionIsNotNull(expr);
} catch (OgnlException e) {
return handleOgnlException(expr, throwExceptionOnFailure, e);
} catch (Exception e) {
return handleOtherException(expr, throwExceptionOnFailure, e);
} finally {
ReflectionContextState.clear(context);
}
}
接着调用tryFindValueWhenExpressionIsNotNull(expr)
private Object tryFindValueWhenExpressionIsNotNull(String expr) throws OgnlException {
if (expr == null) {
return null;
}
return tryFindValue(expr);
}
接着调用tryFindValue(expr)
private Object tryFindValue(String expr) throws OgnlException {
Object value;
expr = lookupForOverrides(expr);
if (defaultType != null) {
value = findValue(expr, defaultType);
} else {
value = getValueUsingOgnl(expr);
if (value == null) {
value = findInContext(expr);
}
}
return value;
}
接着调用getValueUsingOgnl
private Object getValueUsingOgnl(String expr) throws OgnlException {
try {
return ognlUtil.getValue(expr, context, root);
} finally {
context.remove(THROW_EXCEPTION_ON_FAILURE);
}
}
接着调用ognlUtil.getValue(expr, context, root)
就又到了
public Object getValue(String name, Map<String, Object> context, Object root) throws OgnlException {
return Ognl.getValue(compile(name), context, root);
}
和之前的001都一样了。
账号申请

- 洞态IAST合作伙伴计划之整体开源联合开发,申请方式请扫描下方二维码
g)
- 如需加入技术讨论群,扫描二维码添加微信并备注"洞态IAST-加群",工作人员将拉您进群

本文迁移自知识星球“火线Zone”