Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/module_validation_spec.rb
19534 views
1
RSpec.describe ModuleValidation::Validator do
2
let(:mod_class) { Msf::Exploit }
3
let(:mod_options) do
4
{
5
framework: framework,
6
name: 'Testing bad chars',
7
author: [
8
Msf::Author.new('Foobar'),
9
Msf::Author.new('Jim'),
10
Msf::Author.new('Bob')
11
],
12
license: MSF_LICENSE,
13
references: [Msf::Module::SiteReference.new('URL', 'https://example.com')],
14
rank_to_s: Msf::RankingName[Msf::ExcellentRanking],
15
rank: Msf::ExcellentRanking,
16
notes: {
17
'Stability' => [Msf::CRASH_SAFE],
18
'SideEffects' => [Msf::ARTIFACTS_ON_DISK],
19
'Reliability' => [Msf::FIRST_ATTEMPT_FAIL],
20
'AKA' => %w[SMBGhost CoronaBlue]
21
},
22
stability: [Msf::CRASH_SAFE],
23
side_effects: [Msf::ARTIFACTS_ON_DISK],
24
reliability: [Msf::FIRST_ATTEMPT_FAIL],
25
file_path: 'modules/exploits/windows/smb/cve_2020_0796_smbghost.rb',
26
type: 'exploit',
27
platform: Msf::Module::PlatformList.new(Msf::Module::Platform::Windows),
28
arch: [Rex::Arch::ARCH_X86],
29
targets: [Msf::Module::Target.new('Windows 10 v1903-1909 x64', { 'Platform' => 'win', 'Arch' => ['x64'] })],
30
description: %q{
31
A vulnerability exists within the Microsoft Server Message Block 3.1.1 (SMBv3) protocol that can be leveraged to
32
execute code on a vulnerable server. This remove exploit implementation leverages this flaw to execute code
33
in the context of the kernel, finally yielding a session as NT AUTHORITY\SYSTEM in spoolsv.exe. Exploitation
34
can take a few minutes as the necessary data is gathered.
35
}
36
}
37
end
38
let(:framework) do
39
instance_double(Msf::Framework)
40
end
41
42
let(:mod) do
43
instance_double(mod_class, **mod_options)
44
end
45
46
subject { described_class.new(mod) }
47
48
describe '#errors' do
49
before(:each) do |example|
50
subject.validate unless example.metadata[:skip_before]
51
end
52
53
context 'when the module is valid' do
54
it 'has no errors' do
55
expect(subject.errors.full_messages).to be_empty
56
end
57
end
58
59
context 'when notes contains an invalid value' do
60
let(:mod_options) do
61
super().merge(notes: {
62
'Stability' => [Msf::CRASH_SAFE],
63
'SideEffects' => [Msf::ARTIFACTS_ON_DISK],
64
'Reliability' => [Msf::FIRST_ATTEMPT_FAIL],
65
'AKA' => %w[SMBGhost CoronaBlue],
66
'NOCVE' => 'Reason not given'
67
})
68
end
69
70
it 'has errors' do
71
expect(subject.errors.full_messages).to eq ['Notes note value "NOCVE" must be an array, got "Reason not given"']
72
end
73
end
74
75
context 'when the stability rating contains an invalid value' do
76
let(:mod_options) do
77
super().merge(stability: ['CRASH_SAFE'], rank: Msf::GreatRanking, rank_to_s: 'great')
78
end
79
80
it 'has errors' do
81
expect(subject.errors.full_messages).to eq ['Stability contains invalid values ["CRASH_SAFE"] - only ["crash-safe", "crash-service-restarts", "crash-service-down", "crash-os-restarts", "crash-os-down", "service-resource-loss", "os-resource-loss"] is allowed']
82
end
83
end
84
85
context 'when the stability rating contains an invalid values and an excellent ranking' do
86
let(:mod_options) do
87
super().merge(stability: [Msf::CRASH_SERVICE_RESTARTS])
88
end
89
90
it 'has errors' do
91
expect(subject.errors.full_messages).to eq ['Stability must have CRASH_SAFE value if module has an ExcellentRanking, instead found ["crash-service-restarts"]']
92
end
93
end
94
95
context 'when the side effects rating contains an invalid value' do
96
let(:mod_options) do
97
super().merge(side_effects: ['ARTIFACTS_ON_DISK'])
98
end
99
100
it 'has errors' do
101
expect(subject.errors.full_messages).to eq ['Side effects contains invalid values ["ARTIFACTS_ON_DISK"] - only ["artifacts-on-disk", "config-changes", "ioc-in-logs", "account-lockouts", "account-logout", "screen-effects", "audio-effects", "physical-effects"] is allowed']
102
end
103
end
104
105
context 'when the reliability rating contains an invalid value' do
106
let(:mod_options) do
107
super().merge(reliability: ['FIRST_ATTEMPT_FAIL'])
108
end
109
110
it 'has errors' do
111
expect(subject.errors.full_messages).to eq ['Reliability contains invalid values ["FIRST_ATTEMPT_FAIL"] - only ["first-attempt-fail", "repeatable-session", "unreliable-session", "event-dependent"] is allowed']
112
end
113
end
114
115
context 'when the references contains an invalid value' do
116
let(:mod_options) do
117
super().merge(references: [
118
Msf::Module::SiteReference.new('url', 'https://example.com'),
119
Msf::Module::SiteReference.new('FOO', 'https://example.com'),
120
Msf::Module::SiteReference.new('NOCVE', 'Reason not given'),
121
Msf::Module::SiteReference.new('AKA', 'Foobar'),
122
Msf::Module::SiteReference.new('ATTACK', 'Foobar'),
123
])
124
end
125
126
it 'has errors' do
127
expect(subject.errors.full_messages).to eq [
128
"References url is not valid, must be in [\"ATT&CK\", \"CVE\", \"CWE\", \"BID\", \"MSB\", \"EDB\", \"US-CERT-VU\", \"ZDI\", \"URL\", \"WPVDB\", \"PACKETSTORM\", \"LOGO\", \"SOUNDTRACK\", \"OSVDB\", \"VTS\", \"OVE\"]",
129
"References FOO is not valid, must be in [\"ATT&CK\", \"CVE\", \"CWE\", \"BID\", \"MSB\", \"EDB\", \"US-CERT-VU\", \"ZDI\", \"URL\", \"WPVDB\", \"PACKETSTORM\", \"LOGO\", \"SOUNDTRACK\", \"OSVDB\", \"VTS\", \"OVE\"]",
130
"References NOCVE please include NOCVE values in the 'notes' section, rather than in 'references'",
131
"References AKA please include AKA values in the 'notes' section, rather than in 'references'",
132
"References ATTACK is not valid, must be in [\"ATT&CK\", \"CVE\", \"CWE\", \"BID\", \"MSB\", \"EDB\", \"US-CERT-VU\", \"ZDI\", \"URL\", \"WPVDB\", \"PACKETSTORM\", \"LOGO\", \"SOUNDTRACK\", \"OSVDB\", \"VTS\", \"OVE\"]"
133
]
134
end
135
end
136
137
context 'when the license contains an invalid value' do
138
let(:mod_options) do
139
super().merge(license: 'MSF_LICENSE')
140
end
141
142
it 'has errors' do
143
expect(subject.errors.full_messages).to eq ['License must include a valid license']
144
end
145
end
146
147
context 'when the rank contains an invalid value' do
148
let(:mod_options) do
149
super().merge(rank: 'ExcellentRanking')
150
end
151
152
it 'has errors' do
153
expect(subject.errors.full_messages).to eq ['Rank must include a valid module ranking']
154
end
155
end
156
157
context 'when the author is missing' do
158
let(:mod_options) do
159
super().merge(author: [])
160
end
161
162
it 'has errors' do
163
expect(subject.errors.full_messages).to eq ["Author can't be blank"]
164
end
165
end
166
167
context 'when the author contains bad characters' do
168
let(:mod_options) do
169
super().merge(author: [
170
Msf::Author.new('@Foobar'),
171
Msf::Author.new('Foobar')
172
])
173
end
174
175
it 'has errors' do
176
expect(subject.errors.full_messages).to eq ['Author must not include username handles, found "@Foobar". Try leaving it in a comment instead']
177
end
178
end
179
180
context 'when the module name contains bad characters' do
181
let(:mod_options) do
182
super().merge(name: 'Testing <> bad & chars')
183
end
184
185
it 'has errors' do
186
expect(subject.errors.full_messages).to eq ['Name must not contain the characters &<>']
187
end
188
end
189
190
context 'when the name has non-printable ascii characters' do
191
let(:mod_options) do
192
super().merge(name: 'Testing human-readable printable ascii characters ≤')
193
end
194
195
it 'has errors' do
196
expect(subject.errors.full_messages).to eq ['Name must only contain human-readable printable ascii characters']
197
end
198
end
199
200
context 'when the module file path is not snake case' do
201
let(:mod_options) do
202
super().merge(file_path: 'modules/exploits/windows/smb/CVE_2020_0796_smbghost.rb')
203
end
204
205
it 'has errors' do
206
expect(subject.errors.full_messages).to eq ['File path must be snake case, instead found "modules/exploits/windows/smb/CVE_2020_0796_smbghost.rb"']
207
end
208
end
209
210
context 'when the description is missing' do
211
let(:mod_options) do
212
super().merge(description: nil)
213
end
214
215
it 'has errors' do
216
expect(subject.errors.full_messages).to eq ["Description can't be blank"]
217
end
218
end
219
220
context 'when the description has non-printable ascii characters' do
221
let(:mod_options) do
222
super().merge(description: "Testing human-readable printable ascii characters ≤\n\tand newlines/tabs")
223
end
224
225
it 'has errors' do
226
expect(subject.errors.full_messages).to eq ['Description must only contain human-readable printable ascii characters, including newlines and tabs']
227
end
228
end
229
230
context 'when the platform value is invalid', skip_before: true do
231
let(:mod_options) do
232
super().merge(platform: Msf::Module::PlatformList.new('foo'))
233
end
234
235
it 'raises an ArgumentError' do
236
expect { subject }.to raise_error ArgumentError, 'No classes in Msf::Module::Platform for foo!'
237
end
238
end
239
240
context 'when the arch array contains a valid value' do
241
it 'has no errors' do
242
expect(subject.errors.full_messages).to be_empty
243
end
244
end
245
246
context 'when the arch array contains an invalid value' do
247
let(:mod_options) do
248
super().merge(arch: ["Rex::Arch::ARCH_X86"])
249
end
250
251
it 'has errors' do
252
expect(subject.errors.full_messages).to eq ["Arch contains invalid values [\"Rex::Arch::ARCH_X86\"] - only [\"x86\", \"x86_64\", \"x64\", \"mips\", \"mipsle\", \"mipsbe\", \"mips64\", \"mips64le\", \"ppc\", \"ppce500v2\", \"ppc64\", \"ppc64le\", \"cbea\", \"cbea64\", \"sparc\", \"sparc64\", \"armle\", \"armbe\", \"aarch64\", \"cmd\", \"php\", \"tty\", \"java\", \"ruby\", \"dalvik\", \"python\", \"nodejs\", \"firefox\", \"zarch\", \"r\", \"riscv32be\", \"riscv32le\", \"riscv64be\", \"riscv64le\", \"loongarch64\"] is allowed"]
253
end
254
end
255
256
context 'when the platform is missing and targets does not contain platform values' do
257
let(:mod_options) do
258
super().merge(platform: nil, targets: [Msf::Module::Target.new('Windows 10 v1903-1909 x64', { 'Arch' => ['x64'] })])
259
end
260
261
it 'has errors' do
262
expect(subject.errors.full_messages).to eq ['Platform must be included either within targets or platform module metadata']
263
end
264
end
265
266
context 'when the notes section contains sentinel values' do
267
let(:mod_options) do
268
new_module_options = {
269
notes: {
270
'Stability' => Msf::UNKNOWN_STABILITY,
271
'SideEffects' => Msf::UNKNOWN_SIDE_EFFECTS,
272
'Reliability' => Msf::UNKNOWN_RELIABILITY,
273
},
274
stability: Msf::UNKNOWN_STABILITY,
275
side_effects: Msf::UNKNOWN_SIDE_EFFECTS,
276
reliability: Msf::UNKNOWN_RELIABILITY,
277
}
278
super().merge(new_module_options)
279
end
280
281
it 'has no errors' do
282
expect(subject.errors.full_messages).to be_empty
283
end
284
end
285
286
context 'when the notes section contains in correct sentinel values' do
287
let(:mod_options) do
288
new_module_options = {
289
notes: {
290
'Stability' => [Msf::UNKNOWN_STABILITY],
291
'SideEffects' => [Msf::UNKNOWN_SIDE_EFFECTS],
292
'Reliability' => [Msf::UNKNOWN_RELIABILITY],
293
},
294
stability: [Msf::UNKNOWN_STABILITY],
295
side_effects: [Msf::UNKNOWN_SIDE_EFFECTS],
296
reliability: [Msf::UNKNOWN_RELIABILITY],
297
}
298
super().merge(new_module_options, rank: Msf::GreatRanking, rank_to_s: 'great')
299
end
300
301
it 'has errors' do
302
expect(subject.errors.full_messages).to eq [
303
"Stability contains invalid values [[\"unknown-stability\"]] - only [\"crash-safe\", \"crash-service-restarts\", \"crash-service-down\", \"crash-os-restarts\", \"crash-os-down\", \"service-resource-loss\", \"os-resource-loss\"] is allowed",
304
"Side effects contains invalid values [[\"unknown-side-effects\"]] - only [\"artifacts-on-disk\", \"config-changes\", \"ioc-in-logs\", \"account-lockouts\", \"account-logout\", \"screen-effects\", \"audio-effects\", \"physical-effects\"] is allowed",
305
"Reliability contains invalid values [[\"unknown-reliability\"]] - only [\"first-attempt-fail\", \"repeatable-session\", \"unreliable-session\", \"event-dependent\"] is allowed"
306
]
307
end
308
end
309
310
311
context 'when the references contains ATT&CK values' do
312
let(:mod_options) do
313
super().merge(references: [
314
Msf::Module::SiteReference.new('ATT&CK', 'T1059.001'),
315
Msf::Module::SiteReference.new('ATT&CK', 'BAD1059.001')
316
])
317
end
318
319
it 'has errors for invalid ATT&CK references' do
320
expect(subject.errors.full_messages).to eq ["References ATT&CK reference 'BAD1059.001' is invalid. Must start with one of [\"TA\", \"DS\", \"S\", \"M\", \"A\", \"G\", \"C\", \"T\"] and be followed by digits/periods, no whitespace."]
321
end
322
323
context 'with only valid ATT&CK references' do
324
let(:mod_options) do
325
super().merge(references: [Msf::Module::SiteReference.new('ATT&CK', 'T1059.001')])
326
end
327
328
it 'has no errors' do
329
expect(subject.errors.full_messages).to be_empty
330
end
331
end
332
end
333
end
334
end
335
336