GSoC/Meterpreter_Web_Console
h00die 2018-09-16 20:11:30 -04:00
commit ff5de7b81d
12 changed files with 192 additions and 45 deletions

View File

@ -125,10 +125,10 @@ GEM
docile (1.3.1)
erubis (2.7.0)
eventmachine (1.2.7)
factory_bot (4.11.0)
factory_bot (4.11.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.11.0)
factory_bot (~> 4.11.0)
factory_bot_rails (4.11.1)
factory_bot (~> 4.11.1)
railties (>= 3.0.0)
faker (1.9.1)
i18n (>= 0.7)
@ -188,7 +188,7 @@ GEM
nexpose (7.2.1)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
octokit (4.11.0)
octokit (4.12.0)
sawyer (~> 0.8.0, >= 0.5.3)
openssl-ccm (1.2.1)
openvas-omp (0.0.4)
@ -307,7 +307,7 @@ GEM
rspec-support (3.8.0)
ruby-macho (2.0.0)
ruby-rc4 (0.1.5)
ruby_smb (1.0.3)
ruby_smb (1.0.4)
bindata
rubyntlm
windows_error

View File

@ -89842,7 +89842,7 @@
"targets": [
"Windows 7 and Server 2008 R2 (x64) All Service Packs"
],
"mod_time": "2018-07-10 11:05:00 +0000",
"mod_time": "2018-08-29 23:53:58 +0000",
"path": "/modules/exploits/windows/smb/ms17_010_eternalblue.rb",
"is_install_path": true,
"ref_name": "windows/smb/ms17_010_eternalblue",

View File

@ -620,10 +620,12 @@ class ReadableText
'Indent' => indent,
'SortIndex' => 1)
framework.db.sessions.each do |session|
unless session.closed_at.nil?
row = create_mdm_session_row(session, show_extended)
tbl << row
if framework.db.active
framework.db.sessions.each do |session|
unless session.closed_at.nil?
row = create_mdm_session_row(session, show_extended)
tbl << row
end
end
end

View File

@ -373,11 +373,11 @@ class Exploit < Msf::Module
end
#
# Performs last-minute sanity checking of auxiliary parameters. This method
# Performs last-minute sanity checking of exploit parameters. This method
# is called during automated exploitation attempts and allows an
# auxiliary module to filter bad attempts, obtain more information, and choose
# better parameters based on the available data. Returning anything that
# evaluates to "false" will cause this specific auxiliary attempt to
# exploit to filter bad targets, obtain more information, and choose
# better targets based on the available data. Returning anything that
# evaluates to "false" will cause this specific exploit attempt to
# be skipped. This method can and will change datastore values and
# may interact with the backend database.
#

View File

@ -135,6 +135,19 @@ module Msf::Post::File
end
end
#
# See if +path+ on the remote system exists and is writable
#
# @param path [String] Remote path to check
#
# @return [Boolean] true if +path+ exists and is writable
#
def writable?(path)
raise "writable?' method does not support Windows systems" if session.platform == 'windows'
cmd_exec("test -w '#{path}' && echo true").to_s.include? 'true'
end
#
# Check for existence of +path+ on the remote file system
#

View File

@ -11,19 +11,12 @@ module Priv
# Returns true if running as root, false if not.
#
def is_root?
root_priv = false
user_id = cmd_exec("id -u")
clean_user_id = user_id.to_s.gsub(/[^\d]/,"")
unless clean_user_id.empty?
if clean_user_id =~ /^0$/
root_priv = true
elsif clean_user_id =~ /^\d*$/
root_priv = false
end
else
user_id = cmd_exec('id -u')
clean_user_id = user_id.to_s.gsub(/[^\d]/, '')
if clean_user_id.empty?
raise "Could not determine UID: #{user_id.inspect}"
end
return root_priv
(clean_user_id == '0')
end
end # Priv

View File

