diff --git a/lib/msf/http/wordpress/version.rb b/lib/msf/http/wordpress/version.rb index 0358d7cbbf..2e224acbb0 100644 --- a/lib/msf/http/wordpress/version.rb +++ b/lib/msf/http/wordpress/version.rb @@ -82,6 +82,25 @@ module Msf::HTTP::Wordpress::Version check_version_from_readme(:theme, theme_name, fixed_version, vuln_introduced_version) end + # Checks a custom file for a vulnerable version + # + # @param [String] uripath The relative path of the file + # @param [String] fixed_version Optional, the version the vulnerability was fixed in + # @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced + # + # @return [ Msf::Exploit::CheckCode ] + def check_version_from_custom_file(uripath, fixed_version = nil, vuln_introduced_version = nil) + res = send_request_cgi( + 'uri' => uripath, + 'method' => 'GET' + ) + + # file not found + return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200 + + return extract_and_check_version(res.body.to_s, :custom, 'custom file', fixed_version, vuln_introduced_version) + end + private def wordpress_version_helper(url, regex) @@ -149,6 +168,8 @@ module Msf::HTTP::Wordpress::Version # Example line: # Version: 1.5.2 version = body[/(?:Version):\s*([0-9a-z.-]+)/i, 1] + when :custom + version = body[/(?:Version):\s*([0-9a-z.-]+)/i, 1] else fail("Unknown file type #{type}") end diff --git a/spec/lib/msf/http/wordpress/version_spec.rb b/spec/lib/msf/http/wordpress/version_spec.rb index 6aeebfd397..1dc3b123fa 100644 --- a/spec/lib/msf/http/wordpress/version_spec.rb +++ b/spec/lib/msf/http/wordpress/version_spec.rb @@ -238,4 +238,92 @@ describe Msf::HTTP::Wordpress::Version do end end + + describe '#check_version_from_custom_file' do + before :each do + allow(subject).to receive(:send_request_cgi) do |opts| + res = Rex::Proto::Http::Response.new + res.code = wp_code + res.body = wp_body + res + end + end + + let(:wp_code) { 200 } + let(:wp_body) { nil } + let(:wp_path) { '/test/' } + let(:wp_fixed_version) { nil } + + context 'when no file is found' do + let(:wp_code) { 404 } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Unknown) } + end + + context 'when no version can be extracted from style' do + let(:wp_code) { 200 } + let(:wp_body) { 'invalid content' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Detected) } + end + + context 'when version from style has arbitrary leading whitespace' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_body) { 'Version: 1.0.0' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) } + let(:wp_body) { 'Version:1.0.0' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) } + end + + context 'when installed version is vulnerable' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_body) { 'Version: 1.0.0' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) } + end + + context 'when installed version is not vulnerable' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_body) { 'Version: 1.0.2' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Safe) } + end + + context 'when installed version is vulnerable (version range)' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.2' } + let(:wp_introd_version) { '1.0.0' } + let(:wp_body) { 'Version: 1.0.1' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Appears) } + end + + context 'when installed version is older (version range)' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_introd_version) { '1.0.0' } + let(:wp_body) { 'Version: 0.0.9' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Safe) } + end + + context 'when installed version is newer (version range)' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_introd_version) { '1.0.0' } + let(:wp_body) { 'Version: 1.0.2' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Safe) } + end + + context 'when installed version is newer (text in version number)' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.5.3' } + let(:wp_body) { 'Version: 2.0.0-beta1' } + it { expect(subject.send(:check_version_from_custom_file, wp_path, wp_fixed_version)).to be(Msf::Exploit::CheckCode::Safe) } + end + + context 'when all versions are vulnerable' do + let(:wp_code) { 200 } + let(:wp_body) { 'Version: 1.0.0' } + it { expect(subject.send(:check_version_from_custom_file, wp_path)).to be(Msf::Exploit::CheckCode::Appears) } + end + end + end