Skip to content

Commit

Permalink
fix time parsing, add command support
Browse files Browse the repository at this point in the history
fix search list, reduce duplicated code

testing added
  • Loading branch information
zgoldman-r7 committed Oct 4, 2023
1 parent d7abe5d commit 3f80f2d
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 36 deletions.
14 changes: 8 additions & 6 deletions lib/msf/base/serializer/readable_text.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: binary -*-


module Msf
module Serializer

Expand Down Expand Up @@ -834,6 +833,7 @@ def self.dump_datastore(name, ds, indent = DefaultIndent, col = DefaultColumnWra
def self.dump_sessions(framework, opts={})
output = ""
verbose = opts[:verbose] || false
session_ids = opts[:session_ids] || nil
show_active = opts[:show_active] || false
show_inactive = opts[:show_inactive] || false
# if show_active and show_inactive are false the caller didn't
Expand All @@ -859,8 +859,10 @@ def self.dump_sessions(framework, opts={})
'Header' => "Active sessions",
'Columns' => columns,
'Indent' => indent)
framework.sessions.each_sorted { |k|
session = framework.sessions[k]

framework.sessions.each { |k|
next unless session_ids.nil? || session_ids.include?(k[0])
session = k[1]
row = create_msf_session_row(session, show_extended)
tbl << row
}
Expand Down Expand Up @@ -979,16 +981,16 @@ def self.dump_sessions_verbose(framework, opts={})
out = "Active sessions\n" +
"===============\n\n"

if framework.sessions.length == 0 || (opts[:search] && opts[:ids].nil?)
if framework.sessions.length == 0
out << "No active sessions.\n"
return out
end

framework.sessions.each_sorted do |k|
session = framework.sessions[k]

if opts[:search]
unless opts[:ids].include? session.sid
if opts[:session_ids]
unless opts[:session_ids].include? session.sid
next
end
end
Expand Down
93 changes: 63 additions & 30 deletions lib/msf/ui/console/command_dispatcher/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@


require 'msf/core/opt_condition'

require 'optparse'

module Msf
Expand Down Expand Up @@ -1448,18 +1447,14 @@ def cmd_sessions(*args)
# any arguments that don't correspond to an option or option arg will
# be put in here
extra = []

if args.length == 1 && args[0] =~ /-?\d+/
method = 'interact'
sid = args[0].to_i
else
# Parse the command options
@@sessions_opts.parse(args) do |opt, idx, val|
@@sessions_opts.parse(args) do |opt, idx, val|
next if has_script_arguments
# if val == "--search" || val == '-S'
# matching_sessions = filter_sessions_by_search(args[-1])
# val = matching_sessions
# end

case opt
when "-q", "--quiet"
quiet = true
Expand Down Expand Up @@ -1507,6 +1502,7 @@ def cmd_sessions(*args)
# Search for specific session
when "-S", "--search"
search_term = val
# Display help banner
when "-h", "--help"
cmd_sessions_help
return false
Expand Down Expand Up @@ -1548,9 +1544,18 @@ def cmd_sessions(*args)
print_error("No command specified!")
return false
end
if search_term
matching_sessions = get_matching_sessions(search_term)
if matching_sessions == []
print_error("No matching sessions.")
return
end
end
cmds.each do |cmd|
if sid
sessions = session_list
elsif matching_sessions
sessions = matching_sessions
else
sessions = framework.sessions.keys.sort
end
Expand Down Expand Up @@ -1661,16 +1666,19 @@ def cmd_sessions(*args)
end
when 'killall'
if search_term
matching_sessions = []
terms = search_term.split
terms.each do |term|
matching_sessions << filter_sessions_by_search(term) if filter_sessions_by_search(term)
matching_sessions = get_matching_sessions(search_term)
if matching_sessions == []
print_status("No matching sessions.")
return
end
print_status("Killing matching sessions...")
else
matching_sessions = framework.sessions
print_status("Killing all sessions...")
end
print_status("Killing all sessions...")
framework.sessions.each_sorted.reverse_each do |s|
session = framework.sessions.get(s)
unless matching_sessions.nil? || matching_sessions.include?(session.sid.to_s)
matching_sessions.each do |s|
session = framework.sessions[s]
unless matching_sessions.nil? || matching_sessions.include?(session.sid)
next
end
if session
Expand Down Expand Up @@ -1774,8 +1782,15 @@ def cmd_sessions(*args)
end
end
when 'list', 'list_inactive', nil
if search_term
matching_sessions = get_matching_sessions(search_term)
if matching_sessions == []
print_error("No matching sessions.")
return
end
end
print_line
print(Serializer::ReadableText.dump_sessions(framework, show_active: show_active, show_inactive: show_inactive, show_extended: show_extended, verbose: verbose, search_term: search_term, ids: session_list, search: search))
print(Serializer::ReadableText.dump_sessions(framework, show_active: show_active, show_inactive: show_inactive, show_extended: show_extended, verbose: verbose, session_ids: matching_sessions))
print_line
when 'name'
if session_name.blank?
Expand Down Expand Up @@ -1814,10 +1829,23 @@ def cmd_sessions(*args)
true
end

def get_matching_sessions(search_term)
matching_sessions = []
terms = search_term.split
terms.each do |term|
matches = filter_sessions_by_search(term)
matches.each do |session|
matching_sessions << session.to_i if session
end
end
matching_sessions
end

def filter_sessions_by_search(search_term)
matching_sessions = []

framework.sessions.each do |session|
current_session = framework.sessions.get(session[0])
current_session = framework.sessions[session[0]]
next unless current_session
case search_term.split(":")[0]
when "last_checkin"
Expand All @@ -1830,8 +1858,7 @@ def filter_sessions_by_search(search_term)
matching_sessions << session[0].to_s if evaluate_search_criteria(current_session, search_term)
end
end
matching_sessions unless matching_sessions.length() == 1
matching_sessions[0]
matching_sessions
end

def evaluate_search_criteria(session, search_term)
Expand Down Expand Up @@ -1862,18 +1889,24 @@ def evaluate_search_criteria(session, search_term)
end

def parse_duration(duration)
case duration
when /(\d+)d/
return $1.to_i * 86400
when /(\d+)h/
return $1.to_i * 3600
when /(\d+)m/
return $1.to_i * 60
when /(\d+)s/
return $1.to_i
else
return 0
total_time = 0
time_tokens = duration.scan(/\d+/).zip(duration.scan(/[a-zA-Z]+/))
time_tokens.each do |pair|
raise "Please specify both time units and amounts" if pair[1].nil?
case pair[1]
when "d"
total_time = total_time + pair[0].to_i * 86400
when "h"
total_time = total_time + pair[0].to_i * 3600
when "m"
total_time = total_time + pair[0].to_i * 60
when "s"
total_time = total_time + pair[0].to_i
else
raise "Unrecognized time format"
end
end
return total_time
end

#
Expand Down
86 changes: 86 additions & 0 deletions spec/lib/msf/ui/console/command_dispatcher/core_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,90 @@ def set_tabs_test(option)
end
end
end

describe "#cmd_sessions" do
before(:each) do
allow(driver).to receive(:active_session=)

end

context "with no sessions" do
it "should show an empty table" do
core.cmd_sessions
expect(@output).to eq([
'Active sessions',
'===============',
'',
'No active sessions.'
])
end
end

context "filtering with search results" do
before do
allow(framework).to receive(:sessions).and_return(sessions)
allow(double "Session").to receive(:kill)
end

let(:sessions) do
{
1 => double('Session', last_checkin: Time.now, type: 'meterpreter', sid:1, sname: "sesh1", info: "info", session_host: "127.0.0.1", tunnel_to_s: "tunnel"),
2 => double('Session', last_checkin: (Time.now - 90), type: 'meterpreter', sid:2, sname: "sesh2", info: "info", session_host: "127.0.0.1", tunnel_to_s: "tunnel"),
3 => double('Session', last_checkin: Time.now, type: 'java', sid:3, sname: "sesh3", info: "info", session_host: "127.0.0.1", tunnel_to_s: "tunnel")
}
end

it "filters by session_id" do
core.cmd_sessions("--search", "session_id:2")
expect(@output.join("\n")).to match_table <<~TABLE
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
2 sesh2 meterpreter info tunnel (127.0.0.1)
TABLE
end

it "filters by last checkin" do
core.cmd_sessions("--search", "last_checkin:after:10s")
expect(@output.join("\n")).to match_table <<~TABLE
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
2 sesh2 meterpreter info tunnel (127.0.0.1)
TABLE
end

it "filters by session type" do
core.cmd_sessions("--search", "session_type:java")
expect(@output.join("\n")).to match_table <<~TABLE
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
3 sesh3 java info tunnel (127.0.0.1)
TABLE
end

it "Killall should not kill anything if nothing matches" do
core.cmd_sessions("--search", "session_id:5", "-K")
expect(@output).to eq([
'No matching sessions.'
])
end

it "Killall should kill only the specified session" do
expect(sessions[2]).to receive(:kill)
core.cmd_sessions("--search", "session_id:2", "-K")

expect(@output).to eq([
'Killing matching sessions...',
])
end
end
end
end

0 comments on commit 3f80f2d

Please sign in to comment.