契约锁分析

补丁分析(找线索)

链接地址

https://www.qiyuesuo.com/more/security/servicepack

说明书

方式一 脚本自动化升级 1.停服务,然后检查下libs下是否存在老版本的安全补丁包:private-security-patch.jar(这一步非常 重要),如果有直接删除 2.进入解压后的文件夹可以看到如下结构,双击执行install.bat 文件,然后按照提示输入,以下假定应用 的安装目录为E:\qiyuesuo 为例子 VERSION.pdf INSTALL.pdf private-security-patch.jar private-security-loader-2.jar install.sh 3.把loader包复制到libs目录下进行覆盖,private-security-loader-xxx.jar 4.如果内网情况下 还需要一步,新建一个文件夹security,然后把新版本的private-security-patch.jar 包 放入 5.启动服务 备注:确认是否成功加载通过看日志,日志的确认方式和linux 也是一样的 # cd 到应用目录,请主要当前用户,需要使用qiyuesuo用户 1) cd /opt/qiyuesuo # 新建文件夹 security 2) mkdir security # 把private-security-patch.jar 包复制到security中 # 复制完成之后 等待大概30s 然后查看日志打出上述,内容,说明补丁包已经安装上,如果等待超过三分 钟,这些日志还是没有打印,则直接重启 ... INFO c.q.s.p.loader.SecurityLibManager 179 - 被重新加载的类 ======>com.qiyuesuo.security.patch.common.util.QiyuesuoURIStringUtils ... NFO c.q.s.p.loader.SecurityLibManager 294 - 安全类库管理器收到security-patch的版本 号:3.0.x #如下日志打印【安全包升级检测】说明loader已经被加载了,但是没有找到补丁包patch,等他自动下载 补丁包 INFO c.q.s.p.l.t.SecurityPatchAutoUpgradeTask 111 - 【安全包升级检测】baseVersion : WARN c.q.s.p.loader.SecurityLibManager 54 - 获取版本号失败 #有如下打印时,说明补丁包已经下载并且已经自动加载了 ... INFO c.q.s.p.loader.SecurityLibManager 179 - 被重新加载的类 ======>com.qiyuesuo.security.patch.common.util.QiyuesuoURIStringUtils ... NFO c.q.s.p.loader.SecurityLibManager 294 - 安全类库管理器收到security-patch的版本 号:3.0.x #备注:如上日志并没有全部截取,看到对应字样即可

这上面的脚本是Linux的脚本,Windows一般是直接替换,所以我直接分析jar包

jar包

我看到很多都没有看到 Windows的脚本,所以就放弃寻找了直接从Linux脚本看一下分析一下漏洞到底出在哪里还有日志分析。

这里有真实日志的部分截图,所以可以根据这个找线索。

java 复制代码
#如下日志打印【安全包升级检测】说明loader已经被加载了,但是没有找到补丁包patch,等他自动下载
补丁包
INFO c.q.s.p.l.t.SecurityPatchAutoUpgradeTask 111 - 【安全包升级检测】baseVersion
:
WARN c.q.s.p.loader.SecurityLibManager 54 - 获取版本号失败
#有如下打印时,说明补丁包已经下载并且已经自动加载了
...
INFO c.q.s.p.loader.SecurityLibManager 179 - 被重新加载的类
======>com.qiyuesuo.security.patch.common.util.QiyuesuoURIStringUtils
...
NFO c.q.s.p.loader.SecurityLibManager 294 - 安全类库管理器收到security-patch的版本
号:3.0.x
#备注:如上日志并没有全部截取,看到对应字样即可

com.qiyuesuo.security.patch.common.util.QiyuesuoURIStringUtils

被重新加载的类,可能是有问题的地方

QiyuesuoURIStringUtils

java 复制代码
String words = "hello java,hello php";
String newStr = words.replaceFirst("hello","你好 ");
System.out.println(newStr);    // 输出:你好 java,hello php
java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

//契约锁URI字符串工具类
package com.qiyuesuo.security.patch.common.util;

import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.List;
import org.springframework.util.StringUtils;

