在 Microsoft SQL Server 2005 和更新版本中,多個 SQL Server 執行個體會針對內建的 sa 登入使用相同的密碼編譯鹽。 由於所有安裝的鹽都是相同的,因此如果攻擊者可以先取得雜湊密碼的存取權,某些類型的暴力密碼破解攻擊會變得更實用。 雜湊密碼僅可供 SQL Server 系統管理員使用。
症狀
在 SQL Server 2005 和更新版本中,密碼編譯鹽會與 sa 登入一起產生。 如果啟用CHECK_POLICY,則當使用者變更密碼時,不會重新產生加密鹽,以與密碼歷程記錄一致。 預設情況下,SQL Server 2005 啟用CHECK_POLICY。 停用CHECK_POLICY時,sa 登入將不再需要鹽一致性,並且會在下一次密碼變更時重新產生新的鹽。
雖然所有帳戶都是如此,但 sa 登入帳戶是在建置過程中產生的。 因此,其鹽是在相同建置程序期間建立,並在 SQL Server 安裝程式執行個體期間維護。
注意:在 SQL Server 2008 中,此問題也會影響 [原則式管理] 功能所使用的預設登入,但風險會降低。 預設會停用這些登入。
緩和措施
即使密碼編譯鹽在多個安裝中保持不變,也不足以危害密碼雜湊。 若要利用此行為,惡意使用者必須擁有 SQL Server 執行個體的系統管理存取權,才能取得密碼雜湊。 如果遵循最佳實踐,一般使用者將無法檢索密碼雜湊。 因此,他們將無法利用缺乏加密鹽變異。
原因
SQL Server 2005 的 Service Pack 資訊
如果要解決這個問題,請取得最新的 SQL Server 2005 Service Pack。 如需詳細資訊,請按一下下面的文章編號,檢視「Microsoft 知識庫」中的文章:
913089 如何取得 SQL Server 2005 的最新版 Service Pack
SQL Server 2008 的 Service Pack 資訊
若要解決此問題,請取得 SQL Server 2008 的最新版 Service Pack。 如需詳細資訊,請按一下下面的文章編號,檢視「Microsoft 知識庫」中的文章:
968382 如何取得 SQL Server 2008 的最新版 Service Pack
解決方式
若為 SQL Server 2005 Service Pack 2 或更新版本,您可以執行下列指令碼來重設 sa 登入帳戶的密碼編譯鹽。 若要執行指令碼,您必須使用具有 CONTROL SERVER 權限的帳戶登入,或者該帳戶必須是 sysadmin 伺服器角色的成員。 請注意,重設密碼編譯鹽之後,也會重設 sa 登入的密碼歷程記錄。
-- Work around for SQL Server 2005 SP2+
--
-- Sets the password policy check off for [sa]
-- Replaces [sa] password with a random byte array
-- NOTE: This effectively replaces the sa password hash with
-- a random bag of bytes, including the salt,
-- and finally sets the password policy check on again
--
-- After resetting the salt,
-- it is necessary to set the sa password,
-- or if preferred, disable sa
--
CREATE PROC #sp_set_new_password_and_set_for_sa(@new_password sysname, @print_only int = null)
AS
DECLARE @reset_salt_pswdhash nvarchar(max)
DECLARE @random_data varbinary(24)
DECLARE @hexstring nvarchar(max)
DECLARE @i int
DECLARE @sa_name sysname;
SET @sa_name = suser_sname(0x01);
SET @random_data = convert(varbinary(16), newid()) + convert(varbinary(8), newid())
SET @hexstring = N'0123456789abcdef'
SET @reset_salt_pswdhash = N'0x0100'
SET @i = 1
WHILE @i <= 24
BEGIN
declare @tempint int
declare @firstint int
declare @secondint int
select @tempint = convert(int, substring(@random_data,@i,1))
select @firstint = floor(@tempint/16)
select @secondint = @tempint - (@firstint*16)
select @reset_salt_pswdhash = @reset_salt_pswdhash +
substring(@hexstring, @firstint+1, 1) +
substring(@hexstring, @secondint+1, 1)
set @i = @i+1
END
DECLARE @sql_cmd nvarchar(max)
SET @sql_cmd = N'ALTER LOGIN ' + quotename(@sa_name) + N' WITH CHECK_POLICY = OFF;
ALTER LOGIN ' + quotename(@sa_name) + N' WITH PASSWORD = ' + @reset_salt_pswdhash + N' HASHED;
ALTER LOGIN ' + quotename(@sa_name) + N' WITH CHECK_POLICY = ON;
ALTER LOGIN ' + quotename(@sa_name) + N' WITH PASSWORD = ' + quotename(@new_password, '''') + ';'
IF( @print_only is not null AND @print_only = 1 )
print @sql_cmd
ELSE
EXEC( @sql_cmd )
go
---------------------------------------------------------------------------------------
-- Usage example:
--
DECLARE @new_password sysname
-- Use tracing obfuscation in order to filter the new password from SQL traces
-- http://blogs.msdn.com/sqlsecurity/archive/2009/06/10/filtering-obfuscating-sensitive-text-in-sql-server.aspx
--
SELECT @new_password = CASE WHEN 1=1 THEN
-- TODO: replace password placeholder below with a strong password
--
##[MUST_CHANGE: replace this placehoder with a new password]##:
ELSE EncryptByPassphrase('','') END
EXEC #sp_set_new_password_and_set_for_sa @new_password
go
DROP PROC #sp_set_new_password_and_set_for_sa
go
針對 SQL Server 2008,您可以執行下列指令碼。 若要執行指令碼,您必須使用具有 CONTROL SERVER 權限的帳戶登入,或者該帳戶必須是 sysadmin 伺服器角色的成員。
-- Work around for SQL Server 2008
--
------------------------------------------------------------------------
-- Set the password policy check off for [sa]
-- Reset the password
-- Set the password policy check on for [sa] once again
--
-- NOTE: The password history will be deleted
--
CREATE PROC #sp_set_new_password_and_set_for_sa(@new_password sysname, @print_only int = null)
AS
DECLARE @sql_cmd nvarchar(max);
DECLARE @sa_name sysname;
-- Get the current name for SID 0x01.
-- By default the name should be "sa", but the actual name may have been chnaged by the system administrator
--
SELECT @sa_name = suser_sname(0x01);
-- NOTE: This password will not be subject to password policy or complexity checks
-- if desired, this step can be replaced with a "throw away" password for
-- and set the real password after the check policy setting has been set
--
SELECT @sql_cmd = 'ALTER LOGIN ' + quotename(@sa_name) + ' WITH CHECK_POLICY = OFF;
ALTER LOGIN ' + quotename(@sa_name) + ' WITH PASSWORD = ' + quotename(@new_password, '''') + ';
ALTER LOGIN ' + quotename(@sa_name) + ' WITH CHECK_POLICY = ON;'
IF( @print_only is not null AND @print_only = 1 )
print @sql_cmd
ELSE
EXEC( @sql_cmd )
go
---------------------------------------------------------------------------------------
-- Usage example:
--
DECLARE @new_password sysname
-- Use tracing obfuscation in order to filter the new password from SQL traces
-- http://blogs.msdn.com/sqlsecurity/archive/2009/06/10/filtering-obfuscating-sensitive-text-in-sql-server.aspx
--
SELECT @new_password = CASE WHEN 1=1 THEN
-- TODO: replace password placeholder below with a strong password
--
##[MUST_CHANGE: replace this placehoder with a new password]##:
ELSE EncryptByPassphrase('','') END
EXEC #sp_set_new_password_and_set_for_sa @new_password
go
DROP PROC #sp_set_new_password_and_set_for_sa
go
在 SQL Server 2008 中,您可以使用下列指令碼來重設原則型管理登入的密碼編譯鹽。 若要執行指令碼,您必須使用具有 CONTROL SERVER 權限的帳戶登入,或者該帳戶必須是 sysadmin 伺服器角色的成員。
------------------------------------------------------------------------
-- Set the password policy check off for the Policy principals
-- Reset the password
-- Set the password policy check on for them once again
--
-- NOTE:
-- These principals are not intended to establish connections to SQL Server
-- So this SP will also make sure they are disabled
--
CREATE PROC #sp_reset_password_and_disable(@principal_name sysname, @print_only int = null)
AS
DECLARE @random_password nvarchar(max)
SET @random_password = convert(nvarchar(max), newid()) + convert(nvarchar(max), newid())
DECLARE @sql_cmd nvarchar(max)
SET @sql_cmd = N'ALTER LOGIN ' + quotename(@principal_name) + N' WITH CHECK_POLICY = OFF;
ALTER LOGIN ' + quotename(@principal_name) + N' WITH PASSWORD = ''' + replace(@random_password, '''', '''''') + N''';
ALTER LOGIN ' + quotename(@principal_name) + N' WITH CHECK_POLICY = ON;
ALTER LOGIN ' + quotename(@principal_name) + N' DISABLE;'
IF( @print_only is not null AND @print_only = 1 )
print @sql_cmd
ELSE
EXEC( @sql_cmd )
go
EXEC #sp_reset_password_and_disable '##MS_PolicyEventProcessingLogin##';
EXEC #sp_reset_password_and_disable '##MS_PolicyTsqlExecutionLogin##';
go
SELECT name, password_hash, is_disabled FROM sys.sql_logins
go
因應措施
Microsoft 已確認這是「適用對象」一節中列出的 Microsoft 產品中的問題。
此問題最初已在適用於 SQL Server 2005 的 SQL Server 2005 Service Pack 4 中更正。
此問題最初已於適用於 SQL Server 2008 的 SQL Server 2008 Service Pack 2 中更正。