'root'@'%'是内网提权黄金入口,因其host='%'不校验ip真实性,配合super_priv='y'可执行高危操作;须用drop user彻底删除并验证所有权限表无残留。

因为'root'@'%'这类账号等于把数据库 root 密码贴在内网交换机上——只要拿下任意一台内网机器,就能直连执行LOAD_FILE()、写 WebShell 或调用SYS_EXEC,根本不需要爆破密码。
为什么'root'@'%'是内网提权的黄金入口
Host = '%' 不校验来源 IP 真实性,而内网环境普遍缺乏源地址过滤。ARP 欺骗、容器 overlay 网络、云主机多网卡混用,都让伪造一个192.168.1.100成本极低。一旦攻击者控制了某台 Web 服务器或跳板机,mysql -u root -h db.internal -p 就能直接进库。
关键风险点:
-
Super_priv = 'Y'的账号能执行SHUTDOWN、修改全局变量、绕过所有权限检查 -
account_locked = 'Y'但password_last_changed超过 180 天,属于“僵尸高危账户”,长期未用却仍保留在权限链中 - 即使没设密码,只要存在且
authentication_string为空,也可能被匿名用户规则覆盖后意外启用
检查是否已存在'root'@'%'并确认其权限状态
别只查 mysql.user 表,要确认真实生效的权限组合:
SELECT User, Host, Super_priv, Grant_priv, account_locked FROM mysql.user WHERE User = 'root' AND Host = '%';
如果返回结果非空,且 Super_priv = 'Y',必须立即处理。同理,也要查其他高权限用户,比如:
SELECT User, Host, Super_priv FROM mysql.user WHERE Host = '%' AND Super_priv = 'Y';
删除必须用DROP USER,禁用UPDATE mysql.user
直接 UPDATE mysql.user SET Host = '192.168.1.100' WHERE User = 'root' AND Host = '%' 会引发三类问题:
- MySQL 8.0+ 权限缓存不会自动同步,旧规则可能持续生效数分钟甚至更久
-
mysql.db、mysql.tables_priv等表里仍残留Host = '%'记录,后续新建同名用户时冲突 - 某些版本下触发内部状态损坏,导致后续
GRANT静默失败
正确做法只有一条:
DROP USER 'root'@'%';
删之前务必先备份原始授权:
SHOW GRANTS FOR 'root'@'%';
删完必须验证全链路清理效果
执行 DROP USER 后,不能只查 mysql.user 就认为完事。必须确认所有权限表都清空:
-
SELECT Host FROM mysql.user WHERE Host = '%';—— 应返回空集 SELECT Host FROM mysql.db WHERE Host = '%';SELECT Host FROM mysql.tables_priv WHERE Host = '%';SELECT Host FROM mysql.columns_priv WHERE Host = '%';
哪怕只剩一条 Host = '%' 的记录,就仍存在匹配路径——权限系统不取并集,只取排序后第一条匹配项。











