游客发表
去年冬天,洞何打补丁一个朋友的洞何打补丁电商站被拖库了。攻击者用的洞何打补丁就是MySQL一个已知的UDF提权漏洞,CVE-2016-6662的洞何打补丁变种。他问我:“我这MySQL是洞何打补丁5.7.19,不是洞何打补丁早就修了吗?”我让他跑了一下SELECT VERSION();,结果返回的洞何打补丁是5.7.19-log。问题就出在这个-log上——他装的洞何打补丁是Percona Server的修改版,而Percona当时还没合并Oracle的洞何打补丁补丁。这事说明一个事:打补丁不是洞何打补丁点一下“检查更新”就完事的,你得先搞清楚你跑的洞何打补丁到底是什么。
MySQL的洞何打补丁漏洞补丁分两条线走。Oracle官方每个季度发一次CPU(Critical Patch Update),洞何打补丁比如2023年1月的洞何打补丁CPU就修了十几个MySQL漏洞,包括那个能通过LOAD DATA LOCAL读客户端文件的洞何打补丁CVE-2023-0214。但很多生产环境用的不是Oracle版,是MariaDB、Percona、阿里云RDS、腾讯云TDSQL。这些分支的补丁节奏完全不同。MariaDB通常比Oracle晚2-6周,Percona有时候只发二进制包不发源码补丁。你如果只盯着Oracle的CPU日历,等于蒙着眼睛开车。
具体怎么打?先定位版本。别信mysql --version,那个可能被wrapper脚本改了。登进数据库跑SHOW VARIABLES LIKE 'version%';,看version_comment字段。如果是(Ubuntu),说明是apt装的;如果是Source distribution,那就是自己编译的,补丁得重新编译。我见过有人用yum update mysql-server,结果把Percona换成了Oracle版,数据目录不兼容,直接起不来。所以第一步永远是SELECT @@version, @@version_compile_os, @@version_compile_machine;,把这三个值记下来,再去对应厂商的CVE页面查。
打补丁的方式有三种。第一种是包管理器升级,适合apt/yum装的。但注意,apt upgrade mysql-server有时候只会升小版本,不会跨大版本。比如5.7.40到5.7.41可以,5.7到8.0不行。第二种是二进制替换,下载官方编译好的tar.gz,停库,替换/usr/sbin/mysqld,再启库。这个方式快,但要求你的glibc版本匹配。我有次在CentOS 7上换了一个为CentOS 8编译的mysqld,启动直接报GLIBC_2.28 not found。第三种是源码编译,最稳但最慢。适合用了自定义存储引擎或者打了其他patch的场景。编译参数必须和原来一致,cmake那行命令最好从information_schema.plugins里反推。
补丁打完不是就完了。你得验证。跑SELECT * FROM performance_schema.session_variables WHERE VARIABLE_NAME='version';确认新版本。然后针对具体漏洞做PoC测试。比如修CVE-2021-2307(那个LOAD DATA本地文件读取),你可以写一个LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test;,看是否被拒绝。如果还成功,说明补丁没生效,可能是客户端库没更新——很多漏洞是客户端和服务端都要打补丁的。
还有一个坑:主从复制环境。你从库打了补丁,主库没打,binlog格式可能不兼容。特别是涉及JSON函数或者窗口函数的漏洞修复,5.7.22和5.7.23之间的binlog事件类型有细微差别。我建议先打从库,观察SHOW SLAVE STATUS里的Seconds_Behind_Master和Last_SQL_Error,稳定运行24小时再打主库。别信那些“滚动升级零停机”的教程,MySQL的复制协议没那么智能。
最后说个真实教训。某银行的内网MySQL,DBA打了补丁但忘了更新mysql-community-client。结果应用服务器上的libmysqlclient.so.20还是旧版,连接时触发了一个客户端侧的堆溢出。攻击者没攻进数据库,但通过应用服务器拿到了数据库密码。所以补丁清单里必须包含:服务端、客户端库、连接器(JDBC/ODBC)、以及任何嵌入MySQL的第三方组件。少一个都是洞。
友情链接