简介

Apache Flink 1.11.0-1.11.2中引入的一项更改,允许攻击者通过JobManager进程的REST接口读取本地文件系统上的任何文件,访问仅限于JobManager进程可访问的文件。

复现

下载源码:

1
git clone https://github.com/apache/flink.git

根据官方公告可以得到修复的commitb561010b0ee741543c3953306037f00d7a9f0801

image-20210107143634279

里边还有测试用例可以去看看。

使用未打补丁的parent-commit搭建环境。

1
git checkout 7fed9f0243aaf80d0060f075b95ba46b3207c8a8

编译

1
mvn clean package -DskipTests

一般半小时就行

image-20210107144153649

编译后会出现build-target目录,修改配置文件用于IDEA-DEBUG动态调试

1
flink-debug-src/build-target/conf/flink-conf.yaml

IDEA调试配置

image-20210107150200415

在配置文件最后添加:

1
env.java.opts: -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5006

开启服务

1
flink-debug-src/build-target/bin/start-cluster.sh

POC

1
http://localhost:8081/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd

image-20210107150637102

分析

从路由处开始分析。

org.apache.flink.runtime.rest.handler.router.Router#route(org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpMethod, java.lang.String, java.util.Map<java.lang.String,java.util.List<java.lang.String>>)

image-20210107151109544

跟踪POC的path部分,POC的后半部分是双URL编码的,到达服务器自动解码一次,第二次解码处理发生在decodePathTokens函数。

org.apache.flink.runtime.rest.handler.router.Router#decodePathTokens

image-20210107151745044

对path使用/进行分割,然后得到三个元素,接着遍历三个元素使用QueryStringDecoder.decodeComponent进行URL解码并返回包含穿越目录的tokens

org.apache.flink.runtime.rest.handler.router.MethodlessRouter#route

image-20210107152508941

routes.entrySet()进行循环遍历

image-20210107152622902

然后和前面的pathTokens进行匹配判断,跟进pattern.match

org.apache.flink.runtime.rest.handler.router.PathPattern#match

image-20210107152957021

遍历并判断key是否:开头,然后将../../../../../../../../../../../../etc/passwd放进Map中并返回ture

org.apache.flink.runtime.rest.handler.router.RouteResult#RouteResult

image-20210107153528894

在上层中通过if判断,并将Map作为参数穿个RouteResult实例化。

org.apache.flink.runtime.rest.handler.router.RouterHandler#routed

image-20210107154627828

实例化的RouteResult对象又作为参数传入RoutedRequest对象。

org.apache.flink.runtime.rest.handler.router.RoutedRequest#RoutedRequest

image-20210107154908561

最终的RoutedRequest对象成员如下:

image-20210107155023211

org/apache/flink/runtime/rest/handler/AbstractHandler.java:161

image-20210107155139823

层层跟进至关键创建HandlerRequest对象的部分,跟进构造参数routedRequest.getRouteResult().pathParams()

org.apache.flink.runtime.rest.handler.router.RoutedRequest#getRouteResult

image-20210107155451909

org.apache.flink.runtime.rest.handler.router.RouteResult#pathParams

image-20210107155529976

结果为包含目录穿越的MAP

image-20210107155655748

org.apache.flink.runtime.rest.handler.HandlerRequest#HandlerRequest(R, M, java.util.Map<java.lang.String,java.lang.String>, java.util.Map<java.lang.String,java.util.List<java.lang.String>>, java.util.Collection<java.io.File>)

image-20210107160113154

Map中取出目录穿越的POC,然后传入resolveFromString

org.apache.flink.runtime.rest.messages.MessageParameter#resolveFromString

image-20210107160345187

最终放入MessageParameter对象的value成员中,接着将MessageParameter对象放入以class为键的MAP中。

实例化后的HandlerRequest对象成员为:

image-20210107160805942

org/apache/flink/runtime/rest/handler/AbstractHandler.java:179

image-20210107160957164

HandlerRequest对象又作为参数传入respondToRequest函数

org.apache.flink.runtime.rest.handler.cluster.AbstractJobManagerFileHandler#respondToRequest

image-20210107161126748

HandlerRequest对象又传入getFile函数。

org.apache.flink.runtime.rest.handler.cluster.JobManagerCustomLogHandler#getFile

image-20210107161255328

org.apache.flink.runtime.rest.handler.HandlerRequest#getPathParameter

image-20210107161423045

取出../../../../../../../../../../../../etc/passwd然后用于创建File对象,最后在HandlerUtils.transferFile中读取文件对象并作为响应返回。

参考

https://mp.weixin.qq.com/s/ZsNOKC8ulVk66BZZxqD-BA

https://lists.apache.org/thread.html/r6843202556a6d0bce9607ebc02e303f68fc88e9038235598bde3b50d%40%3Cdev.flink.apache.org%3E