Skip to content

Commit 42d1fae

Browse files
author
RageLtMan
committed
Upstream console search additions and fixes
The -S flag for console commands, backed by search functionality in Rex' tables, originally pushed upstream in rapid7#1604 (iirc), lacks coverage for a number of commands which benefit a good deal from inline filtering of the potentially large number of results. Push more -S flags and surrounding table functionality upstream to provide coverage for the console commands included in framework. Include a fix for deleting hosts when DB references are a problem. Include a fix for the upstream route command wherein scope must be defined for the routing target by assuming a /32 without explicit definition. Note: With this in place, console behavior when filtering results is roughly analagous to the R7 filtering in web UI, which should help those of us trying to use both maintain corresponding workflows. Testing: Used in-house for years, though changes to the diff from upstream and our fork (expunging some internal code) are untested, so would appreciate eyes and hands on.
1 parent 9ce0bb9 commit 42d1fae

File tree

7 files changed

+150
-73
lines changed

7 files changed

+150
-73
lines changed

lib/msf/ui/console/command_dispatcher/core.rb

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class Core
5151
"-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ],
5252
"-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ],
5353
"-t" => [ true, "Set a response timeout (default: 15)" ],
54+
"-S" => [ true, "Row search filter." ],
5455
"-x" => [ false, "Show extended information in the session table" ])
5556

5657
@@threads_opts = Rex::Parser::Arguments.new(
@@ -85,6 +86,10 @@ class Core
8586
"-k" => [ true, "Keep (include) arg lines at start of output." ],
8687
"-c" => [ false, "Only print a count of matching lines." ])
8788

89+
@@search_opts = Rex::Parser::Arguments.new(
90+
"-h" => [ false, "Help banner." ],
91+
"-S" => [ true, "Row search filter." ])
92+
8893
@@history_opts = Rex::Parser::Arguments.new(
8994
"-h" => [ false, "Help banner." ],
9095
"-a" => [ false, "Show all commands in history." ],
@@ -95,7 +100,6 @@ class Core
95100
"-h" => [ false, "Help banner." ],
96101
"-e" => [ true, "Expression to evaluate." ])
97102