public class QiyuesuoURIStringUtils {
    private static final String HALT_REQUEST_FLAG = "HALT_REQUEST_FLAG";

//request.getParameter()方法是获取通过类似post,get等方式传入的数据,即获取客户端到服务端的数据,代表HTTP请求数据。
//获取信息头
//路径穿越?
//注册机制,可能没用,看情况
//进入入口可能有用
//资源路径不可以穿越,不然报错
//不是规不规范化的问题吧,他路由注册是绑定的,不遵循规则,你根本进不去。
    public static Object getChainStatus(HttpServletRequest request) {
        return request.getAttribute("HALT_REQUEST_FLAG");
    }

    public static void setExecutedFlag(HttpServletRequest request, int value) {
//设置信息头
        request.setAttribute("HALT_REQUEST_FLAG", value);
    }

    public static String uriProcessor(HttpServletRequest request) throws IOException {
//获取信息体url
        String uri = request.getRequestURI();
//解码
        uri = urlDecode(uri);
//获取上下文路径,比如app专属路径
        String contextPath = request.getContextPath();
//如果上下文不是空
        if (!StringUtils.isEmpty(contextPath)) {
//替换contextPath 为空
//获取有效路径
            uri = uri.replaceFirst(contextPath, "");
        }
//返回过滤的url
        return removeEndSlash(removeDuplicateSlash(uri));
    }

    public static String removeDuplicateSlash(String uri) {
//替换//为/
        return uri.contains("//") ? uri.replaceAll("/+", "/") : uri;
    }

    public static String removeEndSlash(String uri) {
//过滤/后面的东西
        return uri.endsWith("/") && uri.length() > 1 ? uri.substring(0, uri.length() - 1) : uri;
    }

    public static String urlDecode(String uri) throws IOException {
        return URLDecoder.decode(uri, "UTF-8");
    }

    public static boolean ListContainsStr(List<String> list, String str) {
        for(String keyword : list) {
            if (str.contains(keyword)) {
                return true;
            }
        }

        return false;
    }

    public static boolean ListStartWithStr(List<String> list, String str) {
        for(String keyword : list) {
            if (str.startsWith(keyword)) {
                return true;
            }
        }

        return false;
    }

    public static boolean ListHaveStr(List<String> list, String str) {
        for(String keyword : list) {
            if (str.equals(keyword)) {
                return true;
            }
        }

        return false;
    }
}
java 复制代码
public static String removeDuplicateSlash(String uri) {
        return uri.contains("//") ? uri.replaceAll("/+", "/") : uri;
    }
java 复制代码
public static String removeEndSlash(String uri) {
        return uri.endsWith("/") && uri.length() > 1 ? uri.substring(0, uri.length() - 1) : uri;
    }
java 复制代码
public static String urlDecode(String uri) throws IOException {
        return URLDecoder.decode(uri, "UTF-8");
    }
java 复制代码
 public static String decode(String s, String enc) throws UnsupportedEncodingException {
        if (enc.isEmpty()) {
            throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
        }

        try {
            Charset charset = Charset.forName(enc);
            return decode(s, charset);
        } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
            throw new UnsupportedEncodingException(enc);
        }
    }

SecurityLibManager

线索,版本检查

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.qiyuesuo.security.patch.loader;

import com.qiyuesuo.core.SpringContextHolder;
import com.qiyuesuo.security.patch.loader.filter.QvdFilter;
import com.qiyuesuo.security.patch.loader.listener.ContextRefreshedListener;
import com.qiyuesuo.security.patch.loader.listener.QvdContextReadyListener;
import com.qiyuesuo.security.patch.loader.loader.SecurityLibClassLoader;
import com.qiyuesuo.security.patch.loader.util.CommonUtil;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

public class SecurityLibManager {
    private static final Logger logger = LoggerFactory.getLogger(SecurityLibManager.class);
    public static final String SECURITY_JAR_PATH = "./security/private-security-patch.jar";
    private static final String QVD_COMPONENTS_CLASS_PKG_NAME = "com.qiyuesuo.security.patch.qvd.component";
    private static final String QVD_COMPONENT_DISPATCH = "com.qiyuesuo.security.patch.qvd.component.QvdComponentDispatch";
    private static final String QVD_ASP = "com.qiyuesuo.security.patch.qvd.QvdAspect";
    private static final String QVD_FILTER = "com.qiyuesuo.security.patch.qvd.QvdFilter";
    private static final String IQVD = "com.qiyuesuo.security.patch.qvd.IQvd";
    private String currentCheckSum;
    private SecurityLibClassLoader targetLibClassLoader;
    private Object qvdLogicManager;
    private static final int RETRY_INTERVAL_MS = 500;
    private final String UPDATE_STATUS = "SECURITY_PATCH_UPDATE_STATUS:" + CommonUtil.getLocalIp();
    private Object simpleCacheClient;

    public String getSecurityPatchVersion() {
        try {
            return (String)ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(this.qvdLogicManager.getClass(), "getSecurityPatchVersion"), this.qvdLogicManager);
        } catch (Exception var2) {
            logger.warn("获取版本号失败");
            return "";
        }
    }

    public String getSecurityPatchLoaderVersion() {
        try {
            return "2.0.0";
        } catch (Exception var2) {
            logger.warn("获取版本号失败");
            return "";
        }
    }

    public void reload() {
        try {
            this.targetLibClassLoader = null;
            File file = new File("./security/private-security-patch.jar");
            if (file.exists()) {
                URL url = file.toURI().toURL();
                SecurityLibClassLoader targetLibClassLoader = new SecurityLibClassLoader(new URL[]{url}, SecurityLibManager.class.getClassLoader());
                Thread.currentThread().setContextClassLoader(targetLibClassLoader);
                this.targetLibClassLoader = targetLibClassLoader;
            }
        } catch (Exception e) {
            logger.error("加载安全包失败!", e);
        }

    }

    public void deployScheduler() {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor((r) -> {
            Thread thread = new Thread(r);
            thread.setDaemon(true);
            thread.setName("qiyuesuo-security-daemon");
            return thread;
        });
        Runnable task = () -> {
            try {
                File file = new File("./security/private-security-patch.jar");
                if (file.exists()) {
                    String checkSum = sha1ForFile(file);
                    if (this.check(checkSum)) {
                        logger.info("安全补丁包散列值发生改变,注意!");
                        if (this.checkUpdateLock()) {
                            logger.info("当前安全补丁包正在自下载,不进行reload操作");
                            return;
                        }

                        this.currentCheckSum = checkSum;

                        try {
                            this.reload();
                            this.registerQVDLogic();
                            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(this.qvdLogicManager.getClass(), "status"), this.qvdLogicManager);
                        } catch (Exception e) {
                            logger.error("重新加载安全包失败!", e);
                        }
                    } else {
                        logger.debug("安全补丁包散列值未发生改变");
                    }
                } else if (this.currentCheckSum != null) {
                    this.currentCheckSum = null;
                    logger.warn("已经卸载安全补丁包,过滤器内部处理逻辑!");
                    ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(this.qvdLogicManager.getClass(), "clear"), this.qvdLogicManager);
                    ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(this.qvdLogicManager.getClass(), "setSecurityPatchVersion", new Class[]{String.class}), this.qvdLogicManager, new Object[]{""});
                }
            } catch (Throwable e) {
                logger.error("安全补丁包检测失败!", e);
            }

        };
        executor.scheduleAtFixedRate(task, 0L, 30L, TimeUnit.SECONDS);
    }

    private boolean check(String newCheckSum) {
        boolean result = false;
        if (StringUtils.hasText(newCheckSum) && (this.currentCheckSum == null || !this.currentCheckSum.equals(newCheckSum))) {
            result = true;
        }

        return result;
    }

    public static String sha1ForFile(File file) {
        String result = null;

        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            FileInputStream fis = new FileInputStream(file);
            byte[] dataBytes = new byte[1024];

            int bytesRead;
            while((bytesRead = fis.read(dataBytes)) != -1) {
                md.update(dataBytes, 0, bytesRead);
            }

            fis.close();
            byte[] mdBytes = md.digest();
            StringBuilder hexString = new StringBuilder();

            for(byte mdByte : mdBytes) {
                String hex = Integer.toHexString(255 & mdByte);
                if (hex.length() == 1) {
                    hexString.append('0');
                }

                hexString.append(hex);
            }

            result = hexString.toString();
        } catch (Exception e) {
            logger.error("文件散列值计算失败!", e);
        }

        return result;
    }

    public static String md5ForFile(File file) {
        String result = null;

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            FileInputStream fis = new FileInputStream(file);
            byte[] dataBytes = new byte[1024];

            int bytesRead;
            while((bytesRead = fis.read(dataBytes)) != -1) {
                md.update(dataBytes, 0, bytesRead);
            }

            fis.close();
            byte[] mdBytes = md.digest();
            StringBuilder hexString = new StringBuilder();

            for(byte mdByte : mdBytes) {
                String hex = Integer.toHexString(255 & mdByte);
                if (hex.length() == 1) {
                    hexString.append('0');
                }

                hexString.append(hex);
            }

            result = hexString.toString();
        } catch (Exception e) {
            logger.error("文件散列值计算失败!", e);
        }

        return result;
    }

    public static List<String> readAndLoadClassNameFromJar(SecurityLibClassLoader securityLibClassLoader, Map<String, byte[]> byteMap) {
        List<String> result = new ArrayList();

        try {
            JarFile jarFile = new JarFile("./security/private-security-patch.jar");
            Enumeration<JarEntry> entries = jarFile.entries();

            while(entries.hasMoreElements()) {
                String className = null;

                try {
                    JarEntry entry = (JarEntry)entries.nextElement();
                    if (entry.getName().endsWith(".class")) {
                        className = entry.getName().replace("/", ".").replace(".class", "");
                        logger.info("被重新加载的类======>{}", className);
                        if (byteMap != null && (className.startsWith("com.qiyuesuo.security.patch.qvd.component") || className.equals("com.qiyuesuo.security.patch.qvd.QvdFilter") || className.equals("com.qiyuesuo.security.patch.qvd.IQvd") || className.equals("com.qiyuesuo.security.patch.qvd.QvdAspect"))) {
                            byte[] classData = readAllBytes(jarFile.getInputStream(entry));
                            byteMap.put(className, classData);
                        }

                        securityLibClassLoader.loadClass(className);
                        result.add(className);
                    }
                } catch (Exception var8) {
                    logger.error("类===>{},加载失败", className);
                }
            }

            jarFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public static void replaceBean(String beanName, Object targetObj) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext context = (ConfigurableApplicationContext)SpringContextHolder.getApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        Map<String, Object> map = (Map)singletonObjects.get(beanFactory);
        map.put(beanName, targetObj);
    }

    public void registerQVDLogic() {
        try {
            ContextRefreshedListener.getLatch().await();
            List<String> newClasses = readAndLoadClassNameFromJar(this.targetLibClassLoader, (Map)null);
            QvdFilter qvdFilterBean = (QvdFilter)SpringContextHolder.getApplicationContext().getBean("QvdFilter");
            QvdContextReadyListener qvdConfigBeanListener = (QvdContextReadyListener)SpringContextHolder.getApplicationContext().getBean("QvdContextReadyListener");
            Object qvdLogicManager = ReflectionUtils.accessibleConstructor(this.targetLibClassLoader.loadClass("com.qiyuesuo.security.patch.qvd.logic.QvdLogicManager"), new Class[0]).newInstance();
            this.qvdLogicManager = qvdLogicManager;

            for(String cell : newClasses) {
                this.registerFilterLogic(cell, qvdLogicManager);
                this.registerBeanConfigLogic(cell, qvdLogicManager);
                this.registerContextReady(cell, qvdLogicManager);
                this.refreshSecurityPatchVersion(cell, qvdLogicManager);
            }

            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(QvdFilter.class, "setQvdLogicManager", new Class[]{Object.class}), qvdFilterBean, new Object[]{qvdLogicManager});
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(QvdContextReadyListener.class, "setQvdLogicManager", new Class[]{Object.class}), qvdConfigBeanListener, new Object[]{qvdLogicManager});
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(qvdLogicManager.getClass(), "doQvdConfigBeanLogic", new Class[]{ApplicationContext.class}), qvdLogicManager, new Object[]{SpringContextHolder.getApplicationContext()});
        } catch (Exception e) {
            logger.error("注册QVD逻辑失败", e);
        }

    }

    public void registerFilterLogic(String cell, Object qvdLogicManager) throws Exception {
        if (cell.startsWith("com.qiyuesuo.security.patch.filter.logic")) {
            Class clazz = this.targetLibClassLoader.loadClass(cell);
            Object logic = clazz.newInstance();
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(qvdLogicManager.getClass(), "register", new Class[]{this.targetLibClassLoader.loadClass("com.qiyuesuo.security.patch.qvd.IQvdFilterLogic")}), qvdLogicManager, new Object[]{logic});
        }

    }

    public void registerBeanConfigLogic(String cell, Object qvdLogicManager) throws Exception {
        if (cell.startsWith("com.qiyuesuo.security.patch.config.logic")) {
            Class clazz = this.targetLibClassLoader.loadClass(cell);
            Object logic = clazz.newInstance();
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(qvdLogicManager.getClass(), "register", new Class[]{this.targetLibClassLoader.loadClass("com.qiyuesuo.security.patch.qvd.IQvdConfigBeanLogic")}), qvdLogicManager, new Object[]{logic});
        }

    }

    public void registerContextReady(String cell, Object qvdLogicManager) throws Exception {
        if (cell.startsWith("com.qiyuesuo.security.patch.ready.logic")) {
            Class clazz = this.targetLibClassLoader.loadClass(cell);
            Object logic = clazz.newInstance();
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(qvdLogicManager.getClass(), "register", new Class[]{this.targetLibClassLoader.loadClass("com.qiyuesuo.security.patch.qvd.IQvdContextReadyLogic")}), qvdLogicManager, new Object[]{logic});
        }

    }

    private void refreshSecurityPatchVersion(String cell, Object qvdLogicManager) throws ClassNotFoundException {
        if (cell.startsWith("com.qiyuesuo.security.patch.SecurityPatchVersion")) {
            Class clazz = this.targetLibClassLoader.loadClass(cell);
            Field[] fields = clazz.getFields();

            for(Field field : fields) {
                if ("VERSION".equals(field.getName())) {
                    try {
                        String version = field.get((Object)null).toString();
                        ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(qvdLogicManager.getClass(), "setSecurityPatchVersion", new Class[]{String.class}), qvdLogicManager, new Object[]{version});
                        logger.info("安全类库管理器收到security-patch的版本号:{}", version);
                        break;
                    } catch (IllegalAccessException var10) {
                        logger.error("解析属性报错,系统未能检测到security-patch的版本!");
                    }
                }
            }
        }

    }

    public SecurityLibClassLoader getTargetLibClassLoader() {
        return this.targetLibClassLoader;
    }

    public Object getQvdLogicManager() {
        return this.qvdLogicManager;
    }

    private static byte[] readAllBytes(InputStream inputStream) throws Exception {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[1024];

        int nRead;
        while((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();
        return buffer.toByteArray();
    }

    public boolean checkUpdateLock() {
        if (this.simpleCacheClient == null) {
            this.simpleCacheClient = SpringContextHolder.getApplicationContext().getBean("simpleCacheClient");
        }

        Object status = ReflectionUtils.invokeMethod((Method)Objects.requireNonNull(ReflectionUtils.findMethod(this.simpleCacheClient.getClass(), "getValue", new Class[]{String.class})), this.simpleCacheClient, new Object[]{this.UPDATE_STATUS});
        return status != null && !Boolean.parseBoolean(status.toString());
    }
}

com/qiyuesuo/security/patch/qvd/logic/QvdLogicManager.class:19

这里

java 复制代码
public class QvdLogicManager {
    private static final Logger logger = LoggerFactory.getLogger(QvdLogicManager.class);
    private String securityPatchVersion = "";
//这里是处理的东西
    private List<IQvdFilterLogic> qvdFilterLogics = new ArrayList();
    private List<IQvdConfigBeanLogic> qvdConfigBeanLogics = new ArrayList();
    private List<IQvdContextReadyLogic> qvdContextReadyLogics = new ArrayList();

    public void doQvdFilterLogic(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//看数组是否不是空并且字节大于0
//方法拦截,过滤
//但是过滤什么呢
        if (null != this.qvdFilterLogics && 0 < this.qvdFilterLogics.size()) {
//遍历
            for(IQvdFilterLogic logic : this.qvdFilterLogics) {
//获取响应,403可疑
                if (response.getStatus() == 403) {
                    break;
                }
//注册,放行?
                logic.doQvdLogic(request, response, filterChain);
            }
        }

    }

这里应该是逻辑管理器的设置

这个类本身不执行任何安全检测,它的职责只有两个:"收纳" 和 "调度"。它像一个工具箱,你可以往里面放入或取出不同的工具(即逻辑),然后在需要的时候统一执行。

java 复制代码
 public void doQvdConfigBeanLogic(ApplicationContext applicationContext) {
        if (null != this.qvdConfigBeanLogics && 0 < this.qvdConfigBeanLogics.size()) {
            for(IQvdConfigBeanLogic logic : this.qvdConfigBeanLogics) {
                logic.changeConfig(applicationContext);
            }
        }

    }

    public void doQvdContextReadyLogic(ApplicationContext applicationContext) {
        if (null != this.qvdContextReadyLogics && 0 < this.qvdContextReadyLogics.size()) {
            for(IQvdContextReadyLogic logic : this.qvdContextReadyLogics) {
                logic.executeLogic(applicationContext);
            }
        }

    }

    public void register(IQvdFilterLogic logic) {
        this.qvdFilterLogics.add(logic);
    }

    public void register(IQvdConfigBeanLogic logic) {
        this.qvdConfigBeanLogics.add(logic);
    }

    public void register(IQvdContextReadyLogic logic) {
        this.qvdContextReadyLogics.add(logic);
    }

    public void unregister(IQvdFilterLogic logic) {
        this.qvdFilterLogics.remove(logic);
    }

    public void unregister(IQvdConfigBeanLogic logic) {
        this.qvdConfigBeanLogics.remove(logic);
    }

    public void unregister(IQvdContextReadyLogic logic) {
        this.qvdContextReadyLogics.remove(logic);
    }

    public void clear() {
        this.qvdFilterLogics.clear();
        this.qvdConfigBeanLogics.clear();
        this.qvdContextReadyLogics.clear();
    }

    public void status() {
        logger.info("【QVD逻辑管理器】已加载的【web过滤器逻辑】个数====>{}", this.qvdFilterLogics.size());

        for(IQvdFilterLogic logic : this.qvdFilterLogics) {
            logger.info("【QVD逻辑管理器】已加载的【web过滤器逻辑】类====>{}", logic.getClass().getName());
        }

        logger.info("【QVD逻辑管理器】已加载的【配置bean更改逻辑】个数====>{}", this.qvdConfigBeanLogics.size());

        for(IQvdConfigBeanLogic logic : this.qvdConfigBeanLogics) {
            logger.info("【QVD逻辑管理器】已加载的【配置bean更改逻辑】类====>{}", logic.getClass().getName());
        }

        logger.info("【QVD逻辑管理器】已加载的【容器就绪逻辑】个数====>{}", this.qvdContextReadyLogics.size());

        for(IQvdContextReadyLogic logic : this.qvdContextReadyLogics) {
            logger.info("【QVD逻辑管理器】已加载的【容器就绪逻辑】类====>{}", logic.getClass().getName());
        }

    }

    public String getSecurityPatchVersion() {
        return this.securityPatchVersion;
    }

    public void setSecurityPatchVersion(String securityPatchVersion) {
        this.securityPatchVersion = securityPatchVersion;
    }
}

shell

分析一下里面的逻辑,也许会找到关键的jar包或者漏洞点是什么

java 复制代码
#!/bin/bash

# 获取当前目录下的loader jar文件
//替换符号,通配符号,错误信息直接丢弃
//直接获取文件,读取
loader_jar=$(ls private-security-loader-*.jar 2>/dev/null)

# 检查是否找到loader jar
//查找有没有jar包
if [ -z "$loader_jar" ]; then
    echo "未找到private-security-loader-xxx.jar文件,请检查文件是否存在。"
    exit 1
fi

# 提取loader版本号
//获取jar包并且搜索名字中的版本号
loader_version=$(echo "$loader_jar" | grep -oP 'private-security-loader-\K\d+\.\d+\.\d+')

# 判断当前用户是否为root
if [ "$(id -u)" -eq 0 ]; then
    echo "当前用户为root用户。是否要继续进行安装?(y/n)"
    echo "您正在安装的loader版本为: 2.0.0"
    read -r continue_install
    if [ "$continue_install" != "y" ]; then
        echo "安装已取消。"
        exit 1
    fi
fi

# 提示用户输入部署目录
echo "请输入qiyuesuo部署目录(全路径),例如:/opt/qiyuesuo"
read -r install_dir

# 验证路径是否存在
if [ ! -d "$install_dir" ]; then
    echo "路径不合法,目录不存在。"
    exit 1
fi

# 检查libs目录是否存在
libs_dir="$install_dir/libs"
if [ ! -d "$libs_dir" ]; then
    echo "安装目录中libs不存在,请检查。"
    exit 1
fi

# 动态检查并处理libs目录下的旧patch.jar和loader-xxx.jar
//这里重点
patch_jar="$libs_dir/private-security-patch.jar"
old_patch_dir="$install_dir/old_patch"

# 检查并找到可能存在的旧的 private-security-loader.jar 文件
old_loader_jar=$(ls "$libs_dir"/private-security-loader-*.jar 2>/dev/null)

if [ -f "$patch_jar" ] || [ -f "$old_loader_jar" ]; then
    echo "检测到旧的patch.jar或loader-xxx.jar包,正在删除并备份..."
    
    # 创建old_patch目录
    mkdir -p "$old_patch_dir"
    
    # 备份并删除旧的patch.jar
    if [ -f "$patch_jar" ]; then
        mv "$patch_jar" "$old_patch_dir/"
        echo "已经删除并备份老的patch.jar包到$old_patch_dir/。"
    fi

    # 备份并删除旧的loader jar文件
    if [ -f "$old_loader_jar" ]; then
        mv "$old_loader_jar" "$old_patch_dir/"
        echo "已经删除并备份老的loader jar文件到$old_patch_dir/。"
    fi
fi

# 复制新的loader-xxx.jar到libs目录
cp "$loader_jar" "$libs_dir/private-security-loader-$loader_version.jar"
echo "private-security-loader-$loader_version.jar已复制到$libs_dir/。"

# 创建security目录并处理patch.jar
security_dir="$install_dir/security"
mkdir -p "$security_dir"

# 如果security目录下存在旧的patch.jar,先删除
if [ -f "$security_dir/private-security-patch.jar" ];then
    rm -f "$security_dir/private-security-patch.jar"
    echo "已经删除security目录下的旧private-security-patch.jar包。"
fi

# 复制新的patch.jar到security目录
cp private-security-patch.jar "$security_dir/"
echo "private-security-patch.jar已复制到$security_dir/。"

echo "补丁包安装成功!正在安装的loader版本为: 2.0.0"
java 复制代码
# 提示用户输入部署目录
echo "请输入qiyuesuo部署目录(全路径),例如:/opt/qiyuesuo"
read -r install_dir

# 验证路径是否存在
if [ ! -d "$install_dir" ]; then
    echo "路径不合法,目录不存在。"
    exit 1
fi

path在$install_dir/security下面
$libs_dir/用户输入
lode在"private-security-loader-$loader_version.jar已复制到$libs_dir/。"
相关推荐
承渊政道3 小时前
Linux系统学习【进程概念从入门到深入理解】
linux·服务器·笔记·学习·ubuntu·系统架构·bash
无忧.芙桃4 小时前
进程间通信的基本概念(上)
linux·运维·服务器
运维瓦工4 小时前
DevOps 生态介绍(四):Sonarqube&jacoco 与jenkins集成使用
运维·jenkins·devops
草莓熊Lotso6 小时前
【Linux系统加餐】从原理到封装:基于建造者模式实现System V信号量工业级C++封装
android·linux·运维·服务器·网络·c++·建造者模式
广州灵眸科技有限公司12 小时前
瑞芯微(EASY EAI)RV1126B 核心板供电电路
linux·运维·服务器·单片机·嵌入式硬件·电脑
keyipatience12 小时前
18.Linux进程退出和进程等待机制详解
linux·运维·服务器
仙柒41512 小时前
控制平面组件和节点组件
运维·容器·kubernetes
齐齐大魔王12 小时前
Linux-网络编程实战
linux·运维·网络