Lucene search

K

Huawei VRP Default Credentials (HTTP)

🗓️ 15 Apr 2020 00:00:00Reported by Copyright (C) 2020 Greenbone Networks GmbHType 
openvas
 openvas
🔗 plugins.openvas.org👁 66 Views

The remote Huawei Versatile Routing Platform (VRP) device is using known default credentials for the HTTP login. This issue may be exploited by a remote attacker to gain access to sensitive information or modify system configuration. The device is lacking a proper password configuration, making critical information and actions accessible for people with knowledge of the default credentials. Mitigation: Change the default password

Show more
Refs
Code
# Copyright (C) 2020 Greenbone Networks GmbH
# Some text descriptions might be excerpted from (a) referenced
# source(s), and are Copyright (C) by the respective right holder(s).
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

if(description)
{
  script_oid("1.3.6.1.4.1.25623.1.0.108746");
  script_version("2023-03-06T10:19:58+0000");
  script_tag(name:"cvss_base", value:"7.5");
  script_tag(name:"cvss_base_vector", value:"AV:N/AC:L/Au:N/C:P/I:P/A:P");
  script_tag(name:"last_modification", value:"2023-03-06 10:19:58 +0000 (Mon, 06 Mar 2023)");
  script_tag(name:"creation_date", value:"2020-04-15 08:04:09 +0000 (Wed, 15 Apr 2020)");
  script_category(ACT_ATTACK);
  script_copyright("Copyright (C) 2020 Greenbone Networks GmbH");
  script_family("Default Accounts");
  script_name("Huawei VRP Default Credentials (HTTP)");
  script_dependencies("gb_huawei_vrp_network_device_consolidation.nasl", "gb_default_credentials_options.nasl");
  script_require_ports("Services/www", 80);
  script_mandatory_keys("huawei/vrp/http/detected");
  script_exclude_keys("default_credentials/disable_default_account_checks");

  script_xref(name:"URL", value:"https://support.huawei.com/enterprise/en/doc/EDOC1000178166/1257fc63/what-is-the-default-login-password");
  script_xref(name:"URL", value:"https://support.huawei.com/enterprise/en/doc/EDOC1000060368/25506195/understanding-the-list-of-default-user-names-and-passwords");

  script_tag(name:"summary", value:"The remote Huawei Versatile Routing Platform (VRP) device is
  using known default credentials for the HTTP login.");

  script_tag(name:"impact", value:"This issue may be exploited by a remote attacker to gain access
  to sensitive information or modify system configuration.");

  script_tag(name:"insight", value:"The remote Huawei Versatile Routing Platform (VRP) device is
  lacking a proper password configuration, which makes critical information and actions accessible
  for people with knowledge of the default credentials.");

  script_tag(name:"vuldetect", value:"Tries to login using the default credentials: 'admin:admin',
  'root:admin', 'admin:[email protected]' or 'super:sp-admin'.");

  script_tag(name:"solution", value:"Change the default password.");

  script_tag(name:"solution_type", value:"Mitigation");
  script_tag(name:"qod_type", value:"remote_vul");

  exit(0);
}

if( get_kb_item( "default_credentials/disable_default_account_checks" ) )
  exit( 0 );

include("host_details.inc");
include("misc_func.inc");
include("http_func.inc");
include("http_keepalive.inc");
include("dump.inc");

# nb: Tested against:
# S5735-S24T4X with firmware V200R019C00SPC500
# AirEngine 5760-10 with firmware V200R019C00SPC300
# AR 6120 with firmware V300R019C00SPC300

CPE_PREFIX = "cpe:/o:huawei:";

if( ! infos = get_app_port_from_cpe_prefix( cpe:CPE_PREFIX, service:"www" ) )
  exit( 0 );

port = infos["port"];
CPE = infos["cpe"];

if( ! get_app_location( cpe:CPE, port:port, nofork:TRUE ) )
  exit( 0 );

# nb: All three tested devices responded with a 301 and one of the following URLs:
# /simple/view/login.html (S5735-S24T4X)
# /view/loginPro.html (AR 6120)
# /view/login.html (AirEngine 5760-10)
# This will be used later to choose the correct Cookie / URL and post data
res = http_get_cache( port:port, item:"/" );
if( ! res || res !~ "^HTTP/1\.[01] 301" )
  exit( 0 );

if( "/simple/view/login.html" >< res )
  type = 0;
else if( "/view/loginPro.html" >< res )
  type = 1;
else if( "/view/login.html" >< res )
  type = 2;
else
  type = 3; # unknown, various requests below will be used.

creds = make_list( "admin:[email protected]",
                   "admin:admin",
                   "root:admin",
                   "super:sp-admin" );

url = "/login.cgi";
headers = make_array( "Content-Type", "application/x-www-form-urlencoded" );

foreach cred( creds ) {

  split = split( cred, sep:":", keep:FALSE );
  if( max_index( split ) != 2 )
    continue;

  username = split[0];
  password = split[1];
  valid_login = FALSE;

  # nb: Used post data depends on the type of the Web-GUI implementation on specific devices (see comment above)
  if( type == 0 )
    post_data_list = make_list( "UserName=" + username + "&Password=" + password + "&Edition=0" );
  else if( type == 1 || type == 2 )
    post_data_list = make_list( "UserName=" + username + "&Password=" + password + "&LanguageType=0" );
  else
    post_data_list = make_list( "UserName=" + username + "&Password=" + password + "&LanguageType=0",
                                "UserName=" + username + "&Password=" + password + "&Edition=0" );

  foreach post_data( post_data_list ) {

    req = http_post_put_req( port:port, url:url, data:post_data, add_headers:headers );
    res = http_keepalive_send_recv( port:port, data:req );
    if( ! res )
      continue;

    # nb: When doing the request on 80/tcp (which is redirecting to 443/tcp) then we're
    # getting a HTTP/1.1 403 Forbidden back so we're exiting directly so that we're not
    # unnecessarily checking the other credentials.
    if( res =~ "^HTTP/1\.[01] 403" )
      exit( 0 );

    # For a failed login the ErrorMsg=1008 is thrown but still we're getting a 200 back
    # so we need to check both.
    # nb: If the post data doesn't match the Web-GUI implementation of a specific device
    # we're getting a 400 status code back with a single "Bad Request" string in the body.
    if( res !~ "^HTTP/1\.[01] 200" || "ErrorMsg=1008" >< res )
      continue;

    # nb: All tested devices are providing / returning such a SessionID
    sessionid = http_get_cookie_from_header( buf:res, pattern:"(SessionID=[^;]+;)" );
    if( ! sessionid )
      continue;

    body = http_extract_body_from_response( data:res );
    if( ! body )
      continue;

    # If the "type" is "3" and we're getting the correct response we don't want to continue
    # with a possible second request.
    valid_login = TRUE;
    break;
  }

  # nb: No need to continue if the requests above are not valid (e.g. wrong credentials).
  if( ! valid_login )
    continue;

  # The response should look like e.g. for a valid account on "type == 0" :
  # NoChangeFlag=0&Location=/simple/view/main/main.html&Token=Pjx6Bpwd0tO6i3ky0OPnDMNIhAlgYKdn
  # and the following if a change of a password was requested (two different possibilities):
  # ChangeFlag=2&Token=iJYPmuHUKwqu0Dj5KiMd3zAZileTD4Bz&AAAMsg=
  # ChangeFlag=1&Token=iJYPmuHUKwqu0Dj5KiMd3zAZileTD4Bz&AAAMsg=
  #
  # for the AirEngine 5760-10 and AR 6120 we're just getting a 0 back in the body and without
  # the Token extracted later for the other device.
  location = eregmatch( string:body, pattern:"Location=([^&]+)", icase:FALSE );
  if( ! location[1] && ( "ChangeFlag=2" >< body || "ChangeFlag=1" >< body ) ) {
    if( type == 0 )
      urls = make_list( "/simple/view/main/modifyPwd.html" );
    else if( type == 1 )
      urls = make_list( "/professional/view/main/modifyPwd.html" );
    else if( type == 2 )
      urls = make_list( "/view/main/modifyPwd.html" );
    else
      urls = make_list( "/simple/view/main/modifyPwd.html", "/professional/view/main/modifyPwd.html", "/view/main/modifyPwd.html" );
  } else if( ! location[1] ) {
    if( type == 0 )
      urls = make_list( "/simple/view/main/main.html" );
    else if( type == 1 )
      urls = make_list( "/professional/view/main/default.html" );
    else if( type == 2 )
      urls = make_list( "/view/main/default.html" );
    else
      urls = make_list( "/simple/view/main/main.html", "/professional/view/main/default.html", "/view/main/default.html" ); # Fallback
  } else {
    urls = make_list( location[1] );
  }

  # nb: This is optional and depends on the Web-GUI implementation (the token is sometimes embedded directly into the html code as a "tTag" variable).
  token = eregmatch( string:body, pattern:"Token=([^&]+)", icase:FALSE );

  # Cookie should look like e.g.:
  # Cookie: LSWlanguage=lsw_lang_en.js; icbs_language=en; UserName=username; loginFlag=true; SessionID=CLkd5brguZa1xcvRMMxnrvqOijjGaGRl; Token=Pjx6Bpwd0tO6i3ky0OPnDMNIhAlgYKdn
  # OR this (depending on the Web-GUI implementation):
  # Cookie: loginUrl=loginPro; FactoryName=Huawei%20Technologies%20Co.; FactoryLogoUrl=../../images/; Package=NO; SessionID=pVjCDX4LjfayMN2lHCWOsRMus9SKFImN; ResetFlag=0; loginFlag=true; ARlanguage=property-en_CN.js
  # OR even this:
  # Cookie: resetFlag=6; language=property-en_CN.js; SessionID=l0Q8NcxZo6aCaFhQM7XU2zPubSwgv0Wg; userName=username

  if( type == 0 ) {
    cookie = "LSWlanguage=lsw_lang_en.js; icbs_language=en; UserName=" + username + "; loginFlag=true; " + sessionid;
    if( token[1] )
      cookie += " Token=" + token[1];
    cookies = make_list( cookie );
  }
  else if( type == 1 )
    cookies = make_list( "loginUrl=loginPro; FactoryName=Huawei%20Technologies%20Co.; FactoryLogoUrl=../../images/; Package=NO; " + sessionid + " ResetFlag=0; loginFlag=true; ARlanguage=property-en_CN.js" );
  else if( type == 2 )
    cookies = make_list( "resetFlag=0; language=property-en_CN.js; " + sessionid + " userName=" + username );
  else
    cookies = make_list( "LSWlanguage=lsw_lang_en.js; icbs_language=en; UserName=" + username + "; loginFlag=true; " + sessionid + " " + token[1],
                         "loginUrl=loginPro; FactoryName=Huawei%20Technologies%20Co.; FactoryLogoUrl=../../images/; Package=NO; " + sessionid + " ResetFlag=0; loginFlag=true; ARlanguage=property-en_CN.js",
                         "resetFlag=0; language=property-en_CN.js; " + sessionid + " userName=" + username );

  foreach cookie( cookies ) {

    headers = make_array( "Cookie" , cookie );
    valid_creds = FALSE;

    foreach url( urls ) {
      url = url + "?language=en";
      if( type == 2 )
        url += "&pageid=" + rand_str( length:5, charset:"0123456789" );

      req = http_get_req( port:port, url:url, add_headers:headers );
      res = http_keepalive_send_recv( port:port, data:req );
      if( ! res || res !~ "^HTTP/1\.[01] 200" )
        continue;

      if( 'icbs_lang="LG.publicModule.equ_board"' >< res || 'icbs_lang="LG.tree.common_maintenance"' >< res || "Current User: " + username >< res ||
          '<span id="current_login_userName"' >< res || 'onclick="confirmLogout' >< res || "icbs_lang=LG.publicModule.languageBtn" >< res) {
        VULN = TRUE;
        valid_creds = TRUE;
        report += '\nUsername: "' + username + '", Password: "' + password + '", URL: "' + http_report_vuln_url( port:port, url:url, url_only:TRUE ) + '"';
        break;
      } else if( "'loginCaption' id='oldPasswordCaption'" >< res || "'loginCaption' id='newPasswordCaption'" >< res ) {
        VULN = TRUE;
        valid_creds = TRUE;
        report += '\nUsername: "' + username + '", Password: "' + password + '" (The system is enforcing a change of the current password), URL: "' + http_report_vuln_url( port:port, url:url, url_only:TRUE ) + '"';
        break;
      }
    }

    if( valid_creds ) {
      # nb: Some devices are only able to handle a few logins so we're logging the user out to avoid blocking situations.
      # messageID is generated like e.g. messageId=Math.round(randomFun(1)*1000); with an internal randomFun function but it seems every random number is good.
      # htmlID is saved in the HTML source code and incremented on each page request. For type == 0 this doesn't exist, for the other types see below.
      if( type == 0 ) {
        # nb: Cookie doesn't include the loginFlag and the Token, the Token is a separate Header field.
        headers = make_array( "Referer", http_report_vuln_url( port:port, url:url, url_only:TRUE ), "Content-Type", "application/x-www-form-urlencoded; text/xml; charset=UTF-8", "Token", token[1], "Cookie", "LSWlanguage=lsw_lang_en.js; icbs_language=en; UserName=" + username + "; " + sessionid );
        message_id = rand_str( length:3, charset:"0123456789" );
        post_data = 'MessageID=' + message_id + '&<rpc message-id="' + message_id + '" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\n<close-session/></rpc>]]>]]>';
        req = http_post_put_req( port:port, url:"/config.cgi", data:post_data, add_headers:headers );
        http_keepalive_send_recv( port:port, data:req );
      } else if( type == 1 ) {
        # nb: In this case the Cookie includes the loginFlag for some reason
        # We also need to extract the "Token" from a second page first
        # Cookie: loginUrl=loginPro; FactoryName=Huawei%20Technologies%20Co.; FactoryLogoUrl=../../images/; Package=NO; ResetFlag=0; loginFlag=true; ARlanguage=property-en_CN.js; SessionID=iWhQ4ihI0na7supa6EfMr9P9B1ZWDPZl
        req = http_get_req( port:port, url:"/professional/view/deviceSummary/equSummary.html", add_headers:headers );
        res = http_keepalive_send_recv( port:port, data:req );
        # tTag = "EL2Ycp6PH2al4LPS0GuSpYrilHZ9DTMD";
        token = eregmatch( string:res, pattern:'tTag = "([^"]+)";', icase:FALSE );
        headers = make_array( "Referer", http_report_vuln_url( port:port, url:url, url_only:TRUE ), "Content-Type", "application/x-www-form-urlencoded; text/xml; charset=UTF-8", "Token", token[1], "Cookie", cookie );
        message_id = rand_str( length:3, charset:"0123456789" );
        # See comment about htmlID above. We have two .html requests done so far so htmlID is 1001.
        post_data = 'htmlID=1001&MessageID=' + message_id + '&<rpc message-id="' + message_id + '" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\n<close-session/></rpc>]]>]]>';
        req = http_post_put_req( port:port, url:"/professional/view/main/config.cgi", data:post_data, add_headers:headers );
        http_keepalive_send_recv( port:port, data:req );
      } else if( type == 2 ) {
        token = eregmatch( string:res, pattern:'tTag = "([^"]+)";', icase:FALSE );
        headers = make_array( "Referer", http_report_vuln_url( port:port, url:url, url_only:TRUE ), "Content-Type", "application/x-www-form-urlencoded; text/xml; charset=UTF-8", "Token", token[1], "Cookie", cookie );
        message_id = rand_str( length:3, charset:"0123456789" );
        # See comment about htmlID above. We have one .html request done so far so htmlID is 1000.
        post_data = 'htmlID=1000&MessageID=' + message_id + '&<rpc message-id="' + message_id + '" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\n<close-session/></rpc>]]>]]>';
        req = http_post_put_req( port:port, url:"/config.cgi", data:post_data, add_headers:headers );
        http_keepalive_send_recv( port:port, data:req );
      }

      break;
    }
  }
}

if( VULN ) {
  report = 'It was possible to login with the following default credentials:\n' + report;
  security_message( port:port, data:report );
  exit( 0 );
}

exit( 99 );

Transform Your Security Services

Elevate your offerings with Vulners' advanced Vulnerability Intelligence. Contact us for a demo and discover the difference comprehensive, actionable intelligence can make in your security strategy.

Book a live demo