from:https://www.netspi.com/blog/entryid/221/decrypting-mssql-database-link-server-passwords
建議在看之前先了解下什么是linked server。比如參考微軟的相關學習資料:
http://technet.microsoft.com/zh-cn/library/ms188279.aspx
文章很多專有名詞,而且老外說話的方式和中國的差別還是太大了點……所以有很多地方翻譯的不是很好,見諒。
從重要系統中獲取明文密碼的過程總是充滿著樂趣。MSSQL服務器對本地保存的密碼是進行了加密操作的,鏈接服務器的相關憑證也不例外,但與此同時MSSQL也是有自己的手段可以對相關的密碼憑證進行解密。而你可以直接參考使用本文發布的Powershell腳本對相關的憑證進行解密。以進攻者的角度來看,如果想要解密相關的憑證,我們需要有MSSQL的Sysadmin權限和本地服務器系統管理員的權限。從防御的層面來看,這篇文章的目的主要是想提醒下相關的管理員,不必要的數據庫鏈接、高權限數據庫鏈接和使用SQL server的身份認證會比使用集成的身份認證產生更多不必要的風險。這篇博文推薦給對數據庫感興趣的黑客及打算深入學習的管理員們。
Microsoft SQL Server允許用戶使用MSSQL管理其它不同類型的數據庫,一般情況下鏈接服務器用來管理與本地不同版本的MSSQL服務。當鏈接建立之后,它們可以被配置為使用安全的上下文和靜態sql server憑據。如果sql server的憑據被添加使用了,相關的用戶名和密碼會被加密存儲到相關的表內,而這一加密是可逆的。單向不可逆的hash是不可以用于鏈接服務器的,因為sql server必須要使用明文的密碼信息去訪問其它的數據庫。所以,如果密碼信息是使用了對稱加密而不是單向hash的話,sql server自然會有方法去解密相關的密文憑證。本文主要介紹這一加密、解密的過程及其工具化的實現。
MSSQL將鏈接服務器的信息(包含加密的密碼)保存在master.sys.syslnklgns表中。我們重點關注的加密密碼是保存在字段“pwdhash”中的(雖然寫著hash但是他不是一個普通的hash),下圖是一個例子:
master.sys.syslnklgns表在正常的數據庫連接情況下是無法訪問的,必須在專用管理員連接(DAC)下才可以訪問(更多關于DAC的信息請查看http://technet.microsoft.com/en-us/library/ms178068%28v=sql.105%29.aspx)。打開專用管理員連接有兩個條件:一是需要有mssql的Sysadmin權限,二是本地服務器的管理員權限。
如果本地管理員沒有獲得Sysadmin的權限,你只需要將MSSQL權限修改為本地系統賬戶即可。更多信息請參考https://www.netspi.com/blog/entryid/133/sql-server-local-authorization-bypass
下面介紹一些MSSQL加密的基本原理。首先我們可以先了解一下服務主密鑰(SMK)(更多信息請參考http://technet.microsoft.com/en-us/library/ms189060.aspx)。根據微軟的描述“服務主密鑰為 SQL Server 加密層次結構的根。
服務主密鑰是首次需要它來加密其他密鑰時自動生成的”可知SMK保存在master.sys.key_encryptions表中,而他的key_id對應的值是102。SMK是使用DPAPI來加密的,而這里他有兩個可用的版本,第一種是使用的LocalMachine加密,另一種是CurrentUser的相關上下文(意思是SQL Server服務運行的賬戶)。這里我們挑使用LocalMachine的Machinekey來單獨加密的、解密時不依賴于SQL Server賬戶的格式來討論。下面是一個例子:
為了增強加密的強度,算法中會加入熵(密碼學用語,可自行查閱),不過算法中使用到的熵字節我們可以從注冊表HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\[instancename]\Security\Entropy
中找到。再次提醒,訪問此表項需要本地系統的管理員權限。下圖是熵的一個例子:
搞定上面這些之后(同時必須去除填充字節等)我們就可以使用DPAPI來解密SMK了。
從SMK的長度(或MSSQL的版本)我們可以看出兩種不同的加密算法:MSSQL 2012使用的是AES,而早期的版本使用的是3DES。另外,pwdhash必須解析為bit才可以找到相關的加密密碼。版本使用的算法參考了高級T-SQL程序員發布的文章,見http://stackoverflow.com/questions/2822592/how-to-get-compatibility-between-c-sharp-and-sql2k8-aes-encryption
即使數據的格式和文章內給出的不太一致,但是也并不難發現正確的加密數據。到此,我們已經有辦法使用SMK解密出所有的明文憑證了(當使用的是SQL Server賬戶而不是windows身份認證)。
下面給出powershell的自動解密腳本Get-MSSQLLinkPasswords.psm1的源碼鏈接(譯者提示:該腳本必須在powershell2.0下運行):
https://github.com/NetSPI/Powershell-Modules/blob/master/Get-MSSQLLinkPasswords.psm1
該腳本必須在MSSQL服務器本地運行(DPAPI必須可以訪問到local machine key),同時運行該腳本的用戶必須有數據庫的sysadmin權限(在DAC下)可以訪問所有的數據庫實例,而且該賬戶也必須擁有系統管理器權限(用于讀取注冊表內的熵)。另外,如果啟用了UAC,腳本必須以管理員身份運行。下面幾個是腳本運行的關鍵步驟概要:
1. 獲取本服務器所有MSSQL的實例
2. 為每個實例打開DAC訪問
3. 獲取每個實例的pwdhash字段值
4. 從master.sys.key_encryptions表中讀取出所有key_id值為102的行所對應的SMK,并根據thumbprint字段來判斷其版本
5. 讀取HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\[instancename]\Security\Entropy 中的熵
6. 使用以上信息解密SMK
7. 程序根據MSSQL的版本和SMK的長度來確定使用AES算法或3DES算法
8. 使用SMK明文去解密鏈接服務器的憑證
9. 若程序運行成功則會回顯相關的密碼信息,比如下圖就是一個例子:
在測試這個的過程中很多問題的產生,要不是DAC登錄不上,就是powershell的腳本一直有問題。
目前測試了兩個環境:
1. win2003 + mssql2005
2. win2008 + mssql2008
除了腳本有問題,其它都是可以獲取到的。腳本大部分語法是類似.NET的,基本都是在調用.NET的庫,由于一些時間問題,我就不再獻丑去改了等大牛們來一個“一鍵獲取”。
先看點2003的測試圖:
1.pwdhash
2.讀取加密的SMK
3.查看注冊表key
但是在運行腳本的時候(注意要2.0以上)還是報錯了:
已經測試過兩個參數都非空,而且應該是正確的。
在2008下也是類似的情況。時間關系不再深入,等有興趣的牛牛們再搞搞。
另外,這也是一種“找數據庫連接信息”的方法。雖然有點奇葩,但是預計還是可行的,以后如果可以安排得過來,而且沒有大牛修改上面的腳本的話……我再來獻丑。
第一次搞翻譯,翻譯的不好大家多多原諒。