@TOC
申明:本文只做学习交流使用,严禁任何组织和个人通过转发、转载等方式进行传播,因此导致的法律后果与本文作者无关。
小菜鸡昨晚正在积极进补雷神大大的课程的时候:
老板的消息划破了寂静的夜空,也打断了我学习的脚步:
按照我的尿性,这种时候我肯定偷偷装死没跑了。
不过这个漏洞还是引起了我的兴趣,毕竟热度就那么多,蹭一蹭就没有了,我肯定也要蹭一蹭了。于是在昨晚瞎整了一晚上没结果后,今天上班的时候划水就把这整个利用过程给跑通了…..
果然上班划水才是生产力啊。
首先,我们使用maven进行项目管理,搭建漏洞环境:
在pom.xml中引入下面的两个依赖:
1 | <dependency> |
漏洞存在的版本就懒得说了,反正不是最新版就对了,手动狗头!!
然后写个小页面:
1 | package com.armandhe.log4j2; |
然后打断点直接开始调试:
跳进去,懂的都懂:
到了这儿后据说是一个非常重要的步骤,调用logIfEnabled
方法判断是否启用日志记录,这里的日志记录分为不同的等级,可以在log4j2的配置文件log4j2.properties中进行配置日志记录的级别。
我们继续跟进该方法:
虽然不知道logMessage
函数干什么的,不过肯定不是我们需要的,继续跟进:logMessageSafely
函数,翻译一下就是日志信息安全性,猜一下可能是进行安全性判断的吧?因为是从零开始的期间我还跟进了newMessage函数,发现是将我们的message封装成了一个对象,对我们的目标没有大的影响, 跟进:
就想这样,将message封装进了一个ReusableSimpleMessage
对象,继续回到logMessageSafely
函数跟进:
跟进logMessageTrackRecursion
函数,不懂就问recursion什么意思?所以我抽空去有道查了一下:
函数名翻译过来就是日志信息跟踪递归,什么意思?俺也不知道,继续跟进:
哦豁,原来就在下面,跟进函数tryLogMessage
,老规矩还是翻译一下,捕获日志信息,还是不知道什么意思,但是又有什么关系呢,继续跟进:
管他什么呢,无脑继续跟:
又能怎么样呢,继续:
好烦啊,无限套娃:
先进去看看:
好像做了很多,又好像什么也没做,就是setMessage哪儿换了个对象封装message:
意义不大,所以我们继续单步执行:
到这儿后跟进this.log
然后进入processLogEvent
:
到了这儿后,如果我们直接单步向下会发现处理发生了延迟,这就是我们的主机在请求dns解析产生的延迟,我也是在发现了这个特点之后才能在这又臭又长的调用链中坚持到最后,继续跟进:
这儿很关键啊,兄弟们,不信我们往下看:
继续:
这儿是挨着的两次调用:
继续:
这儿三重套娃:
二重套娃:
刚才说错了兄弟们,前面不重要,这儿很重要啊,这儿有11重循环,当循环到第8层的时候会有惊喜,所以我们至今到第8次循环让你们见识见识什么他么的叫他么的惊喜:
好了看到i等于8了吗:
跟进去咯:
继续咯,不用我教你吧:
亲,敲黑板划重点了啊!!!!!
这里有个进入的前提条件:this.config
不为空,且this.noLookups
为false
,这也是为什么你在各种各样的公众号看到的该漏洞的一个解决方案就是将noLookups
的值设置为true的原因。
workingBuiler
是个啥?我也不知道啊,怎么可能,这玩意就是一个stringBuilder
,所以你懂了吧?
因为他娘的在这个声明过了,那么问题来了,长度80,也就是我的日志长度不能超过80?扯淡呢吧?当然超过80了,搞不懂搞不懂。
进入的条件判断有一个offset调试后发现是59,查了一下发现是$,也就是说message前面的58个字符的长度是固定的咯,我们输入的信息从第59个开始:
然后判断连续两个字符是是否为\${
,如果是进入正题,截取了从59到后面的所有字符赋值给value
,然后给我们的workingBuilder
设置了长度并将截取的value进行处理之后赋值给他,在这里我利用了前面说到的延时特性观察到命令执行就发生在这里的对value处理过程中,所以我们跟进这个处理过程:
source就是value的值,继续跟进:
又开始套娃了:
这个substitute
函数可以说是写的又臭又长,总结一下左右就是提取那个啥?就那个我们的payload就对了,一直单步到这儿:
进去:
到这儿后其实variableName
就是我们的payload主体了,继续:
这里有两个重要的操作,一个是获得了协议前缀,一个是获取了具体的paload内容,this.strLookupMap
里面定义了很多支持的协议,我们可以看一下:
进入进入断点,判断event是否为空,肯定不为空啊,所以进入的是lookup.lookup(name)
:
到了这里就有意思而了,第一个红框是获取一个JndiManager
,但是在我调试的时候这里面好像是报错了还是怎么了,总是进不到第二个红框里面,而执行命令的代码又恰好在第二个红框里面,你说奇怪不奇怪?
是有意我直接强行跟踪到了第二个红框里面的代码:
重中之重就在这里了哈!!!lookup函数,看到这个你想到了什么?不确定吗?那来看看this.context
是什么,InitialContext
有没有想起点什么????
打完收工!!!!!