当前位置:编程学堂 > Web攻防

Web攻防

  • 发布:2023-10-01 20:23

JNDI注入

什么是JNDI
JNDI 代表 Java 命名和目录接口(Java Naming and Directory Interface)。它是一组应用程序接口,为开发人员查找和访问各种资源提供统一的通用接口。它可用于定义用户、网络、机器和对象。和服务。

JNDI支持的服务主要包括:DNS、LDAP、CORBA、RMI等。

从简单的安全角度来看,JNDI是Java中的一组接口。它支持的服务中,最常用的是RMI和LDAP服务
RMI:远程方法调用注册表
LDAP:轻量级目录访问协议
通过这两个协议,目标服务器可以加载远程Class文件,攻击者可以通过构造Class文件来达到RCE的效果
以下包在jdk中提供了JDNI服务

javax.naming:主要用于命名操作。它包含命名服务的类和接口。该包定义了Context接口和InitialContext类;

www.sychzs.cnory:主要用于目录操作,它定义了DirContext接口和InitialDir-Context类;

javax.naming.event:请求命名目录服务器中的事件通知;

javax.naming.ldap:提供LDAP支持;

javax.naming.spi:允许动态插入不同的实现,为不同命名目录服务提供者的开发者提供了一种开发和实现的方式,使得应用程序可以通过JNDI访问相关服务。

可以通过InitialContext类中的lookup()方法使用RMI和LDAP协议进行远程调用。
其他组件中的包也引用了lookup()方法
例如

RMI服务中调用InitialContext.lookup()的类有:
org.springframework.transaction.jta.JtaTransactionManager.readObject()
com.sun.rowset.JdbcRowSetImpl.execute()javax.management.remote.rmi.RMIConnector.connect()
org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)

LDAP服务中调用InitialContext.lookup()的类有:
InitialDirContext.lookup()
Spring LdapTemplate.lookup()
LdapTemplate.lookupContext()

简单的JNDIdemo代码示例

导入javax.naming.InitialContext;
导入 javax.naming.NamingException;

公共类 jndi {
    公共静态无效主(字符串[] args)抛出NamingException {
        字符串uri =“rmi://127.0.0.1:1099/work”;
        InitialContext initialContext = new InitialContext();//获取初始目录环境的引用
        initialContext.lookup(uri);//获取指定的远程对象
    }
}

如果获取到的远程对象是可控的,可以编写恶意的Class文件,让服务器加载该文件,达到命令执行的效果
比如

导入java.io.IOException;

公开课测试{
    公共测试()抛出IOException {
        Runtime.getRuntime().exec("notepad");//调用计算器
    }
}

注入工具 JNDI-注入-利用

详细解释请参考
安全技术系列JNDI注入
Java 安全 JNDI 注入

如果想成功使用JNDI注入,需要观察当前服务器的JDK版本。不同版本号限制内容不同

  • JDK 6u45及7u21之后:java.rmi.server.useCodebaseOnly的默认值设置为true。当该值为 true 时,将禁用远程类文件的自动加载,并且仅从 CLASSPATH 指定的路径和当前 JVM 的 java.rmi.server.codebase 加载类文件。使用此属性可以防止客户端VM从其他Codebase地址动态加载类,从而提高RMI ClassLoader的安全性。
  • JDK 6u141、7u131和8u121之后:添加了com.sun.jndi.rmi.object.trustURLCodebase选项。默认值为 false,这会禁止 RMI 和 CORBA 协议使用远程代码库选项。因此,上述JDK版本不支持RMI和CORBA。该漏洞无法被触发,但仍然可以通过指定URI为LDAP协议来执行JNDI注入攻击。
  • JDK 6u211、7u201 和 8u191 之后:添加了 com.sun.jndi.ldap.object.trustURLCodebase 选项。默认为 false,禁止 LDAP 协议使用远程代码库选项,同时也禁止 LDAP 协议的攻击通道。
    如图所示。

Log4j 漏洞

什么是Log4j

Apache 的一个开源项目。通过使用Log4j,我们可以控制日志信息传输的目的地到控制台、文件、GUI组件,甚至socket服务器、NT事件记录器、UNIX Syslog守护进程等;我们还可以控制每条日志的输出格​​式;通过定义各个日志信息的级别,我们可以更详细地控制日志的生成过程。最有趣的是,这些可以通过配置文件灵活配置,而无需修改应用程序代码。

使用原理

这里的漏洞原理是利用JNDI服务机制远程加载文件,实现命令执行
首先,log4j有四个级别的打印日志:debug、info、warn、error。无论采用哪种方式打印日志,在正常的日志处理过程中,都会检测到两个相邻的字符${。一旦遇到类似表达式结构的字符串就会触发替换机制。
一旦在日志字符串中检测到${},它将解析该字符串并尝试使用lookup()进行查询。因此,只要能够控制日志参数内容,就有机会利用该漏洞。
简单演示部分示例:

包com.example.log4jwebdemo;

导入 org.apache.logging.log4j.LogManager;
导入 org.apache.logging.log4j.Logger;

导入 javax.servlet.ServletException;
导入 javax.servlet.annotation.WebServlet;
导入 javax.servlet.http.HttpServlet;
导入 javax.servlet.http.HttpServletRequest;
导入 javax.servlet.http.HttpServletResponse;
导入java.io.IOException;


@WebServlet(“/log4j”)
公共类 Log4jServlet 扩展 HttpServlet {
    //构造一个HTTP Web服务,并使用存在漏洞的Log4j版本来实现功能
    私有静态最终 Logger log= LogManager.getLogger(Log4jServlet.class);
    @覆盖
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 抛出 ServletException, IOException {字符串代码 =req.getParameter("code");
        log.error("{}",代码);

        //1.开发源码中引用log4j等易受攻击的组件
        //2.开发中使用的组件代码(触发漏洞的代码)
        //3.可控变量传递Payload实施攻击
        //4.该代码接受有效负载并需要进行 url 编码。
    }
}

Fastjson反序列化漏洞

fastjson是什么

在前后端数据传输交互中,我们经常会遇到string、json、xml等格式的相互转换和解析。其中,json因其跨语言、跨前端、前端的优点,在开发中被频繁使用。基本上它是一种标准的数据交换格式。其界面简单易用,已广泛应用于缓存序列化、协议交互、Web输出等各种应用场景。 FastJson是阿里巴巴的开源库,用于解析和打包JSON格式的数据。

简单演示片段示例
首先定义User类

包com.Pengj;

//用于fastjson数据转换测试
公共类用户{
    私有字符串名称;
    私有整数年龄;

    公共整数 getAge() {
        返回年龄;
    }

    公共字符串 getName() {
        返回名称;
    }


    公共无效setAge(整数年龄){
        this.age = 年龄;
        System.out.println(年龄);
    }

    公共无效setName(字符串名称){
        www.sychzs.cn = 名称;
        System.out.println(名称);
    }
}

调用执行命令的文件

包com.Pengj;导入java.io.IOException;

公共课运行{
    公共 Run() 抛出 IOException {
        Runtime.getRuntime().exec("calc");
    }
}

json数据序列化与反序列化

包com.Pengj;


导入com.alibaba.fastjson.JSON;
导入com.alibaba.fastjson.JSONObject;
导入 com.alibaba.fastjson.serializer.SerializerFeature;

//使用fastjson处理User类数据
公共类 FastjsonTest {
    公共静态无效主(字符串[] args){
        //实例化用户
        用户 u = 新用户();
        u.setAge(20);
        u.setName("Pengj");
        //json对象转换json数据转换结果:{"age":20,"name":"Pengj"}
        字符串 jsonString = JSONObject.toJSONString(u);
        System.out.println("这是json格式:"+jsonString);

       //引入autotype函数后的对象转换为json数据。转换结果:{"@type":"com.Pengj.User","age":20,"name":"Pengj"}
        字符串 jsonString1 = JSONObject.toJSONString(u, SerializerFeature.WriteClassName);
        System.out.println(jsonString1);
        


       
        //下面的 JSON -> 对象String test = "{\"@type\":\"www.sychzs.cn\",\"age\":20,\"name\":\"Pengj\"}";//修改包含类在信息后命名 json 数据
        //反序列化json数据
        JSONObject jsonObject = JSON.parseObject(测试);
        System.out.println(jsonObject);

    }


}

上面的代码片段中,使用JSONObject类中的toJSONString方法将对象转换为json数据,启用SerializerFeature.WriteClassName功能,输出带有@type标记的类名信息,完成对象转换为json数据过程。
使用 JSON.parseObject 方法将 json 数据反序列化为对象时,如果将类名信息修改为其他类,则程序在反序列化过程中会尝试将 @type 标记的类信息反序列化为对象。这样,@type标记的类就被加载了。但是@type标记的类可能是被恶意构造的。只需要合理构造一个JSON,并使用@type指定想要的攻击类库即可实现攻击。例如,可以通过将@type指定为包含lookup()方法的库来实现JNDI注入。

ParserConfig.getGlobalInstance().setAutoTypeSupport(false); //禁用自动输入
ParserConfig.getGlobalInstance().setSafeMode(true); //启用自动输入

以上内容仅供学习记录。如有错误或纰漏,敬请批评指正。感谢您的阅读。

相关文章

最新资讯

热门推荐