如何通过限制文件写入权限来防止黑客利用SQL注入获取WebShell?
- 内容介绍
- 文章标签
- 相关推荐
本文共计796个文字,预计阅读时间需要4分钟。
由于SQL注入写入WebShell的链路短、成功率高达、直接提升权限,而限制文件写入权限是阻断该链路最有有效的底层手段。
MySQL的SELECT ... INTO OUTFILE为什么能直接写WebShell
这不是漏洞,而是MySQL合法功能被滥用:只要攻击者能控制SQL语句末尾,就能用INTO OUTFILE把任意内容(比如<?php @eval($_POST['cmd']);?>)写到服务器磁盘上。关键在于它不校验内容类型——写PHP、写JSP、写ASPX,全凭攻击者构造。
- 必须满足三个硬性条件:
FILE权限 +secure_file_priv允许目标路径 + 知道网站根目录的绝对路径 - 常见错误现象:
Can't create/write to file或报错中明确出现secure_file_priv,说明权限或配置卡在第一步 -
INTO DUMPFILE比OUTFILE更常用,因为它不自动添加换行和转义,适合写二进制或单行一句话木马
绕过secure_file_priv的现实路径非常有限
很多人以为“改配置就行”,但MySQL 5.6.34+默认secure_file_priv = NULL,且无法通过SQL动态修改。你只能靠运维层面干预,而生产环境几乎不会放开。
- 如果
secure_file_priv设为具体目录(如/var/lib/mysql-files/),你只能往那里写——但该目录通常不在Web可访问路径下,写完也打不开 - 日志文件绕过(如开启
general_log并指定log输出路径)需要SUPER权限,DBA都不一定有,普通注入用户基本没戏 - 试图用
LOAD DATA INFILE反向读取再重写?前提是你得先有可读的恶意文件——这又回到路径和权限死循环
真正有效的文件写入限制不是靠MySQL参数
数据库层的限制容易被高权限账号绕过,而操作系统级限制对所有MySQL进程一视同仁,且不可被SQL语句更改。
- Linux下用AppArmor或SELinux限制
mysqld进程的文件系统能力,例如禁止写/var/www/及其子目录 - Windows下通过服务属性设置“登录身份”为低权限账户,或用组策略禁用对Web目录的写入继承权限
- 关键点:限制目标必须是Web服务器实际解析PHP的路径,而不是MySQL默认数据目录——后者放开毫无意义
知道绝对路径这件事,比权限更难伪造
没有路径,INTO OUTFILE就是盲打。而现代框架、容器化部署、CDN等让路径越来越难猜:/app/public、/usr/share/nginx/html、/var/task/… 它们不会出现在报错里,也不会被phpinfo()直接暴露。
- 常见路径探测方式(如
?id=1' and extractvalue(1,concat(0x7e,(select @@datadir)))--+)返回的是MySQL数据目录,不是Web根目录 - 利用
load_file()读/etc/passwd或/proc/self/cmdline可能泄露部分路径线索,但成功率随环境复杂度指数下降 - 一旦Web服务跑在Docker里,宿主机路径对MySQL进程可能是不可见的——这时连
secure_file_priv都成了伪命题
本文共计796个文字,预计阅读时间需要4分钟。
由于SQL注入写入WebShell的链路短、成功率高达、直接提升权限,而限制文件写入权限是阻断该链路最有有效的底层手段。
MySQL的SELECT ... INTO OUTFILE为什么能直接写WebShell
这不是漏洞,而是MySQL合法功能被滥用:只要攻击者能控制SQL语句末尾,就能用INTO OUTFILE把任意内容(比如<?php @eval($_POST['cmd']);?>)写到服务器磁盘上。关键在于它不校验内容类型——写PHP、写JSP、写ASPX,全凭攻击者构造。
- 必须满足三个硬性条件:
FILE权限 +secure_file_priv允许目标路径 + 知道网站根目录的绝对路径 - 常见错误现象:
Can't create/write to file或报错中明确出现secure_file_priv,说明权限或配置卡在第一步 -
INTO DUMPFILE比OUTFILE更常用,因为它不自动添加换行和转义,适合写二进制或单行一句话木马
绕过secure_file_priv的现实路径非常有限
很多人以为“改配置就行”,但MySQL 5.6.34+默认secure_file_priv = NULL,且无法通过SQL动态修改。你只能靠运维层面干预,而生产环境几乎不会放开。
- 如果
secure_file_priv设为具体目录(如/var/lib/mysql-files/),你只能往那里写——但该目录通常不在Web可访问路径下,写完也打不开 - 日志文件绕过(如开启
general_log并指定log输出路径)需要SUPER权限,DBA都不一定有,普通注入用户基本没戏 - 试图用
LOAD DATA INFILE反向读取再重写?前提是你得先有可读的恶意文件——这又回到路径和权限死循环
真正有效的文件写入限制不是靠MySQL参数
数据库层的限制容易被高权限账号绕过,而操作系统级限制对所有MySQL进程一视同仁,且不可被SQL语句更改。
- Linux下用AppArmor或SELinux限制
mysqld进程的文件系统能力,例如禁止写/var/www/及其子目录 - Windows下通过服务属性设置“登录身份”为低权限账户,或用组策略禁用对Web目录的写入继承权限
- 关键点:限制目标必须是Web服务器实际解析PHP的路径,而不是MySQL默认数据目录——后者放开毫无意义
知道绝对路径这件事,比权限更难伪造
没有路径,INTO OUTFILE就是盲打。而现代框架、容器化部署、CDN等让路径越来越难猜:/app/public、/usr/share/nginx/html、/var/task/… 它们不会出现在报错里,也不会被phpinfo()直接暴露。
- 常见路径探测方式(如
?id=1' and extractvalue(1,concat(0x7e,(select @@datadir)))--+)返回的是MySQL数据目录,不是Web根目录 - 利用
load_file()读/etc/passwd或/proc/self/cmdline可能泄露部分路径线索,但成功率随环境复杂度指数下降 - 一旦Web服务跑在Docker里,宿主机路径对MySQL进程可能是不可见的——这时连
secure_file_priv都成了伪命题

