前言

前一阵一直在忙着申请研究生,所以审计这一块落下了好多,今天拿出键盘都落灰了。最近在学习的时候遇到了一些瓶颈,无论是wbe挖洞还是审计都感觉自己只是懂得一些表面知识,比较肤浅,对于整个流程在脑子里面没有办法构成一张完整的图。还是看了一位师傅的代码审计学习道路,找到一些Poc据此进行分析,跟进整个流程希望通过借鉴这种学习方法可以提升自己一点。另外写文章的文笔也需要提高,其实就是思路上要理清楚,一环扣一环,把不懂的人给讲清楚,本篇文章我也会尽我所能将细枝末节的地方理清楚,讲清楚。

从Poc开始

从舍友推荐的网站上看到了这个CMS的漏洞,主要是其中的SQL注入比较多,首先将所有的Poc放出来一个接一个分析。

http://localhost/TheCarProject/cp/info.php?man_id=3&car_id=-1 or 1=1 and (SELECT 1 and ROW(1,1)>(SELECT COUNT(*),CONCAT(CHAR(95),CHAR(33),CHAR(64),CHAR(52),CHAR(100),CHAR(105),CHAR(108),CHAR(101),CHAR(109),CHAR(109),CHAR(97),0x3a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.COLLATIONS GROUP BY x)a)

http://localhost/TheCarProject/cp/info.php?man_id=3&car_id=-1 or 1=1 and (SELECT 1 and ROW(1,1)>(SELECT COUNT(*),CONCAT(CHAR(95),CHAR(33),CHAR(64),CHAR(52),CHAR(100),CHAR(105),CHAR(108),CHAR(101),CHAR(109),CHAR(109),CHAR(97),0x3a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.COLLATIONS GROUP BY x)a)

首先分析一下Poc, car_id 提交正常参数 1 之后未使用单/双引号\' \" 进行闭合,所以判断为数字型SQL注入。后面跟随的是SQL查询语句,concat 函数作用是连接括号内所有字符串参数成为一个字符串,第一个参数均使用了ASCII进行转码,第二个参数是一个16进制编码字符,将concat函数中的参数翻译过来的Poc语句是 :

SELECT 1 and (ROW(1,1)>(SELECT COUNT(*), CONCAT(_!@4dilemma,:, FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.COLLECTIONS GROUP BY x)a;

可能有些小伙伴跟我一样平时也不太在意SQL注入语句中的具体含义,sqlmap直接跑一下就好,但是秉承着给自己找麻烦的原则,我来分析一下这个语句的含义。首先将目光聚焦在语句前面部分的比较符号上 (>)ROW函数 函数在MySQL官方文档中给出的定义如下:

[

翻译过来的意思为:标量或列子查询返回一个值或一列值。
行子查询是返回单行的子查询变体,因此可以返回多个列值。听起来是不是十分拗口难懂。其实Poc中的ROW(1,1)包含两部分,一部分是ROW函数本身,另一部分是被称作行构造函数表达式的(1,1)。MySQL官方文档中有一个例子:

第一个和第二个表达式的意义是相等的。那么再回头看一看整体的 ROW(1,1)> 便能理解其中的含义,即第一个查询结果的第一列要大于第二个查询结果的第一列。如果成功就返回结果,不成功返回空值。至于为什么不是 ROW(1) 而是 ROW(1,1) 同样的MySQL官方文档也给了我们解释:

理解了其中的细节之后我们在从总体上看这一句Poc,很明显是一个报错型SQL注入,报错原因是因为临时表中的主键值重复,造成重复的原因是Poc语句中的 FLOOR(RAND(0)*2) 产生规律的 011011011...... 序列导致分组统计 count(*)...group by 时临时表中的主键值重复抛出错误信息。实现起来是这样的:

首先使用 floor(rand(0)*2) 生成011序列作为临时表中的键值:

接着使用分组统计触发临时表主键值重复问题爆出错误:

可以看到上图中已经爆出错误信息,其中包含我们希望查询到的数据库版本 10.3.12-MariaDB-2 .

爆数据库

分析完了Poc中的各个部分之后让我们总体看一下:

代码审计

从Poc可以看出存在SQL注入的文件是 cp/info.php

代码 第9行 中出现了car_id 参数,是由用户以 get 方式从url提交的变量,直接赋值给 motor_id 参数,跟进一下

看到文件中包含多个将 motor_id 拼接入内的sql查询语句,均未使用单/双引号包裹,参数也未经过任何过滤函数,因此可以判断存在注入。接下来我们需要寻找SQL注入的回显地点,上面三张图中 第191行 第289行 第343行 分别使用变量接受了SQL查询结果 选取最后一个一个为例子,参数 $cpr_image_mail 接受了函数 mysqli_fetch_array 读取的MySQL返回结果,并假设其中存在以 FILE_NAME 为数组键的数组值,将数组值赋给了变量 $cpr_image_single,跟进

在代码 第350行 中,参数 $cpr_image_single 在hidden型的input输入框中作为输入值在 第347行 提交给了 smtp_info.php ,抓包即可获取发送数据得到SQL注入的信息回显。

修复

SQL注入的修复我认为要从SQL注入的成因开始针对,本漏洞中成因简单的不能再简单,在拼接入SQL语句的时候没有进行单/双/反引号的闭合,对变量也没有进行消毒处理,根据此原因,首先在SQL查询语句中使用双引号包裹变量之外,还要对用户输入变量进行消毒处理,给出的修复代码如下:

if(isset($_GET['car_id'])) { $motor_id = mysqli_real_escape_string($_GET['car_id']); //$motor_id = PDO::quote($_GET['car_id']); ...... }

mysqli_real_escape_string 函数的作用是过滤字符串参数中的非法字符,MySQL官方文档中给出定义:

同时还要补充两点:一是应避免使用GBK编码数据库,以免造成宽字节注入。二是由于在写入数据库的时候写入的是原始信息,所以在获取数据库查询信息的时候也应该调用此函数进行消毒处理,以免造成二次注入。

总结

整体看漏洞触发链比较短,产生原因也是最简单的原因,但是作为一个学习过程的开始还算合适。本篇文章主要秉承着将最细节的地方搞清楚的原则写成,现在看来主要在Poc分析的时候细节比较多,下次要选择一个漏洞触发链长或者是触发条件苛刻的CMS来审计。自己也是第一次脱离网上的任何现有文章,所以难免会有一些错误和文笔不通顺,如果哪位师傅看到了还烦请指正小弟,感激不尽。

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