Drupal CVE-2018-7600 分析及 PoC 构造

漏洞分析

Drupal 在 3 月 28 日爆出一个远程代码执行漏洞,CVE 编号 CVE-2018-7600,通过对比官方的补丁,可以得知是请求中存在 # 开头的参数。Drupal Render API 对于 # 有特殊处理,比如如下的数组:

比如 #prefix 代表了在 Render 时元素的前缀,#suffix 代表了后缀。

通过查阅 Drupal 的代码和文档,可以知道,对于 #pre_render#post_render#submit#validate 等变量,Drupal 通过 call_user_func 的方式进行调用。

在 Drupal 中,对于 #pre_render 的处理如下:

所以如果我们能将这些变量注入到 $form 数组中,即可造成代码执行的问题。

但是由于 Drupal 代码复杂,调用链很长,所以导致了所谓“开局一个 #,剩下全靠猜”的尴尬局面,即使知道了漏洞触发点,但是找不到入口点一样尴尬。直到昨日,CheckPoint 发布了一篇分析博客,我才注意到原来 Drupal 8.5 提供了 Ajax 上传头像的点,并且明显存在一个 $form 数组的操纵。在已经知道触发点的情况下,构造剩下的 PoC 就非常容易了。

PoC 构造

CheckPoint 提供的截图显示,是在 Drupal 8.5.0 注册处,漏洞文件为:\core\modules\file\src\Element\ManagedFile.php,代码如下:

代码第五行,取出 $_GET["element_parents"] 赋值给 $form_parents,然后进入 NestedArray::getValue 进行处理:

NestedArray::getValue 函数的主要功能就是将 $parents 作为 key path,然后逐层取出后返回。举个例子,对于数组:

$parentsa/b/c,最后得到的结果为 456

查看一下在正常上传中,传入的 $form

似乎 #value 是我们传入的变量,尝试注入数组:

发现成功注入:

那么通过 NestedArray::getValue 函数,可以传入 element_parentsaccount/mail/#value,最后可以令 $form 为我们注入的数组:

在 Render API 处理 #pre_render 时候造成代码执行:

Exploit 构造

虽然实现了代码执行,但是 #pre_render 调用的参数是一个数组,所以导致我们不能任意的执行代码。不过 Render API 存在很多可以查看的地方,通过翻阅 Renderer::doRender 函数,注意到 #lazy_builder

#lazy_builder 是一个 array,其中元素 0 为函数名,元素 1 是一个数组,是参数列表。接着利用 call_user_func_array 进行调用。不过注意到上方这段代码:

意思为传入的 $elements 数组中不能存在除了 $supported_keys 之外的 key,常规传入的数组为:

比要求的数组多了 #suffix#prefix。不过 Render API 有 children element 的说法:

当数组中的参数不以 # 开头时,会当作 children element 进行子渲染,所以我们传入 mail[a][#lazy_builder] ,在进行子渲染的过程中,就会得到一个干净的数组,最终导致命令执行。

其他版本

本文分析的是 Drupal 8.5.0,对于 8.4.x,在注册时默认没有上传头像处,但是也可以直接进行攻击,对于 Drupal 7,暂时未找到可控点。

Reference

https://research.checkpoint.com/uncovering-drupalgeddon-2/

原文发布于微信公众号 - 云鼎实验室(YunDingLab)

原文发表时间:2018-04-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏python学习之旅

Python+Selenium笔记(十三):Page Object设计模式

(一) 前言 简单的说就是分为2层,页面class 和测试class。 页面class:分为父类和子类(子类指具体的页面,每一个页面都创建一个类),父类中定义公...

4307
来自专栏张善友的专栏

URL安全的Base64编码

Base64编码可用于在HTTP环境下传递较长的标识信息。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Ba...

5039
来自专栏西安-晁州

struts2随笔

1、struts.properties配置常量等同于struts.xml中配置(置于类加载路径下面) struts.multipart.maxSize文件上传最...

2100
来自专栏Scott_Mr 个人专栏

React Native 系列(一) -- JS入门知识

37710
来自专栏运维技术迷

shell生成随机字符的几种方法

一般在写shell脚本的时候,会有需要生成一些随机字符,比如在写批量生成用户+随机密码的脚本的时候,就会用到随机生成的字符串来作为新建用户的密码。以下的几种方式...

1.3K6
来自专栏C/C++基础

Linux命令(32)——grep命令

grep(Globally search a Regular Expression and Print)是GNU开发的一款免费开源的文本搜索工具。grep家族包...

1363
来自专栏北京马哥教育

Python 基础语法

Python语言与Perl,C和Java等语言有许多相似之处。但是,也存在一些差异。 在本章中我们将来学习Python的基础语法,让你快速学会Python编程...

3806
来自专栏杨建荣的学习笔记

shell基础学习总结(二) (r3笔记第72天)

-->关于shell编程之文件比较 可以使用如下的选项来做文件的比较。有了这些选项,文件的比较来说都是游刃有余。 -d file file是否存在...

2544
来自专栏企鹅号快讯

十个实用MySQL函数

前言 继上一次《十个实用MySQL命令》后,今天奉上十个实用MySQL函数。下面都是一些比较常用且简单的函数,在工作中也是非常常用的。 函数 0. 显示当前时间...

1936
来自专栏武培轩的专栏

Keep面经汇总

原理:泛型的实现是靠类型擦除技术,类型擦除是在编译期完成的,在编译期,编译器会将泛型的类型参数都擦除成它的限定类型,如果没有则擦除为object类型之后在获取的...

1132

扫码关注云+社区