Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brocade post module and config eater #11927

Merged
merged 4 commits into from
Sep 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions documentation/modules/auxiliary/admin/brocade/brocade_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## General Notes

This module imports a Brocade configuration file into the database.
This is similar to `post/brocade/gather/enum_brocade` only access isn't required,
and assumes you already have the file.

Example files for import can be found on git, like [this](https://raw.githubusercontent.com/h00die/MSF-Testing-Scripts/master/brocade_08.0.30hT311_ic_icx6430.conf).

## Verification Steps

1. Have a Brocade configuration file
2. Start `msfconsole`
3. `use auxiliary/admin/brocade/brocade_config`
4. `set RHOST x.x.x.x`
5. `set CONFIG /tmp/file.config`
6. `run`

## Options

**RHOST**

Needed for setting services and items to. This is relatively arbitrary.

**CONFIG**

File path to the configuration file.

## Scenarios

```
msf5 > wget https://raw.githubusercontent.com/h00die/MSF-Testing-Scripts/master/brocade_08.0.30hT311_ic_icx6430.conf -o /dev/null -O /tmp/brocade.conf
msf5 > use auxiliary/admin/brocade/brocade_config
msf5 auxiliary(admin/brocade/brocade_config) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf5 auxiliary(admin/brocade/brocade_config) > set config /tmp/brocade.conf
config => /tmp/brocade.conf
msf5 auxiliary(admin/brocade/brocade_config) > run
[*] Running module against 127.0.0.1

[*] Importing config
[+] password-display is enabled, hashes will be displayed in config
[+] enable password hash $1$QP3H93Wm$uxYAs2HmAK0lQiP3ig5tm.
[+] User brocade of type 8 found with password hash $1$f/uxhovU$dST5lNskZCPQe/5QijULi0.
[+] ENCRYPTED SNMP community $MlVzZCFAbg== with permissions ro
[+] ENCRYPTED SNMP community $U2kyXj1k with permissions rw
[+] Config import successful
[*] Auxiliary module execution completed
```


93 changes: 93 additions & 0 deletions documentation/modules/post/brocade/gather/enum_brocade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
## Vulnerable Application

This module has been tested on the following hardware/OS combinations.

* Brocade ICX 6430-24
* Firmware: 08.0.20T311

The ICX config can be found [no passwords](https://github.com/h00die/MSF-Testing-Scripts/blob/master/brocade_icx6430_nopass.conf),
[hashes](https://github.com/h00die/MSF-Testing-Scripts/blob/master/brocade_icx6430_pass.conf)

This module will look for the follow parameters which contain credentials:

* FastIron
* `show configuration`

!!! keep in mind 'password-display' http://wwwaem.brocade.com/content/html/en/command-reference-guide/fastiron-08040-commandref/GUID-169889CD-1A74-4A23-AC78-38796692374F.html
!!! need to be able to give a password to enable

* super-user-password
* username
* SNMP

## Verification Steps

1. Start msfconsole
2. Get a shell
3. Do: ```use post/brocade/gather/enum_brocade```
4. Do: ```set session [id]```
5. Do: ```set verbose true```
6. Do: ```run```

## Scenarios

### ICX 6430-24, FastIron 08.0.20T311

#### SSH Session with password-display off

```
resource (brocade.rb)> use post/brocade/gather/enum_brocade
resource (brocade.rb)> set session 1
session => 1
resource (brocade.rb)> set verbose true
verbose => true
resource (brocade.rb)> run
[*] In a non-enabled cli
[*] Getting version information
[*] OS: 08.0.30hT311
[+] Version information stored in to loot /root/.msf4/loot/20190601203656_default_10.0.4.51_brocade.version_751557.txt
[*] Gathering info from show configuration
[!] password-display is disabled, no password hashes displayed in config
[*] Post module execution completed
```

#### SSH Session with Enable run

```
resource (brocade.rb)> use post/brocade/gather/enum_brocade
resource (brocade.rb)> set session 1
session => 1
resource (brocade.rb)> set verbose true
verbose => true
[*] In an enabled cli
[*] Getting version information
[*] OS: 08.0.30hT311
[+] Version information stored in to loot /root/.msf4/loot/20190601221921_default_10.0.4.51_brocade.version_839783.txt
[*] Gathering info from show configuration
[+] password-display is enabled, hashes will be displayed in config
[+] enable password hash $1$QP3H93Wm$uxYAs2HmAK0lQiP3ig5tm.
[+] User brocade of type 8 found with password hash $1$f/uxhovU$dST5lNskZCPQe/5QijULi0.
[+] ENCRYPTED SNMP community $MlVzZCFAbg== with permissions ro
[+] ENCRYPTED SNMP community $U2kyXj1k with permissions rw
[*] Post module execution completed
msf5 post(brocade/gather/enum_brocade) > loot

Loot
====

host service type name content info path
---- ------- ---- ---- ------- ---- ----
10.0.4.51 brocade.version version.txt text/plain Brocade Version /root/.msf4/loot/20190601221959_default_10.0.4.51_brocade.version_003751.txt
10.0.4.51 brocade.config config.txt text/plain Brocade Configuration /root/.msf4/loot/20190601222004_default_10.0.4.51_brocade.config_998514.txt

msf5 post(brocade/gather/enum_brocade) > creds
Credentials
===========

host origin service public private realm private_type
---- ------ ------- ------ ------- ----- ------------
10.0.4.51 10.0.4.51 22/tcp enable $1$QP3H93Wm$uxYAs2HmAK0lQiP3ig5tm. Nonreplayable hash
10.0.4.51 10.0.4.51 161/udp (snmp) $MlVzZCFAbg== Nonreplayable hash
10.0.4.51 10.0.4.51 161/udp (snmp) $U2kyXj1k Nonreplayable hash
10.0.4.51 10.0.4.51 22/tcp brocade $1$f/uxhovU$dST5lNskZCPQe/5QijULi0 Nonreplayable hash
```
6 changes: 6 additions & 0 deletions lib/metasploit/framework/login_scanner/ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ def gather_proof
# Juniper JunOS CLI
elsif proof =~ /unknown command: id/
proof = ssh_socket.exec!("show version\n").split("\n")[2..4].join(", ").to_s
# Brocade CLI
elsif proof =~ /Invalid input -> id/ || proof =~ /Protocol error, doesn't start with scp\!/
proof = ssh_socket.exec!("show version\n").to_s
if proof =~ /Version:(?<os_version>.+).+HW: (?<hardware>)/mi
proof = "Model: #{hardware}, OS: #{os_version}"
end
else
proof << ssh_socket.exec!("help\n?\n\n\n").to_s
end
Expand Down
128 changes: 128 additions & 0 deletions lib/msf/core/auxiliary/brocade.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# -*- coding: binary -*-
module Msf

###
#
# This module provides methods for working with Brocade equipment
#
###
module Auxiliary::Brocade
include Msf::Auxiliary::Report

def create_credential_and_login(opts={})
return nil unless active_db?

if self.respond_to?(:[]) and self[:task]
opts[:task_id] ||= self[:task].record.id
end

core = opts.fetch(:core, create_credential(opts))
access_level = opts.fetch(:access_level, nil)
last_attempted_at = opts.fetch(:last_attempted_at, nil)
status = opts.fetch(:status, Metasploit::Model::Login::Status::UNTRIED)

login_object = nil
retry_transaction do
service_object = create_credential_service(opts)
login_object = Metasploit::Credential::Login.where(core_id: core.id, service_id: service_object.id).first_or_initialize

if opts[:task_id]
login_object.tasks << Mdm::Task.find(opts[:task_id])
end

login_object.access_level = access_level if access_level
login_object.last_attempted_at = last_attempted_at if last_attempted_at
if status == Metasploit::Model::Login::Status::UNTRIED
if login_object.last_attempted_at.nil?
login_object.status = status
end
else
login_object.status = status
end
login_object.save!
end

login_object
end


def brocade_config_eater(thost, tport, config)
# this is for brocade type devices.
# It is similar to cisco
# Docs: enable password-display -> http://wwwaem.brocade.com/content/html/en/command-reference-guide/fastiron-08040-commandref/GUID-169889CD-1A74-4A23-AC78-38796692374F.html

credential_data = {
address: thost,
port: tport,
protocol: 'tcp',
workspace_id: myworkspace.id,
origin_type: :service,
service_name: '',
module_fullname: self.fullname,
status: Metasploit::Model::Login::Status::UNTRIED
}

store_loot('brocade.config', 'text/plain', thost, config.strip, 'config.txt', 'Brocade Configuration')

# Brocade has this one configuration called "password display". With it, we get hashes. With out it, just ...
if config =~ /enable password-display/
print_good('password-display is enabled, hashes will be displayed in config')
else
print_bad('password-display is disabled, no password hashes displayed in config')
end

# enable password
# Example lines:
# enable super-user-password 8 $1$QP3H93Wm$uxYAs2HmAK01QiP3ig5tm.
config.scan(/enable super-user-password 8 (?<admin_password_hash>.+)/i).each do |result|
admin_hash = result[0].strip
unless admin_hash == '.....'
print_good("enable password hash #{admin_hash}")
cred = credential_data.dup
cred[:username] = 'enable'
cred[:private_data] = admin_hash
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
end
end

# user account
# Example lines:
# username brocade password 8 $1$YBaHUWpr$PzeUrP0XmVOyVNM5rYy99/
config.scan(/username "?(?<user_name>[a-z0-9]+)"? password (?<user_type>\w+) (?<user_hash>[0-9a-z=\$\/]{34})/i).each do |result|
user_name = result[0].strip
user_type = result[1].strip
user_hash = result[2].strip
unless user_hash == '.....'
print_good("User #{user_name} of type #{user_type} found with password hash #{user_hash}.")
cred = credential_data.dup
cred[:username] = user_name
cred[:private_data] = user_hash
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
end
end

# snmp
# Example lines:
# snmp-server community 1 $Si2^=d rw
# these at times look base64 encoded, which they may be, but are also encrypted
config.scan(/snmp-server community (?<snmp_id>[\d]+) (?<snmp_community>.+) (?<snmp_permissions>rw|ro)/i).each do |result|
snmp_community = result[1].strip
snmp_permissions = result[2].strip
unless snmp_community == '.....'
print_good("#{'ENCRYPTED ' if snmp_community.start_with?('$')}SNMP community #{snmp_community} with permissions #{snmp_permissions}")
cred = credential_data.dup
cred[:protocol] = 'udp'
cred[:port] = 161
cred[:service_name] = 'snmp'
cred[:private_data] = snmp_community
cred[:private_type] = :nonreplayable_hash
create_credential_and_login(cred)
end
end

end
end
end

1 change: 1 addition & 0 deletions lib/msf/core/auxiliary/mixins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
require 'msf/core/auxiliary/rservices'
require 'msf/core/auxiliary/cisco'
require 'msf/core/auxiliary/juniper'
require 'msf/core/auxiliary/brocade'
require 'msf/core/auxiliary/kademlia'
require 'msf/core/auxiliary/llmnr'
require 'msf/core/auxiliary/mdns'
Expand Down
8 changes: 8 additions & 0 deletions lib/msf/core/module/platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,14 @@ class Unifi < Msf::Module::Platform
Alias = "unifi"
end

#
# Brocade
#
class Brocade < Msf::Module::Platform
Rank = 100
Alias = "brocade"
end

#
# Solaris
#
Expand Down
1 change: 1 addition & 0 deletions lib/msf/core/payload/uuid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Msf::Payload::UUID
25 => 'apple_ios',
26 => 'juniper',
27 => 'unifi',
28 => 'brocade',
}

# The raw length of the UUID structure
Expand Down
40 changes: 40 additions & 0 deletions modules/auxiliary/admin/brocade/brocade_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/auxiliary/brocade'

class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Brocade
def initialize(info={})
super( update_info( info,
'Name' => 'Brocade Configuration Importer',
'Description' => %q{
This module imports a Brocade device configuration.
},
'License' => MSF_LICENSE,
'Author' => [ 'h00die'],
))

register_options(
[
OptPath.new('CONFIG', [true, 'Path to configuration to import']),
Opt::RHOST(),
Opt::RPORT(22)
])

end

def run
unless ::File.exist?(datastore['CONFIG'])
fail_with Failure::BadConfig, "Brocade config file #{datastore['CONFIG']} does not exists!"
end
brocade_config = ::File.open(datastore['CONFIG'], "rb")
print_status('Importing config')
brocade_config_eater(datastore['RHOSTS'],datastore['RPORT'],brocade_config.read)
print_good('Config import successful')
end
end


Loading