Pages

Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Tuesday, 7 August 2012

SQL Server: List Explicit Permission on Database for Login and Database Role

As part of security audit of login's, we have discussed earlier about the orphan users , listing server level and database level role membership.To keep the the SQL server secure, it is very important to review the permission/authorization  level of users in database. A user can have access on database in two ways, either through explicit permission or through database role membership.

It is not very easy or there is no system stored procedure to list the explicit permission granted for a user or a database role. The List Login explicit permission on database.sql help us to list the explicit permission granted/denied for user either in object level or in database level. This script will return six columns.Database Name,user name mapped to this login,object(table/function/store procedure etc) name, object type, permission state (grant/deny) and the permission granted /denied. On providing the login name , this script will list permission details of that login in  all databases.

In the same way, List Database Role explicit permission on database.sql help us to list the explicit permission granted/denied for a database role.On providing the database role name , this script will list permission details of that role in  all databases.This will help us if you have same role name across multiple databases.

To summarize the point that we discussed on reviewing the security of database sever:


Hope these scripts will help to review the access level of your environment. 

If you liked this post, do like my page on FaceBook


Monday, 6 August 2012

SQL Server : Lost all Administrator Account in SQL Server and Forgot sa Account Password

What will happen if you lost all your administrator account by mistake ? As per the best practice you have disabled the sa login. Those who had login with sysadmin rights left the company or not able to remember their password. Now you do not have any login with sysadmin rights. How do you get the administrative rights back?  

I had the same kind of scenario on a server which we use very rarely. Later we realized that we lost the administrative rights on that instance and we did not had any idea to get back the sysadmin rights. The only option was destroy the instance and rebuild it.But Microsoft thought about this scenario and kept an option to recover the sysadmin rights. Let us discuss this in detail through this post.

How it works

To solve this issue, we should know two sql server start up parameter 

-f Starts an instance of SQL Server with minimal configuration. This is useful if the setting of a configuration value (for example, over-committing memory) has prevented the server from starting. Starting SQL Server in minimal configuration mode places SQL Server in single-user mode.
-m Starts an instance of SQL Server in single-user mode. When you start an instance of SQL Server in single-user mode, only a single user can connect, and the CHECKPOINT process is not started. CHECKPOINT guarantees that completed transactions are regularly written from the disk cache to the database device. Typically, this option is used if you experience problems with system databases that should be repaired.
Enables the sp_configure allow updates option. By default, allow updates is disabled. Starting SQL Server in single-user mode enables any member of the computer's local Administrators group to connect to the instance of SQL Server as a member of the sysadmin fixed server role.



When we start SQL server in single user mode, it is very common that application which using this server might take the connection and you will not get the connection. To avoid this situation there is an option to give the application name along with the start up parameter. For example, -mSQLCMD will restrict the  connection only from an application named as SQLCMD. To connect only from SQMS, -mMicrosoft SQL Server Management Studio - Query Note that the application name is case sensitive.Any custom build application can change its name by tweaking the connection string(How to do it?)

Now we are going to connect the instance using windows authentication method . Make sure that your windows account is part of the local administrator group of the server on which SQL server resides. Follow the below steps :
  • Stop the sql server instance : This can be done by using the command prompt , SQL server configuration manager or services.msc. To stop from the command prompt, open the command prompt window with administrative rights(right click on the cmd icon  and select Run as administrator)  and run the command  net stop mssqlserver  for  default instance and for named instance                net stop smsqlserver$myinst replace myinst with your instance name.
  • To start the SQL server in single user mode, run the following command from command prompt.                                                       net start mssqlserver /mSQLCMD for named instance,net start mssqlserver$myinst /mSQLCMD   .You can do the same using the SQL server configuration manager by editing the startup parameter as given below and start the service from configuration manager.


  I personally prefer to do it from the command prompt,which gives more control. Make sure that you are mentioning the correct application name with proper case. if you give application name as sqlcmd, when you try to connect it from either from commad prompt or SSMS, it will throw an error :
Login failed for user 'Mydomain\loginname'. Reason: Server is in single user mode. Only one administrator can connect at this time. (Microsoft SQL Server, Error: 18461)
The error itself is misleading. When i tried , I was getting this error and took some time to find out  the issue.

  • Now you can connect to the sql server from the command prompt and can create a login with sysadmin rights or can assign sysadmin rights to an existing login. To connect to the SQL  server from the command prompt , for default instance SQLCMD -Smyservername  for named instance   SQLCMD -Smyservername\myinstancename. Then you can use the following command to create a new login and adding into sysadmin role. 
USE MASTER
GO
CREATE login NewsysadminLogin WITH password='passwordtest123'
GO
sp_addsrvrolemember 'NewsysadminLogin','sysadmin'



