Skip to content

Commit 8ec985f

Browse files
Part 1 of refactoring of Get-DecryptedObject (#10150)
1 parent de6db36 commit 8ec985f

1 file changed

Lines changed: 66 additions & 45 deletions

File tree

private/functions/Get-DecryptedObject.ps1

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,60 @@
11
function Get-DecryptedObject {
22
<#
3-
.SYNOPSIS
4-
Internal function.
3+
.SYNOPSIS
4+
Internal function.
5+
6+
.DESCRIPTION
7+
Decrypts credentials or linked server passwords from a SQL Server instance using the service master key.
8+
This is necessary because SQL Server does not allow retrieval of plaintext passwords for security reasons.
9+
By leveraging the service master key and the encryption mechanism used by SQL Server, this function can extract the actual passwords for credentials and linked servers.
10+
11+
This function is used by the following public functions:
12+
- Copy-DbaCredential
13+
- Copy-DbaDbMail
14+
- Copy-DbaLinkedServer
15+
- Export-DbaCredential
16+
- Export-DbaLinkedServer
17+
18+
This function is heavily based on Antti Rantasaari's script at http://goo.gl/wpqSib
19+
Antti Rantasaari 2014, NetSPI
20+
License: BSD 3-Clause http://opensource.org/licenses/BSD-3-Clause
21+
22+
.PARAMETER SqlInstance
23+
Dedicated admin connection (DAC) to the SQL Server instance.
24+
25+
.PARAMETER Credential
26+
This command requires access to the Windows OS via PowerShell remoting. Use this credential to connect to Windows using alternative credentials.
27+
28+
.PARAMETER Type
29+
LinkedServer or Credential - what type of object to decrypt.
30+
31+
.PARAMETER EnableException
32+
By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
33+
This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting.
34+
Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch.
535
6-
This function is heavily based on Antti Rantasaari's script at http://goo.gl/wpqSib
7-
Antti Rantasaari 2014, NetSPI
8-
License: BSD 3-Clause http://opensource.org/licenses/BSD-3-Clause
936
#>
1037
param (
1138
[Parameter(Mandatory)]
1239
[Microsoft.SqlServer.Management.Smo.Server]$SqlInstance,
40+
[pscredential]$Credential,
1341
[Parameter(Mandatory)]
1442
[ValidateSet("LinkedServer", "Credential")]
1543
[string]$Type,
1644
[switch]$EnableException
1745
)
1846

1947
$server = $SqlInstance
20-
$sourceName = $server.Name
48+
$sourceName = $server.DomainInstanceName
2149

2250
# Query Service Master Key from the database - remove padding from the key
2351
# key_id 102 eq service master key, thumbprint 3 means encrypted with machinekey
2452
Write-Message -Level Verbose -Message "Querying service master key"
2553
try {
26-
$sql = "SELECT SUBSTRING(crypt_property,9,LEN(crypt_property)-8) AS smk FROM sys.key_encryptions WHERE key_id=102 AND thumbprint=0x0300000001"
54+
$sql = "SELECT SUBSTRING(crypt_property, 9, LEN(crypt_property) - 8) AS smk FROM sys.key_encryptions WHERE key_id = 102 AND thumbprint = 0x0300000001"
2755
$smkBytes = $server.Query($sql).smk
2856
if (-not $smkBytes) {
29-
$sql = "SELECT SUBSTRING(crypt_property,9,LEN(crypt_property)-8) AS smk FROM sys.key_encryptions WHERE key_id=102 AND thumbprint=0x03"
57+
$sql = "SELECT SUBSTRING(crypt_property, 9, LEN(crypt_property) - 8) AS smk FROM sys.key_encryptions WHERE key_id = 102 AND thumbprint = 0x03"
3058
$smkBytes = $server.Query($sql).smk
3159
}
3260
} catch {
@@ -39,7 +67,7 @@ function Get-DecryptedObject {
3967

4068
Write-Message -Level Verbose -Message "Decrypt the service master key"
4169
try {
42-
$serviceKey = Invoke-Command2 -Raw -Credential $Credential -ComputerName $fullComputerName -ArgumentList $serviceInstanceId, $smkBytes {
70+
$serviceKey = Invoke-Command2 -Raw -ComputerName $fullComputerName -Credential $Credential -ArgumentList $serviceInstanceId, $smkBytes {
4371
$serviceInstanceId = $args[0]
4472
$smkBytes = $args[1]
4573
Add-Type -AssemblyName System.Security
@@ -71,34 +99,38 @@ function Get-DecryptedObject {
7199
$ivlen = 16
72100
}
73101

74-
<# NOTE: This query is accessing syslnklgns table. Can only be done via the DAC connection #>
75-
76102
$sql = switch ($Type) {
77103
"LinkedServer" {
78-
"SELECT sysservers.srvname,
79-
syslnklgns.name,
80-
SUBSTRING(syslnklgns.pwdhash,5,$ivlen) iv,
81-
SUBSTRING(syslnklgns.pwdhash,$($ivlen + 5),
82-
LEN(syslnklgns.pwdhash)-$($ivlen + 4)) pass
104+
"SELECT sysservers.srvname AS Name,
105+
NULL AS Quotename,
106+
syslnklgns.name AS [Identity],
107+
SUBSTRING(syslnklgns.pwdhash, 5, $ivlen) AS iv,
108+
SUBSTRING(syslnklgns.pwdhash, $($ivlen + 5), LEN(syslnklgns.pwdhash) - $($ivlen + 4)) AS pass,
109+
NULL AS MappedClassType,
110+
NULL AS ProviderName
83111
FROM master.sys.syslnklgns
84112
INNER JOIN master.sys.sysservers
85-
ON syslnklgns.srvid=sysservers.srvid
86-
WHERE LEN(pwdhash) > 0"
113+
ON syslnklgns.srvid = sysservers.srvid
114+
WHERE LEN(syslnklgns.pwdhash) > 0"
87115
}
88116
"Credential" {
89-
#"SELECT name,QUOTENAME(name) quotename,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"
90-
"SELECT cred.name,QUOTENAME(cred.name) quotename,credential_identity,SUBSTRING(imageval,5,$ivlen) iv, SUBSTRING(imageval,$($ivlen + 5),LEN(imageval)-$($ivlen + 4)) pass,target_type AS 'mappedClassType', cp.name AS 'ProviderName' FROM sys.credentials cred INNER JOIN sys.sysobjvalues obj ON cred.credential_id = obj.objid LEFT OUTER JOIN sys.cryptographic_providers cp ON cred.target_id = cp.provider_id WHERE valclass=28 AND valnum=2"
117+
"SELECT cred.name AS Name,
118+
QUOTENAME(cred.name) AS Quotename,
119+
cred.credential_identity AS [Identity],
120+
SUBSTRING(obj.imageval, 5, $ivlen) AS iv,
121+
SUBSTRING(obj.imageval, $($ivlen + 5), LEN(obj.imageval) - $($ivlen + 4)) AS pass,
122+
cred.target_type AS MappedClassType,
123+
cp.name AS ProviderName
124+
FROM sys.credentials cred
125+
INNER JOIN sys.sysobjvalues obj
126+
ON cred.credential_id = obj.objid
127+
LEFT OUTER JOIN sys.cryptographic_providers cp
128+
ON cred.target_id = cp.provider_id
129+
WHERE valclass = 28
130+
AND valnum = 2"
91131
}
92132
}
93133

94-
Write-Message -Level Debug -Message $sql
95-
96-
<#
97-
Query link server password information from the Db.
98-
Remove header from pwdhash, extract IV (as iv) and ciphertext (as pass)
99-
Ignore links with blank credentials (integrated auth ?)
100-
#>
101-
102134
Write-Message -Level Verbose -Message "Query password information from the Db."
103135

104136
if ($server.Name -like 'ADMIN:*') {
@@ -188,24 +220,13 @@ function Get-DecryptedObject {
188220
$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; }
189221
$decrypted = $decrypted[8 .. $i]
190222

191-
if ($Type -eq "LinkedServer") {
192-
$name = $result.srvname
193-
$quotename = $null
194-
$identity = $result.Name
195-
} else {
196-
$name = $result.name
197-
$quotename = $result.quotename
198-
$identity = $result.credential_identity
199-
$mappedClassType = $result.mappedClassType
200-
$ProviderName = $result.ProviderName
201-
}
202-
[pscustomobject]@{
203-
Name = $name
204-
Quotename = $quotename
205-
Identity = $identity
223+
[PSCustomObject]@{
224+
Name = $result.Name
225+
Quotename = $result.Quotename
226+
Identity = $result.Identity
206227
Password = $encode.GetString($decrypted)
207-
MappedClassType = $mappedClassType
208-
ProviderName = $ProviderName
228+
MappedClassType = $result.MappedClassType
229+
ProviderName = $result.ProviderName
209230
}
210231
}
211232
}

0 commit comments

Comments
 (0)