Skip to content

Commit cfd71e9

Browse files
committed
Land rapid7#19324, Add improvements to rcp_session lib
Updates rpc compatible modules to handle unknown sessions
2 parents 0e7b9d3 + 604227f commit cfd71e9

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

lib/msf/core/rpc/v10/rpc_session.rb

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -506,14 +506,18 @@ def rpc_meterpreter_directory_separator(sid)
506506
# @example Here's how you would use this from the client:
507507
# rpc.call('session.compatible_modules', 3)
508508
def rpc_compatible_modules(sid)
509-
session_type = self.framework.sessions[sid].type
510-
search_params = { 'session_type' => [[session_type], []] }
511-
cached_modules = Msf::Modules::Metadata::Cache.instance.find(search_params)
512-
509+
session = self.framework.sessions[sid]
513510
compatible_modules = []
514-
cached_modules.each do |cached_module|
515-
m = _find_module(cached_module.type, cached_module.fullname)
516-
compatible_modules << m.fullname if m.session_compatible?(sid)
511+
512+
if session
513+
session_type = session.type
514+
search_params = { 'session_type' => [[session_type], []] }
515+
cached_modules = Msf::Modules::Metadata::Cache.instance.find(search_params)
516+
517+
cached_modules.each do |cached_module|
518+
m = _find_module(cached_module.type, cached_module.fullname)
519+
compatible_modules << m.fullname if m.session_compatible?(sid)
520+
end
517521
end
518522

519523
{ "modules" => compatible_modules }

spec/lib/msf/core/rpc/v10/rpc_session_spec.rb

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,45 @@
11
# -*- coding:binary -*-
22
require 'spec_helper'
3+
require 'rex/post/meterpreter/extensions/stdapi/command_ids'
34

45
RSpec.describe Msf::RPC::RPC_Session do
56
include_context 'Msf::Simple::Framework'
67
include_context 'Metasploit::Framework::Spec::Constants cleaner'
78
include_context 'Msf::Framework#threads cleaner', verify_cleanup_required: false
89
include_context 'wait_for_expect'
910

11+
def command_ids_for(base_extension_command_id)
12+
(base_extension_command_id..base_extension_command_id+Rex::Post::Meterpreter::COMMAND_ID_RANGE).to_a
13+
end
14+
1015
def create_mock_session(klass)
1116
instance_double(
1217
klass,
1318
sid: target_sid,
14-
type: klass.type
19+
type: klass.type,
20+
)
21+
end
22+
23+
def create_mock_meterpreter_session(klass)
24+
new_klass_with_core_alias = Class.new(klass) do
25+
# This methods is dynamically registered on a real session; so we need to define it
26+
# upfront for instance_double to work
27+
def core
28+
nil
29+
end
30+
end
31+
instance = instance_double(
32+
new_klass_with_core_alias,
33+
sid: target_sid,
34+
type: klass.type,
35+
platform: 'linux',
36+
base_platform: 'linux',
37+
arch: ARCH_PYTHON,
38+
commands: command_ids_for(Rex::Post::Meterpreter::EXTENSION_ID_CORE) + command_ids_for(Rex::Post::Meterpreter::Extensions::Stdapi::EXTENSION_ID_STDAPI),
39+
ext: instance_double(Rex::Post::Meterpreter::ObjectAliasesContainer, aliases: []),
40+
core: instance_double(Rex::Post::Meterpreter::ClientCore, use: nil)
1541
)
42+
instance
1643
end
1744

1845
let(:service) { Msf::RPC::Service.new(framework) }
@@ -41,7 +68,7 @@ def create_mock_session(klass)
4168
instance_double(Rex::IO::Stream)
4269
end
4370

44-
let(:meterpreter_session) { create_mock_session(::Msf::Sessions::Meterpreter_x64_Win) }
71+
let(:meterpreter_session) { create_mock_meterpreter_session(::Msf::Sessions::Meterpreter_x64_Win) }
4572
let(:postgresql_session) { create_mock_session(::Msf::Sessions::PostgreSQL) }
4673
let(:shell_session) { create_mock_session(::Msf::Sessions::CommandShell) }
4774

@@ -131,6 +158,27 @@ def create_mock_session(klass)
131158
end
132159
end
133160

161+
describe '#rpc_compatible_modules' do
162+
context 'when the session does not exist' do
163+
let(:session) { meterpreter_session }
164+
165+
it 'returns an empty array' do
166+
expect(rpc.rpc_compatible_modules(-1)).to eq({ "modules" => [] })
167+
end
168+
end
169+
170+
context 'when the session exists' do
171+
let(:session) { meterpreter_session }
172+
173+
it 'returns compatible modules' do
174+
expected = {
175+
"modules" => array_including("auxiliary/cloud/kubernetes/enum_kubernetes")
176+
}
177+
expect(rpc.rpc_compatible_modules(target_sid)).to match(expected)
178+
end
179+
end
180+
end
181+
134182
describe '#rpc_meterpreter_read' do
135183
subject(:response) { rpc.rpc_meterpreter_read(target_sid) }
136184

0 commit comments

Comments
 (0)