ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

数据库提权实战:从权限分析到命令执行的完整指南

数据库提权实战:从权限分析到命令执行的完整指南 数据库提权这事说起来挺有意思。很多人第一次接触渗透测试看到“提权”两个字就觉得是高深莫测的漏洞利用但真上手之后才发现大部分情况下比的不是谁掌握的黑魔法多而是谁更理解目标系统本身的“权限设计逻辑”。尤其是数据库它几乎可以说是整个权限提升链条里最容易被低估的一环。这篇东西我把自己在授权测试里常用的命令和判断思路整理出来不聊虚的全是能落到终端里跑一跑、能帮你把“下一步怎么走”想清楚的干货。不管你是刚入行的安全新人还是被叫去救火的运维老哥只要你的工作里会碰到数据库这台“权限中转站”这篇文章都值得你花十分钟认真看一遍。先说清楚一个前提所有内容都建立在你有明确授权、或者在自己的实验环境里操作的基础上。没有授权去碰别人的库那不是渗透测试是违法这点没有任何模糊空间。下面聊的所有命令和思路更多是帮你理解攻击者会怎么想、怎么看从而知道该在哪些地方堵住缺口。1. 数据库提权到底在提什么权先把核心问题想清楚1.1 为什么数据库会成为权限提升的重点目标我在之前的文章里反复提过一个观点渗透测试里真正决定成败的往往不是那个最炫的漏洞而是攻击路径上有没有一个“权限放大器”。数据库就是最典型的权限放大器。原因其实不复杂。首先数据库是几乎所有业务系统的核心它必须被应用服务器连接、被运维人员管理、被备份系统读取所以它天然拥有很多“合法”的高权限入口。其次很多数据库服务进程本身的运行权限就非常高——Windows下SQL Server常以LocalSystem或NetworkService运行Linux下MySQL也可能因为历史原因被配置成root启动这就意味着一旦你能在数据库里执行命令你执行的命令实际上带着这个高权限进程的身份。更关键的是数据库系统本身提供了大量“扩展能力”自定义函数、存储过程、CLR程序集、外部脚本、文件读写……这些功能设计的初衷是方便开发者但在安全视角下每一个都是通往操作系统的潜在跳板。攻击者拿到一个脆弱的数据库账号未必能直接读到敏感数据但如果他能借助这些扩展功能把能力放大到操作系统层面后续的横向移动和数据窃取就只是时间问题了。这里可以打个比方。数据库就像大楼的物业管理办公室表面上你进去只能查点水电记录但办公室里放着整栋楼的设备图纸、钥匙卡和维修工具。如果物业人员安全意识差把钥匙卡乱放那一个本来只该在门厅活动的人就可能顺着办公室里的工具间一路摸到核心机房。加固数据库本质就是在管理这间“物业办公室”的钥匙。1.2 提权路径的本质从数据权限到操作系统权限理解了“权限放大器”这个定位再看提权路径就会发现不管是什么数据库路径骨架都出奇一致。通常的路径是这样的先是外围突破攻击者通过Web漏洞、弱口令、备份文件泄漏等方式拿到一个数据库账号然后是这个账号本身的权限扩张从只能查数据到能写文件、能创建函数、能执行系统命令最后一步是数据库服务进程权限向系统权限的跨越比如借助服务账号过高权限直接拿到系统Shell甚至域管理员权限。这里面有三个关键节点值得注意。第一个节点是“从查询到写入”也就是说攻击者需要获得FILE权限或者能操作文件系统的能力这是从数据库内部走向外部的物理前提。第二个节点是“从写入到执行”比如往插件目录写入动态链接库并创建自定义函数或者启用xp_cmdshell这样的扩展存储过程这一步完成了从数据操作到命令执行的跨越。第三个节点是“从普通命令到高权限命令”这一步往往不取决于数据库本身而取决于数据库服务进程是以什么身份在跑——如果服务本身就是SYSTEM那执行命令直接就拿到了系统最高权限。防御方要做的不是在这三个节点上全部严防死守——那几乎不可能——而是选择成本最低、效果最好的那一两个节点重点布防。比如禁止DIRECTORY写权限、禁用扩展存储过程、确保服务账号最小权限只要砍断其中一环这条链就断了。1.3 一个必须划清的边界授权测试与非法入侵写到这里必须停下来把边界说透。网上很多“提权命令大全”“数据库提权速查”之所以让人反感是因为它们把攻击步骤写得像菜谱一样好像对着任何一台机器都能来一遍。但真正的安全从业者都清楚没有授权边界的“测试”就是不折不扣的攻击。我在实际工作中见过不少因为边界模糊翻车的案例。有人觉得自己只是“练练手”找了个公网IP试了试结果对方系统当场宕机最后被请去喝茶也有人明明只被授权测试某个Web应用却顺手把内网的数据库全部扫了一遍导致客户直接终止合作并报警。所以无论你看到多少命令、多少技巧先问自己一句这台机器我有没有权碰我的测试范围和动作边界在哪里这篇文章里出现的所有命令在自有环境或者授权测试里怎么跑都行但拿到生产系统上每一个命令都可能变成呈堂证供。这是底线没有商量的余地。2. 常见数据库提权路径与原理解读先懂原理再谈命令2.1 MySQL自定义函数UDF与文件读写权限是最经典的跳板MySQL的提权路径里最经典、也最常被提到的就是UDFUser Defined Function用户自定义函数提权。这个机制的初衷是让开发者能自己编写函数扩展MySQL的功能但问题在于MySQL加载UDF时需要往插件目录写入动态库文件如果数据库账号具有FILE权限且插件目录对MySQL进程可写那就等于给攻击者开了一扇直接通往系统命令执行的大门。实际操作中攻击者的思路大致是这样先拿到MySQL账号并确认其权限然后查看插件目录位置和secure_file_priv参数限制接着尝试通过SELECT ... INTO OUTFILE把构造好的动态库文件写入插件目录最后创建自定义函数调用它执行系统命令。整个过程每一步都不复杂但每一步的基础都是数据库自身把权限放得太宽。作为防御者你需要知道几个关键的查询命令。比如查看当前账号权限用 SHOW GRANTS FOR CURRENT_USER();查看插件目录用 SHOW VARIABLES LIKE plugin_dir;查看文件读写限制用 SHOW VARIABLES LIKE secure_file_priv;。这些命令在授权测试中也能帮助你快速判断目标的暴露面有多大。顺带提一句MySQL还有一个容易被忽略的高风险点general_log 和 slow_query_log 的日志文件写入。在旧版本或配置不当的情况下攻击者可以尝试把日志文件路径指向Web目录再往日志里写入恶意内容达到getshell的效果。这个思路与UDF不同但对配置检测的要求更高实战中也更隐蔽。2.2 SQL Serverxp_cmdshell与CLR程序集的“权力通道”SQL Server的提权故事里xp_cmdshell是绕不开的角色。这个扩展存储过程的作用就是直接执行操作系统命令它的本意是给管理员提供方便但由于历史版本里权限控制不严格一旦数据库账号具备sysadmin角色就能轻松启用并调用它执行任意命令。除了xp_cmdshellCLR公共语言运行时程序集是另一个常见路径。SQL Server允许注册.NET程序集作为存储过程或函数这意味着只要数据库账号有CREATE ASSEMBLY权限就可以把一个自己写的.NET代码注册进去然后在SQL里调用它执行任意操作包括启动进程、访问文件系统、发起网络请求等。相比xp_cmdshellCLR的隐蔽性更好因为它不依赖系统预置组件而是把恶意逻辑打包成“合法”的数据库对象。检测方面你可以用SQL语句直接查系统配置SELECT name, value_in_use FROM sys.configurations WHERE name xp_cmdshell;也可以查可疑的CLR程序集SELECT * FROM sys.assemblies;。在授权测试中这些命令能快速确认SQL Server是否开启了高危功能也能帮助你在应急响应时判断这台机器是否已经被“照顾”过。这里要特别强调一个认知xp_cmdshell本身不是漏洞它是功能。真正的问题在于这个功能被暴露给了不必要的账号而且服务进程往往以过高的权限运行。所以加固SQL Server的关键不是见到xp_cmdshell就删而是确保只有真正的管理员才能接触这些能力服务账号尽可能用最小权限的虚拟账号。2.3 Oracle与PostgreSQLJava存储过程与扩展模块是另一片战场相比MySQL和SQL ServerOracle和PostgreSQL的提权路径往往更容易被新手忽略但它们在实际攻防里一点都不少见。Oracle数据库的提权手段不少常见的有利用Java存储过程。Oracle内置了Java虚拟机允许在数据库里执行Java代码如果攻击者获得了创建Java存储过程的权限就能借此调用Runtime.exec()执行系统命令。这个过程不需要向文件系统写任何东西完全在数据库内部完成隐蔽性很强。另一个方向是利用外部表External Table读取操作系统文件尤其是读取Linux下的/etc/passwd、Web配置等敏感文件。PostgreSQL的话最常被人提起的是COPY命令和自定义函数CVE-2019-9193等历史问题。默认情况下数据库账号如果具备超级用户权限可以借助COPY ... FROM PROGRAM直接执行系统命令。这个思路极其直接一条SQL就能完成从数据库到系统的跨越。PostgreSQL还有一个特性是支持PL/pgSQL语言可以编写触发器和函数在特定条件下执行任意代码这在权限维持场景中很常见。所以如果你在授权测试里碰到Oracle或PostgreSQL千万别只盯着数据库版本和漏洞库先看看账号角色、函数、触发器、扩展模块这些“常规功能”有没有被滥用。很多时候真正的风险恰恰来自这些“合法能力”。2.4 国产数据库与容器化场景新瓶装旧酒原理还是那一套这些年用达梦、人大金仓、GaussDB等国产数据库的政企项目越来越多很多安全新人会下意识觉得“国产库应该安全些吧”。但接触过之后你就知道数据库的权限设计逻辑是共通的换了个壳不代表内核思路就变了。以达梦为例它兼容Oracle和MySQL的部分语法同样支持存储过程、自定义函数、外部文件读写等能力。有些版本在默认配置下数据库账号对某些目录的访问权限控制并不比商业数据库更严格这其实就是老熟人换了张新面孔。容器化环境也一样MySQL跑在Docker里未必就比裸机更安全——容器内的权限隔离确实削弱了一部分提权路径但也带来了新的风险面比如数据库文件挂载目录的权限、容器逃逸、以及镜像里预置的高危配置。在测试时我先用常规思路把数据库的权限地图画出来再根据具体产品文档补充它特有的功能点。国产库往往有更细的“模式”“表空间”“包”概念搞清楚这些之后很多提权路径的本质就清晰了。3. 授权环境下的实操一份可参考的检测与验证命令清单3.1 先把实验环境搭起来没有靶场一切命令都是纸上谈兵如果你打算把下面这些命令亲手跑一遍第一件事不是找目标而是搭一个完全可控的本地环境。我的习惯是准备两台虚拟机一台装Windows Server并部署SQL Server另一台装Linux并部署MySQL和PostgreSQL网络模式设为仅主机或者NAT加防火墙拦截出站确保实验环境与真实生产网络彻底隔离。安装时要注意数据库版本尽量选接近你在实际工作中会遇到的版本因为不同版本的安全配置和默认权限差异很大。装好之后记得先做快照方便随时回滚。我见过不少人在自己环境里测试时把数据库搞坏了没有快照只能重装浪费时间。搭建过程中你顺便可以体验一下“默认配置有多危险”。比如MySQL刚装完时root账号是空密码还是随机密码SQL Server的sa账号是否启用了混合认证这些细节稍后都会变成测试的突破口。3.2 核心命令块一MySQL下怎么快速摸清权限底牌连接上MySQL之后我通常会按顺序执行下面这组命令把数据库的权限地图先画出来-- 查看当前登录用户和主机 SELECT current_user(), user(); -- 查看当前用户拥有的权限 SHOW GRANTS FOR CURRENT_USER(); -- 查看全局文件读写限制 SHOW VARIABLES LIKE secure_file_priv; -- 查看插件目录位置 SHOW VARIABLES LIKE plugin_dir; -- 查看MySQL版本 SELECT version(); -- 查看已有的自定义函数 SELECT * FROM mysql.func; -- 查看是否开启日志文件写入 SHOW VARIABLES LIKE general_log; SHOW VARIABLES LIKE slow_query_log;这些命令本身非常基础没有任何破坏性但在授权测试时却能让你快速判断几个关键问题当前账号有没有FILE权限决定能否读写文件、secure_file_priv是空还是NULL还是指定目录决定文件能写到哪、插件目录在哪决定UDF利用是否可行、mysql.func里有没有可疑函数判断目标是否已经被打过。您可以看到信息收集是整个提权判断的第一步也是最关键的一步。3.3 核心命令块二SQL Server里检测高危配置和扩展存储过程SQL Server这边我常用的检测命令集中在系统视图和系统配置上-- 查看当前登录账号和服务器角色 SELECT SUSER_SNAME(); SELECT IS_SRVROLEMEMBER(sysadmin); -- 查看xp_cmdshell是否启用 SELECT name, value_in_use FROM sys.configurations WHERE name xp_cmdshell; -- 查看所有扩展存储过程重点关注有命令执行能力的 SELECT * FROM sys.all_objects WHERE type X ORDER BY name; -- 查看数据库中的CLR程序集 SELECT * FROM sys.assemblies; -- 查看所有数据库账号及角色 SELECT name, type_desc FROM sys.database_principals;这里要提醒一点sys.configurations里的value_in_use为1只代表当前运行状态已启用不代表配置已经持久化。在测试环境中如果你想验证XP_cmdshell执行的边界可以用sp_configure开启后再关闭操作完后务必确认已经复原。在生产环境里这类操作哪怕只是临时开启也要经过审批并留下记录不能随手就做。对于CLR程序集我见过不少运维根本不知道自己的库里有第三方程序集更不知道这些程序集是干嘛的。所以排查CLR时遇到看不懂名字的、来源不明的程序集宁可先把它禁掉也不要留着当定时炸弹。3.4 核心命令块三Oracle与PostgreSQL的信息收集命令Oracle和PostgreSQL的权限体系各有一套逻辑我简单列一下我在测试时常用的查询Oracle侧-- 查看当前用户 SELECT user FROM dual; -- 查看当前用户系统权限 SELECT * FROM session_privs; -- 查看用户角色 SELECT * FROM user_role_privs; -- 查看Java存储过程 SELECT object_name, object_type FROM user_objects WHERE object_type LIKE %JAVA%; -- 查看外部表 SELECT table_name FROM user_tables WHERE table_name IN (SELECT table_name FROM user_external_tables);PostgreSQL侧-- 查看当前用户和权限 SELECT current_user; SELECT * FROM information_schema.role_table_grants WHERE grantee current_user; -- 查看是否超级用户 SELECT rolsuper FROM pg_roles WHERE rolname current_user; -- 查看扩展模块 SELECT * FROM pg_extension; -- 查看自定义函数 SELECT proname FROM pg_proc WHERE pronamespace public::regnamespace;这些命令背后对应的是攻击者会看的东西有没有Java存储过程权限、有没有外部表权限、是不是超级用户、能不能创建扩展。如果你在加固时发现某个业务账号拥有超级用户权限或者PUBLIC角色对这些函数有执行权限这就是一个值得立即整改的红线问题。3.5 用日志和审计功能做一次“反向溯源”除了主动查询配置我还特别建议在实验环境里把数据库日志审计打开看看一次完整的提权尝试会在数据库里留下什么痕迹。以MySQL为例-- 开启通用日志仅限实验环境 SET GLOBAL general_log ON; SET GLOBAL general_log_file /tmp/mysql_general.log; -- 查看binlog状态 SHOW VARIABLES LIKE log_bin; SHOW BINARY LOGS;在SQL Server里可以开启审计功能或者在测试前把默认跟踪打开。做完一次模拟测试后回到日志里看看哪些命令被记录、哪些操作能对上号。这个过程能帮你建立“攻击行为痕迹”的敏感度将来做应急响应时你会更容易从海量日志里捞出关键线索。3.6 红线自检从防御者视角给数据库打分最后每次测试结束后我都会做一次“红线自检”相当于给这台数据库的安全状态打分。打分维度包括服务账号是否最小权限、是否有非管理员账号拥有FILE或sysadmin等高权限、高危扩展存储过程和自定义函数是否清理干净、数据库补丁是否到位、错误日志和审计日志是否定期备份并留存、数据库配置文件里有没有明文密码或过宽监听地址。打分不是为了写报告好看而是让自己形成一套可重复的检查习惯。你不需要一次把所有项目都做到满分但至少要清楚自己的系统在哪些维度上扣了分以及这些扣分项如果被攻击者利用会造成多大影响。4. 常见问题与排查技巧实录4.1 明明有权限为什么文件就是写不进去这个问题我很早期测试时遇过多次明明SHOW GRANTS里带着FILE权限SELECT ... INTO OUTFILE却总是报错。后来排查多了才发现大概率是下面几个原因。头号嫌疑犯是secure_file_priv参数。这个参数在MySQL 5.7及以上版本默认控制很严如果值是NULL那就完全禁止文件读写如果值指定了目录那么只能往这个目录里写别的路径一概不行。很多测试者没意识到这个参数的存在在/tmp或WEB目录下一顿操作结果全部失败。第二个常见原因是操作系统目录权限MySQL进程用户对目标目录没有写权限这跟数据库权限无关纯粹是文件系统层面的限制。第三个原因就要复杂一点可能是安全防护软件或EDR对写入行为做了拦截这种在Windows上尤其常见杀毒软体会把dll或exe的写入视为恶意行为直接阻止。遇到这类问题我的习惯是先确认参数再确认目录权限最后才考虑是不是有安全软件拦截。排查顺序反了很容易浪费时间。4.2 低版本数据库为什么总是提权重灾区原因有三层。第一老版本数据库本身存在大量已公开但未修复的漏洞比如老版本MySQL的UDF提权漏洞、老版本SQL Server的xp_cmdshell滥用、PostgreSQL的某些COPY命令漏洞等。这些漏洞在网上有大量现成的利用工具和详细的复现教程攻击门槛极低。第二老版本数据库通常运行在更老的操作系统上操作系统本身的补丁可能也不全数据库漏洞和系统漏洞叠加问题就成倍放大。第三历史遗留配置问题很多数据库是多年前部署的当年安全意识不强服务账号直接用了administrator或root各种扩展功能也开着后期没人敢动也不敢重启就一直带病运行。所以遇到低版本数据库先别想着怎么利用把补丁清单拉出来、把服务账号权限捋一遍、把高危功能查一遍光这“老三样”就能堵住绝大多数已知路径。4.3 容器化数据库是不是更安全别高兴太早Docker里的MySQL或PostgreSQL确实比裸机多一些限制比如容器默认不会给root权限、文件系统有写保护、网络默认隔离等。但很多团队在实际部署时为了提高便利性往往会加--privileged参数、挂载宿主机目录、使用root用户运行容器进程这些操作等于把容器的安全隔离亲手拆掉了。我见过一个案例某业务把MySQL丢在Docker里但挂载了宿主机整个/etc目录用于“方便备份”结果攻击者通过SQL注入拿到数据库权限后反向读出了宿主机的SSH私钥。这种风险不是数据库本身的问题而是使用容器的方式出了问题。所以在容器化场景下检测重心要从数据库内部延伸到容器外——重点看挂载目录是不是敏感、容器是否以特权模式运行、进程是否以root身份运行、宿主机Docker API是否暴露到了网络上。4.4 真实排查案例从一次“高权限数据库账号”看应急响应的完整思路最后分享一个我处理过的典型案例。某天客户突然发现他们一台应用服务器被上传了Webshell排查后发现入侵者最早是从一个老旧的业务后台系统注入SQL拿到MySQL的root权限然后利用UDF自定义函数执行系统命令再通过计划任务建立了持久化后门最终用这台服务器当跳板在内网翻了一圈。整个排查过程里数据库相关的工作占了很大比例。我先通过慢查询日志和binlog定位到了恶意SQL语句的执行时间再检查mysql.func表发现了新增的恶意函数接着在val插件目录里找到了攻击者留下的动态库文件最后顺着系统登录日志和计划任务脚本把后门清理干净。处置完成后给客户的建议也很直接这套系统已经无法完全信任建议在迁移数据后彻底重建同时把数据库升级到最新版本、停止使用高权限业务账号、删除UDF插件目录里的非白名单文件、开启审计日志并异地备份。这个案例想说明什么说明数据库层面的提权不是一个孤立的“技术炫技”它是整个攻击链里非常关键的一环。只有理解这一环防御者才知道该在哪里设卡、该保留什么证据、该整改哪些系统。我自己这些年做下来最大的感受是提权命令清单这种东西真正有用的不是那几条具体的SQL命令而是命令背后的“权限思维”。当你拿到一个数据库连接时能在脑子里快速画出一条从当前权限到系统权限的路径图并且知道哪条路已经被堵死、哪条路还开着那你无论是做攻击侧的验证还是做防御侧的加固都会比单纯背命令高效得多。最后再多说一句实验环境尽量多用快照、多清理现场测试完之后把日志、文件、临时账号都恢复原状这既是职业习惯也是基本的操作素养。
返回列表