metasploit-framework/spec/module_validation_spec.rb

228 lines
8.2 KiB
Ruby

RSpec.describe ModuleValidation::Validator do
let(:mod_class) { Msf::Exploit }
let(:mod_options) do
{
framework: framework,
name: 'Testing bad chars',
author: [
Msf::Author.new('Foobar'),
Msf::Author.new('Jim'),
Msf::Author.new('Bob')
],
license: MSF_LICENSE,
references: [Msf::Module::SiteReference.new('URL', 'https://example.com')],
rank_to_s: Msf::RankingName[Msf::ExcellentRanking],
rank: Msf::ExcellentRanking,
notes: {
'Stability' => [Msf::CRASH_SAFE],
'SideEffects' => [Msf::ARTIFACTS_ON_DISK],
'Reliability' => [Msf::FIRST_ATTEMPT_FAIL],
'AKA' => %w[SMBGhost CoronaBlue]
},
stability: [Msf::CRASH_SAFE],
side_effects: [Msf::ARTIFACTS_ON_DISK],
reliability: [Msf::FIRST_ATTEMPT_FAIL],
file_path: 'modules/exploits/windows/smb/cve_2020_0796_smbghost.rb',
type: 'exploit',
platform: Msf::Module::PlatformList.new(Msf::Module::Platform::Windows),
targets: [Msf::Module::Target.new('Windows 10 v1903-1909 x64', { 'Platform' => 'win', 'Arch' => ['x64'] })],
description: %q{
A vulnerability exists within the Microsoft Server Message Block 3.1.1 (SMBv3) protocol that can be leveraged to
execute code on a vulnerable server. This remove exploit implementation leverages this flaw to execute code
in the context of the kernel, finally yielding a session as NT AUTHORITY\SYSTEM in spoolsv.exe. Exploitation
can take a few minutes as the necessary data is gathered.
}
}
end
let(:framework) do
instance_double(Msf::Framework)
end
let(:mod) do
instance_double(mod_class, **mod_options)
end
subject { described_class.new(mod) }
describe '#errors' do
before(:each) do |example|
subject.validate unless example.metadata[:skip_before]
end
context 'when the module is valid' do
it 'has no errors' do
expect(subject.errors.full_messages).to be_empty
end
end
context 'when notes contains an invalid value' do
let(:mod_options) do
super().merge(notes: {
'Stability' => [Msf::CRASH_SAFE],
'SideEffects' => [Msf::ARTIFACTS_ON_DISK],
'Reliability' => [Msf::FIRST_ATTEMPT_FAIL],
'AKA' => %w[SMBGhost CoronaBlue],
'NOCVE' => 'Reason not given'
})
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Notes note value "NOCVE" must be an array, got "Reason not given"']
end
end
context 'when the stability rating contains an invalid value' do
let(:mod_options) do
super().merge(stability: ['CRASH_SAFE'], rank: Msf::GreatRanking, rank_to_s: 'great')
end
it 'has errors' do
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']
end
end
context 'when the stability rating contains an invalid values and an excellent ranking' do
let(:mod_options) do
super().merge(stability: [Msf::CRASH_SERVICE_RESTARTS])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Stability must have CRASH_SAFE value if module has an ExcellentRanking, instead found ["crash-service-restarts"]']
end
end
context 'when the side effects rating contains an invalid value' do
let(:mod_options) do
super().merge(side_effects: ['ARTIFACTS_ON_DISK'])
end
it 'has errors' do
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", "screen-effects", "audio-effects", "physical-effects"] is allowed']
end
end
context 'when the reliability rating contains an invalid value' do
let(:mod_options) do
super().merge(reliability: ['FIRST_ATTEMPT_FAIL'])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Reliability contains invalid values ["FIRST_ATTEMPT_FAIL"] - only ["first-attempt-fail", "repeatable-session", "unreliable-session"] is allowed']
end
end
context 'when the references contains an invalid value' do
let(:mod_options) do
super().merge(references: [
Msf::Module::SiteReference.new('url', 'https://example.com'),
Msf::Module::SiteReference.new('FOO', 'https://example.com'),
Msf::Module::SiteReference.new('NOCVE', 'Reason not given'),
Msf::Module::SiteReference.new('AKA', 'Foobar'),
])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq [
'References url is not valid, must be in ["CVE", "CWE", "BID", "MSB", "EDB", "US-CERT-VU", "ZDI", "URL", "WPVDB", "PACKETSTORM", "LOGO", "SOUNDTRACK", "OSVDB", "VTS", "OVE"]',
'References FOO is not valid, must be in ["CVE", "CWE", "BID", "MSB", "EDB", "US-CERT-VU", "ZDI", "URL", "WPVDB", "PACKETSTORM", "LOGO", "SOUNDTRACK", "OSVDB", "VTS", "OVE"]',
"References NOCVE please include NOCVE values in the 'notes' section, rather than in 'references'",
"References AKA please include AKA values in the 'notes' section, rather than in 'references'"
]
end
end
context 'when the license contains an invalid value' do
let(:mod_options) do
super().merge(license: 'MSF_LICENSE')
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['License must include a valid license']
end
end
context 'when the rank contains an invalid value' do
let(:mod_options) do
super().merge(rank: 'ExcellentRanking')
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Rank must include a valid module ranking']
end
end
context 'when the author is missing' do
let(:mod_options) do
super().merge(author: [])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ["Author can't be blank"]
end
end
context 'when the author contains bad characters' do
let(:mod_options) do
super().merge(author: [
Msf::Author.new('@Foobar'),
Msf::Author.new('Foobar')
])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Author must not include username handles, found "@Foobar". Try leaving it in a comment instead']
end
end
context 'when the module name contains bad characters' do
let(:mod_options) do
super().merge(name: 'Testing <> bad & chars')
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Name must not contain the characters &<>']
end
end
context 'when the module file path is not snake case' do
let(:mod_options) do
super().merge(file_path: 'modules/exploits/windows/smb/CVE_2020_0796_smbghost.rb')
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['File path must be snake case, instead found "modules/exploits/windows/smb/CVE_2020_0796_smbghost.rb"']
end
end
context 'when the description is missing' do
let(:mod_options) do
super().merge(description: nil)
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ["Description can't be blank"]
end
end
context 'when the platform value is invalid', skip_before: true do
let(:mod_options) do
super().merge(platform: Msf::Module::PlatformList.new('foo'))
end
it 'raises an ArgumentError' do
expect { subject }.to raise_error ArgumentError, 'No classes in Msf::Module::Platform for foo!'
end
end
context 'when the platform is missing and targets does not contain platform values' do
let(:mod_options) do
super().merge(platform: nil, targets: [Msf::Module::Target.new('Windows 10 v1903-1909 x64', { 'Arch' => ['x64'] })])
end
it 'has errors' do
expect(subject.errors.full_messages).to eq ['Platform must be included either within targets or platform module metadata']
end
end
end
end