98-
99103
# Returns the list of commands supported by this command dispatcher
100104
def commands
101105
{
@@ -171,9 +175,6 @@ def cmd_color(*args)
171175
driver.update_prompt
172176
end
173177

174-
175-
176-
177178
def cmd_cd_help
178179
print_line "Usage: cd <directory>"
179180
print_line
@@ -869,10 +870,12 @@ def cmd_route(*args)
869870

870871
when "add", "remove", "del"
871872
subnet = args.shift
872-
netmask = nil
873-
if subnet
874-
subnet, cidr_mask = subnet.split("/")
875-
netmask = Rex::Socket.addr_ctoa(cidr_mask.to_i) if cidr_mask
873+
subnet,cidr_mask = subnet.split("/")
874+
if Rex::Socket.is_ipv4?(args.first)
875+
netmask = args.shift
876+
else
877+
cidr_mask = '32' if cidr_mask.nil?
878+
netmask = Rex::Socket.addr_ctoa(cidr_mask.to_i)
876879
end
877880

878881
netmask = args.shift if netmask.nil?
@@ -1074,7 +1077,6 @@ def cmd_save(*args)
10741077
print_line("Saved configuration to: #{Msf::Config.config_file}")
10751078
end
10761079

1077-
10781080
def cmd_spool_help
10791081
print_line "Usage: spool <off>|<filename>"
10801082
print_line
@@ -1139,6 +1141,7 @@ def cmd_sessions(*args)
11391141
script = nil
11401142
reset_ring = false
11411143
response_timeout = 15
1144+
search_term = nil
11421145

11431146
# any arguments that don't correspond to an option or option arg will
11441147
# be put in here
@@ -1151,53 +1154,58 @@ def cmd_sessions(*args)
11511154
# Parse the command options
11521155
@@sessions_opts.parse(args) do |opt, idx, val|
11531156
case opt
1154-
when '-q'
1157+
when "-q"
11551158
quiet = true
11561159
# Run a command on all sessions, or the session given with -i
1157-
when '-c'
1160+
when "-c"
11581161
method = 'cmd'
11591162
cmds << val if val
1160-
when '-C'
1163+
when "-C"
11611164
method = 'meterp-cmd'
11621165
cmds << val if val
1163-
when '-x'
1166+
when "-x"
11641167
show_extended = true
1165-
when '-v'
1168+
when "-v"
11661169
verbose = true
11671170
# Do something with the supplied session identifier instead of
11681171
# all sessions.
1169-
when '-i'
1172+
when "-i"
11701173
sid = val
11711174
# Display the list of active sessions
1172-
when '-l'
1175+
when "-l"
11731176
method = 'list'
1174-
when '-k'
1177+
when "-k"
11751178
method = 'kill'
11761179
sid = val || false
1177-
when '-K'
1180+
when "-K"
11781181
method = 'killall'
11791182
# Run a script on all meterpreter sessions
1180-
when '-s'
1183+
when "-s"
11811184
unless script
11821185
method = 'scriptall'
11831186
script = val
11841187
end
11851188
# Upload and exec to the specific command session
1186-
when '-u'
1189+
when "-u"
11871190
method = 'upexec'
11881191
sid = val || false
1192+
# Search for specific session
1193+
when "-S", "--search"
1194+
search_term = val
11891195
# Reset the ring buffer read pointer
1190-
when '-r'
1196+
when "-r"
11911197
reset_ring = true
11921198
method = 'reset_ring'
11931199
# Display help banner
1194-
when '-h'
1200+
when "-h"
11951201
cmd_sessions_help
11961202
return false
1197-
when '-t'
1203+
when "-t"
11981204
if val.to_s =~ /^\d+$/
11991205
response_timeout = val.to_i
12001206
end
1207+
when "-S", "--search"
1208+
search_term = val
12011209
else
12021210
extra << val
12031211
end
@@ -1463,7 +1471,7 @@ def cmd_sessions(*args)
14631471
end
14641472
when 'list',nil
14651473
print_line
1466-
print(Serializer::ReadableText.dump_sessions(framework, :show_extended => show_extended, :verbose => verbose))
1474+
print(Serializer::ReadableText.dump_sessions(framework, :show_extended => show_extended, :verbose => verbose, :search_term => search_term))
14671475
print_line
14681476
end
14691477

@@ -1952,7 +1960,6 @@ def cmd_unsetg_tabs(str, words)
19521960

19531961
alias cmd_unsetg_help cmd_unset_help
19541962

1955-
19561963
#
19571964
# Returns the revision of the framework and console library
19581965
#
@@ -2411,7 +2418,6 @@ def binary_install
24112418
return binary_paths.include? Msf::Config.install_root
24122419
end
24132420

2414-
24152421
#
24162422
# Returns an array of lines at the provided line number plus any before and/or after lines requested
24172423
# from all_lines by supplying the +before+ and/or +after+ parameters which are always positive

lib/msf/ui/console/command_dispatcher/creds.rb

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Creds
1515
include Msf::Ui::Console::CommandDispatcher
1616
include Metasploit::Credential::Creation
1717
include Msf::Ui::Console::CommandDispatcher::Common
18-
18+
1919
#
2020
# The dispatcher's name.
2121
#
@@ -31,11 +31,11 @@ def commands
3131
"creds" => "List all credentials in the database"
3232
}
3333
end
34-
34+
3535
def allowed_cred_types
3636
%w(password ntlm hash)
3737
end
38-
38+
3939
#
4040
# Returns true if the db is connected, prints an error and returns
4141
# false if not.
@@ -51,22 +51,55 @@ def active?
5151
end
5252
true
5353
end
54-
54+
55+
#
56+
# Miscellaneous option helpers
57+
#
58+
59+
# Parse +arg+ into a {Rex::Socket::RangeWalker} and append the result into +host_ranges+
60+
#
61+
# @note This modifies +host_ranges+ in place
62+
#
63+
# @param arg [String] The thing to turn into a RangeWalker
64+
# @param host_ranges [Array] The array of ranges to append
65+
# @param required [Boolean] Whether an empty +arg+ should be an error
66+
# @return [Boolean] true if parsing was successful or false otherwise
67+
def arg_host_range(arg, host_ranges, required=false)
68+
if (!arg and required)
69+
print_error("Missing required host argument")
70+
return false
71+
end
72+
begin
73+
rw = Rex::Socket::RangeWalker.new(arg)
74+
rescue
75+
print_error("Invalid host parameter, #{arg}.")
76+
return false
77+
end
78+
79+
if rw.valid?
80+
host_ranges << rw
81+
else
82+
print_error("Invalid host parameter, #{arg}.")
83+
return false
84+
end
85+
return true
86+
end
87+
5588
#
5689
# Can return return active or all, on a certain host or range, on a
5790
# certain port or range, and/or on a service name.
5891
#
5992
def cmd_creds(*args)
6093
return unless active?
61-
94+
6295
# Short-circuit help
6396
if args.delete "-h"
6497
cmd_creds_help
6598
return
6699
end
67-
100+
68101
subcommand = args.shift
69-
102+
70103
case subcommand
71104
when 'help'
72105
cmd_creds_help
@@ -79,7 +112,7 @@ def cmd_creds(*args)
79112
end
80113

