Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/scanner/misc/ibm_mq_channel_brute.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary67include Msf::Exploit::Remote::Tcp8include Msf::Auxiliary::Scanner9include Msf::Auxiliary::Report1011def initialize12super(13'Name' => 'IBM WebSphere MQ Channel Name Bruteforce',14'Description' => 'This module uses a dictionary to bruteforce MQ channel names. For all identified channels it also returns if SSL is used and whether it is a server-connection channel.',15'Author' => 'Petros Koutroumpis',16'License' => MSF_LICENSE17)18register_options([19Opt::RPORT(1414),20OptInt.new('TIMEOUT', [true, "The socket connect timeout in seconds", 10]),21OptInt.new('CONCURRENCY', [true, "The number of concurrent channel names to check", 10]),22OptPath.new('CHANNELS_FILE',23[ true, "The file that contains a list of channel names"]24)])25end2627def create_packet(chan)28packet = "\x54\x53\x48\x20"+ # StructID29"\x00\x00\x01\x0c"+ # MQSegmLen30"\x02" + # Byte Order31"\x01" + # SegmType32"\x01" + # CtlFlag133"\x00" + # CtlFlag234"\x00\x00\x00\x00\x00\x00\x00\x00"+ # LUWIdent35"\x22\x02\x00\x00"+ # Encoding36"\xb5\x01" + # CCSID37"\x00\x00" + # Reserved38"\x49\x44\x20\x20" + # StructID39"\x0d" + # FAP Level40"\x26" + # CapFlag1 - Channel Type41"\x00" + # ECapFlag142"\x00" + # IniErrFlg143"\x00\x00" + # Reserved44"\x32\x00" + # MaxMsgBtch45"\xec\x7f\x00\x00" + # MaxTrSize46"\x00\x00\x40\x00" + # MaxMsgSize47"\xff\xc9\x9a\x3b" + # SegWrapVal48+ chan + # Channel name49"\x20" + # CapFlag250"\x20" + # ECapFlag251"\x20\x20" + # ccsid52"QM1" + "\x20"*45 + # Queue Manager Name53"\x20\x20\x20\x20" + # HBInterval54"\x20\x20" + # EFLLength55"\x20" + # IniErrFlg256"\x20" + # Reserved157"\x20\x20" + # HdrCprLst58"\x20\x20\x20\x20\x2c\x01\x00\x00"+ # MSGCprLst159"\x8a\x00\x00\x55\x00\xff\x00\xff"+ # MsgCprLst260"\xff\xff" + # Reserved261"\xff\xff\xff\xff" + # SSLKeyRst62"\xff\xff\xff\xff" + # ConvBySKt63"\xff" + # CapFlag364"\xff" + # ECapFlag365"\xff\xff" + # Reserved366"\x00\x00\x00\x00" + # ProcessId67"\x00\x00\x00\x00" + # ThreadId68"\x00\x00\x05\x00" + # TraceId69"\x00\x00\x10\x13\x00\x00" + # ProdId70"\x01\x00\x00\x00\x01\x00" + # ProdId71"MQMID" + "\x20"*43 + # MQM Id72"\x20\x20\x20\x20\x20\x20\x20\x20"+ # Unknown73"\x20\x20\x20\x20\x20\x20\x00\x00"+ # Unknown74"\xff\xff\xff\xff\xff\xff\xff\xff"+ # Unknown75"\xff\xff\xff\xff\xff\xff\xff\xff"+ # Unknown76"\xff\xff\x00\x00\x00\x00\x00\x00"+ # Unknown77"\x00\x00\x00\x00\x00\x00" # Unknown78end798081def run_host(ip)82@channels = []83@unencrypted_mqi_channels = []84begin85channel_list86rescue ::Rex::ConnectionRefused87fail_with(Failure::Unreachable, "TCP Port closed.")88rescue ::Rex::ConnectionError, ::IOError, ::Timeout::Error, Errno::ECONNRESET89fail_with(Failure::Unreachable, "Connection Failed.")90rescue ::Exception => e91fail_with(Failure::Unknown, e)92end93if(@channels.empty?)94print_status("#{ip}:#{rport} No channels found.")95else96print_good("Channels found: #{@channels}")97print_good("Unencrypted MQI Channels found: #{@unencrypted_mqi_channels}")98report_note(99:host => rhost,100:port => rport,101:type => 'mq.channels'102)103print_line104end105end106107def channel_list108channel_data = get_channel_names109while (channel_data.length > 0)110t = []111r = []112begin1131.upto(datastore['CONCURRENCY']) do114this_channel = channel_data.shift115if this_channel.nil?116next117end118t << framework.threads.spawn("Module(#{self.refname})-#{rhost}:#{rport}", false, this_channel) do |channel|119connect120vprint_status "#{rhost}:#{rport} - Sending request for #{channel}..."121if channel.length.to_i > 20122print_error("Channel names cannot exceed 20 characters. Skipping.")123next124end125chan = channel + "\x20"*(20-channel.length.to_i)126timeout = datastore['TIMEOUT'].to_i127s = connect(false,128{129'RPORT' => rport,130'RHOST' => rhost,131}132)133s.put(create_packet(chan))134data = s.get_once(-1,timeout)135if data.nil?136print_status("No response received. Try increasing timeout.")137next138end139if not data[0...3].include? 'TSH'140next141end142if data[-4..-1] == "\x01\x00\x00\x00" # NO_CHANNEL code143next144end145if data[-4..-1] == "\x18\x00\x00\x00" # CIPHER_SPEC code146print_status("Found channel: #{channel}, IsEncrypted: True, IsMQI: N/A")147elsif data[-4..-1] == "\x02\x00\x00\x00" # CHANNEL_WRONG_TYPE code148print_status("Found channel: #{channel}, IsEncrypted: False, IsMQI: False")149else150print_status("Found channel: #{channel}, IsEncrypted: False, IsMQI: True")151@unencrypted_mqi_channels << channel152end153@channels << channel154disconnect155end156end157t.each {|x| x.join }158end159end160end161162def get_channel_names163if(! @common)164File.open(datastore['CHANNELS_FILE'], "rb") do |fd|165data = fd.read(fd.stat.size)166@common = data.split(/\n/).compact.uniq167end168end169@common170end171172end173174175