Now the login NewsysadminLogin will have the sysadmin rights on the server . Stop the service and start it .If you have modified the startup parameter through the configuration manager , do not forget to remove the singer user switch (-m) from there.


If you liked this post, do like my page on FaceBook

Sunday, 5 August 2012

SQL Server : List Login's Database and Server Level Role Permission

In my last post, we have discussed about the orphaned users and fixing the orphaned users. The next step in the security audit of our server was to review the login's database role membership and server role membership. 

There is a system stored procedure sp_helpsrvrolemember to list server role membership of login, but it is difficult to review the result of this procedure . Below script will give us the server role membership in more readable format.By copying the the result to Excel, it is more easy to review the server role membership of logins. More over system store procedure will not list the logins which have control server permission.

WITH CTE_Role (name,role,type_desc)
AS
(SELECT PRN.name,
srvrole.name AS [role]
Prn.Type_Desc 
FROM sys.server_role_members membership 
INNER JOIN (SELECT * FROM sys.server_principals  WHERE type_desc='SERVER_ROLE') srvrole 
ON srvrole.Principal_id= membership.Role_principal_id 
RIGHT JOIN sys.server_principals  PRN 
ON PRN.Principal_id= membership.member_principal_id WHERE Prn.Type_Desc NOT IN ('SERVER_ROLE') AND PRN.is_disabled =0

UNION ALL


SELECT p.[name], 'ControlServer' ,p.type_desc AS loginType FROM sys.server_principals p
  
JOIN sys.server_permissions Sp
  
ON p.principal_id = sp.grantee_principal_id WHERE sp.class = 100
  
AND sp.[type] = 'CL'
  
AND state = 'G' )

SELECT 
name,
Type_Desc ,
CASE WHEN [public]=1 THEN 'Y' ELSE 'N' END AS 'Public',
CASE WHEN [sysadmin] =1 THEN 'Y' ELSE 'N' END AS 'SysAdmin' ,
CASE WHEN [securityadmin] =1 THEN 'Y' ELSE 'N' END AS 'SecurityAdmin',
CASE WHEN [serveradmin] =1 THEN 'Y' ELSE 'N' END AS 'ServerAdmin',
CASE WHEN [setupadmin] =1 THEN 'Y' ELSE 'N' END AS 'SetupAdmin',
CASE WHEN [processadmin] =1 THEN 'Y' ELSE 'N' END AS 'ProcessAdmin',
CASE WHEN [diskadmin] =1 THEN 'Y' ELSE 'N' END AS 'DiskAdmin',
CASE WHEN [dbcreator] =1 THEN 'Y' ELSE 'N' END AS 'DBCreator',
CASE WHEN [bulkadmin] =1 THEN 'Y' ELSE 'N' END AS 'BulkAdmin' ,
CASE WHEN [ControlServer] =1 THEN 'Y' ELSE 'N' END AS 'ControlServer' 
FROM CTE_Role
PIVOT
(
COUNT(role) FOR role IN ([public],[sysadmin],[securityadmin],[serveradmin],[setupadmin],[processadmin],[diskadmin],[dbcreator],[bulkadmin],[ControlServer])
)
AS pvtWHERE Type_Desc NOT IN ('SERVER_ROLE')ORDER BY name,type_desc



The system stored procedure sp_helprolemember  will help us to list the login's database role membership (system defined and user defined database role membership),but this will work only on database level. To get membership across all databases in an instance, this procedure has to run in each databases. The below script will list all users in all  databases and its database role membership.


SET NOCOUNT ON

CREATE TABLE
#DatabaseRoleMemberShip
  
(
        
Username VARCHAR(100),
        
Rolename VARCHAR(100),
        
Databasename VARCHAR(100)
        
    )
