补丁分析(找线索)

链接地址
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/。"