@ -11,12 +11,12 @@ module Priv
# Returns true if running as root, false if not.
#
def is_root?
root_priv = false
user_id = cmd_exec("/usr/xpg4/bin/id -u")
if user_id.to_i == 0
root_priv = true
clean_user_id = user_id.to_s.gsub(/[^\d]/, '')
if clean_user_id.empty?
raise "Could not determine UID: #{user_id.inspect}"
end
return root_priv
(clean_user_id == '0')
end
end # Priv

View File

@ -115,9 +115,9 @@ module System
#
def pidof(program)
pids = []
full = cmd_exec('ps aux').to_s
full = cmd_exec('ps -elf').to_s
full.split("\n").each do |pid|
pids << pid.split(' ')[1].to_i if pid.include? program
pids << pid.split(' ')[3].to_i if pid.include? program
end
pids
end

View File

@ -1200,6 +1200,10 @@ class Core
end
end
if show_inactive && !framework.db.active
print_warning("Database not connected; list of inactive sessions unavailable")
end
last_known_timeout = nil
# Now, perform the actual method

View File

@ -22,7 +22,7 @@ class Console::CommandDispatcher::Stdapi::Sys
#
@@execute_opts = Rex::Parser::Arguments.new(
"-a" => [ true, "The arguments to pass to the command." ],
"-c" => [ false, "Channelized I/O (required for interaction)." ],
"-c" => [ false, "Channelized I/O (required for interaction)." ], # -i sets -c
"-f" => [ true, "The executable command to run." ],
"-h" => [ false, "Help menu." ],
"-H" => [ false, "Create the process hidden from view." ],
@ -33,6 +33,14 @@ class Console::CommandDispatcher::Stdapi::Sys
"-k" => [ false, "Execute process on the meterpreters current desktop" ],
"-s" => [ true, "Execute process in a given session as the session user" ])
#
# Options used by the 'shell' command.
#
@@shell_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help menu." ],
"-l" => [ false, "List available shells (/etc/shells)." ],
"-t" => [ true, "Spawn a PTY shell (/bin/bash if no argument given)." ]) # ssh(1) -t
#
# Options used by the 'reboot' command.
#
@ -249,37 +257,149 @@ class Console::CommandDispatcher::Stdapi::Sys
[]
end
def cmd_shell_help
print_line 'Usage: shell [options]'
print_line
print_line 'Opens an interactive native shell.'
print_line @@shell_opts.usage
end
def cmd_shell_tabs(str, words)
return @@shell_opts.fmt.keys if words.length == 1
[]
end
#
# Drop into a system shell as specified by %COMSPEC% or
# as appropriate for the host.
#
def cmd_shell(*args)
use_pty = false
sh_path = '/bin/bash'
@@shell_opts.parse(args) do |opt, idx, val|
case opt
when '-h'
cmd_shell_help
return true
when '-l'
return false unless client.fs.file.exist?('/etc/shells')
begin
client.fs.file.open('/etc/shells') do |f|
print(f.read) until f.eof
end
rescue
return false
end
return true
when '-t'
use_pty = true
# XXX: No other options must follow
sh_path = val if val
end
end
case client.platform
when 'windows'
path = client.fs.file.expand_path("%COMSPEC%")
path = (path and not path.empty?) ? path : "cmd.exe"
path = client.fs.file.expand_path('%COMSPEC%')
path = (path && !path.empty?) ? path : 'cmd.exe'
# attempt the shell with thread impersonation
begin
cmd_execute("-f", path, "-c", "-H", "-i", "-t")
cmd_execute('-f', path, '-c', '-i', '-H', '-t')
rescue
# if this fails, then we attempt without impersonation
print_error( "Failed to spawn shell with thread impersonation. Retrying without it." )
cmd_execute("-f", path, "-c", "-H", "-i")
print_error('Failed to spawn shell with thread impersonation. Retrying without it.')
cmd_execute('-f', path, '-c', '-i', '-H')
end
when 'linux', 'osx'
if use_pty && pty_shell(sh_path)
return true
end
# Don't expand_path() this because it's literal anyway
path = "/bin/sh"
cmd_execute("-f", path, "-c", "-i")
cmd_execute('-f', '/bin/sh', '-c', '-i')
else
# Then this is a multi-platform meterpreter (php or java), which
# Then this is a multi-platform meterpreter (e.g., php or java), which
# must special-case COMSPEC to return the system-specific shell.
path = client.fs.file.expand_path("%COMSPEC%")
path = client.fs.file.expand_path('%COMSPEC%')
# If that failed for whatever reason, guess it's unix
path = (path and not path.empty?) ? path : "/bin/sh"
cmd_execute("-f", path, "-c", "-i")
path = (path && !path.empty?) ? path : '/bin/sh'
if use_pty && path == '/bin/sh' && pty_shell(sh_path)
return true
end
cmd_execute('-f', comspec, '-c', '-i')
end
end
#
# Spawn a PTY shell
#
def pty_shell(sh_path)
sh_path = client.fs.file.exist?(sh_path) ? sh_path : '/bin/sh'
# Python Meterpreter calls pty.openpty() - No need for other methods
if client.arch == 'python'
cmd_execute('-f', sh_path, '-c', '-i')
return true
end
# Check for the following in /usr{,/local}/bin:
# script
# python{,2,3}
# socat
# expect
paths = %w[
/usr/bin/script
/usr/bin/python
/usr/local/bin/python
/usr/bin/python2
/usr/local/bin/python2
/usr/bin/python3
/usr/local/bin/python3
/usr/bin/socat
/usr/local/bin/socat
/usr/bin/expect
/usr/local/bin/expect
]
# Select method for spawning PTY Shell based on availability on the target.
path = paths.find { |p| client.fs.file.exist?(p) }
return false unless path
# Commands for methods
cmd =
case path
when /script/
if client.platform == 'linux'
"#{path} -qc #{sh_path} /dev/null"
else
# script(1) invocation for BSD, OS X, etc.
"#{path} -q /dev/null #{sh_path}"
end
when /python/
"#{path} -c 'import pty; pty.spawn(\"#{sh_path}\")'"
when /socat/
# sigint isn't passed through yet
"#{path} - exec:#{sh_path},pty,sane,setsid,sigint,stderr"
when /expect/
"#{path} -c 'spawn #{sh_path}; interact'"
end
# "env TERM=xterm" provides colors, "clear" command, etc. as available on the target.
cmd.prepend('env TERM=xterm HISTFILE= ')
print_status(cmd)
cmd_execute('-f', cmd, '-c', '-i')
true
end
#
# Gets the process identifier that meterpreter is running in on the remote

View File

@ -47,6 +47,7 @@ module Shell
# Initialize the prompt
self.cont_prompt = ' > '
self.cont_flag = false
self.prompt = prompt
self.prompt_char = prompt_char
self.histfile = histfile

View File

@ -322,7 +322,7 @@ class MetasploitModule < Msf::Exploit::Remote
def smb1_anonymous_connect_ipc
sock = connect(false)
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, password: smb_pass)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, domain: smb_domain, password: smb_pass)
response_code = client.login
unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS
@ -365,7 +365,7 @@ class MetasploitModule < Msf::Exploit::Remote
def smb1_free_hole(start)
sock = connect(false)
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, password: smb_pass)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, domain: smb_domain, password: smb_pass)
client.negotiate
pkt = ""
@ -696,4 +696,18 @@ class MetasploitModule < Msf::Exploit::Remote
''
end
end
# Returns the value to be passed to SMB clients for
# the domain. If the user has not supplied a domain
# it returns an empty string to trigger an anonymous
# logon.
#
# @return [String] the domain value
def smb_domain
if datastore['SMBDomain'].present?
datastore['SMBDomain']
else
''
end
end
end