Skip to content

Instantly share code, notes, and snippets.

@RamblingCookieMonster
Last active October 6, 2017 17:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save RamblingCookieMonster/efcdd93cbcbffded1567 to your computer and use it in GitHub Desktop.
Save RamblingCookieMonster/efcdd93cbcbffded1567 to your computer and use it in GitHub Desktop.
Fun with Thycotic Secret Server
<#
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