feat: add jsp unicode packer

This commit is contained in:
ReaJason
2026-01-18 23:49:41 +08:00
parent 686be6b59a
commit c0c78c4372
6 changed files with 136 additions and 7 deletions
@@ -400,16 +400,16 @@ public class ShellAssertion {
public static void injectIsOk(String url, String shellType, String shellTool, String content, Packers packer, GenericContainer<?> container) {
switch (packer) {
case JSP, ClassLoaderJSP, DefineClassJSP -> {
case JSP, ClassLoaderJSP, ClassLoaderJSPUnicode, DefineClassJSP, DefineClassJSPUnicode -> {
String uploadEntry = url + "/upload";
String filename = shellType + shellTool + packer + ".jsp";
String shellUrl = url + "/" + filename;
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
VulTool.urlIsOk(shellUrl);
}
case JSPX -> {
case JSPX, JSPXUnicode -> {
String uploadEntry = url + "/upload";
String filename = shellType + shellTool + ".jspx";
String filename = shellType + shellTool + packer + ".jspx";
String shellUrl = url + "/" + filename;
VulTool.uploadJspFileToServer(uploadEntry, filename, content);
VulTool.urlIsOk(shellUrl);
@@ -23,10 +23,7 @@ import com.reajason.javaweb.packer.h2.H2Packer;
import com.reajason.javaweb.packer.jar.*;
import com.reajason.javaweb.packer.jexl.JEXLPacker;
import com.reajason.javaweb.packer.jinjava.JinJavaPacker;
import com.reajason.javaweb.packer.jsp.ClassLoaderJspPacker;
import com.reajason.javaweb.packer.jsp.DefineClassJspPacker;
import com.reajason.javaweb.packer.jsp.JspPacker;
import com.reajason.javaweb.packer.jsp.JspxPacker;
import com.reajason.javaweb.packer.jsp.*;
import com.reajason.javaweb.packer.jxpath.JXPathPacker;
import com.reajason.javaweb.packer.jxpath.JXPathScriptEnginePacker;
import com.reajason.javaweb.packer.jxpath.JXPathSpringGzipJDK17Packer;
@@ -79,8 +76,11 @@ public enum Packers {
*/
JSP(new JspPacker()),
ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class),
ClassLoaderJSPUnicode(new ClassLoaderJspUnicodePacker(), JspPacker.class),
DefineClassJSP(new DefineClassJspPacker(), JspPacker.class),
DefineClassJSPUnicode(new DefineClassJspUnicodePacker(), JspPacker.class),
JSPX(new JspxPacker(), JspPacker.class),
JSPXUnicode(new JspxUnicodePacker(), JspPacker.class),
/**
* BigInteger
@@ -0,0 +1,12 @@
package com.reajason.javaweb.packer.jsp;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
public class ClassLoaderJspUnicodePacker implements Packer {
@Override
public String pack(ClassPackerConfig classPackerConfig) {
return JspUnicoder.encode(Packers.ClassLoaderJSP.getInstance().pack(classPackerConfig), true);
}
}
@@ -0,0 +1,20 @@
package com.reajason.javaweb.packer.jsp;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.packer.Util;
import lombok.SneakyThrows;
/**
* @author ReaJason
* @since 2024/11/26
*/
public class DefineClassJspUnicodePacker implements Packer {
@Override
@SneakyThrows
public String pack(ClassPackerConfig config) {
return JspUnicoder.encode(Packers.DefineClassJSP.getInstance().pack(config), true);
}
}
@@ -0,0 +1,84 @@
package com.reajason.javaweb.packer.jsp;
import org.apache.commons.codec.binary.Hex;
import java.nio.charset.StandardCharsets;
public class JspUnicoder {
public static String encode(String content, boolean isJsp) {
if (content == null) {
return null;
}
StringBuilder result = new StringBuilder(content.length());
int lineStart = 0;
int length = content.length();
for (int i = 0; i < length; i++) {
if (content.charAt(i) == '\n') {
appendEncodedLine(result, content.substring(lineStart, i), isJsp);
result.append('\n');
lineStart = i + 1;
}
}
if (lineStart <= length) {
appendEncodedLine(result, content.substring(lineStart), isJsp);
}
return result.toString();
}
private static void appendEncodedLine(StringBuilder output, String line, boolean isJsp) {
if (shouldSkipLine(line, isJsp)) {
output.append(line);
return;
}
if (line.contains("page import") || line.contains("page pageEncoding") || line.contains("page contentType")) {
int firstQuote = line.indexOf('"');
int lastQuote = line.lastIndexOf('"');
if (firstQuote != -1 && lastQuote > firstQuote) {
String oldStr = line.substring(firstQuote + 1, lastQuote);
String encoded = encodeWordChars(oldStr);
output.append(line, 0, firstQuote + 1)
.append(encoded)
.append(line.substring(lastQuote));
return;
}
}
output.append(encodeWordChars(line));
}
private static boolean shouldSkipLine(String line, boolean isJsp) {
if (line == null) {
return false;
}
if (!isJsp && (line.contains("jsp:root")
|| line.contains("jsp:declaration")
|| line.contains("jsp:scriptlet")
|| line.contains("jsp:directive.page"))) {
return true;
}
return false;
}
private static String encodeWordChars(String input) {
StringBuilder encoded = new StringBuilder(input.length() * 4);
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if (isWordChar(ch)) {
encoded.append(toUnicodeEscape(ch));
} else {
encoded.append(ch);
}
}
return encoded.toString();
}
private static boolean isWordChar(char ch) {
return Character.isLetterOrDigit(ch) || ch == '_';
}
private static String toUnicodeEscape(char ch) {
byte[] bytes = String.valueOf(ch).getBytes(StandardCharsets.UTF_8);
return "\\u00" + Hex.encodeHexString(bytes);
}
}
@@ -0,0 +1,13 @@
package com.reajason.javaweb.packer.jsp;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
public class JspxUnicodePacker implements Packer {
@Override
public String pack(ClassPackerConfig classPackerConfig) {
String content = Packers.JSPX.getInstance().pack(classPackerConfig);
return JspUnicoder.encode(content, false);
}
}