Last active
October 6, 2017 17:57
-
-
Save RamblingCookieMonster/efcdd93cbcbffded1567 to your computer and use it in GitHub Desktop.
Fun with Thycotic Secret Server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Picked up a trial for Thycotic Secret Server. | |
Very impressed so far. Simple setup, had a quick and dirty Get-Secret function a few minutes later. | |
All code here assumes you have configured IIS and Secret Server to allow Windows Authentication, and have enabled web services. | |
This is quick and dirty, i.e. we don't handle errors, we don't handle varying environments, etc. | |
ConvertTo-FlatObject is here: https://gallery.technet.microsoft.com/ConvertTo-FlatObject-396a6e0a | |
#> | |
#First steps! What are we working with? | |
#Create a web service proxy using your windows creds | |
$uri = 'https://secretserver.FQDN/winauthwebservices/sswinauthwebservice.asmx' | |
$proxy = New-WebServiceProxy -uri $uri -UseDefaultCredential | |
#What sort of methods and properties are exposed? API docs indicate most of this, and you can browse to the asmx for a handy tool | |
$Proxy | Get-Member | |
#SearchSecrets sounds good. What do we need to pass it? | |
$proxy.SearchSecrets | |
#Looks like we need a searchterm (null for all), and whether to include deleted and restricted. Let's try calling it | |
$proxy.SearchSecrets($null,$false,$false) | |
<# | |
Errors SecretSummaries | |
------ --------------- | |
{} {REDACTED...} | |
#> | |
#Okay, time to start using ConvertTo-FlatObject - https://gallery.technet.microsoft.com/ConvertTo-FlatObject-396a6e0a | |
$proxy.SearchSecrets($null,$false,$false) | ConvertTo-FlatObject -ExcludeDefault $False | |
<# | |
$Object.SecretSummaries : {REDACTED...} | |
$Object.SecretSummaries[0].SecretId : 5 | |
$Object.SecretSummaries[0].SecretName : REDACTED | |
$Object.SecretSummaries[0].SecretName.Length : 19 | |
$Object.SecretSummaries[0].SecretTypeName : Windows Account | |
$Object.SecretSummaries[0].SecretTypeName.Length : 15 | |
$Object.SecretSummaries[0].SecretTypeId : 6003 | |
$Object.SecretSummaries[0].FolderId : 26 | |
$Object.SecretSummaries[0].IsRestricted : False | |
$Object.SecretSummaries[1].SecretId : 3 | |
$Object.SecretSummaries[1].SecretName : REDACTED | |
$Object.SecretSummaries[1].SecretName.Length : 27 | |
$Object.SecretSummaries[1].SecretTypeName : Password | |
$Object.SecretSummaries[1].SecretTypeName.Length : 8 | |
$Object.SecretSummaries[1].SecretTypeId : 2 | |
$Object.SecretSummaries[1].FolderId : 4 | |
$Object.SecretSummaries[1].IsRestricted : False | |
#> | |
#I explore more, find GetSecret command. See secret ID above? we use that | |
$proxy.GetSecret(5,$false, $null) | |
<# | |
Errors SecretError Secret | |
------ ----------- ------ | |
{} Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1vices_sswinauthwebservice_asmx.Secret | |
#> | |
#ConvertTo-FlatObject again... Now we get the good stuff! | |
$proxy.GetSecret(5,$false, $null) | ConvertTo-FlatObject -ExcludeDefault $False | |
<# | |
$Object.Secret : Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1vices_sswinauthwebservice_asmx.Secret | |
$Object.Secret.Name : REDACTED | |
$Object.Secret.Name.Length : 19 | |
$Object.Secret.Items : {17, 18, 19, 20} | |
$Object.Secret.Items[0].Value : Clients | |
$Object.Secret.Items[0].Value.Length : 7 | |
$Object.Secret.Items[0].Id : 17 | |
$Object.Secret.Items[0].FieldId : 83 | |
$Object.Secret.Items[0].FieldName : Machine | |
$Object.Secret.Items[0].FieldName.Length : 7 | |
$Object.Secret.Items[0].IsFile : False | |
$Object.Secret.Items[0].IsNotes : False | |
$Object.Secret.Items[0].IsPassword : False | |
$Object.Secret.Items[0].FieldDisplayName : Machine | |
$Object.Secret.Items[0].FieldDisplayName.Length : 7 | |
$Object.Secret.Items[1].Value : REDACTED | |
$Object.Secret.Items[1].Value.Length : 13 | |
$Object.Secret.Items[1].Id : 18 | |
$Object.Secret.Items[1].FieldId : 86 | |
$Object.Secret.Items[1].FieldName : Username | |
$Object.Secret.Items[1].FieldName.Length : 8 | |
$Object.Secret.Items[1].IsFile : False | |
$Object.Secret.Items[1].IsNotes : False | |
$Object.Secret.Items[1].IsPassword : False | |
$Object.Secret.Items[1].FieldDisplayName : Username | |
$Object.Secret.Items[1].FieldDisplayName.Length : 8 | |
$Object.Secret.Items[2].Value : REDACTED | |
$Object.Secret.Items[2].Value.Length : 9 | |
$Object.Secret.Items[2].Id : 19 | |
$Object.Secret.Items[2].FieldId : 85 | |
$Object.Secret.Items[2].FieldName : Password | |
$Object.Secret.Items[2].FieldName.Length : 8 | |
$Object.Secret.Items[2].IsFile : False | |
$Object.Secret.Items[2].IsNotes : False | |
$Object.Secret.Items[2].IsPassword : True | |
$Object.Secret.Items[2].FieldDisplayName : Password | |
$Object.Secret.Items[2].FieldDisplayName.Length : 8 | |
$Object.Secret.Items[3].Value : REDACTED | |
$Object.Secret.Items[3].Value.Length : 55 | |
$Object.Secret.Items[3].Id : 20 | |
$Object.Secret.Items[3].FieldId : 84 | |
$Object.Secret.Items[3].FieldName : Notes | |
$Object.Secret.Items[3].FieldName.Length : 5 | |
$Object.Secret.Items[3].IsFile : False | |
$Object.Secret.Items[3].IsNotes : True | |
$Object.Secret.Items[3].IsPassword : False | |
$Object.Secret.Items[3].FieldDisplayName : Notes | |
$Object.Secret.Items[3].FieldDisplayName.Length : 5 | |
$Object.Secret.Id : 5 | |
$Object.Secret.SecretTypeId : 6003 | |
$Object.Secret.FolderId : 26 | |
$Object.Secret.IsWebLauncher : False | |
$Object.Secret.Active : True | |
$Object.Secret.CheckOutMinutesRemaining : | |
$Object.Secret.IsCheckedOut : | |
$Object.Secret.CheckOutUserDisplayName : | |
$Object.Secret.CheckOutUserDisplayName.Length : 0 | |
$Object.Secret.CheckOutUserId : | |
$Object.Secret.IsOutOfSync : | |
$Object.Secret.IsRestricted : False | |
$Object.Secret.OutOfSyncReason : | |
$Object.Secret.OutOfSyncReason.Length : 0 | |
$Object.Secret.SecretSettings : | |
$Object.Secret.SecretPermissions : | |
#> | |
#That's it! Now I know the basic composition. A varying number of 'items' describing properties of the secret, etc. | |
#I spend a few minutes and try to write a quick function with the data I expect: | |
Function Get-Secret | |
{ | |
<# | |
.SYNOPSIS | |
Get details on secrets from secret server | |
.DESCRIPTION | |
Get details on secrets from secret server | |
Code assumes you have win auth configured, URL should end like this: | |
winauthwebservices/sswinauthwebservice.asmx | |
Requires powershell 3 or later | |
.PARAMETER SearchTerm | |
String to search for. Accepts wildcards as '*'. | |
.PARAMETER As | |
Credential Build credential from stored domain (optional), username, password | |
PlainText Return password in ***plaintext*** | |
.PARAMETER uri | |
uri for your win auth web service. | |
Code assumes you have win auth configured, URL should end like this: | |
winauthwebservices/sswinauthwebservice.asmx | |
#> | |
[cmdletbinding()] | |
param( | |
[string]$SearchTerm = $null, | |
[validateset("Credential","PlainText")]$As = "Credential", | |
[string]$Uri = 'https://secretserver.FQDN/winauthwebservices/sswinauthwebservice.asmx' | |
) | |
#Windows Auth works. Uses SOAP | |
$proxy = New-WebServiceProxy -uri $Uri -UseDefaultCredential | |
#Find all passwords we have visibility to | |
#Secret server assumes a wild card match. filter this out at the end if the SearchTerm is not null | |
$AllSecrets = @( $proxy.SearchSecrets($SearchTerm,$false,$false).SecretSummaries ) | Where-Object { if($SearchTerm){ $_.SecretName -like $SearchTerm } else { $True } } | |
#Extract the secrets | |
foreach($Secret in $AllSecrets) | |
{ | |
#Start building up output | |
$Hash = [ordered]@{} | |
$Hash.SecretId = $Secret.SecretId | |
$Hash.SecretType = $Secret.SecretTypeName | |
#Items contains a collection of properties about the secret that can change based on the type of secret | |
$Items = $proxy.GetSecret($Secret.SecretId,$false, $null) | Select -ExpandProperty Secret | Select -ExpandProperty Items | |
foreach($Item in $Items) | |
{ | |
#If they want the credential, we convert to a secure string | |
if($Item.FieldName -like "Password" -and $As -notlike "PlainText") | |
{ | |
$password = $Item.Value | ConvertTo-SecureString -asPlainText -Force | |
$Hash.Add($Item.FieldName, $password) | |
} | |
else | |
{ | |
$Hash.Add($Item.FieldName, $Item.Value) | |
} | |
} | |
#If they want a credential, compose the username, create the credential | |
if($As -like "Credential" -and $Hash.Contains("Password") -and $Hash.Contains("Username")) | |
{ | |
if($Hash.Domain) | |
{ | |
$User = $Hash.Domain, $Hash.Username -join "\" | |
} | |
else | |
{ | |
if($Hash.Username -notlike "") | |
{ | |
$User = $Hash.Username | |
} | |
else | |
{ | |
$User = "NONE" | |
} | |
} | |
$Hash.Credential = New-Object System.Management.Automation.PSCredential($user,$password) | |
} | |
#Output | |
[pscustomobject]$Hash | |
} | |
$Proxy = $null | |
} | |
#Now call the function, see what we get! | |
Get-Secret -Uri $uri | |
<# | |
SecretId : 5 | |
SecretType : Windows Account | |
Machine : REDACTED | |
Username : REDACTED | |
Password : System.Security.SecureString | |
Notes : REDACTED | |
Credential : System.Management.Automation.PSCredential | |
SecretId : 3 | |
SecretType : Password | |
Server : REDACTED | |
Username : | |
Password : System.Security.SecureString | |
Notes : REDACTED | |
Credential : System.Management.Automation.PSCredential | |
SecretId : 6 | |
SecretType : SQL Server Account | |
Server : REDACTED | |
Username : REDACTED | |
Password : System.Security.SecureString | |
Notes : | |
Credential : System.Management.Automation.PSCredential | |
#> | |
#That's as far as I go until we get this purchase approved : ) | |
#I now have a function that requires no secrets or regularly updated credentials per running user/system (PSCredentials), i.e. http://ramblingcookiemonster.wordpress.com/2014/11/27/quick-hits-credentials-and-dynamic-parameters/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment