Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a mixin to get SPIP version and make use of it #19401

Merged
merged 3 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lib/msf/core/exploit/remote/http/spip.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: binary -*-

module Msf
module Exploit::Remote::HTTP::Spip

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super

register_options([
OptString.new('TARGETURI', [true, 'Path to Spip install', '/'])
])
end

# Determine Spip version
#
# @return [Rex::Version] Version as Rex::Version
def spip_version
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "spip.php")
)

return unless res

version = nil

version_string = res.get_html_document.at('head/meta[@name="generator"]/@content')&.text
if version_string =~ /SPIP (.*) /
version = ::Regexp.last_match(1)
end

if version.nil? && res.headers['Composed-By'] =~ /SPIP (.*) /
version = ::Regexp.last_match(1)
end

if version.nil?
return nil
end

return Rex::Version.new(version)
end

end
end
22 changes: 6 additions & 16 deletions modules/exploits/unix/webapp/spip_connect_exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Spip

def initialize(info = {})
super(update_info(info,
Expand Down Expand Up @@ -49,30 +50,19 @@ def initialize(info = {})
end

def check
version = nil
uri = normalize_uri(target_uri.path, "spip.php")

res = send_request_cgi({ 'uri' => "#{uri}" })

if res and res.code == 200 and res.body =~ /<meta name="generator" content="SPIP (.*) \[/
version = $1
end

if version.nil? and res.code == 200 and res.headers["Composed-By"] =~ /SPIP (.*) @/
version = $1
end
version = spip_version()

if version.nil?
return Exploit::CheckCode::Unknown
end

vprint_status("SPIP Version detected: #{version}")
print_status("SPIP Version detected: #{version}")

if version =~ /^2\.0/ and version < "2.0.21"
if version.between?(Rex::Version::new("2.0.0"), Rex::Version::new("2.0.21"))
return Exploit::CheckCode::Appears
elsif version =~ /^2\.1/ and version < "2.1.16"
elsif version.between?(Rex::Version::new("2.2.0"), Rex::Version::new("2.1.16"))
return Exploit::CheckCode::Appears
elsif version =~ /^3\.0/ and version < "3.0.3"
elsif version.between?(Rex::Version::new("3.0.0"), Rex::Version::new("3.0.03"))
return Exploit::CheckCode::Appears
end

Expand Down
41 changes: 12 additions & 29 deletions modules/exploits/unix/webapp/spip_rce_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::CmdStager
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HTTP::Spip

def initialize(info = {})
super(
Expand Down Expand Up @@ -83,38 +84,20 @@ def check
res = send_request_cgi({ 'uri' => uri.to_s })

return Exploit::CheckCode::Unknown('Target is unreachable.') unless res
return Exploit::CheckCode::Unknown("Target responded with unexpected HTTP response code: #{res.code}") unless res.code == 200

version_string = res.get_html_document.at('head/meta[@name="generator"]/@content')&.text
return Exploit::CheckCode::Unknown('Unable to find the version string on the page: spip.php') unless version_string =~ /SPIP (.*)/
rversion = spip_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

msf6 exploit(unix/webapp/spip_rce_form) > check http://127.0.0.1:8000

[-] Exploit failed: ArgumentError Malformed version number string SPIP 4.2.12
[-] 127.0.0.1:8000 - Check failed: The state could not be determined.

Seems like this is pulling out SPIP 4.2.12 for me in this module and Rex:Version does not like that
I replicated on the other module too, not sure if this is a version specific thing or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right, I didn't test the PR well enough. I just pushed some changes that should fix this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

msf6 exploit(unix/webapp/spip_rce_form) > check http://127.0.0.1:8000

[-] Exploit failed: ArgumentError Malformed version number string 4.2.12 @ www.spip.net +
[-] 127.0.0.1:8000 - Check failed: The state could not be determined.

getting a slightly different error now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused as why the regex (/SPIP (.*) /) doesn't match. I don't have a testing environment handy (holidays, yay!), but something like /SPIP ([0-9.]+) / might fix the issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want /SPIP (.*)/ seems like there was a rogue space messing things up

[7] pry(#<Msf::Modules::Exploit__Unix__Webapp__Spip_rce_form::MetasploitModule>)> version_string
=> "SPIP 4.2.12"
[8] pry(#<Msf::Modules::Exploit__Unix__Webapp__Spip_rce_form::MetasploitModule>)> version_string =~ /SPIP (.*) /
=> nil
[9] pry(#<Msf::Modules::Exploit__Unix__Webapp__Spip_rce_form::MetasploitModule>)> version_string =~ /SPIP (.*)/
=> 0
[10] pry(#<Msf::Modules::Exploit__Unix__Webapp__Spip_rce_form::MetasploitModule>)> ::Regexp.last_match(1)
=> "4.2.12"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! Care to fix it so this can land, or do you prefer to wait until I get back home?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do it no problem

Copy link
Contributor Author

@jvoisin jvoisin Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll owe your a beverage of your choice shall we ever meet in the meatspace then, tanks <3

return Exploit::CheckCode::Unknown('Unable to determine the version of SPIP') unless rversion

version = ::Regexp.last_match(1)
print_status("SPIP Version detected: #{rversion}")

if version.nil? && res.headers['Composed-By'] =~ /SPIP (.*) @/
version = ::Regexp.last_match(1)
end

return Exploit::CheckCode::Unknown('Unable to determine the version of SPIP') unless version

print_status("SPIP Version detected: #{version}")

rversion = Rex::Version.new(version)
if rversion >= Rex::Version.new('4.2.0')
if rversion < Rex::Version.new('4.2.1')
return Exploit::CheckCode::Appears
end
elsif rversion >= Rex::Version.new('4.1.0')
if rversion < Rex::Version.new('4.1.18')
return Exploit::CheckCode::Appears
end
elsif rversion >= Rex::Version.new('4.0.0')
if rversion < Rex::Version.new('4.0.10')
return Exploit::CheckCode::Appears
end
elsif rversion >= Rex::Version.new('3.2.0')
if rversion < Rex::Version.new('3.2.18')
return Exploit::CheckCode::Appears
end
if rversion.between?(Rex::Version.new('4.2.0'), Rex::Version.new('4.2.1'))
return Exploit::CheckCode::Appears
elsif rversion.between?(Rex::Version.new('4.1.0'), Rex::Version.new('4.1.18'))
return Exploit::CheckCode::Appears
elsif rversion.between?(Rex::Version.new('4.0.0'), Rex::Version.new('4.0.10'))
return Exploit::CheckCode::Appears
elsif rversion.between?(Rex::Version.new('3.2.0'), Rex::Version.new('3.2.18'))
return Exploit::CheckCode::Appears
end

return Exploit::CheckCode::Safe
Expand Down