Lucene search
K

Identify Queue Manager Name and MQ Version

🗓️ 28 Oct 2018 16:09:17Reported by Petros KoutroumpisType 
metasploit
 metasploit
🔗 www.rapid7.com👁 24 Views

Identify Queue Manager Name and MQ Version. This module helps to identify the name and version of an IBM MQ Queue Manager by running against its listening port

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

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Identify Queue Manager Name and MQ Version',
      'Description'    => 'Run this auxiliary against the listening port of an IBM MQ Queue Manager to identify its name and version. Any channel type can be used to get this information as long as the name of the channel is valid.',
      'Author'         => [ 'Petros Koutroumpis' ],
      'License'        => MSF_LICENSE
    ))
    register_options(
      [
        OptString.new('CHANNEL', [ true, "Channel to use" ,"SYSTEM.DEF.SVRCONN"]),
        OptInt.new('CONCURRENCY', [true, "The number of concurrent ports to check per host", 10]),
        OptInt.new('TIMEOUT', [true, "The socket connect timeout in seconds", 10]),
        OptString.new('PORTS', [true, 'Ports to probe', '1414']),

      ])
    deregister_options('RPORT')
  end


  def create_packet(channel_type)
    chan = datastore['CHANNEL'] + "\x20"*(20-datastore['CHANNEL'].length.to_i)
    if channel_type == 0
      chan_type = "\x26"
    elsif channel_type == 1
      chan_type = "\x07"
    elsif channel_type == 2
      chan_type = "\x08"
    end

    packet = "\x54\x53\x48\x20" + 		# StructID
    "\x00\x00\x01\x0c" + 			# MQSegmLen
    "\x02" + 					# ByteOrder
    "\x01" + 					# SegmType
    "\x01" + 					# CtlFlag1
    "\x00" + 					# CtlFlag2
    "\x00\x00\x00\x00\x00\x00\x00\x00" +	# LUW Ident
    "\x22\x02\x00\x00" + 			# Encoding
    "\xb5\x01" + 				# CCSID
    "\x00\x00" + 				# Reserved
    "\x49\x44\x20\x20" + 			# StructId
    "\x0d" + 					# FAP level
    chan_type + 				# CapFlag1 - Message Type
    "\x00" + 					# ECapFlag1
    "\x00" + 					# IniErrFlg1
    "\x00\x00" + 				# Reserved
    "\x32\x00" + 				# MaxMsgBtch
    "\xec\x7f\x00\x00" + 			# MaxTrSize
    "\x00\x00\x40\x00" + 			# MaxMsgSize
    "\xff\xc9\x9a\x3b" + 			# SeqWrapVal
    chan + 					# Channel Name
    "\x87" + 					# CapFlag2
    "\x00" + 					# ECapFlag2
    "\x5b\x01" +				# ccsid
    "QM1" + "\x20"*45 +			# Queue Manager Name
    "\x2c\x01\x00\x00" + 			# HBInterval
    "\x8a\x00" + 				# EFLLength
    "\x00" + 					# IniErrFlg2
    "\x55" + 					# Reserved1
    "\x00\xff" +				# HdrCprsLst
    "\x00\xff\xff\xff\xff\xff\xff\xff\xff" + 	# MsgCprsLst1
    "\xff\xff\xff\xff\xff\xff\xff" + 		# MsgCprsLst2
    "\x00\x00" + 				# Reserved2
    "\x00\x00\x00\x00" + 			# SSLKeyRst
    "\x00\x00\x00\x00" + 			# ConvBySkt
    "\x05" + 					# CapFlag3
    "\x00" + 					# ECapFlag3
    "\x00\x00" + 				# Reserved3
    "\x10\x13\x00\x00" + 			# ProcessId
    "\x01\x00\x00\x00" + 			# ThreadId
    "\x01\x00\x00\x00" + 			# TraceId
    "MQMM09000000" +		 		# ProdId
    "MQMID" + "\x20"*43 + 			# MQM ID
    "\x00\x00\xff\xff\xff\xff\xff\xff\xff" +	# Unknown1
    "\xff\xff\xff\xff\xff\xff\xff\xff\xff" + 	# Unknown2
    "\xff\xff\x00\x00\x00\x00\x00\x00\x00" + 	# Unknown3
    "\x00\x00\x00\x00\x00" 			# Unknown4
  end


  def run_host(ip)
    chan = datastore['CHANNEL']
    if chan.length > 20
      print_error("Channel name must be less than 20 characters.")
      raise Msf::OptionValidateError.new(['CHANNEL'])
    end
    ports = Rex::Socket.portspec_crack(datastore['PORTS'])
    while(ports.length > 0)
      t = []
      r = []
      begin
        1.upto(datastore['CONCURRENCY']) do
          this_port = ports.shift
          break if not this_port
          t << framework.threads.spawn("Module(#{self.refname})-#{ip}:#{this_port}", false, this_port) do |port|
            begin
                data_recv = ""
                3.times do |channel_type|
                  data_recv = send_packet(ip,port,channel_type)
                  if data_recv.nil?
                    next
                  end
                  # check if CHANNEL_WRONG_TYPE error received and retry with different type
                  if data_recv[data_recv.length-4...data_recv.length] != "\x02\x00\x00\x00"
                    break
                  end
                end
                if data_recv.nil?
                  print_status("No response received. Try increasing TIMEOUT value.")
                  print_line
                  next
                end
                status_code = data_recv[-4..-1]
                if status_code == "\x18\x00\x00\x00"
                  print_status("Channel Requires SSL. Could not get more information.")
                  print_line
                end
                if not data_recv[0...3].include?('TSH')
                  next
                end
                if status_code == "\x01\x00\x00\x00"
                  print_error('Channel "' + chan + '" does not exist.')
                  print_line
                end
                if status_code == "\x02\x00\x00\x00" or status_code == "\x06\x00\x00\x00"
                  print_error('Unsupported channel type. Try a different channel.')
                  print_line
                end
                if data_recv.length < 180
                  next
                end
                qm_name = data_recv[76...124].delete(' ')
                mq_version = data_recv[180...188].scan(/../).collect{|x| x.to_i}.join('.')
                print_good("#{ip}:#{port} - Queue Manager Name: #{qm_name} - MQ Version: #{mq_version}")
                print_line
            end
          end
        end
        t.each {|x| x.join }
      end
    end
  end

  def send_packet(ip,port,channel_type)
    begin
      timeout = datastore['TIMEOUT'].to_i
      packet = create_packet(channel_type)
      s = connect(false,
       {
         'RPORT' => port,
         'RHOST' => ip,
        }
      )
      s.put(packet)
      data = s.get_once(-1,timeout)
      return data
    rescue ::Rex::ConnectionRefused
      print_error("#{ip}:#{port} - TCP Port Closed.")
      print_line
    rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error, Errno::ECONNRESET
      print_error("#{ip}:#{port} - Connection Failed.")
      print_line
    rescue ::Interrupt
      raise $!
    ensure
      if s
        disconnect(s) rescue nil
      end
    end
  end

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

21 Nov 2018 22:09Current
6.7Medium risk
Vulners AI Score6.7
24