**摘要:**log4j问题的余波还在继续,为什么这个问题潜伏了这么长时间,大家一直没有发现?这里从静态分析的角度谈下log4j问题的发现。
本文分享自华为云社区《使用污点分析检查log4j问题》,作者: Uncle_Tom。
这次log4j的问题主要是由于JNDI问题造成的,先介绍下JNDI。
JNDI提供的服务
JNDI 包含在 Java SE 平台中。要使用 JNDI,必须使用JNDI类和一个或多个服务提供者。 JDK 包括以下命名/目录服务的服务提供者:
轻量级目录访问协议 (Lightweight Directory Access Protocol (LDAP));
域名服务 (Domain Name Service (DNS))。
网络信息服务(Network Information Service(NIS));
名称服务 Java 远程方法调用(Java Remote Method Invocation (RMI));
通用对象请求代理体系结构 (Common Object Request Broker Architecture (CORBA)) 通用对象服务 (Object Services (COS))。
JNDI的Java实现
JNDI程序包:
javax.naming:包含了访问命名服务的类和接口。例如,它定义了Context接口,这是命名服务执行查询的入口。
javax.naming.directory:对命名包的扩充,提供了访问目录服务的类和接口。例如,它为属性增加了新的类,提供了表示目录上下文的DirContext接口,定义了检查和更新目录对象的属性的方法。
javax.naming.event:提供了对访问命名和目录服务时的事件通知的支持。例如,定义了NamingEvent类,这个类用来表示命名/目录服务产生的事件,定义了侦听NamingEvents的NamingListener接口。
javax.naming.ldap:这个包提供了对LDAP 版本3扩充的操作和控制的支持,通用包javax.naming.directory没有包含这些操作和控制。
javax.naming.spi:这个包提供了一个方法,通过javax.naming和有关包动态增加对访问命名和目录服务的支持。这个包是为有兴趣创建服务提供者的开发者提供的。
JNDI上下文(javax.naming.Context)
javax.naming 包定义了一个 Context 接口,它是查找、绑定/解除绑定、重命名对象以及创建和销毁子上下文的核心接口。
lookup: 最常用的操作是lookup()。通过lookup()查找对象的名称,它返回绑定到该名称的对象。
Bindings:listBindings() 返回名称到对象绑定的枚举。绑定是一个元组,包含绑定对象的名称、对象类的名称和对象本身。
list: list() 与 listBindings() 类似,不同之处在于它返回包含对象名称和对象类名称的名称枚举。 list() 对于诸如浏览器之类的应用程序很有用,这些应用程序希望发现有关绑定在上下文中的对象的信息,但不需要所有实际对象。尽管 listBindings() 提供了所有相同的信息,但它可能是一个更昂贵的操作。
Name: Name 是一个表示通用名称的接口, 包含零个或多个组件的有序序列。命名系统使用此接口来定义遵循其约定的名称。
JNDI初始化
在JNDI中,所有命名和目录操作都是相对于上下文执行的,没有绝对的根路径。因此,JNDI 定义了一个 InitialContext,它为命名和目录操作提供了一个起点。通过初始的上下文,就可以使用它来查找其他上下文和对象。
JNDI 通过InitialContext.lookup(String name)一个字符串参数进行初始化,如果该参数来自不受信任的源,则可能通过远程类加载导致远程代码执行。当请求对象的名称由攻击者控制时,可能会将受害者Java应用程序指向恶意RMI/LDAP/CORBA服务器,并使用任意对象进行响应。
本次log4j的JNDI注入问题,就是因为当log4j的日志输出为"${xxx}"的时候,log4j会认为这是个JNDI调用的标志,并将xxx解析为JNDI资源后,加载运行。如果xxx为恶意服务地址的时候,危害也就发生了。
污点分析(Taint analysis)可以被看作是信息流分析(Information Flow Analysis)的一种,主要是追踪数据在程序中的走向。
在漏洞分析中,使用污点分析技术将所感兴趣的数据(通常来自程序的外部输入)标记为污点数据,然后通过跟踪和污点数据相关的信息的流向,可以知道它们是否会影响某些关键的程序操作,进而挖掘程序漏洞。即将程序是否存在外部输入导致漏洞的问题,转化为污点信息是否会被 Sink 点上的操作所使用的问题。
污点分析技术目前主要有静态和动态分析两种方式。本文主要讲述通过静态分析工具所采用的静态分析方法。
通常外部输入数据都被认为是一种可能引起安全风险的源头,被称为污染源。这些信息被程序的接收或处理函数收到后,在程序内部通过程序内部的各个功能模块被加工、处理或调用某些外部接口执行。这些信息如果未做有效的检验就可能造成各类安全风险。
下图是污染分析在分析污染传播的过程中所经历的主要过程,这个过程被划分为:污染源、污染传播、污染清理、污染爆发。
数据流入系统
外部污染通常由信任域意外传入信任域内,会导致系统运行的问题。主要有:
外部输入:用户界面的输入、外部发来的请求电文、数据库读取的信息;
环境和设置信息:在不安全的环境中运行时,需要从环境中读入的信息。例如:环境变量、配置文件等;
数据内部流转
在程序内部,会有一些因为设计或编码过程中引入的数据范围不当设置或判断,最终导致安全问题。例如除零、数组越界等。
数据流出系统
信任区域内的关键或需要保密的信息,被泄露到信任域外的场景一样可以通过污点分析技术进行分析。例如:
系统内部信息:系统内部的信息往往会暴漏系统的内部结构,这些信息给外部攻击提供了明确的嗅探目标。例如:日志的输出的包含堆栈信息的异常信息等;
敏感信息:敏感信息是需要严格保护的,这些信息的泄露也会给系统带来巨大的损失。例如:个人身份信息、个人财产信息、个人健康信息等。
污染的信息会通过应用软件特定的函数被引入到应用系统中,这也是污染分析的起点。静态分析工具中,通常采用下面的方法完成污染源的定义:
污染传播是污染分析中最复杂的一个阶段,主要分为显示分析和隐式分析。
在显示分析和隐式分析中,都不可避免的会遇到:内置函数、第三方函数,以及应用框架的问题。
内置函数、第三方函数,以及应用框架都会造成分析中断的问题,从而使污染分析不能有效的进行。为了解决这个问题,静态分析软件需要定义这些函数,帮助分析程序完成污染传播的继续分析。
这些函数的定义方式基本和污染源的定义方式相同,采用配置的方式匹配到这些函数,同时还需要明确这些函数污染传入的参数和传出的参数。以方便静态分析软件在碰到这些函数时,根据传出参数继续分析。
在编程的过程中,如果对于不安全的外部输入,已经做了相应的处理,但如果静态分析工具无法知道这些检查和处理,让然给出告警,将成为误报,反而会增加分析的成本。所以在程序分析的过程中需要对污染清理做出分析,以便减少不必要的误报,同时还可以提高分析效率。
污染清理主要分为两种处理方式:
对于清理函数的处理,同样可以采用配置的方式完成。只要对适配到的函数,做污染标记清楚就可以了,使静态分析工具在经过这些函数不再带有继续分析的标记,终止后续的分析。
当污染经过传播仍然进入到一些特定的函数或语句时,就会引发安全漏洞的发生。这些安全漏洞主要有:
例如:输入中指定数量的不正确验证 - (1284); 输入中指定索引、位置或偏移量的不正确验证 - (1285)等。
例如:不检查输入大小的缓冲区复制(“经典缓冲区溢出”) - (120); 整数溢出导致缓冲区溢出 - (680)等。
例如:在命令中使用的特殊元素转义处理不恰当(“命令注入”) - (77); SQL 命令中使用的特殊元素转义处理不恰当(“SQL 注入”) - (89)等。
例如:使用外部控制输入来选择类或代码(“不安全反射”) - (470);不可信数据的反序列化 - (502), 这次的log4j JNDI问题被NVD定义的CWE。
信息泄露
将敏感信息暴露给未经授权的使用者 - (200)
$ git clone --branch rel/2.14.1 https://gitbox.apache.org/repos/asf/logging-log4j2.git
package org.apache.logging;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class testJndi {
private static final Logger LOG = LogManager.getLogger();
public static void main (String[] args){
LOG.error("${jndi:xxx}");
}
}
污染分析设置:
污染源: org.apache.logging.log4j.Logger.error函数,且第一个参数中包含"${" 和 “}”,加这个约束的目的是降低工具的分析难度;
爆发点: JNDI主要的的调用函数:javax.naming.Context.lookup()函数,且污染进入这个函数的第一个参数,同时查找继承和派生这个函数的函数;
污染传播:java的内置函数,例如这个问题里用到的String.substring() 等等;
静态分析工具完整的分析链如下:
图很长,并做了节选,拆成两段:
图1
图2
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://huaweicloud.blog.csdn.net/article/details/122937017
内容来源于网络,如有侵权,请联系作者删除!