UDF与MOF提权:数据库权限提升的两条经典路径详解
拿到数据库权限时我第一反应往往不是看表而是看服务进程以什么身份在跑。在内网攻防演练里一个看似低价值的数据库账号往往藏着通往系统最高权限的暗线UDF提权与MOF提权就是其中最经典的两条。它们的共同点都是借助高权限进程来完成低权限用户本不该具备的操作不同点则在于一个把数据库引擎当跳板一个把Windows自带的WMI机制当成入口。这篇文章我会把两条链路的原理、前置条件、可用场景拆开讲清楚同时站在蓝队视角梳理检测和加固手段。所有演示命令都只在我的隔离虚拟机中跑过用途仅限技术验证不构成任何实际攻击载荷请务必在授权范围内使用。1. 为什么数据库权限和MOF目录成为提权的突破口1.1 提权问题的本质高权限服务被间接调用Windows下的权限模型其实很简单普通用户的令牌权限有限但系统服务、计划任务、服务类进程往往以更高权限的账户运行比如SYSTEM、Administrators、网络服务账户等。如果攻击者已经拿到了一部分文件写入能力或数据库命令执行能力却不能直接反弹一个高权限Shell就需要找一条“桥”把低权限输入送进高权限进程中触发它执行系统命令。数据库服务就是最常见的桥。MySQL、SQL Server这类组件在内网服务器上太常见了很多运维人员图省事直接用高权限账户启动数据库服务甚至把数据库账号和系统管理员账号混在一起。于是攻击者只要拿到数据库的查询权限或文件写入权限就有可能把“SQL语句”升级为“系统命令执行”。MOF目录则是另一条桥。Windows的WMI服务负责管理各种系统事件它会把某个目录下的脚本化定义文件自动编译并加载。如果攻击者能将文件写入这个目录就相当于给WMI喂了一段由高权限服务代为解释的指令。WMI服务在处理文件时是什么身份命令便以什么身份执行——很多时候就是SYSTEM。这两个口子本质上都算不上什么新颖的“漏洞”而是高权限进程与低权限用户之间存在职责边界却被利用者借道完成了一次权限提升。1.2 两条路线的适用场景定位UDF提权更适合数据库权限可控的场景。比如已经通过弱口令、SQL注入、备份文件泄漏等方式拿到数据库连接或者拿到Webshell后能够执行SQL语句同时当前数据库用户具备创建函数或加载扩展存储过程的权限。MOF提权更适合已经有任意文件写入能力但还缺一个“转化为代码执行”的出口。早期比较经典的一种情况是通过SQL差异备份或者利用漏洞把文件写到系统目录然后等待WMI自动编译执行。用一张表看场景差异会更清楚对比维度UDF提权MOF提权核心入口数据库客户端/SQL语句文件写入能力依赖权限CREATE FUNCTION、文件写入插件目录、加载DLL向wbem\mof目录写入文件执行身份数据库服务账户WMI服务或系统SYSTEM常见目标MySQL、MSSQL Service较早的Windows版本技术栈定位数据库功能滥用Windows管理机制滥用理解了两条路径的定位接下来就一个个拆原理。2. UDF提权让数据库引擎成为系统命令的搬运工2.1 MySQL UDF 是什么为什么它能执行命令UDF全程叫User Defined Function也就是用户自定义函数。MySQL提供了一套扩展机制允许开发者用C/C编写函数编译成动态库后放到插件目录再通过CREATE FUNCTION语句在数据库里注册。注册之后SQL语句里就可以像调用内置函数一样调用它。正常情况下这个功能是为了让数据库处理复杂业务逻辑比如自定义计算、字符串处理等。但问题在于如果你在动态库里写的函数内部直接封装了系统命令执行那MySQL就从一个存储引擎变成了一个命令执行引擎。调用这个函数的SQL语句本质上就是在系统层执行命令。为什么能提权关键不在UDF本身而在MySQL服务进程的运行身份。如果MySQL服务是用SYSTEM或管理员账户启动的那么UDF里触发的命令自然也就继承这个高权限身份。低权限的数据库账号通过注册一个函数再调用它就拿到了系统权限。MSSQL里的xp_cmdshell虽然名义上是扩展存储过程不是严格意义的UDF但在战术目标上和MySQL UDF完全一致找一个数据库引擎提供的系统级命令调用接口借服务进程的高权限去执行命令。因此不少安全资料会把xp_cmdshell也归纳在广义的UDF/自定义执行链里。本文后面提到的UDF默认以MySQL UDF为主碰到MSSQL时会特别说明。2.2 前置条件与实验环境准备在真正的测试环境里第一步永远不是急着加载DLL而是检查前置条件。拿MySQL来说至少要满足以下几条当前数据库用户具备FILE权限或可以写文件能够把动态库文件写入MySQL插件目录MySQL实例的secure_file_priv变量没有限制插件目录写入插件目录存在且当前服务账户对该目录具备写权限动态库文件与MySQL版本、操作系统位数兼容。这些条件查起来很快。登录数据库后运行SHOW VARIABLES LIKE plugin_dir; SHOW VARIABLES LIKE secure_file_priv; SELECT user, host, File_priv FROM mysql.user WHERE user CURRENT_USER();如果plugin_dir返回一个可写路径secure_file_priv返回空字符串或者允许写入且当前用户具备File_priv那这条路就基本通畅了。MSSQL这边则要看几个配置xp_cmdshell是否开启当前账号是否有sysadmin角色或者至少具备EXECUTE权限。xp_cmdshell默认是关闭的但很多历史遗留环境为了业务方方便会把高级选项打开并启用它。检查命令大概是EXEC sp_configure show advanced options, 1; RECONFIGURE; EXEC sp_configure xp_cmdshell;在一台配置合格的测试机上通常会用独立的MySQL服务、干净的系统快照而不是直接在业务环境里尝试。2.3 简化验证步骤隔离环境为了验证整条调用链我在隔离虚拟机里做过一组很克制的实验只执行whoami没有任何弹Shell或破坏性动作。大致步骤如下第一步准备一个自定义函数动态库。安全测试中一般会自己编译或者使用公开研究项目里的演示版本。我这里只说思路动态库里需要暴露一个函数比如sys_eval其内部实现对传入的命令字符串调用系统API执行并返回执行结果。关键点是函数签名要能被MySQL识别同时位数必须匹配。第二步把动态库放到插件目录。在有FILE权限的情况下可以通过SELECT ... INTO DUMPFILE把二进制文件写出。这一步在真实环境中往往是最容易失败的因为插件目录通常不在Web目录下且可能需要系统文件写权限。第三步在MySQL中注册函数CREATE FUNCTION sys_eval RETURNS STRING SONAME udf_example.dll;第四步调用并观察结果SELECT sys_eval(whoami);我在测试机上看到的输出是nt authority\system说明整条调用链确实生效了。此时一个原本只能查表的低权限数据库账号已经具备系统命令执行能力。到这里攻击链的技术验证就完成了接下来的重点就该是把环境恢复、看日志、梳理检测规则。之所以强调只执行whoami是因为UDF一旦上手很容易让人想一步到位做更多事。但从学习角度验证调用链比加载一个重型工具更有价值也更容易把思路吃透。2.4 常见的失败原因与实战心得UDF提权看起来简单实际成功率并不高尤其是现代系统。以下是我在测试中经常踩中的问题插件目录不可写这是最常见的拦路虎。MySQL服务账户权限越低这条路越难走。secure_file_priv限定死目录很多新版MySQL默认限制导出文件只能在特定目录想直接把DLL塞进插件目录会失败。位数不匹配32位动态库往64位MySQL里注册直接报错。杀软和EDR对动态库加载敏感加载路径不在常规白名单里行为检测很快触发告警。组件缺失某些极简安装版MySQL没有UDF扩展模块注册函数会提示找不到符号。还有一类失败完全是因为对“权限”的预期太高。即使MySQL服务是管理员账户运行的到了Windows上如果服务配置了降级或者被调整过服务令牌实际执行命令拿到的是服务账户权限不是完整SYSTEM。所以在测试前最稳妥的做法是先执行一条安全命令查清楚当前身份再决定下一步怎么走。3. MOF提权系统自带机制被当成命令执行入口3.1 WMI、MOF 文件与目录监视MOF是Managed Object Format的缩写翻译过来就是“托管对象格式”。WMI体系用这种文本格式来描述类定义、实例数据、事件等信息。一台Windows机器上WMI服务会定期检查C:\Windows\System32\wbem\mof目录发现新增的MOF文件就会尝试编译并加载到系统中的WMI存储库。这个机制本来是为了方便管理员通过脚本化文件扩展WMI功能比如自动注册一些监控类。问题在于编译和加载动作由WMI服务执行而WMI服务通常拥有本地SYSTEM权限。如果攻击者能把一个精心编写的MOF文件扔进该目录就等于让SYSTEM权限的WMI服务帮助自己完成了一次代码执行。在较早的Windows系统比如Windows Server 2003、Windows XPwbem\mof目录的ACL权限设置并不严格很多低权限用户或服务账号都能写入。后面系统逐渐加固目录默认权限收紧但一些配置错误或降级部署的机器仍然可能放开这个口子。这也是为什么MOF提权被称为“古董级”手段却在老系统中依然有效。3.2 一次MOF文件被编译的过程从写入到执行我拆解一下一次完整链路方便理解攻击者通过某种文件写入能力将MOF文件放入wbem\mof目录WMI服务扫描到新文件调用编译器处理MOF中定义的WMI事件过滤器与消费者被注册当绑定事件触发比如定时器到期、特定进程启动消费者中指定的命令行被执行执行者身份是WMI服务所在的高权限账户通常为SYSTEM。为了说明文件内容结构我在虚拟机里构造过一个“残片”只定义了一个消费者类并没有配套的事件过滤器和绑定关系所以不会真正触发。代码如下instance of CommandLineEventConsumer as $Consumer { Name DemoConsumer; CommandLineTemplate cmd.exe /c whoami C:\\Windows\\Temp\\demo.txt; };这段内容只是用来展示CommandLineEventConsumer的结构它指定了一个Name并在CommandLineTemplate里写了要执行的具体命令。真正的提权还要补上__EventFilter与__EventFilterToConsumerBinding让事件过滤器与这个消费者绑定在一起再由某个事件源触发。这里我不展开完整的可执行载荷因为这已经超出“原理讲解”的边界了。把文件放进目录后如果系统权限允许WMI会在几十秒内完成对该文件的编译。演示机里最终能看到whoami的结果被写入指定文件这说明整条链路已经走通。但我也只在快照虚拟机里这样做过因为一旦触发那条命令就会以SYSTEM身份执行在业务机器上属于非常危险的动作。3.3 MOF提权的适用版本与限制Windows版本对MOF提权的影响非常明显。早期Windows系统里wbem\mof目录对普通用户和多个服务账户开得比较宽导致这类手法大量被用于内网横向后的本地提权。后来微软收紧权限并配合杀毒软件这个目录的好日子基本到头了。从实际测试经验看Windows Server 2003/XP经典适用权限设置宽松成功率较高Windows 7/Server 2008看具体ACL部分降级配置仍然可写Windows 10/Server 2016默认不可行目录权限严格即便有写入能力也大概率被系统拦截。另外现代系统对WMI活动监控越来越强即使文件被写进去后续的事件订阅注册行为也很容易被安全产品识别。所以MOF提权更像是一种需要结合系统版本来看的“时代技术”它现在的价值更多体现在理解WMI机制和检测历史攻击痕迹上。3.4 防御启发从蓝队视角看MOF提权最值得留意的不是那一个文件而是它背后暴露的“高权限服务扫描目录并自动执行”这一模式。类似机制还有启动项、计划任务、系统服务等全部都是“写入”与“触发”的组合。凡是看到这类组合出现都应该警觉。具体到WMI如果安全监控突然发现某台机器上新增了CommandLineEventConsumer或__EventFilter基本可以等同于看到了命令执行前兆。日志也好、EDR也好这类注册行为都是高价值告警信号。4. 两种提权方式的横向对比与组合使用4.1 对比表把两条链路放在一起看脉络会更清楚对比维度UDF提权MOF提权利用入口SQL语句/数据库账户文件写入能力必要权限数据库账号可创建函数/扩展存储过程可写wbem\mof目录最终执行身份数据库服务账户SYSTEM/WMI服务触发方式显式调用SQL函数系统定时扫描/事件触发对系统版本敏感度主要取决于MySQL版本与配置高度依赖Windows版本被检测难度中等行为可能被数据库审计中等偏高WMI活动可被监控典型适用阶段拿到数据库权限后拿到文件写入后这张表也解释了为什么许多安全工程师遇到这两种提权时会一起讨论它们一个是“从远到近”一个是“从文件到代码执行”殊途同归。4.2 组合使用的思路在授权攻防演练中UDF和MOF有时候并不是二选一而是可以串联的。最典型的场景是攻击者已经拿到数据库高权限账号但目标机器的MySQL插件目录不可写secure_file_priv也做了限制UDF走不通。此时如果数据库还能通过差异备份等方式把文件写到系统目录那就可以把MOF文件塞进wbem\mof目录用WMI机制完成命令执行。反过来也一样如果已经有文件写入权但MOF目录权限收得很紧那么可以通过其他手段提升数据库权限再走UDF路线。还有一种思路是把两者作为后门建立和维护的两个备选入口。UDF适合从SQL入口反复进出MOF则更隐蔽因为它不依赖数据库连接只要文件还在系统周期扫描后就能重新注册。但要注意这两类行为都属于安全产品重点监控对象在真实内网中不仅容易暴露还可能直接把系统搞崩。没有授权的前提下碰任何一个都是不可接受的。4.3 哪些场景会选择哪种选择哪条路本质是看当前手上有什么筹码如果已经通过Webshell获得数据库连接的权限且数据库是MySQL优先检查plugin_dir和CREATE FUNCTION权限条件合适直接走UDF如果数据库是MSSQL且xp_cmdshell可用那直接走扩展存储过程路线不需要绕如果手上只有文件写入能力比如Webshell可以写文件但执行不了命令检查系统版本老系统里MOF是性价比很高的选择如果目标系统很新、目录权限收紧那么无论UDF还是MOF都不该作为第一优先项而是要考虑其他配置类漏洞。这里给一条很实用的判断顺序先看服务身份再看目录权限最后才决定载荷形式。很多新手一上来就想着加载DLL或者写MOF文件结果因为前置条件不满足白忙一场。5. 蓝队视角如何发现与阻断这两条提权链5.1 关键日志点对蓝队来说UDF和MOF提权都可以被归纳成几个可观察的异常行为首先是进程链异常。正常情况下wmiprvse.exe不应频繁派生cmd.exe或powershell.exe。如果安全监控里看到WMI服务创建了命令行子进程尤其命令行里还带下载执行、反弹连接等参数这是非常明确的异常信号。其次是文件系统变化。wbem\mof目录新增文件或者MySQL插件目录出现新的DLL都可能意味着有人在布置下一步动作。很多EDR会把这类目录加入敏感路径但传统基于签名的防病毒未必能发现。再次是数据库层面。MySQL的通用查询日志会记录CREATE FUNCTION、SELECT ... INTO DUMPFILE等语句。MSSQL的审计和错误日志里则能看到xp_cmdshell相关配置变更和调用记录。把数据库审计打开虽然不是每套业务系统都能接受但至少对高权限实例应该开启。最后是WMI事件订阅。使用管理员权限在目标机器上执行以下命令可以查看当前存在哪些事件订阅Get-WmiObject -Namespace root\subscription -Class __EventFilter Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer Get-WmiObject -Namespace root\subscription -Class __EventFilterToConsumerBinding正常系统里这些结果通常很少出现大段可疑命令行的消费者基本可以确认有问题。5.2 加固清单防护并不是靠某一个补丁而是把整条提权链路上可被借力的点都收紧。数据库方面MSSQL如果不需要xp_cmdshell直接禁用是最简单的EXEC sp_configure show advanced options, 1; RECONFIGURE; EXEC sp_configure xp_cmdshell, 0; RECONFIGURE;MySQL方面限制secure_file_priv到指定目录不要把插件目录设置成服务账户和Web账户都可写同时用独立的低权限服务账户运行数据库。系统层面对wbem\mof目录做ACL收敛。老系统上可以用icacls把目录权限收紧到SYSTEM和Administrators但这需要评估业务影响因为一些依赖WMI的管理脚本可能受影响。EDR和HIDS侧重点关注WMI活动、DLL加载、服务账户异常命令执行并把UDF注册、MOF目录写入这类行为加入自定义规则。这里想多提一句加固不是把所有口子都封死而是在不影响业务的前提下把“低权限入口”和“高权限执行”之间的距离拉大。距离拉得越大攻击者就需要越多的前置条件暴露机会也就越多。5.3 检测手段的盲区日志和EDR并非百分百可靠。数据库查询日志如果没开UDF注册动作是看不到的WMI日志如果被攻击者在拿到SYSTEM权限后清理前期痕迹也能被抹掉。所以蓝队不能只依赖单一数据源而是要围绕“服务进程为什么创建了可疑子进程”这一点做关联。实操中可以配合Sysmon把进程创建、DLL加载、文件写入时间线打通。一旦wmiprvse.exe、cmd.exe、C:\Windows\Temp这几个元素同时出现告警优先级直接拉满。6. 我的一点实测体会隔离环境里做实验一定要养成先做快照的习惯。我第一次复现UDF提权时由于动态库位数不匹配MySQL服务直接崩溃折腾半天才恢复。后面无论是验证UDF还是MOF我都坚持先把虚拟机快照做好再动手。另一个体会是这类老技术放到今天的攻防演练里价值早已从“直接打穿”转向“理解攻击思维”。UDF和MOF的细节可能过时但“找一个高权限服务替你执行命令”这条思路永远不过时。蓝队如果只记住两条具体告警而不理解背后的权限转移逻辑遇到新变种还是会反应不过来。最后分享一个很实际的小技巧不管做红队还是蓝队拿到一台机器的权限后先执行whoami和systeminfo看完身份、补丁、目录权限再决定下一步用什么技术。UDF和MOF只是工具箱里的两个工具工具用不用取决于环境支不支持而不是你想不想。我在实践中吃过好几次“工具很酷环境不配合”的亏提前把前置条件摸清楚能替你省下大把时间。授权范围内慢就是快。