CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/modules/auxiliary/scanner/ssh/ssh_login_spec.rb
Views: 1904
1
require 'rspec'
2
require 'metasploit/framework/login_scanner/ssh'
3
4
RSpec.describe 'SSH Login Check Scanner' do
5
include_context 'Msf::Simple::Framework#modules loading'
6
7
subject do
8
load_and_create_module(
9
module_type: 'auxiliary',
10
reference_name: 'scanner/ssh/ssh_login'
11
)
12
end
13
14
describe '#rport' do
15
it 'returns the defined RPORT option' do
16
subject.options.add_options([Msf::Opt::RPORT(99)])
17
subject.import_defaults(false)
18
19
expect(subject.rport).to eql 99
20
end
21
end
22
23
describe '#session_setup' do
24
let(:credential) do
25
Metasploit::Framework::Credential.new(private: password, public: username)
26
end
27
let(:datastore) { Msf::ModuleDataStoreWithFallbacks.new(subject) }
28
let(:host) { '10.10.10.10' }
29
let(:module_manager) { instance_double(Msf::ModuleManager) }
30
let(:password) { 'secret' }
31
let(:platform) { 'unifi' }
32
let(:proof) { 'this is the proof' }
33
let(:result) do
34
Metasploit::Framework::LoginScanner::Result.new(
35
credential: credential,
36
proof: proof
37
)
38
end
39
let(:scanner) do
40
instance_double(
41
Metasploit::Framework::LoginScanner::SSH,
42
ssh_socket: ssh_session,
43
get_platform: platform,
44
host: host
45
)
46
end
47
let(:session_manager) do
48
instance_double(Msf::SessionManager, register: nil)
49
end
50
let(:ssh_command_shell_bind) do
51
instance_double(
52
Msf::Sessions::SshCommandShellBind,
53
alive: true,
54
arch: nil,
55
exploit_datastore: datastore,
56
exploit_task: nil,
57
exploit_uuid: nil,
58
info: nil,
59
platform: platform,
60
register?: true,
61
rstream: ssh_commandstream,
62
session_host: host,
63
session_port: nil,
64
set_from_exploit: nil,
65
sid: nil,
66
tunnel_peer: nil,
67
type: nil,
68
username: nil,
69
uuid: nil,
70
via_exploit: nil,
71
via_payload: nil,
72
workspace: 'default'
73
).as_null_object.tap do |mock|
74
allow(mock).to receive(:kind_of?) { |args| args == Msf::Session }
75
end
76
end
77
let(:ssh_commandstream) { instance_double(Net::SSH::CommandStream) }
78
let(:ssh_session) do
79
instance_double(Net::SSH::Connection::Session, transport: transport_session)
80
end
81
let(:socket) do
82
double(Object)
83
end
84
let(:transport_session) do
85
instance_double(Net::SSH::Transport::Session).tap do |mock|
86
allow(mock).to receive(:socket).and_return(socket)
87
end
88
end
89
let(:username) { 'root' }
90
91
before(:each) do
92
allow(Msf::Sessions::SshCommandShellBind).to receive(:new).and_return(ssh_command_shell_bind)
93
# This is mocked as SessionManager appears to be directly or indirectly triggering the
94
# error for too many threads
95
allow(subject.framework).to receive(:sessions).and_return(session_manager)
96
end
97
98
it 'requests the platform from the scanner' do
99
expect(scanner).to receive(:get_platform).with(proof)
100
101
subject.session_setup(result, scanner)
102
end
103
104
it 'instantiates a SshCommandShellBind instance' do
105
expect(Msf::Sessions::SshCommandShellBind).to receive(:new).with(ssh_session)
106
107
subject.session_setup(result, scanner)
108
end
109
110
it 'configures the SshCommandShellBind instance' do
111
expect(ssh_command_shell_bind).to receive(:set_from_exploit).with(subject)
112
113
subject.session_setup(result, scanner)
114
end
115
116
it 'updates the exploit datastore for the session' do
117
subject.session_setup(result, scanner)
118
119
expect(datastore.search_for('USERNAME').value).to eql username
120
expect(datastore.search_for('PASSWORD').value).to eql password
121
end
122
123
it 'deletes the ssh session from the collection of sockets' do
124
subject.add_socket(ssh_commandstream)
125
126
subject.session_setup(result, scanner)
127
128
expect(subject.send(:sockets)).to be_empty
129
end
130
131
it 'registers the session' do
132
expect(session_manager).to receive(:register).with(ssh_command_shell_bind)
133
134
subject.session_setup(result, scanner)
135
end
136
137
it 'passes module datastore to bootstrap method of the SshCommandShellBind instance' do
138
expect(ssh_command_shell_bind).to receive(:bootstrap).with(subject.datastore)
139
140
subject.session_setup(result, scanner)
141
end
142
143
it 'processes any autoruns defined for the module' do
144
expect(ssh_command_shell_bind).to receive(:process_autoruns).with(subject.datastore)
145
146
subject.session_setup(result, scanner)
147
end
148
149
it 'registers the session open event' do
150
expect(ssh_command_shell_bind).to receive(:db_record=).with(an_instance_of(Mdm::Session))
151
152
subject.session_setup(result, scanner)
153
end
154
155
it 'deletes the ssh transport socket from the collection of sockets' do
156
subject.add_socket(socket)
157
158
subject.session_setup(result, scanner)
159
160
expect(subject.send(:sockets)).to be_empty
161
end
162
163
it 'sets the platform on the SshCommandShellBind instance' do
164
expect(ssh_command_shell_bind).to receive(:platform=).with(platform)
165
166
subject.session_setup(result, scanner)
167
end
168
169
it 'returns a SshCommandShellBind instance' do
170
expect(subject.session_setup(result, scanner)).to eql ssh_command_shell_bind
171
end
172
173
it 'reports the host' do
174
expect do
175
subject.session_setup(result, scanner)
176
end.to change(Mdm::Host, :count).by(1)
177
178
expect(Mdm::Host.last.os_name).to eql platform
179
end
180
181
context 'when scanner does not have an ssh connection' do
182
before(:each) do
183
allow(scanner).to receive(:ssh_socket).and_return(nil)
184
end
185
186
it 'returns nil' do
187
expect(subject.session_setup(result, scanner)).to be_nil
188
end
189
end
190
191
context 'when the scanner platform is set to `unknown`' do
192
let(:platform) { 'unknown' }
193
194
it 'does not set the os_name for the Host record' do
195
subject.session_setup(result, scanner)
196
197
expect(Mdm::Host.last.os_name).to be_nil
198
end
199
end
200
end
201
end
202
203