DECLARE @Cmd AS VARCHAR(MAX)DECLARE @PivotColumnHeaders VARCHAR(4000)           SET @Cmd = 'USE [?] ;insert into #DatabaseRoleMemberShip
select u.name,r.name,''?'' from sys.database_role_members RM inner join
sys.database_principals U on U.principal_id=RM.member_principal_id
inner join sys.database_principals R on R.principal_id=RM.role_principal_id
where u.type<>''R'''
EXEC sp_MSforeachdb @command1=@cmd

SELECT  @PivotColumnHeaders =                        
  
COALESCE(@PivotColumnHeaders + ',[' + CAST(rolename AS VARCHAR(MAX)) + ']','[' + CAST(rolename AS VARCHAR(MAX))+ ']'                     
  
)                     
  
FROM (SELECT DISTINCT rolename FROM #DatabaseRoleMemberShip )a ORDER BY rolename  ASC


SET
@Cmd = 'select
databasename,username,'
+@PivotColumnHeaders+'
from
(
select   * from #DatabaseRoleMemberShip) as p
pivot
(
count(rolename  )
for rolename in ('
+@PivotColumnHeaders+') )as pvt'EXECUTE(@Cmd )        DROP TABLE #DatabaseRoleMemberShip 



The same scripts are available Server and Database Role Membership.sql



If you liked this post, do like my page on FaceBook





Thursday, 2 August 2012

SQL Server : Fixing the Orphaned Users

In my last post , we have discussed about orphaned uses and how to find out the orphaned users. In this post let us see how to fix the orphaned users.

In the scenario where the login is got deleted , the orphan users can be fixed by dropping the user from the databases using the below script.
DROP USER Testwindows

Some time the above script may throw an error saying that the users owns a schema.Find out the schema owned by this login by querying the catalog view sys.schema and mapping the principal_id to sys.database_principals.Either drop these schemas or change the ownership based on your environment. To change the ownership of the schema ,use the below command

ALTER AUTHORIZATION ON SCHEMA::SchemaName TO NewUserName;

In the scenario where  database restored in a different environment, we can fix the SID mismatch between the sys.server_principals and sys.database_principals by using the system stored procedure sp_change_users_login. For example you have login Mydomain\Lastname.Firstname in two instances namely INST1 and INST2. This login is associated with the user TestWindowsUser with  db_owner right on one of the database (MyDb) in INST1. Now you have taken backup of MyDb and restored it on the INST2 and  Mydomain\Lastname.Firstname will not be able to access the restored database as its SID is not matching with sys.server_principals SID . To fix this issue we can run the below command on the restored database.
USE MyDb
GO
Exec sp_change_users_login 'update_one''TestWindowsUser''Mydomain\Lastname.Firstname'

Note: This is a deprecated feature in SQL server 2008 and you can use alter user as given below

ALTER USER TestWindowsUser WITH LOGIN [Mydomain\Lastname.Firstname]

If you liked this post, do like my page on FaceBook 

SQL Server:Finding the Orphaned Users

Orphaned user is a common problem in SQL server world.When I was working on internal security audit of our production servers, I realized that sp_change_users_login with report option will not work with users associated with the windows login.

Who is an Orphan Users?

An user in a database is called orphaned when the associated login does not exists in the server or login has different SID. The first scenario can happen when you delete a login from the server. For example you created a login for an employee Mydomain\Lastname.Firstname  and given access to couple of databases.Later this employee left the company or moved to different department.As a part of process we will delete his/her login (Mydomain\Lastname.Firstname) from the server. Now the databases on which he had access will have orphaned users.

The second scenario will happen when you restore the database from one environment (instance) to  another environment(instance) or when you drop the login and create it again.For example you have login Mydomain\Lastname.Firstname in two instances namely INST1 and INST2. This login has db_owner right on one of the database (MyDb) in INST1. Now you have taken backup of MyDb and restored it on the INST2 and surprisingly Mydomain\Lastname.Firstname will not be able to access the restored database. If he/she tries to access the database , SQL server throw  an error

Msg 916, Level 14, State 1, Line 1
The server principal "Mydomain\Lastname.Firstname" is not able to access the database "MyDb" under the current security context.

When you try to create a user on the restored database for Mydomain\Lastname.Firstname , it will throw an error as below
Msg 15023, Level 16, State 1, Line 1
User, group, or role ' Mydomain\Lastname.Firstname ' already exists in the current database.

This is happening because the SID of the login and user in the database is not matching. You can check this by examining the catalog views sys.server_principals and sys.database_principals.


Identifying the orphaned users

To keep the database environment clean and safe, it is important to  delete/fix the orphan users. In general ,the orphaned users created by the  first scenario(login deleted) should be deleted and orphaned users created by second scenario should be fixed. The easiest way to identify the orphaned users is , use the system procedure sp_change_users_login  with report option as given below.

EXEC SP_CHANGE_USERS_LOGIN 'Report'


But interestingly, this procedure will list only the orphaned users associated with the SQL login. If the login associated with windows login, the above procedure will not return the desired result. Let us see an example.

USE MASTER
GO
CREATE LOGIN [MyDomain\TestWindowsLogin] FROM WINDOWS
GO

USE MyDb
GO

CREATE USER Testwindows FROM LOGIN [MyDomain\TestWindowsLogin]
GO

DROP LOGIN [MyDomain\TestWindowsLogin]

Now the user Testwindows  in MyDb is an orphaned users as the login associated with it does not exists. Let us execute procedure sp_change_users_login to report the orphaned users on MyDb database.
USE MyDb
GO

EXEC SP_CHANGE_USERS_LOGIN 'Report'

This execution will not report the TestWindows user as orphaned user.  I have used the script List Orphaned Users.sql  to list the orphaned users from the all databases of an instance.In the script, I have used sp_change_users_login to list the orphaned users associated with SQL logins and custom scrip by joining sys.server_principals and sys.database_principals for orphaned users associated with windows logins.

Also note that in SQL server you can create users with out login for some special purpose. Be careful with that type users while looking for orphaned users  using the catalog view sys.server_principals and sys.database_principals. This special users can be identified by using the below query.


SELECT * FROM sys.database_principals WHERE (LEN(sid) > 16) AND TYPE IN ('S')


I will explain how to fix the orphaned users in my next post.

If you liked this post, do like my page on FaceBook 


Thursday, 29 March 2012

Caveats of a CONTROL SERVER permission

Today morning I was working on one of the server to complete the regular documentation of security audit with details of logins with sysadmin rights and their access to various database. Later I have realized that, one login has access to all database but it is not captured by my auditing script. Here comes the culprit , the CONTROL SERVER rights.

By default CONTROL SERVER rights is equivalent to sysadmin permission except the fact that logins with CONTROL SERVER rights will honor the explicitly denied server level permission where the members of sysadmin server role bypass the explicitly denied server level permission. Also note that logins with control server permission will have implicit access to the databases like the sysadmin members and database owners. 

Logins with control server rights will not have mapping entry in the sys.database_principals but it will have access to all databases. The worst part is, logins with CONROL SERVER permission are not easy to find out unless you prepare explicit query. It is not listed in the UI of  SSMS or there is no system procedure like sp_helpsrvrolemember to list the logins with CONTROL SERVER  right.

Let us walk through a sample script. Create two logins using the below script

CREATE login SysadminLogin WITH password ='password123~'
GO
CREATE login controlserverlogin WITH password ='password123~'
GO
EXEC sp_addsrvrolemember 'SysadminLogin','sysadmin'
GO
GRANT control server TO controlserverlogin 
Now log in to the server using the controlserverlogin  and you can access all the databases and perform any actions. Let us see what will happen on explicitly denying the server level permission.

DENY VIEW ANY DATABASE TO controlserverlogin
GO
DENY VIEW ANY DATABASE TO sysadminlogin
GO

Now log in to the server using both the login. You can notice that, in the session that connected with the controlserverlogin will list only Master and Tempdb databases while the session connected with sysadminlogin will list all available databases.
The other potential issue with logins having control server right is , they can add them self  to the sysadmin server role or can create a new login with membership to the sysadmin server role. Fortunately it is not possible to do it in straight forward steps. Let us see how it will work .Connect to the server using the  controlserverlogin and  execute the below scripts


/* Fortunately  this will fail */ 
EXEC sp_addsrvrolemember 'controlserverlogin','sysadmin';
GO
/* Unfortunately  this will work even if sa account is disabled*/
EXECUTE AS LOGIN = 'sa';
GO
EXEC sp_addsrvrolemember 'controlserverlogin','sysadmin';
GO
REVERT;


Now the controlserverlogin has sysadmin role membership and you can see all available databases.


Below script  list the logins with sysadmin role membership and control server permission.


/* List login with membership to Sysadmin server role and Control Server right*/
SELECT p.[name] [Login], 'sysadmin Role Member' [Access] ,p.type_desc AS loginTypeFROM sys.server_principals p
  
JOIN sys.server_role_members RM
  
ON p.principal_id = rm.member_principal_id
  
JOIN sys.server_principals rp
  
ON rm.role_principal_id = rp.principal_id WHERE rp.NAME = 'sysadmin' UNION ALL SELECT p.[name], 'Control Server Right' ,p.type_desc AS loginTypeFROM sys.server_principals p
  
JOIN sys.server_permissions Sp
  
ON p.principal_id = sp.grantee_principal_id WHERE sp.class = 100
  
AND sp.[type] = 'CL'
  
AND state = 'G' GO

Below script will help to list the explicitly denied server level permission for logins which have control server permission.


/* List Explicitly denied permission for the login that has control server permission*/

SELECT CSL.*,sp.permission_name [Explicitly Denied Permission]  FROM sys.server_permissions  SP INNER JOIN (SELECT p.principal_id ,p.[name], p.type_desc AS loginTypeFROM sys.server_principals p
  
JOIN sys.server_permissions Sp
  
ON p.principal_id = sp.grantee_principal_id WHERE sp.class = 100
  
AND sp.[type] = 'CL'
  
AND state = 'G' ) CSL ON CSL.principal_id = sp.grantee_principal_id
  
WHERE state ='D'



If you liked this post, do like my page on FaceBook at http://www.facebook.com/practicalSqlDba