81114
end
82-
115+
83116
#
84117
# TODO: this needs to be cleaned up to use the new syntax
85118
#
@@ -126,7 +159,7 @@ def cmd_creds_help
126159
print_line " creds add user:other hash:d19c32489b870735b5f587d76b934283"
127160
print_line " # Add a NonReplayableHash"
128161
print_line " creds add hash:d19c32489b870735b5f587d76b934283"
129-
162+
130163
print_line
131164
print_line "General options"
132165
print_line " -h,--help Show this help information"
@@ -156,7 +189,7 @@ def cmd_creds_help
156189
print_line " creds -d -s smb"
157190
print_line
158191
end
159-
192+
160193
# @param private_type [Symbol] See `Metasploit::Credential::Creation#create_credential`
161194
# @param username [String]
162195
# @param password [String]
@@ -168,35 +201,35 @@ def creds_add(*args)
168201
hsh[opt[0]] = opt[1..-1].join(':') # everything before the first : is the key, reasembling everything after the colon. why ntlm hashes
169202
hsh
170203
end
171-
204+
172205
begin
173206
params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name')
174207
rescue ArgumentError => e
175208
print_error(e.message)
176209
end
177-
210+
178211
# Verify we only have one type of private
179212
if params.slice('password','ntlm','ssh-key','hash').length > 1
180213
private_keys = params.slice('password','ntlm','ssh-key','hash').keys
181214
print_error("You can only specify a single Private type. Private types given: #{private_keys.join(', ')}")
182215
return
183216
end
184-
217+
185218
login_keys = params.slice('address','port','protocol','service-name')
186219
if login_keys.any? and login_keys.length < 3
187220
missing_login_keys = ['host','port','proto','service-name'] - login_keys.keys
188221
print_error("Creating a login requires a address, a port, and a protocol. Missing params: #{missing_login_keys}")
189222
return
190223
end
191-
224+
192225
data = {
193226
workspace_id: framework.db.workspace,
194227
origin_type: :import,
195228
filename: 'msfconsole'
196229
}
197-
230+
198231
data[:username] = params['user'] if params.key? 'user'
199-
232+
200233
if params.key? 'realm'
201234
if params.key? 'realm-type'
202235
if Metasploit::Model::Realm::Key::SHORT_NAMES.key? params['realm-type']
@@ -235,7 +268,7 @@ def creds_add(*args)
235268
data[:private_type] = :nonreplayable_hash
236269
data[:private_data] = params['hash']
237270
end
238-
271+
239272
begin
240273
if login_keys.any?
241274
data[:address] = params['address']
@@ -250,7 +283,7 @@ def creds_add(*args)
250283
print_error("Failed to add #{data['private_type']}: #{e}")
251284
end
252285
end
253-
286+
254287
def creds_search(*args)
255288
host_ranges = []
256289
origin_ranges = []
@@ -264,6 +297,7 @@ def creds_search(*args)
264297
cred_table_columns = [ 'host', 'origin' , 'service', 'public', 'private', 'realm', 'private_type' ]
265298
user = nil
266299
delete_count = 0
300+
search_term = nil
267301

268302
while (arg = args.shift)
269303
case arg
@@ -314,6 +348,8 @@ def creds_search(*args)
314348
return
315349
end
316350
arg_host_range(hosts, origin_ranges)
351+
when '-S', '--search-term'
352+
search_term = args.shift
317353
else
318354
# Anything that wasn't an option is a host to search for
319355
unless (arg_host_range(arg, host_ranges))
@@ -343,7 +379,8 @@ def creds_search(*args)
343379
svcs.flatten!
344380
tbl_opts = {
345381
'Header' => "Credentials",
346-
'Columns' => cred_table_columns
382+
'Columns' => cred_table_columns,
383+
'SearchTerm' => search_term
347384
}
348385

349386
tbl = Rex::Text::Table.new(tbl_opts)
@@ -481,8 +518,8 @@ def cmd_creds_tabs(str, words)
481518
end
482519
return tabs
483520
end
484-
485-
521+
522+
486523
end
487524

488525
end end end end

0 commit comments

Comments
 (0)